/* 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; }
int bgp_multiaccess_check_v4 (struct in_addr nexthop, struct peer *peer) { struct bgp_node *rn1; struct bgp_node *rn2; struct prefix p; int ret; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = nexthop; rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p); if (!rn1) return 0; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = peer->su.sin.sin_addr; rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p); if (!rn2) { bgp_unlock_node(rn1); return 0; } ret = (rn1 == rn2) ? 1 : 0; bgp_unlock_node(rn1); bgp_unlock_node(rn2); return (ret); }
/* Check specified multiaccess next-hop. */ int bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer) { struct bgp_node *rn1; struct bgp_node *rn2; struct prefix p1; struct prefix p2; struct in_addr addr; int ret; ret = inet_aton (peer, &addr); if (! ret) return 0; memset (&p1, 0, sizeof (struct prefix)); p1.family = AF_INET; p1.prefixlen = IPV4_MAX_BITLEN; p1.u.prefix4 = nexthop; memset (&p2, 0, sizeof (struct prefix)); p2.family = AF_INET; p2.prefixlen = IPV4_MAX_BITLEN; p2.u.prefix4 = addr; /* If bgp scan is not enabled, return invalid. */ if (zlookup->sock < 0) return 0; rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p1); if (! rn1) return 0; bgp_unlock_node (rn1); rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p2); if (! rn2) return 0; bgp_unlock_node (rn2); /* This is safe, even with above unlocks, since we are just comparing pointers to the objects, not the objects themselves. */ if (rn1 == rn2) 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; }
/* Reset and free all BGP nexthop cache. */ static void bgp_nexthop_cache_reset (struct bgp_table *table) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) if ((bnc = rn->info) != NULL) { bnc_free (bnc); rn->info = NULL; bgp_unlock_node (rn); } }
void bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) { struct bgp_adj_in *adj; for (adj = rn->adj_in; adj; adj = adj->next) if (adj->peer == peer) break; if (! adj) return; bgp_adj_in_remove (rn, adj); bgp_unlock_node (rn); }
void bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p, afi_t afi, safi_t safi) { struct bgp_adj_out *adj; struct bgp_advertise *adv; #ifdef DISABLE_BGP_ANNOUNCE return; #endif /* DISABLE_BGP_ANNOUNCE */ /* Lookup existing adjacency, if it is not there return immediately. */ for (adj = rn->adj_out; adj; adj = adj->next) if (adj->peer == peer) break; if (! adj) return; /* Clearn up previous advertisement. */ if (adj->adv) bgp_advertise_clean (peer, adj, afi, safi); if (adj->attr) { /* We need advertisement structure. */ adj->adv = bgp_advertise_new (); adv = adj->adv; adv->rn = rn; adv->adj = adj; /* Add to synchronization entry for withdraw announcement. */ FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo); /* Schedule packet write. */ BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } else { /* Remove myself from adjacency. */ BGP_ADJ_OUT_DEL (rn, adj); /* Free allocated information. */ bgp_adj_out_free (adj); bgp_unlock_node (rn); } }
void bgp_connected_delete (struct connected *ifc) { struct prefix p; struct prefix *addr; struct interface *ifp; struct bgp_node *rn; struct bgp_connected_ref *bc; ifp = ifc->ifp; if (if_is_loopback (ifp)) return; addr = ifc->address; if (addr->family == AF_INET) { PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); apply_mask_ipv4 ((struct prefix_ipv4 *) &p); if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) return; bgp_address_del (addr); rn = bgp_node_lookup (bgp_connected_table[AFI_IP], &p); if (! rn) return; bc = rn->info; bc->refcnt--; if (bc->refcnt == 0) { XFREE (MTYPE_BGP_CONN, bc); rn->info = NULL; } bgp_unlock_node (rn); bgp_unlock_node (rn); } #ifdef HAVE_IPV6 else if (addr->family == AF_INET6) { PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); apply_mask_ipv6 ((struct prefix_ipv6 *) &p); if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) return; if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) return; rn = bgp_node_lookup (bgp_connected_table[AFI_IP6], (struct prefix *) &p); if (! rn) return; bc = rn->info; bc->refcnt--; if (bc->refcnt == 0) { XFREE (MTYPE_BGP_CONN, bc); rn->info = NULL; } bgp_unlock_node (rn); bgp_unlock_node (rn); } #endif /* HAVE_IPV6 */ }
/* Check specified next-hop is reachable or not. */ int bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, int *changed, int *metricchanged) { struct bgp_node *rn; struct prefix p; struct bgp_nexthop_cache *bnc; struct in_addr addr; /* If lookup is not enabled, return valid. */ if (zlookup->sock < 0) { if (ri->extra) ri->extra->igpmetric = 0; return 1; } #ifdef HAVE_IPV6 if (afi == AFI_IP6) return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); #endif /* HAVE_IPV6 */ addr = ri->attr->nexthop; memset (&p, 0, sizeof (struct prefix)); p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = addr; /* IBGP or ebgp-multihop */ rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP], &p); if (rn->info) { bnc = rn->info; bgp_unlock_node (rn); } else { if (NULL == (bnc = zlookup_query (addr))) bnc = bnc_new (); else { if (changed) { struct bgp_table *old; struct bgp_node *oldrn; if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP]) old = cache2_table[AFI_IP]; else old = cache1_table[AFI_IP]; oldrn = bgp_node_lookup (old, &p); if (oldrn) { struct bgp_nexthop_cache *oldbnc = oldrn->info; bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; bgp_unlock_node (oldrn); } } } rn->info = bnc; } if (changed) *changed = bnc->changed; if (metricchanged) *metricchanged = bnc->metricchanged; if (bnc->valid && bnc->metric) (bgp_info_extra_get(ri))->igpmetric = bnc->metric; else if (ri->extra) ri->extra->igpmetric = 0; return bnc->valid; }
/* Check specified next-hop is reachable or not. */ static int bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, int *metricchanged) { struct bgp_node *rn; struct prefix p; struct bgp_nexthop_cache *bnc; struct attr *attr; /* If lookup is not enabled, return valid. */ if (zlookup->sock < 0) { if (ri->extra) ri->extra->igpmetric = 0; return 1; } /* Only check IPv6 global address only nexthop. */ attr = ri->attr; if (attr->extra->mp_nexthop_len != 16 || IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global)) return 1; memset (&p, 0, sizeof (struct prefix)); p.family = AF_INET6; p.prefixlen = IPV6_MAX_BITLEN; p.u.prefix6 = attr->extra->mp_nexthop_global; /* IBGP or ebgp-multihop */ rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP6], &p); if (rn->info) { bnc = rn->info; bgp_unlock_node (rn); } else { if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global))) bnc = bnc_new (); else { if (changed) { struct bgp_table *old; struct bgp_node *oldrn; if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6]) old = cache2_table[AFI_IP6]; else old = cache1_table[AFI_IP6]; oldrn = bgp_node_lookup (old, &p); if (oldrn) { struct bgp_nexthop_cache *oldbnc = oldrn->info; bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; bgp_unlock_node (oldrn); } } } rn->info = bnc; } if (changed) *changed = bnc->changed; if (metricchanged) *metricchanged = bnc->metricchanged; if (bnc->valid && bnc->metric) (bgp_info_extra_get (ri))->igpmetric = bnc->metric; else if (ri->extra) ri->extra->igpmetric = 0; return bnc->valid; }