diff options
Diffstat (limited to 'bgpd/bgp_route.c')
| -rw-r--r-- | bgpd/bgp_route.c | 1009 |
1 files changed, 730 insertions, 279 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f0b1e5ddf9..7094e8ca45 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "plist.h" #include "thread.h" #include "workqueue.h" +#include "queue.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -56,6 +57,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nht.h" +#include "bgpd/bgp_updgrp.h" /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; @@ -986,7 +988,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, { if (IPV4_ADDR_SAME (&peer->remote_id, &riattr->extra->originator_id)) { - if (bgp_debug_update(peer, p, 0)) + if (bgp_debug_update(peer, p, NULL, 0)) zlog_debug("%s [Update:SEND] %s/%d originator-id is same as remote router-id", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -1008,7 +1010,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, /* Output filter check. */ if (bgp_output_filter (peer, p, riattr, afi, safi) == FILTER_DENY) { - if (bgp_debug_update(peer, p, 0)) + if (bgp_debug_update(peer, p, NULL, 0)) zlog_debug("%s [Update:SEND] %s/%d is filtered", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -1020,7 +1022,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, /* AS path loop check. */ if (aspath_loop_check (riattr->aspath, peer->as)) { - if (bgp_debug_update(peer, p, 0)) + if (bgp_debug_update(peer, p, NULL, 0)) zlog_debug("%s [Update:SEND] suppress announcement to peer AS %u is AS path.", peer->host, peer->as); return 0; @@ -1032,7 +1034,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, { if (aspath_loop_check(riattr->aspath, bgp->confed_id)) { - if (bgp_debug_update(peer, p, 0)) + if (bgp_debug_update(peer, p, NULL, 0)) zlog_debug("%s [Update:SEND] suppress announcement to peer AS %u is AS path.", peer->host, bgp->confed_id); @@ -1228,6 +1230,331 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, return 1; } +static void +subgroup_announce_reset_nhop (u_char family, struct attr *attr) +{ + if (family == AF_INET) + attr->nexthop.s_addr = 0; +#ifdef HAVE_IPV6 + if (family == AF_INET6) + memset (&attr->extra->mp_nexthop_global, 0, IPV6_MAX_BYTELEN); +#endif +} + +int +subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp, + struct prefix *p, struct attr *attr) +{ + struct bgp_filter *filter; + struct peer *from; + struct peer *peer; + struct peer *onlypeer; + struct bgp *bgp; + struct attr *riattr; + struct peer_af *paf; + char buf[SU_ADDRSTRLEN]; + int ret; + int transparent; + int reflect; + afi_t afi; + safi_t safi; + + if (DISABLE_BGP_ANNOUNCE) + return 0; + + afi = SUBGRP_AFI(subgrp); + safi = SUBGRP_SAFI(subgrp); + peer = SUBGRP_PEER(subgrp); + onlypeer = NULL; + if (CHECK_FLAG (peer->flags, PEER_FLAG_LONESOUL)) + onlypeer = SUBGRP_PFIRST(subgrp)->peer; + + from = ri->peer; + filter = &peer->filter[afi][safi]; + bgp = SUBGRP_INST(subgrp); + riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr; + + /* Aggregate-address suppress check. */ + if (ri->extra && ri->extra->suppress) + if (! UNSUPPRESS_MAP_NAME (filter)) + { + return 0; + } + + /* Do not send announces to RS-clients from the 'normal' bgp_table. */ + if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + { + return 0; + } + + /* Do not send back route to sender. */ + if (onlypeer && from == onlypeer) + { + return 0; + } + + /* Transparency check. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) + && CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + transparent = 1; + else + transparent = 0; + + /* If community is not disabled check the no-export and local. */ + if (! transparent && bgp_community_filter (peer, riattr)) + { + if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) + zlog_debug ("subgrpannouncecheck: community filter check fail"); + return 0; + } + + /* If the attribute has originator-id and it is same as remote + peer's id. */ + if (onlypeer && + riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID) && + (IPV4_ADDR_SAME (&onlypeer->remote_id, &riattr->extra->originator_id))) + { + if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) + zlog_debug ("%s [Update:SEND] %s/%d originator-id is same as " + "remote router-id", + onlypeer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + return 0; + } + + /* ORF prefix-list filter check */ + if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) + && (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) + || CHECK_FLAG (peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_OLD_RCV))) + if (peer->orf_plist[afi][safi]) + { + if (prefix_list_apply (peer->orf_plist[afi][safi], p) == PREFIX_DENY) + { + return 0; + } + } + + /* Output filter check. */ + if (bgp_output_filter (peer, p, riattr, afi, safi) == FILTER_DENY) + { + if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) + zlog_debug ("%s [Update:SEND] %s/%d is filtered", + peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + return 0; + } + +#ifdef BGP_SEND_ASPATH_CHECK + /* AS path loop check. */ + if (onlypeer && aspath_loop_check (riattr->aspath, onlypeer->as)) + { + if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) + zlog_debug ("%s [Update:SEND] suppress announcement to peer AS %u " + "that is part of AS path.", + onlypeer->host, onlypeer->as); + return 0; + } +#endif /* BGP_SEND_ASPATH_CHECK */ + + /* If we're a CONFED we need to loop check the CONFED ID too */ + if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) + { + if (aspath_loop_check(riattr->aspath, bgp->confed_id)) + { + if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) + zlog_debug ("%s [Update:SEND] suppress announcement to peer AS %u" + " is AS path.", + peer->host, + bgp->confed_id); + return 0; + } + } + + /* Route-Reflect check. */ + if (from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) + reflect = 1; + else + reflect = 0; + + /* IBGP reflection check. */ + if (reflect) + { + /* A route from a Client peer. */ + if (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) + { + /* Reflect to all the Non-Client peers and also to the + Client peers other than the originator. Originator check + is already done. So there is noting to do. */ + /* no bgp client-to-client reflection check. */ + if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT)) + if (CHECK_FLAG (peer->af_flags[afi][safi], + PEER_FLAG_REFLECTOR_CLIENT)) + return 0; + } + else + { + /* A route from a Non-client peer. Reflect to all other + clients. */ + if (! CHECK_FLAG (peer->af_flags[afi][safi], + PEER_FLAG_REFLECTOR_CLIENT)) + return 0; + } + } + + /* For modify attribute, copy it to temporary structure. */ + bgp_attr_dup (attr, riattr); + + /* If local-preference is not set. */ + if ((peer->sort == BGP_PEER_IBGP + || peer->sort == BGP_PEER_CONFED) + && (! (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))) + { + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); + attr->local_pref = bgp->default_local_pref; + } + + /* If originator-id is not set and the route is to be reflected, + set the originator id */ + if (reflect && (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)))) + { + attr->extra = bgp_attr_extra_get(attr); + IPV4_ADDR_COPY(&(attr->extra->originator_id), &(from->remote_id)); + SET_FLAG(attr->flag, BGP_ATTR_ORIGINATOR_ID); + } + + /* Remove MED if its an EBGP peer - will get overwritten by route-maps */ + if (peer->sort == BGP_PEER_EBGP + && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) + { + if (ri->peer != bgp->peer_self && ! transparent + && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) + attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)); + } + + /* Since the nexthop attribute can vary per peer, it is not explicitly set + * in announce check, only certain flags and length (or number of nexthops + * -- for IPv6/MP_REACH) are set here in order to guide the update formation + * code in setting the nexthop(s) on a per peer basis in reformat_peer(). + * Typically, the source nexthop in the attribute is preserved but in the + * scenarios where we know it will always be overwritten, we reset the + * nexthop to "0" in an attempt to achieve better Update packing. An + * example of this is when a prefix from each of 2 IBGP peers needs to be + * announced to an EBGP peer (and they have the same attributes barring + * their nexthop). + */ + if (reflect) + SET_FLAG(attr->rmap_change_flags, BATTR_REFLECTED); + +#ifdef HAVE_IPV6 + /* IPv6/MP starts with 1 nexthop, the link-local address is passed only if + * we're not reflecting the route and the peer (group) to whom we're going + * to announce is on a shared network (directly connected peers) or the + * peer (group) is configured to receive link-local nexthop and it is + * available in the prefix. + * Of course, the operator can always set it through the route-map, if + * so desired. + */ + if (p->family == AF_INET6) + { + attr->extra->mp_nexthop_len = 16; + if (!reflect) + { + if (peer->shared_network || + (CHECK_FLAG (peer->af_flags[afi][safi], + PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) && + IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_local))) + attr->extra->mp_nexthop_len = 32; + } + + /* Clear off link-local nexthop in source, if not needed. This may help + * more prefixes share the same attribute for announcement. + */ + if (!(CHECK_FLAG (peer->af_flags[afi][safi], + PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED))) + memset (&attr->extra->mp_nexthop_local, 0, IPV6_MAX_BYTELEN); + } +#endif /* HAVE_IPV6 */ + + bgp_peer_remove_private_as(bgp, afi, safi, peer, attr); + bgp_peer_as_override(bgp, afi, safi, peer, attr); + + /* Route map & unsuppress-map apply. */ + if (ROUTE_MAP_OUT_NAME (filter) + || (ri->extra && ri->extra->suppress) ) + { + struct bgp_info info; + struct attr dummy_attr; + struct attr_extra dummy_extra; + + dummy_attr.extra = &dummy_extra; + + info.peer = peer; + info.attr = attr; + + /* + * The route reflector is not allowed to modify the attributes + * of the reflected IBGP routes unless explicitly allowed. + */ + if ((from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) + && !bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) + { + bgp_attr_dup (&dummy_attr, attr); + info.attr = &dummy_attr; + } + + SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT); + + if (ri->extra && ri->extra->suppress) + ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info); + else + ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info); + + peer->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) + { + bgp_attr_flush (attr); + return 0; + } + } + + /* After route-map has been applied, we check to see if the nexthop to + * be carried in the attribute (that is used for the announcement) can + * be cleared off or not. We do this in all cases where we would be + * setting the nexthop to "ourselves". For IPv6, we only need to consider + * the global nexthop here; the link-local nexthop would have been cleared + * already, and if not, it is required by the update formation code. + * Also see earlier comments in this function. + */ + if (!(CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_NEXTHOP_CHANGED) || + transparent || + CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED))) + { + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF)) + { + if (!reflect || + CHECK_FLAG (peer->af_flags[afi][safi], + PEER_FLAG_FORCE_NEXTHOP_SELF)) + subgroup_announce_reset_nhop (p->family, attr); + } + else if (peer->sort == BGP_PEER_EBGP) + { + SUBGRP_FOREACH_PEER (subgrp, paf) + { + if (bgp_multiaccess_check_v4 (riattr->nexthop, paf->peer)) + break; + } + if (!paf) + subgroup_announce_reset_nhop (p->family, attr); + } + } + + return 1; +} + static int bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) @@ -1238,11 +1565,9 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, struct bgp_info info; struct peer *from; struct attr *riattr; - struct bgp *bgp; from = ri->peer; filter = &rsclient->filter[afi][safi]; - bgp = rsclient->bgp; riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr; if (DISABLE_BGP_ANNOUNCE) @@ -1273,12 +1598,219 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, peer's id. */ if (riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) { - if (IPV4_ADDR_SAME (&rsclient->remote_id, + if (IPV4_ADDR_SAME (&rsclient->remote_id, &riattr->extra->originator_id)) { - if (bgp_debug_update(rsclient, p, 0)) + if (bgp_debug_update(rsclient, p, NULL, 0)) zlog_debug ("%s [Update:SEND] %s/%d originator-id is same as remote router-id", - rsclient->host, + rsclient->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + return 0; + } + } + + /* ORF prefix-list filter check */ + if (CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) + && (CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) + || CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))) + if (rsclient->orf_plist[afi][safi]) + { + if (prefix_list_apply (rsclient->orf_plist[afi][safi], p) == PREFIX_DENY) + return 0; + } + + /* Output filter check. */ + if (bgp_output_filter (rsclient, p, riattr, afi, safi) == FILTER_DENY) + { + if (bgp_debug_update(rsclient, p, NULL, 0)) + zlog_debug ("%s [Update:SEND] %s/%d is filtered", + rsclient->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + return 0; + } + +#ifdef BGP_SEND_ASPATH_CHECK + /* AS path loop check. */ + if (aspath_loop_check (riattr->aspath, rsclient->as)) + { + if (bgp_debug_update(rsclient, p, NULL, 0)) + zlog_debug ("%s [Update:SEND] suppress announcement to peer AS %u is AS path.", + rsclient->host, rsclient->as); + return 0; + } +#endif /* BGP_SEND_ASPATH_CHECK */ + + /* For modify attribute, copy it to temporary structure. */ + bgp_attr_dup (attr, riattr); + + /* next-hop-set */ + if ((p->family == AF_INET && attr->nexthop.s_addr == 0) +#ifdef HAVE_IPV6 + || (p->family == AF_INET6 && + IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) +#endif /* HAVE_IPV6 */ + ) + { + /* Set IPv4 nexthop. */ + if (p->family == AF_INET) + { + if (safi == SAFI_MPLS_VPN) + memcpy (&attr->extra->mp_nexthop_global_in, &rsclient->nexthop.v4, + IPV4_MAX_BYTELEN); + else + memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); + } +#ifdef HAVE_IPV6 + /* Set IPv6 nexthop. */ + if (p->family == AF_INET6) + { + /* IPv6 global nexthop must be included. */ + memcpy (&attr->extra->mp_nexthop_global, &rsclient->nexthop.v6_global, + IPV6_MAX_BYTELEN); + attr->extra->mp_nexthop_len = 16; + } +#endif /* HAVE_IPV6 */ + } + +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + { + struct attr_extra *attre = attr->extra; + + /* Left nexthop_local unchanged if so configured. */ + if ( CHECK_FLAG (rsclient->af_flags[afi][safi], + PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ) + { + if ( IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local) ) + attre->mp_nexthop_len=32; + else + attre->mp_nexthop_len=16; + } + + /* Default nexthop_local treatment for RS-Clients */ + else + { + /* Announcer and RS-Client are both in the same network */ + if (rsclient->shared_network && from->shared_network && + (rsclient->ifindex == from->ifindex)) + { + if ( IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local) ) + attre->mp_nexthop_len=32; + else + attre->mp_nexthop_len=16; + } + + /* Set link-local address for shared network peer. */ + else if (rsclient->shared_network + && IN6_IS_ADDR_LINKLOCAL (&rsclient->nexthop.v6_local)) + { + memcpy (&attre->mp_nexthop_local, &rsclient->nexthop.v6_local, + IPV6_MAX_BYTELEN); + attre->mp_nexthop_len = 32; + } + + else + attre->mp_nexthop_len = 16; + } + + } +#endif /* HAVE_IPV6 */ + + + /* If this is EBGP peer and remove-private-AS is set. */ + if (rsclient->sort == BGP_PEER_EBGP + && peer_af_flag_check (rsclient, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) + && aspath_private_as_check (attr->aspath)) + attr->aspath = aspath_empty_get (); + + /* Route map & unsuppress-map apply. */ + if (ROUTE_MAP_OUT_NAME (filter) || (ri->extra && ri->extra->suppress) ) + { + info.peer = rsclient; + info.attr = attr; + + SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_OUT); + + if (ri->extra && ri->extra->suppress) + ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info); + else + ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info); + + rsclient->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) + { + bgp_attr_flush (attr); + return 0; + } + } + + return 1; +} + +static int +subgroup_announce_check_rsclient (struct bgp_info *ri, + struct update_subgroup *subgrp, + struct prefix *p, struct attr *attr) +{ + int ret; + char buf[SU_ADDRSTRLEN]; + struct bgp_filter *filter; + struct bgp_info info; + struct peer *from; + struct peer *rsclient; + struct peer *onlypeer; + struct attr *riattr; + struct bgp *bgp; + afi_t afi; + safi_t safi; + + if (DISABLE_BGP_ANNOUNCE) + return 0; + + afi = SUBGRP_AFI(subgrp); + safi = SUBGRP_SAFI(subgrp); + rsclient = SUBGRP_PEER(subgrp); + onlypeer = ((SUBGRP_PCOUNT(subgrp) == 1) ? + (SUBGRP_PFIRST(subgrp))->peer : NULL); + from = ri->peer; + filter = &rsclient->filter[afi][safi]; + bgp = rsclient->bgp; + riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr; + + /* Do not send back route to sender. */ + if (onlypeer && (from == onlypeer)) + return 0; + + /* Aggregate-address suppress check. */ + if (ri->extra && ri->extra->suppress) + if (! UNSUPPRESS_MAP_NAME (filter)) + return 0; + + /* Default route check. */ + if (CHECK_FLAG (rsclient->af_sflags[afi][safi], + PEER_STATUS_DEFAULT_ORIGINATE)) + { + if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) + return 0; +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6 && p->prefixlen == 0) + return 0; +#endif /* HAVE_IPV6 */ + } + + /* If the attribute has originator-id and it is same as remote + peer's id. */ + if (onlypeer && riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) + { + if (IPV4_ADDR_SAME (&onlypeer->remote_id, + &riattr->extra->originator_id)) + { + if (bgp_debug_update(rsclient, p, subgrp->update_group, 0)) + zlog_debug ("%s [Update:SEND] %s/%d originator-id is same as remote router-id", + onlypeer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); return 0; @@ -1298,7 +1830,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, /* Output filter check. */ if (bgp_output_filter (rsclient, p, riattr, afi, safi) == FILTER_DENY) { - if (bgp_debug_update(rsclient, p, 0)) + if (bgp_debug_update(rsclient, p, subgrp->update_group, 0)) zlog_debug ("%s [Update:SEND] %s/%d is filtered", rsclient->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -1308,11 +1840,11 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, #ifdef BGP_SEND_ASPATH_CHECK /* AS path loop check. */ - if (aspath_loop_check (riattr->aspath, rsclient->as)) + if (onlypeer && aspath_loop_check (riattr->aspath, onlypeer->as)) { - if (bgp_debug_update(rsclient, p, 0)) + if (bgp_debug_update(rsclient, p, subgrp->update_group, 0)) zlog_debug ("%s [Update:SEND] suppress announcement to peer AS %u is AS path.", - rsclient->host, rsclient->as); + onlypeer->host, onlypeer->as); return 0; } #endif /* BGP_SEND_ASPATH_CHECK */ @@ -1355,7 +1887,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, struct attr_extra *attre = attr->extra; /* Left nexthop_local unchanged if so configured. */ - if ( CHECK_FLAG (rsclient->af_flags[afi][safi], + if ( CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ) { if ( IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local) ) @@ -1363,11 +1895,11 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, else attre->mp_nexthop_len=16; } - + /* Default nexthop_local treatment for RS-Clients */ - else - { - /* Announcer and RS-Client are both in the same network */ + else + { + /* Announcer and RS-Client are both in the same network */ if (rsclient->shared_network && from->shared_network && (rsclient->ifindex == from->ifindex)) { @@ -1561,27 +2093,32 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, return; } -static int -bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, - struct bgp_node *rn, afi_t afi, safi_t safi) +/* + * A new route/change in bestpath of an existing route. Evaluate the path + * for advertisement to the subgroup. + */ +int +subgroup_process_announce_selected (struct update_subgroup *subgrp, + struct bgp_info *selected, + struct bgp_node *rn) { struct prefix *p; + struct peer_af *paf; + struct peer *onlypeer; struct attr attr; struct attr_extra extra; + afi_t afi; + safi_t safi; p = &rn->p; - - /* Announce route to Established peer. */ - if (peer->status != Established) - return 0; - - /* Address family configuration check. */ - if (! peer->afc_nego[afi][safi]) - return 0; + afi = SUBGRP_AFI(subgrp); + safi = SUBGRP_SAFI(subgrp); + onlypeer = ((SUBGRP_PCOUNT(subgrp) == 1) ? + (SUBGRP_PFIRST(subgrp))->peer : NULL); /* First update is deferred until ORF or ROUTE-REFRESH is received */ - if (CHECK_FLAG (peer->af_sflags[afi][safi], - PEER_STATUS_ORF_WAIT_REFRESH)) + if (onlypeer && CHECK_FLAG (onlypeer->af_sflags[afi][safi], + PEER_STATUS_ORF_WAIT_REFRESH)) return 0; /* It's initialized in bgp_announce_[check|check_rsclient]() */ @@ -1590,28 +2127,29 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, switch (bgp_node_table (rn)->type) { case BGP_TABLE_MAIN: - /* Announcement to peer->conf. If the route is filtered, + /* Announcement to the subgroup. If the route is filtered, withdraw it. */ - if (selected && bgp_announce_check (selected, peer, p, &attr, afi, safi)) - bgp_adj_out_set (rn, peer, p, &attr, afi, safi, selected); + if (selected && subgroup_announce_check(selected, subgrp, p, &attr)) + bgp_adj_out_set_subgroup(rn, subgrp, &attr, selected); else - bgp_adj_out_unset (rn, peer, p, afi, safi); + bgp_adj_out_unset_subgroup(rn, subgrp); + break; case BGP_TABLE_RSCLIENT: - /* Announcement to peer->conf. If the route is filtered, + /* Announcement to peer->conf. If the route is filtered, withdraw it. */ - if (selected && - bgp_announce_check_rsclient (selected, peer, p, &attr, afi, safi)) - bgp_adj_out_set (rn, peer, p, &attr, afi, safi, selected); + if (selected && + subgroup_announce_check_rsclient (selected, subgrp, p, &attr)) + bgp_adj_out_set_subgroup (rn, subgrp, &attr, selected); else - bgp_adj_out_unset (rn, peer, p, afi, safi); + bgp_adj_out_unset_subgroup(rn, subgrp); break; } return 0; } -struct bgp_process_queue +struct bgp_process_queue { struct bgp *bgp; struct bgp_node *rn; @@ -1632,6 +2170,8 @@ bgp_process_rsclient (struct work_queue *wq, void *data) struct bgp_info_pair old_and_new; struct listnode *node, *nnode; struct peer *rsclient; + struct peer_af *paf; + struct update_subgroup *subgrp; /* Is it end of initial update? (after startup) */ if (!rn) @@ -1672,8 +2212,12 @@ bgp_process_rsclient (struct work_queue *wq, void *data) UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); } - bgp_process_announce_selected (rsclient, new_select, rn, - afi, safi); + paf = peer_af_find(rsclient, afi, safi); + assert(paf); + subgrp = PAF_SUBGRP(paf); + if (!subgrp) /* not an established session */ + continue; + subgroup_process_announce_selected (subgrp, new_select, rn); } } else @@ -1686,12 +2230,14 @@ bgp_process_rsclient (struct work_queue *wq, void *data) bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); } - bgp_process_announce_selected (rsclient, new_select, rn, afi, safi); + paf = peer_af_find(rsclient, afi, safi); + if (paf && (subgrp = PAF_SUBGRP(paf))) /* if an established session */ + subgroup_process_announce_selected (subgrp, new_select, rn); } if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED)) bgp_info_reap (rn, old_select); - + UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } @@ -1752,6 +2298,10 @@ bgp_process_main (struct work_queue *wq, void *data) /* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set */ UNSET_FLAG(rn->flags, BGP_NODE_USER_CLEAR); + /* bestpath has changed; bump version */ + if (old_select || new_select) + bgp_bump_version(rn); + if (old_select) bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); if (new_select) @@ -1761,12 +2311,7 @@ bgp_process_main (struct work_queue *wq, void *data) UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); } - - /* Check each BGP peer. */ - for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) - { - bgp_process_announce_selected (peer, new_select, rn, afi, safi); - } + group_announce_route(bgp, afi, safi, rn, new_select); /* FIB update. */ if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) && (! bgp->name && @@ -1810,27 +2355,6 @@ bgp_processq_del (struct work_queue *wq, void *data) XFREE (MTYPE_BGP_PROCESS_QUEUE, pq); } -static void -bgp_process_queue_complete (struct work_queue *wq) -{ - struct bgp *bgp; - struct peer *peer; - struct listnode *node, *nnode; - - /* Schedule write thread either directly or through the MRAI timer - * if needed. - */ - bgp = bgp_get_default (); - if (!bgp) - return; - - if (BGP_ROUTE_ADV_HOLD(bgp)) - return; - - for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) - bgp_peer_schedule_updates(peer); -} - void bgp_process_queue_init (void) { @@ -1847,7 +2371,6 @@ bgp_process_queue_init (void) bm->process_main_queue->spec.workfunc = &bgp_process_main; bm->process_main_queue->spec.del_item_data = &bgp_processq_del; - bm->process_main_queue->spec.completion_func = &bgp_process_queue_complete; bm->process_main_queue->spec.max_retries = 0; bm->process_main_queue->spec.hold = 50; /* Use a higher yield value of 50ms for main queue processing */ @@ -2165,7 +2688,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, && attrhash_cmp (ri->attr, attr_new)) { - if (bgp_debug_update(peer, p, 1)) + if (bgp_debug_update(peer, p, NULL, 1)) zlog_debug ("%s rcvd %s/%d for RS-client %s...duplicate ignored", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -2183,7 +2706,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, bgp_info_restore (rn, ri); /* Received Logging. */ - if (bgp_debug_update(peer, p, 1)) + if (bgp_debug_update(peer, p, NULL, 1)) zlog_debug ("%s rcvd %s/%d for RS-client %s", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -2210,7 +2733,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, } /* Received Logging. */ - if (bgp_debug_update(peer, p, 1)) + if (bgp_debug_update(peer, p, NULL, 1)) { zlog_debug ("%s rcvd %s/%d for RS-client %s", peer->host, @@ -2240,7 +2763,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, filtered: /* This BGP update is filtered. Log the reason then update BGP entry. */ - if (bgp_debug_update(peer, p, 1)) + if (bgp_debug_update(peer, p, NULL, 1)) zlog_debug ("%s rcvd UPDATE about %s/%d -- DENIED for RS-client %s due to: %s", peer->host, inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -2276,7 +2799,7 @@ bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, /* Withdraw specified route from routing table. */ if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) bgp_rib_withdraw (rn, ri, peer, afi, safi); - else if (bgp_debug_update(peer, p, 1)) + else if (bgp_debug_update(peer, p, NULL, 1)) zlog_debug ("%s Can't find the route %s/%d", peer->host, inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); @@ -2408,7 +2931,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, u_int32_t addpath_id, && peer->sort == BGP_PEER_EBGP && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) { - if (bgp_debug_update(peer, p, 1)) + if (bgp_debug_update(peer, p, NULL, 1)) zlog_debug ("%s rcvd %s/%d", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -2422,7 +2945,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, u_int32_t addpath_id, } else /* Duplicate - odd */ { - if (bgp_debug_update(peer, p, 1)) + if (bgp_debug_update(peer, p, NULL, 1)) { if (!peer->rcvd_attr_printed) { @@ -2453,7 +2976,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Withdraw/Announce before we fully processed the withdraw */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { - if (bgp_debug_update(peer, p, 1)) + if (bgp_debug_update(peer, p, NULL, 1)) zlog_debug ("%s rcvd %s/%d, flapped quicker than processing", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -2462,7 +2985,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, u_int32_t addpath_id, } /* Received Logging. */ - if (bgp_debug_update(peer, p, 1)) + if (bgp_debug_update(peer, p, NULL, 1)) zlog_debug ("%s rcvd %s/%d", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -2546,7 +3069,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, u_int32_t addpath_id, } // End of implicit withdraw /* Received Logging. */ - if (bgp_debug_update(peer, p, 1)) + if (bgp_debug_update(peer, p, NULL, 1)) { if (!peer->rcvd_attr_printed) { @@ -2618,7 +3141,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* This BGP update is filtered. Log the reason then update BGP entry. */ filtered: - if (bgp_debug_update(peer, p, 1)) + if (bgp_debug_update(peer, p, NULL, 1)) { if (!peer->rcvd_attr_printed) { @@ -2689,7 +3212,7 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id, } /* Logging. */ - if (bgp_debug_update(peer, p, 1)) + if (bgp_debug_update(peer, p, NULL, 1)) zlog_debug ("%s rcvd UPDATE about %s/%d -- withdrawn", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -2713,7 +3236,7 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Withdraw specified route from routing table. */ if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) bgp_rib_withdraw (rn, ri, peer, afi, safi); - else if (bgp_debug_update(peer, p, 1)) + else if (bgp_debug_update(peer, p, NULL, 1)) zlog_debug ("%s Can't find the route %s/%d", peer->host, inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); @@ -2727,175 +3250,103 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id, void bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) { - struct bgp *bgp; - struct attr attr; - struct aspath *aspath; - struct prefix p; - struct peer *from; - struct bgp_node *rn; - struct bgp_info *ri; - int ret = RMAP_DENYMATCH; - - if (!(afi == AFI_IP || afi == AFI_IP6)) - return; - - bgp = peer->bgp; - from = bgp->peer_self; - - bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); - aspath = attr.aspath; - attr.local_pref = bgp->default_local_pref; - memcpy (&attr.nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN); - - if (afi == AFI_IP) - str2prefix ("0.0.0.0/0", &p); -#ifdef HAVE_IPV6 - else if (afi == AFI_IP6) - { - struct attr_extra *ae = attr.extra; + struct update_subgroup *subgrp; + subgrp = peer_subgroup(peer, afi, safi); + subgroup_default_originate(subgrp, withdraw); +} - str2prefix ("::/0", &p); - /* IPv6 global nexthop must be included. */ - memcpy (&ae->mp_nexthop_global, &peer->nexthop.v6_global, - IPV6_MAX_BYTELEN); - ae->mp_nexthop_len = 16; +/* + * bgp_stop_announce_route_timer + */ +void +bgp_stop_announce_route_timer (struct peer_af *paf) +{ + if (!paf->t_announce_route) + return; - /* If the peer is on shared nextwork and we have link-local - nexthop set it. */ - if (peer->shared_network - && !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local)) - { - memcpy (&ae->mp_nexthop_local, &peer->nexthop.v6_local, - IPV6_MAX_BYTELEN); - ae->mp_nexthop_len = 32; - } - } -#endif /* HAVE_IPV6 */ - - if (peer->default_rmap[afi][safi].name) - { - SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT); - for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) - { - for (ri = rn->info; ri; ri = ri->next) - { - struct attr dummy_attr; - struct attr_extra dummy_extra; - struct bgp_info info; - - /* Provide dummy so the route-map can't modify the attributes */ - dummy_attr.extra = &dummy_extra; - bgp_attr_dup(&dummy_attr, ri->attr); - info.peer = ri->peer; - info.attr = &dummy_attr; - - ret = route_map_apply(peer->default_rmap[afi][safi].map, &rn->p, - RMAP_BGP, &info); - - /* The route map might have set attributes. If we don't flush them - * here, they will be leaked. */ - bgp_attr_flush(&dummy_attr); - if (ret != RMAP_DENYMATCH) - break; - } - if (ret != RMAP_DENYMATCH) - break; - } - bgp->peer_self->rmap_type = 0; - - if (ret == RMAP_DENYMATCH) - withdraw = 1; - } - - if (withdraw) - { - if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) - bgp_default_withdraw_send (peer, afi, safi); - UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); - } - else - { - if (! CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) - { - SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); - bgp_default_update_send (peer, &attr, afi, safi, from); - } - } - - bgp_attr_extra_free (&attr); - aspath_unintern (&aspath); + THREAD_TIMER_OFF (paf->t_announce_route); } -static void -bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, - struct bgp_table *table, int rsclient) +/* + * bgp_announce_route_timer_expired + * + * Callback that is invoked when the route announcement timer for a + * peer_af expires. + */ +static int +bgp_announce_route_timer_expired (struct thread *t) { - struct bgp_node *rn; - struct bgp_info *ri; - struct attr attr; - struct attr_extra extra; + struct peer_af *paf; + struct peer *peer; - if (! table) - table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi]; - if (safi != SAFI_MPLS_VPN - && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) - bgp_default_originate (peer, afi, safi, 0); + paf = THREAD_ARG (t); + peer = paf->peer; - /* It's initialized in bgp_announce_[check|check_rsclient]() */ - attr.extra = &extra; + assert (paf->t_announce_route); + paf->t_announce_route = NULL; - for (rn = bgp_table_top (table); rn; rn = bgp_route_next(rn)) - for (ri = rn->info; ri; ri = ri->next) - if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->peer != peer) - { - if ( (rsclient) ? - (bgp_announce_check_rsclient (ri, peer, &rn->p, &attr, afi, safi)) - : (bgp_announce_check (ri, peer, &rn->p, &attr, afi, safi))) - bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri); - else - bgp_adj_out_unset (rn, peer, &rn->p, afi, safi); - } + if (peer->status != Established) + return 0; + + if (!peer->afc_nego[paf->afi][paf->safi]) + return 0; + + peer_af_announce_route (paf, 1); + return 0; } +/* + * bgp_announce_route + * + * *Triggers* announcement of routes of a given AFI/SAFI to a peer. + */ void bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi) { - struct bgp_node *rn; - struct bgp_table *table; - - if (peer->status != Established) - return; + struct peer_af *paf; + struct update_subgroup *subgrp; - if (! peer->afc_nego[afi][safi]) + paf = peer_af_find (peer, afi, safi); + if (!paf) return; + subgrp = PAF_SUBGRP(paf); - /* First update is deferred until ORF or ROUTE-REFRESH is received */ - if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) + /* + * Ignore if subgroup doesn't exist (implies AF is not negotiated) + * or a refresh has already been triggered. + */ + if (!subgrp || paf->t_announce_route) return; - if (safi != SAFI_MPLS_VPN) - bgp_announce_table (peer, afi, safi, NULL, 0); - else - for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; - rn = bgp_route_next(rn)) - if ((table = (rn->info)) != NULL) - bgp_announce_table (peer, afi, safi, table, 0); - - if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) - bgp_announce_table (peer, afi, safi, NULL, 1); - /* - * The write thread needs to be scheduled since it may not be done as - * part of building adj_out. + * Start a timer to stagger/delay the announce. This serves + * two purposes - announcement can potentially be combined for + * multiple peers and the announcement doesn't happen in the + * vty context. */ - bgp_peer_schedule_updates(peer); -} - + THREAD_TIMER_MSEC_ON (master, paf->t_announce_route, + bgp_announce_route_timer_expired, paf, + (subgrp->peer_count == 1) ? + BGP_ANNOUNCE_ROUTE_SHORT_DELAY_MS : + BGP_ANNOUNCE_ROUTE_DELAY_MS); +} + +/* + * Announce routes from all AF tables to a peer. + * + * This should ONLY be called when there is a need to refresh the + * routes to the peer based on a policy change for this peer alone + * or a route refresh request received from the peer. + * The operation will result in splitting the peer from its existing + * subgroups and putting it in new subgroups. + */ void bgp_announce_route_all (struct peer *peer) { + struct peer_af *paf; + int af; afi_t afi; safi_t safi; @@ -3146,6 +3597,10 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, bgp_unlock_node (rn); break; } + + /* + * Can't do this anymore. adj-outs are not maintained per peer. + * for (aout = rn->adj_out; aout; aout = aout->next) if (aout->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { @@ -3153,7 +3608,7 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, bgp_unlock_node (rn); break; } - + */ for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { @@ -3641,7 +4096,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, == RMAP_DENY) { /* This BGP update is filtered. Log the reason then update BGP entry. */ - if (bgp_debug_update(rsclient, p, 1)) + if (bgp_debug_update(rsclient, p, NULL, 1)) zlog_debug ("Static UPDATE about %s/%d -- DENIED for RS-client %s due to: import-policy", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host); @@ -6613,11 +7068,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, vty_out (vty, "%s", VTY_NEWLINE); } -#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, "\ - "h history, * valid, > best, = multipath,%s"\ - " i internal, r RIB-failure, S Stale, R Removed%s" -#define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s" -#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s" #define BGP_SHOW_HEADER_CSV "Flags, Network, Next Hop, Metric, LocPrf, Weight, Path%s" #define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s" #define BGP_SHOW_FLAP_HEADER " Network From Flaps Duration Reuse Path%s" @@ -6826,7 +7276,7 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router } else if (header) { - vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (*router_id), VTY_NEWLINE); + vty_out (vty, "BGP table version is %llu, local router ID is %s%s", table->version, inet_ntoa (*router_id), VTY_NEWLINE); vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); if (type == bgp_show_type_dampend_paths @@ -10614,7 +11064,7 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, if (! in && CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) { - vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "BGP table version is %llu, local router ID is %s%s", table->version, inet_ntoa (bgp->router_id), VTY_NEWLINE); vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); @@ -10661,47 +11111,48 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, } else { - for (adj = rn->adj_out; adj; adj = adj->next) - if (adj->peer == peer) - { - if (header1) - { - vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); - vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); - vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); - header1 = 0; - } - if (header2) - { - if (delim) - vty_out (vty, BGP_SHOW_HEADER_CSV, VTY_NEWLINE); - else - vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); - header2 = 0; - } - if (adj->attr) - { - if (!CHECK_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_REFLECTOR_CLIENT) - || bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) - { - - bgp_attr_dup(&attr, adj->attr); - ret = bgp_output_modifier(peer, &rn->p, &attr, afi, - safi, rmap_name); - } - else - ret = RMAP_PERMIT; + adj = bgp_adj_peer_lookup(peer, rn); + if (adj) + { + if (header1) + { + vty_out (vty, "BGP table version is %llu, local router ID " + "is %s%s", table->version, + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); + header1 = 0; + } + if (header2) + { + if (delim) + vty_out (vty, BGP_SHOW_HEADER_CSV, VTY_NEWLINE); + else + vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); + header2 = 0; + } + if (adj->attr) + { + if (!CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_REFLECTOR_CLIENT) + || bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) + { + bgp_attr_dup(&attr, adj->attr); + ret = bgp_output_modifier(peer, &rn->p, &attr, afi, + safi, rmap_name); + } + else + ret = RMAP_PERMIT; - if (ret != RMAP_DENY) - { - route_vty_out_tmp (vty, &rn->p, &attr, safi, delim); - output_count++; - } - else - filtered_count++; - } - } + if (ret != RMAP_DENY) + { + route_vty_out_tmp (vty, &rn->p, &attr, safi, delim); + output_count++; + } + else + filtered_count++; + } + } } if (output_count != 0) |
