/* If nexthop exists on connected network return 1. */ int bgp_nexthop_onlink (afi_t afi, struct attr *attr) { struct bgp_node *rn; /* Lookup the address is onlink or not. */ if (afi == AFI_IP) { rn = bgp_node_match_ipv4 (bgp_connected_table[AFI_IP], &attr->nexthop); if (rn) { bgp_unlock_node (rn); return 1; } } else if (afi == AFI_IP6) { if (attr->extra->mp_nexthop_len == 32) return 1; else if (attr->extra->mp_nexthop_len == 16) { if (IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global)) return 1; rn = bgp_node_match_ipv6 (bgp_connected_table[AFI_IP6], &attr->extra->mp_nexthop_global); if (rn) { bgp_unlock_node (rn); return 1; } } } return 0; }
/* If nexthop exists on connected network return 1. */ int bgp_nexthop_onlink (afi_t afi, struct attr *attr) { struct bgp_node *rn; /* If zebra is not enabled return */ if (zlookup->sock < 0) return 1; /* Lookup the address is onlink or not. */ if (afi == AFI_IP) { rn = bgp_node_match_ipv4 (bgp_connected_table[AFI_IP], &attr->nexthop); if (rn) { bgp_unlock_node (rn); return 1; } } #ifdef HAVE_IPV6 else if (afi == AFI_IP6) { if (attr->extra->mp_nexthop_len == 32) return 1; else if (attr->extra->mp_nexthop_len == 16) { if (IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global)) return 1; rn = bgp_node_match_ipv6 (bgp_connected_table[AFI_IP6], &attr->extra->mp_nexthop_global); if (rn) { bgp_unlock_node (rn); return 1; } } } #endif /* HAVE_IPV6 */ return 0; }
void bgp_follow_nexthop_lookup(struct packet_ptrs *pptrs) { struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent, sa_local; struct bgp_peer *nh_peer; struct bgp_node *result_node = NULL; struct bgp_info *info; char *result = NULL, *saved_info = NULL; int peers_idx, ttl = MAX_HOPS_FOLLOW_NH, self = MAX_NH_SELF_REFERENCES; int nh_idx, matched = 0; struct prefix nh, ch; struct in_addr pref4; #if defined ENABLE_IPV6 struct in6_addr pref6; #endif char *saved_agent = pptrs->f_agent; pm_id_t bta; u_int32_t modulo, local_modulo, modulo_idx, modulo_max; start_again: if (config.nfacctd_bgp_to_agent_map && (*find_id_func)) { bta = 0; (*find_id_func)((struct id_table *)pptrs->bta_table, pptrs, &bta, NULL); if (bta) { sa = &sa_local; sa->sa_family = AF_INET; ((struct sockaddr_in *)sa)->sin_addr.s_addr = bta; } } for (nh_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)) { nh_peer = &peers[peers_idx]; break; } } if (nh_peer) { modulo = bgp_route_info_modulo(nh_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; memset(&ch, 0, sizeof(ch)); ch.family = AF_INET; ch.prefixlen = 32; memcpy(&ch.u.prefix4, &nh_peer->addr.address.ipv4, 4); if (!result) { if (pptrs->l3_proto == ETHERTYPE_IP) { memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr)); result = (char *) bgp_node_match_ipv4(bgp_routing_db->rib[AFI_IP][SAFI_UNICAST], &pref4, nh_peer); } #if defined ENABLE_IPV6 else if (pptrs->l3_proto == ETHERTYPE_IPV6) { memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr)); result = (char *) bgp_node_match_ipv6(bgp_routing_db->rib[AFI_IP6][SAFI_UNICAST], &pref6, nh_peer); } #endif } memset(&nh, 0, sizeof(nh)); result_node = (struct bgp_node *) result; if (result_node) { for (local_modulo = modulo, modulo_idx = 0; modulo_idx < modulo_max; local_modulo++, modulo_idx++) { for (info = result_node->info[modulo]; info; info = info->next) { if (info->peer == nh_peer) break; } } } else info = NULL; if (info && info->attr) { if (info->attr->mp_nexthop.family == AF_INET) { nh.family = AF_INET; nh.prefixlen = 32; memcpy(&nh.u.prefix4, &info->attr->mp_nexthop.address.ipv4, 4); for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) { matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh); if (matched) break; } if (matched && self > 0 && ttl > 0) { if (prefix_match(&ch, &nh)) self--; sa = &sa_local; pptrs->f_agent = (char *) &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); saved_info = (char *) info; ttl--; goto start_again; } else goto end; } #if defined ENABLE_IPV6 else if (info->attr->mp_nexthop.family == AF_INET6) { nh.family = AF_INET6; nh.prefixlen = 128; memcpy(&nh.u.prefix6, &info->attr->mp_nexthop.address.ipv6, 16); for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) { matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh); if (matched) break; } if (matched && self > 0 && ttl > 0) { if (prefix_match(&ch, &nh)) self--; sa = &sa_local; pptrs->f_agent = (char *) &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); saved_info = (char *) info; ttl--; goto start_again; } else goto end; } #endif else { nh.family = AF_INET; nh.prefixlen = 32; memcpy(&nh.u.prefix4, &info->attr->nexthop, 4); for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) { matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh); if (matched) break; } if (matched && self > 0 && ttl > 0) { if (prefix_match(&ch, &nh)) self--; sa = &sa_local; pptrs->f_agent = (char *) &sa_local; memset(sa, 0, sizeof(struct sockaddr)); sa->sa_family = AF_INET; memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->nexthop, 4); saved_info = (char *) info; ttl--; goto start_again; } else goto end; } } } end: if (saved_info) pptrs->bgp_nexthop_info = saved_info; pptrs->f_agent = saved_agent; }
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); } }
void bgp_follow_nexthop_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 bgp_peer *nh_peer; struct bgp_node *result_node = NULL; struct bgp_info *info; struct node_match_cmp_term2 nmct2; char *saved_info = NULL; int peers_idx, ttl = MAX_HOPS_FOLLOW_NH, self = MAX_NH_SELF_REFERENCES; int nh_idx, matched = 0; struct prefix nh, ch; struct in_addr pref4; #if defined ENABLE_IPV6 struct in6_addr pref6; #endif char *saved_agent = pptrs->f_agent; pm_id_t bta; u_int32_t modulo, local_modulo, modulo_idx, modulo_max; bms = bgp_select_misc_db(type); inter_domain_routing_db = bgp_select_routing_db(type); if (!bms || !inter_domain_routing_db) return; start_again: if (config.nfacctd_bgp_to_agent_map && (*find_id_func)) { bta = 0; (*find_id_func)((struct id_table *)pptrs->bta_table, pptrs, &bta, NULL); if (bta) { sa = &sa_local; sa->sa_family = AF_INET; ((struct sockaddr_in *)sa)->sin_addr.s_addr = bta; } } for (nh_peer = NULL, peers_idx = 0; peers_idx < bms->max_peers; peers_idx++) { if (!sa_addr_cmp(sa, &peers[peers_idx].addr) || !sa_addr_cmp(sa, &peers[peers_idx].id)) { nh_peer = &peers[peers_idx]; break; } } if (nh_peer) { modulo = bms->route_info_modulo(nh_peer, NULL, bms->table_per_peer_buckets); // XXX: to be optimized if (bms->table_per_peer_hash == BGP_ASPATH_HASH_PATHID) modulo_max = bms->table_per_peer_buckets; else modulo_max = 1; memset(&ch, 0, sizeof(ch)); ch.family = AF_INET; ch.prefixlen = 32; memcpy(&ch.u.prefix4, &nh_peer->addr.address.ipv4, 4); if (!result_node) { struct host_addr peer_dst_ip; rd_t rd; /* XXX: SAFI_MPLS_LABEL, SAFI_MPLS_VPN and peer_dst_ip (add_paths capability) not supported */ memset(&peer_dst_ip, 0, sizeof(peer_dst_ip)); memset(&rd, 0, sizeof(rd)); memset(&nmct2, 0, sizeof(struct node_match_cmp_term2)); nmct2.peer = (struct bgp_peer *) nh_peer; nmct2.rd = &rd; nmct2.peer_dst_ip = &peer_dst_ip; if (pptrs->l3_proto == ETHERTYPE_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_UNICAST], &pref4, nh_peer, bgp_route_info_modulo_pathid, bms->bgp_lookup_node_match_cmp, &nmct2, &result_node, &info); } #if defined ENABLE_IPV6 else if (pptrs->l3_proto == ETHERTYPE_IPV6) { 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_UNICAST], &pref6, nh_peer, bgp_route_info_modulo_pathid, bms->bgp_lookup_node_match_cmp, &nmct2, &result_node, &info); } #endif } memset(&nh, 0, sizeof(nh)); // XXX: to be optimized if (result_node) { for (local_modulo = modulo, modulo_idx = 0; modulo_idx < modulo_max; local_modulo++, modulo_idx++) { for (info = result_node->info[modulo]; info; info = info->next) { if (info->peer == nh_peer) break; } } } else info = NULL; if (info && info->attr) { if (info->attr->mp_nexthop.family == AF_INET) { nh.family = AF_INET; nh.prefixlen = 32; memcpy(&nh.u.prefix4, &info->attr->mp_nexthop.address.ipv4, 4); for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) { matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh); if (matched) break; } if (matched && self > 0 && ttl > 0) { if (prefix_match(&ch, &nh)) self--; sa = &sa_local; pptrs->f_agent = (char *) &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); saved_info = (char *) info; ttl--; goto start_again; } else { if (config.nfacctd_bgp_follow_nexthop_external) saved_info = (char *) info; goto end; } } #if defined ENABLE_IPV6 else if (info->attr->mp_nexthop.family == AF_INET6) { nh.family = AF_INET6; nh.prefixlen = 128; memcpy(&nh.u.prefix6, &info->attr->mp_nexthop.address.ipv6, 16); for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) { matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh); if (matched) break; } if (matched && self > 0 && ttl > 0) { if (prefix_match(&ch, &nh)) self--; sa = &sa_local; pptrs->f_agent = (char *) &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); saved_info = (char *) info; ttl--; goto start_again; } else { if (config.nfacctd_bgp_follow_nexthop_external) saved_info = (char *) info; goto end; } } #endif else { nh.family = AF_INET; nh.prefixlen = 32; memcpy(&nh.u.prefix4, &info->attr->nexthop, 4); for (nh_idx = 0; config.nfacctd_bgp_follow_nexthop[nh_idx].family && nh_idx < FOLLOW_BGP_NH_ENTRIES; nh_idx++) { matched = prefix_match(&config.nfacctd_bgp_follow_nexthop[nh_idx], &nh); if (matched) break; } if (matched && self > 0 && ttl > 0) { if (prefix_match(&ch, &nh)) self--; sa = &sa_local; pptrs->f_agent = (char *) &sa_local; memset(sa, 0, sizeof(struct sockaddr)); sa->sa_family = AF_INET; memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->nexthop, 4); saved_info = (char *) info; ttl--; goto start_again; } else { if (config.nfacctd_bgp_follow_nexthop_external) saved_info = (char *) info; goto end; } } } } end: if (saved_info) pptrs->bgp_nexthop_info = saved_info; pptrs->f_agent = saved_agent; }