void bgp_srcdst_lookup(struct packet_ptrs *pptrs) { struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent, sa_local; struct xflow_status_entry *xs_entry = (struct xflow_status_entry *) pptrs->f_status; struct bgp_peer *peer; struct bgp_node *default_node, *result; struct bgp_info *info; struct prefix default_prefix; int peers_idx, compare_bgp_port; int follow_default = config.nfacctd_bgp_follow_default; struct in_addr pref4; #if defined ENABLE_IPV6 struct in6_addr pref6; #endif u_int32_t modulo, local_modulo, modulo_idx, modulo_max; u_int32_t peer_idx, *peer_idx_ptr; safi_t safi; rd_t rd; pptrs->bgp_src = NULL; pptrs->bgp_dst = NULL; pptrs->bgp_src_info = NULL; pptrs->bgp_dst_info = NULL; pptrs->bgp_peer = NULL; pptrs->bgp_nexthop_info = NULL; compare_bgp_port = FALSE; safi = SAFI_UNICAST; memset(&rd, 0, sizeof(rd)); if (pptrs->bta) { sa = &sa_local; if (pptrs->bta_af == ETHERTYPE_IP) { sa->sa_family = AF_INET; ((struct sockaddr_in *)sa)->sin_addr.s_addr = pptrs->bta; if (pptrs->lookup_bgp_port.set) { ((struct sockaddr_in *)sa)->sin_port = pptrs->lookup_bgp_port.n; compare_bgp_port = TRUE; } } #if defined ENABLE_IPV6 else if (pptrs->bta_af == ETHERTYPE_IPV6) { sa->sa_family = AF_INET6; ip6_addr_32bit_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &pptrs->bta, 0, 0, 1); ip6_addr_32bit_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &pptrs->bta2, 2, 0, 1); if (pptrs->lookup_bgp_port.set) { ((struct sockaddr_in6 *)sa)->sin6_port = pptrs->lookup_bgp_port.n; compare_bgp_port = TRUE; } } #endif } start_again: peer_idx = 0; peer_idx_ptr = NULL; if (xs_entry) { if (pptrs->l3_proto == ETHERTYPE_IP) { peer_idx = xs_entry->peer_v4_idx; peer_idx_ptr = &xs_entry->peer_v4_idx; } #if defined ENABLE_IPV6 else if (pptrs->l3_proto == ETHERTYPE_IPV6) { peer_idx = xs_entry->peer_v6_idx; peer_idx_ptr = &xs_entry->peer_v6_idx; } #endif } if (xs_entry && peer_idx) { if ((!sa_addr_cmp(sa, &peers[peer_idx].addr) || !sa_addr_cmp(sa, &peers[peer_idx].id)) && (!compare_bgp_port || !sa_port_cmp(sa, peers[peer_idx].tcp_port))) { peer = &peers[peer_idx]; pptrs->bgp_peer = (char *) &peers[peer_idx]; } /* If no match then let's invalidate the entry */ else { *peer_idx_ptr = 0; peer = NULL; } } else { for (peer = NULL, peers_idx = 0; peers_idx < config.nfacctd_bgp_max_peers; peers_idx++) { if ((!sa_addr_cmp(sa, &peers[peers_idx].addr) || !sa_addr_cmp(sa, &peers[peers_idx].id)) && (!compare_bgp_port || !sa_port_cmp(sa, peers[peer_idx].tcp_port))) { peer = &peers[peers_idx]; pptrs->bgp_peer = (char *) &peers[peers_idx]; if (xs_entry && peer_idx_ptr) *peer_idx_ptr = peers_idx; break; } } } if (peer) { struct host_addr peer_dst_ip; modulo = bgp_route_info_modulo(peer, NULL); // XXX: to be optimized if (config.bgp_table_per_peer_hash == BGP_ASPATH_HASH_PATHID) modulo_max = config.bgp_table_per_peer_buckets; else modulo_max = 1; if (peer->cap_add_paths && (config.acct_type == ACCT_NF || config.acct_type == ACCT_SF)) { /* administrativia */ struct pkt_bgp_primitives pbgp, *pbgp_ptr = &pbgp; memset(&pbgp, 0, sizeof(struct pkt_bgp_primitives)); /* note: call to [NF|SF]_peer_dst_ip_handler for the purpose of code re-use effectively is defeating the concept of libbgp */ if (config.acct_type == ACCT_NF) NF_peer_dst_ip_handler(NULL, pptrs, &pbgp_ptr); else if (config.acct_type == ACCT_SF) SF_peer_dst_ip_handler(NULL, pptrs, &pbgp_ptr); memcpy(&peer_dst_ip, &pbgp.peer_dst_ip, sizeof(struct host_addr)); } if (pptrs->bitr) { safi = SAFI_MPLS_VPN; memcpy(&rd, &pptrs->bitr, sizeof(rd)); } if (pptrs->l3_proto == ETHERTYPE_IP) { if (!pptrs->bgp_src) { memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_src, sizeof(struct in_addr)); pptrs->bgp_src = (char *) bgp_node_match_ipv4(bgp_routing_db->rib[AFI_IP][safi], &pref4, (struct bgp_peer *) pptrs->bgp_peer); } if (!pptrs->bgp_src_info && pptrs->bgp_src) { result = (struct bgp_node *) pptrs->bgp_src; if (result->p.prefixlen >= pptrs->lm_mask_src) { pptrs->lm_mask_src = result->p.prefixlen; pptrs->lm_method_src = NF_NET_BGP; } for (info = result->info[modulo]; info; info = info->next) { if (safi != SAFI_MPLS_VPN) { if (info->peer == peer) { pptrs->bgp_src_info = (char *) info; break; } } else { if (info->peer == peer && info->extra && !memcmp(&info->extra->rd, &rd, sizeof(rd_t))) { pptrs->bgp_src_info = (char *) info; break; } } } } if (!pptrs->bgp_dst) { memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr)); pptrs->bgp_dst = (char *) bgp_node_match_ipv4(bgp_routing_db->rib[AFI_IP][safi], &pref4, (struct bgp_peer *) pptrs->bgp_peer); } if (!pptrs->bgp_dst_info && pptrs->bgp_dst) { result = (struct bgp_node *) pptrs->bgp_dst; if (result->p.prefixlen >= pptrs->lm_mask_dst) { pptrs->lm_mask_dst = result->p.prefixlen; pptrs->lm_method_dst = NF_NET_BGP; } for (local_modulo = modulo, modulo_idx = 0; modulo_idx < modulo_max; local_modulo++, modulo_idx++) { for (info = result->info[local_modulo]; info; info = info->next) { if (info->peer == peer) { int no_match = FALSE; /* flagging additional checks are required */ if (safi == SAFI_MPLS_VPN) no_match++; if (peer->cap_add_paths) no_match++; if (safi == SAFI_MPLS_VPN) { if (info->extra && !memcmp(&info->extra->rd, &rd, sizeof(rd_t))) no_match--; } if (peer->cap_add_paths) { if (info->attr) { if (info->attr->mp_nexthop.family == peer_dst_ip.family) { if (!memcmp(&info->attr->mp_nexthop, &peer_dst_ip, HostAddrSz)) no_match--; } else if (info->attr->nexthop.s_addr && peer_dst_ip.family == AF_INET) { if (info->attr->nexthop.s_addr == peer_dst_ip.address.ipv4.s_addr) no_match--; } } } if (!no_match) { pptrs->bgp_dst_info = (char *) info; break; } } } /* if having results, let's not potentially look in other buckets */ if (pptrs->bgp_dst_info) break; } } } #if defined ENABLE_IPV6 else if (pptrs->l3_proto == ETHERTYPE_IPV6) { if (!pptrs->bgp_src) { memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_src, sizeof(struct in6_addr)); pptrs->bgp_src = (char *) bgp_node_match_ipv6(bgp_routing_db->rib[AFI_IP6][safi], &pref6, (struct bgp_peer *) pptrs->bgp_peer); } if (!pptrs->bgp_src_info && pptrs->bgp_src) { result = (struct bgp_node *) pptrs->bgp_src; if (result->p.prefixlen >= pptrs->lm_mask_src) { pptrs->lm_mask_src = result->p.prefixlen; pptrs->lm_method_src = NF_NET_BGP; } for (info = result->info[modulo]; info; info = info->next) { if (safi != SAFI_MPLS_VPN) { if (info->peer == peer) { pptrs->bgp_src_info = (char *) info; break; } } else { if (info->peer == peer && info->extra && !memcmp(&info->extra->rd, &rd, sizeof(rd_t))) { pptrs->bgp_src_info = (char *) info; break; } } } } if (!pptrs->bgp_dst) { memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr)); pptrs->bgp_dst = (char *) bgp_node_match_ipv6(bgp_routing_db->rib[AFI_IP6][safi], &pref6, (struct bgp_peer *) pptrs->bgp_peer); } if (!pptrs->bgp_dst_info && pptrs->bgp_dst) { result = (struct bgp_node *) pptrs->bgp_dst; if (result->p.prefixlen >= pptrs->lm_mask_dst) { pptrs->lm_mask_dst = result->p.prefixlen; pptrs->lm_method_dst = NF_NET_BGP; } for (local_modulo = modulo, modulo_idx = 0; modulo_idx < modulo_max; local_modulo++, modulo_idx++) { for (info = result->info[local_modulo]; info; info = info->next) { if (info->peer == peer) { int no_match = FALSE; /* flagging additional checks are required */ if (safi == SAFI_MPLS_VPN) no_match++; if (peer->cap_add_paths) no_match++; if (safi == SAFI_MPLS_VPN) { if (info->extra && !memcmp(&info->extra->rd, &rd, sizeof(rd_t))) no_match--; } if (peer->cap_add_paths) { if (info->attr) { if (info->attr->mp_nexthop.family == peer_dst_ip.family) { if (!memcmp(&info->attr->mp_nexthop, &peer_dst_ip, HostAddrSz)) no_match--; } } } if (!no_match) { pptrs->bgp_dst_info = (char *) info; break; } } } /* if having results, let's not potentially look in other buckets */ if (pptrs->bgp_dst_info) break; } } } #endif if (follow_default && safi != SAFI_MPLS_VPN) { default_node = NULL; if (pptrs->l3_proto == ETHERTYPE_IP) { memset(&default_prefix, 0, sizeof(default_prefix)); default_prefix.family = AF_INET; result = (struct bgp_node *) pptrs->bgp_src; if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; pptrs->bgp_src = NULL; pptrs->bgp_src_info = NULL; } result = (struct bgp_node *) pptrs->bgp_dst; if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; pptrs->bgp_dst = NULL; pptrs->bgp_dst_info = NULL; } } #if defined ENABLE_IPV6 else if (pptrs->l3_proto == ETHERTYPE_IPV6) { memset(&default_prefix, 0, sizeof(default_prefix)); default_prefix.family = AF_INET6; result = (struct bgp_node *) pptrs->bgp_src; if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; info = result->info[modulo]; pptrs->bgp_src = NULL; pptrs->bgp_src_info = NULL; } result = (struct bgp_node *) pptrs->bgp_dst; if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; info = result->info[local_modulo]; pptrs->bgp_dst = NULL; pptrs->bgp_dst_info = NULL; } } #endif if (!pptrs->bgp_src || !pptrs->bgp_dst) { follow_default--; compare_bgp_port = FALSE; // XXX: fixme: follow default in NAT traversal scenarios if (default_node) { if (info && info->attr) { if (info->attr->mp_nexthop.family == AF_INET) { sa = &sa_local; memset(sa, 0, sizeof(struct sockaddr)); sa->sa_family = AF_INET; memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->mp_nexthop.address.ipv4, 4); goto start_again; } #if defined ENABLE_IPV6 else if (info->attr->mp_nexthop.family == AF_INET6) { sa = &sa_local; memset(sa, 0, sizeof(struct sockaddr)); sa->sa_family = AF_INET6; ip6_addr_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &info->attr->mp_nexthop.address.ipv6); goto start_again; } #endif else { sa = &sa_local; memset(sa, 0, sizeof(struct sockaddr)); sa->sa_family = AF_INET; memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->nexthop, 4); goto start_again; } } } } } if (config.nfacctd_bgp_follow_nexthop[0].family && pptrs->bgp_dst && safi != SAFI_MPLS_VPN) bgp_follow_nexthop_lookup(pptrs); } }
void bgp_srcdst_lookup(struct packet_ptrs *pptrs, int type) { struct bgp_misc_structs *bms; struct bgp_rt_structs *inter_domain_routing_db; struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent, sa_local; struct xflow_status_entry *xs_entry = (struct xflow_status_entry *) pptrs->f_status; struct bgp_peer *peer; struct bgp_node *default_node, *result; struct bgp_info *info; struct node_match_cmp_term2 nmct2; struct prefix default_prefix; int compare_bgp_port; int follow_default = config.nfacctd_bgp_follow_default; struct in_addr pref4; #if defined ENABLE_IPV6 struct in6_addr pref6; #endif safi_t safi; rd_t rd; bms = bgp_select_misc_db(type); inter_domain_routing_db = bgp_select_routing_db(type); if (!bms || !inter_domain_routing_db) return; pptrs->bgp_src = NULL; pptrs->bgp_dst = NULL; pptrs->bgp_src_info = NULL; pptrs->bgp_dst_info = NULL; pptrs->bgp_peer = NULL; pptrs->bgp_nexthop_info = NULL; compare_bgp_port = FALSE; safi = SAFI_UNICAST; memset(&rd, 0, sizeof(rd)); if (pptrs->bta || pptrs->bta2) { sa = &sa_local; if (pptrs->bta_af == ETHERTYPE_IP) { sa->sa_family = AF_INET; ((struct sockaddr_in *)sa)->sin_addr.s_addr = pptrs->bta; if (pptrs->lookup_bgp_port.set) { ((struct sockaddr_in *)sa)->sin_port = pptrs->lookup_bgp_port.n; compare_bgp_port = TRUE; } } #if defined ENABLE_IPV6 else if (pptrs->bta_af == ETHERTYPE_IPV6) { sa->sa_family = AF_INET6; ip6_addr_32bit_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &pptrs->bta, 0, 0, 1); ip6_addr_32bit_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &pptrs->bta2, 2, 0, 1); if (pptrs->lookup_bgp_port.set) { ((struct sockaddr_in6 *)sa)->sin6_port = pptrs->lookup_bgp_port.n; compare_bgp_port = TRUE; } } #endif } start_again_follow_default: peer = bms->bgp_lookup_find_peer(sa, xs_entry, pptrs->l3_proto, compare_bgp_port); pptrs->bgp_peer = (char *) peer; if (peer) { struct host_addr peer_dst_ip; memset(&peer_dst_ip, 0, sizeof(peer_dst_ip)); if (peer->cap_add_paths && (config.acct_type == ACCT_NF || config.acct_type == ACCT_SF)) { /* administrativia */ struct pkt_bgp_primitives pbgp, *pbgp_ptr = &pbgp; memset(&pbgp, 0, sizeof(struct pkt_bgp_primitives)); /* note: call to [NF|SF]_peer_dst_ip_handler for the purpose of code re-use effectively is defeating the concept of libbgp */ if (config.acct_type == ACCT_NF) NF_peer_dst_ip_handler(NULL, pptrs, (char **)&pbgp_ptr); else if (config.acct_type == ACCT_SF) SF_peer_dst_ip_handler(NULL, pptrs, (char **)&pbgp_ptr); memcpy(&peer_dst_ip, &pbgp.peer_dst_ip, sizeof(struct host_addr)); } if (pptrs->bitr) { safi = SAFI_MPLS_VPN; memcpy(&rd, &pptrs->bitr, sizeof(rd)); } /* XXX: can be further optimized for the case of no SAFI_UNICAST rib */ start_again_mpls_label: if (pptrs->l3_proto == ETHERTYPE_IP) { if (!pptrs->bgp_src) { memset(&nmct2, 0, sizeof(struct node_match_cmp_term2)); nmct2.peer = (struct bgp_peer *) pptrs->bgp_peer; nmct2.rd = &rd; nmct2.peer_dst_ip = NULL; memcpy(&pref4, &((struct pm_iphdr *)pptrs->iph_ptr)->ip_src, sizeof(struct in_addr)); bgp_node_match_ipv4(inter_domain_routing_db->rib[AFI_IP][safi], &pref4, (struct bgp_peer *) pptrs->bgp_peer, bgp_route_info_modulo_pathid, bms->bgp_lookup_node_match_cmp, &nmct2, &result, &info); } if (!pptrs->bgp_src_info && result) { pptrs->bgp_src = (char *) result; pptrs->bgp_src_info = (char *) info; if (result->p.prefixlen >= pptrs->lm_mask_src) { pptrs->lm_mask_src = result->p.prefixlen; pptrs->lm_method_src = NF_NET_BGP; } } if (!pptrs->bgp_dst) { memset(&nmct2, 0, sizeof(struct node_match_cmp_term2)); nmct2.peer = (struct bgp_peer *) pptrs->bgp_peer; nmct2.rd = &rd; nmct2.peer_dst_ip = &peer_dst_ip; memcpy(&pref4, &((struct pm_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr)); bgp_node_match_ipv4(inter_domain_routing_db->rib[AFI_IP][safi], &pref4, (struct bgp_peer *) pptrs->bgp_peer, bgp_route_info_modulo_pathid, bms->bgp_lookup_node_match_cmp, &nmct2, &result, &info); } if (!pptrs->bgp_dst_info && result) { pptrs->bgp_dst = (char *) result; pptrs->bgp_dst_info = (char *) info; if (result->p.prefixlen >= pptrs->lm_mask_dst) { pptrs->lm_mask_dst = result->p.prefixlen; pptrs->lm_method_dst = NF_NET_BGP; } } } #if defined ENABLE_IPV6 else if (pptrs->l3_proto == ETHERTYPE_IPV6) { if (!pptrs->bgp_src) { memset(&nmct2, 0, sizeof(struct node_match_cmp_term2)); nmct2.peer = (struct bgp_peer *) pptrs->bgp_peer; nmct2.rd = &rd; nmct2.peer_dst_ip = NULL; memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_src, sizeof(struct in6_addr)); bgp_node_match_ipv6(inter_domain_routing_db->rib[AFI_IP6][safi], &pref6, (struct bgp_peer *) pptrs->bgp_peer, bgp_route_info_modulo_pathid, bms->bgp_lookup_node_match_cmp, &nmct2, &result, &info); } if (!pptrs->bgp_src_info && result) { pptrs->bgp_src = (char *) result; pptrs->bgp_src_info = (char *) info; if (result->p.prefixlen >= pptrs->lm_mask_src) { pptrs->lm_mask_src = result->p.prefixlen; pptrs->lm_method_src = NF_NET_BGP; } } if (!pptrs->bgp_dst) { memset(&nmct2, 0, sizeof(struct node_match_cmp_term2)); nmct2.peer = (struct bgp_peer *) pptrs->bgp_peer; nmct2.rd = &rd; nmct2.peer_dst_ip = &peer_dst_ip; memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr)); bgp_node_match_ipv6(inter_domain_routing_db->rib[AFI_IP6][safi], &pref6, (struct bgp_peer *) pptrs->bgp_peer, bgp_route_info_modulo_pathid, bms->bgp_lookup_node_match_cmp, &nmct2, &result, &info); } if (!pptrs->bgp_dst_info && result) { pptrs->bgp_dst = (char *) result; pptrs->bgp_dst_info = (char *) info; if (result->p.prefixlen >= pptrs->lm_mask_dst) { pptrs->lm_mask_dst = result->p.prefixlen; pptrs->lm_method_dst = NF_NET_BGP; } } } #endif if ((!pptrs->bgp_src || !pptrs->bgp_dst) && safi != SAFI_MPLS_LABEL) { if (pptrs->l3_proto == ETHERTYPE_IP && inter_domain_routing_db->rib[AFI_IP][SAFI_MPLS_LABEL]) { safi = SAFI_MPLS_LABEL; goto start_again_mpls_label; } #if defined ENABLE_IPV6 else if (pptrs->l3_proto == ETHERTYPE_IPV6 && inter_domain_routing_db->rib[AFI_IP6][SAFI_MPLS_LABEL]) { safi = SAFI_MPLS_LABEL; goto start_again_mpls_label; } #endif } if (follow_default && safi != SAFI_MPLS_VPN) { default_node = NULL; if (pptrs->l3_proto == ETHERTYPE_IP) { memset(&default_prefix, 0, sizeof(default_prefix)); default_prefix.family = AF_INET; result = (struct bgp_node *) pptrs->bgp_src; if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; pptrs->bgp_src = NULL; pptrs->bgp_src_info = NULL; } result = (struct bgp_node *) pptrs->bgp_dst; if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; pptrs->bgp_dst = NULL; pptrs->bgp_dst_info = NULL; } } #if defined ENABLE_IPV6 else if (pptrs->l3_proto == ETHERTYPE_IPV6) { memset(&default_prefix, 0, sizeof(default_prefix)); default_prefix.family = AF_INET6; result = (struct bgp_node *) pptrs->bgp_src; if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; pptrs->bgp_src = NULL; pptrs->bgp_src_info = NULL; } result = (struct bgp_node *) pptrs->bgp_dst; if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; pptrs->bgp_dst = NULL; pptrs->bgp_dst_info = NULL; } } #endif if (!pptrs->bgp_src || !pptrs->bgp_dst) { follow_default--; compare_bgp_port = FALSE; // XXX: fixme: follow default in NAT traversal scenarios if (default_node) { if (info && info->attr) { if (info->attr->mp_nexthop.family == AF_INET) { sa = &sa_local; memset(sa, 0, sizeof(struct sockaddr)); sa->sa_family = AF_INET; memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->mp_nexthop.address.ipv4, 4); goto start_again_follow_default; } #if defined ENABLE_IPV6 else if (info->attr->mp_nexthop.family == AF_INET6) { sa = &sa_local; memset(sa, 0, sizeof(struct sockaddr)); sa->sa_family = AF_INET6; ip6_addr_cpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &info->attr->mp_nexthop.address.ipv6); goto start_again_follow_default; } #endif else { sa = &sa_local; memset(sa, 0, sizeof(struct sockaddr)); sa->sa_family = AF_INET; memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->nexthop, 4); goto start_again_follow_default; } } } } } if (config.nfacctd_bgp_follow_nexthop[0].family && pptrs->bgp_dst && safi != SAFI_MPLS_VPN) bgp_follow_nexthop_lookup(pptrs, type); } }