diff options
Diffstat (limited to 'bgpd/bgp_route.c')
| -rw-r--r-- | bgpd/bgp_route.c | 601 |
1 files changed, 407 insertions, 194 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 87e03d205f..f9e655b4e7 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -93,10 +93,14 @@ #include "bgpd/bgp_route_clippy.c" #endif +DEFINE_HOOK(bgp_snmp_update_stats, + (struct bgp_node *rn, struct bgp_path_info *pi, bool added), + (rn, pi, added)) + /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; -const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json); + /* PMSI strings. */ #define PMSI_TNLTYPE_STR_NO_INFO "No info" #define PMSI_TNLTYPE_STR_DEFAULT PMSI_TNLTYPE_STR_NO_INFO @@ -208,9 +212,6 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) return; e = *extra; - if (e->damp_info) - bgp_damp_info_free(e->damp_info, 0, e->damp_info->afi, - e->damp_info->safi); e->damp_info = NULL; if (e->parent) { @@ -405,6 +406,7 @@ void bgp_path_info_add(struct bgp_dest *dest, struct bgp_path_info *pi) bgp_dest_lock_node(dest); peer_lock(pi->peer); /* bgp_path_info peer reference */ bgp_dest_set_defer_flag(dest, false); + hook_call(bgp_snmp_update_stats, dest, pi, true); } /* Do the actual removal of info from RIB, for use by bgp_process @@ -420,6 +422,7 @@ void bgp_path_info_reap(struct bgp_dest *dest, struct bgp_path_info *pi) bgp_path_info_mpath_dequeue(pi); bgp_path_info_unlock(pi); + hook_call(bgp_snmp_update_stats, dest, pi, false); bgp_dest_unlock_node(dest); } @@ -1839,7 +1842,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* If community is not disabled check the no-export and local. */ if (!transparent && bgp_community_filter(peer, piattr)) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) - zlog_debug("%s: community filter check fail", __func__); + zlog_debug("%s: community filter check fail for %pFX", + __func__, p); return false; } @@ -2755,7 +2759,10 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, == BGP_ROUTE_REDISTRIBUTE) { if (CHECK_FLAG( dest->flags, - BGP_NODE_REGISTERED_FOR_LABEL)) + BGP_NODE_REGISTERED_FOR_LABEL) + || CHECK_FLAG( + dest->flags, + BGP_NODE_LABEL_REQUESTED)) bgp_unregister_for_label(dest); label_ntop(MPLS_LABEL_IMPLICIT_NULL, 1, &dest->local_label); @@ -2765,10 +2772,13 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, new_select); } } else if (CHECK_FLAG(dest->flags, - BGP_NODE_REGISTERED_FOR_LABEL)) { + BGP_NODE_REGISTERED_FOR_LABEL) + || CHECK_FLAG(dest->flags, + BGP_NODE_LABEL_REQUESTED)) { bgp_unregister_for_label(dest); } - } else if (CHECK_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL)) { + } else if (CHECK_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL) + || CHECK_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED)) { bgp_unregister_for_label(dest); } @@ -3325,14 +3335,16 @@ static void bgp_rib_withdraw(struct bgp_dest *dest, struct bgp_path_info *pi, /* apply dampening, if result is suppressed, we'll be retaining * the bgp_path_info in the RIB for historical reference. */ - if (CHECK_FLAG(peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) - && peer->sort == BGP_PEER_EBGP) - if ((bgp_damp_withdraw(pi, dest, afi, safi, 0)) - == BGP_DAMP_SUPPRESSED) { - bgp_aggregate_decrement(peer->bgp, p, pi, afi, - safi); - return; + if (peer->sort == BGP_PEER_EBGP) { + if (get_active_bdc_from_pi(pi, afi, safi)) { + if (bgp_damp_withdraw(pi, dest, afi, safi, 0) + == BGP_DAMP_SUPPRESSED) { + bgp_aggregate_decrement(peer->bgp, p, pi, afi, + safi); + return; + } } + } #ifdef ENABLE_BGP_VNC if (safi == SAFI_MPLS_VPN) { @@ -3500,6 +3512,36 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, return ret; } +static void bgp_attr_add_no_export_community(struct attr *attr) +{ + struct community *old; + struct community *new; + struct community *merge; + struct community *no_export; + + old = attr->community; + no_export = community_str2com("no-export"); + + assert(no_export); + + if (old) { + merge = community_merge(community_dup(old), no_export); + + if (!old->refcnt) + community_free(&old); + + new = community_uniq_sort(merge); + community_free(&merge); + } else { + new = community_dup(no_export); + } + + community_free(&no_export); + + attr->community = new; + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); +} + int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, @@ -3692,6 +3734,20 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (peer->sort == BGP_PEER_EBGP) { + /* rfc7999: + * A BGP speaker receiving an announcement tagged with the + * BLACKHOLE community SHOULD add the NO_ADVERTISE or + * NO_EXPORT community as defined in RFC1997, or a + * similar community, to prevent propagation of the + * prefix outside the local AS. The community to prevent + * propagation SHOULD be chosen according to the operator's + * routing policy. + */ + if (new_attr.community + && community_include(new_attr.community, + COMMUNITY_BLACKHOLE)) + bgp_attr_add_no_export_community(&new_attr); + /* If we receive the graceful-shutdown community from an eBGP * peer we must lower local-preference */ if (new_attr.community @@ -3749,7 +3805,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, /* Same attribute comes in. */ if (!CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) - && attrhash_cmp(pi->attr, attr_new) + && same_attr && (!has_valid_label || memcmp(&(bgp_path_info_extra_get(pi))->label, label, num_labels * sizeof(mpls_label_t)) @@ -3757,8 +3813,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, && (overlay_index_equal( afi, pi, evpn == NULL ? NULL : &evpn->gw_ip))) { - if (CHECK_FLAG(bgp->af_flags[afi][safi], - BGP_CONFIG_DAMPENING) + if (get_active_bdc_from_pi(pi, afi, safi) && peer->sort == BGP_PEER_EBGP && CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) { if (bgp_debug_update(peer, p, NULL, 1)) { @@ -3852,11 +3907,11 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, bgp_aggregate_decrement(bgp, p, pi, afi, safi); /* Update bgp route dampening information. */ - if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) + if (get_active_bdc_from_pi(pi, afi, safi) && peer->sort == BGP_PEER_EBGP) { /* This is implicit withdraw so we should update - dampening - information. */ + * dampening information. + */ if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) bgp_damp_withdraw(pi, dest, afi, safi, 1); } @@ -3979,7 +4034,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, #endif /* Update bgp route dampening information. */ - if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) + if (get_active_bdc_from_pi(pi, afi, safi) && peer->sort == BGP_PEER_EBGP) { /* Now we do normal update dampening. */ ret = bgp_damp_update(pi, dest, afi, safi); @@ -4013,7 +4068,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, nh_afi = BGP_ATTR_NH_AFI(afi, pi->attr); if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, nh_afi, - pi, NULL, connected) + safi, pi, NULL, connected) || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)) bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID); @@ -4158,7 +4213,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, nh_afi = BGP_ATTR_NH_AFI(afi, new->attr); - if (bgp_find_or_add_nexthop(bgp, bgp, nh_afi, new, NULL, + if (bgp_find_or_add_nexthop(bgp, bgp, nh_afi, safi, new, NULL, connected) || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)) bgp_path_info_set_flag(dest, new, BGP_PATH_VALID); @@ -4595,8 +4650,10 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data) continue; /* graceful restart STALE flag set. */ - if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT) - && peer->nsf[afi][safi] + if (((CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT) + && peer->nsf[afi][safi]) + || CHECK_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_ENHANCED_REFRESH)) && !CHECK_FLAG(pi->flags, BGP_PATH_STALE) && !CHECK_FLAG(pi->flags, BGP_PATH_UNUSEABLE)) bgp_path_info_set_flag(dest, pi, BGP_PATH_STALE); @@ -4847,7 +4904,7 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) struct bgp_path_info *pi; struct bgp_table *table; - if (safi == SAFI_MPLS_VPN) { + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; dest = bgp_route_next(dest)) { struct bgp_dest *rm; @@ -4886,6 +4943,81 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) } } +void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_dest *dest, *ndest; + struct bgp_path_info *pi; + struct bgp_table *table; + + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { + for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; + dest = bgp_route_next(dest)) { + table = bgp_dest_get_bgp_table_info(dest); + if (!table) + continue; + + for (ndest = bgp_table_top(table); ndest; + ndest = bgp_route_next(ndest)) { + for (pi = bgp_dest_get_bgp_path_info(ndest); pi; + pi = pi->next) { + if (pi->peer != peer) + continue; + + if ((CHECK_FLAG( + peer->af_sflags[afi][safi], + PEER_STATUS_ENHANCED_REFRESH)) + && !CHECK_FLAG(pi->flags, + BGP_PATH_STALE) + && !CHECK_FLAG( + pi->flags, + BGP_PATH_UNUSEABLE)) { + if (bgp_debug_neighbor_events( + peer)) + zlog_debug( + "%s: route-refresh for %s/%s, marking prefix %pFX as stale", + peer->host, + afi2str(afi), + safi2str(safi), + bgp_dest_get_prefix( + ndest)); + + bgp_path_info_set_flag( + ndest, pi, + BGP_PATH_STALE); + } + } + } + } + } else { + for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; + dest = bgp_route_next(dest)) { + for (pi = bgp_dest_get_bgp_path_info(dest); pi; + pi = pi->next) { + if (pi->peer != peer) + continue; + + if ((CHECK_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_ENHANCED_REFRESH)) + && !CHECK_FLAG(pi->flags, BGP_PATH_STALE) + && !CHECK_FLAG(pi->flags, + BGP_PATH_UNUSEABLE)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug( + "%s: route-refresh for %s/%s, marking prefix %pFX as stale", + peer->host, + afi2str(afi), + safi2str(safi), + bgp_dest_get_prefix( + dest)); + + bgp_path_info_set_flag(dest, pi, + BGP_PATH_STALE); + } + } + } + } +} + bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) { if (peer->sort == BGP_PEER_IBGP) @@ -5319,7 +5451,8 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, bgp_nexthop = pi->extra->bgp_orig; if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, - afi, pi, NULL, 0)) + afi, safi, pi, NULL, + 0)) bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID); else { @@ -5371,7 +5504,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, /* Nexthop reachability check. */ if (CHECK_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK) && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) { - if (bgp_find_or_add_nexthop(bgp, bgp, afi, new, NULL, 0)) + if (bgp_find_or_add_nexthop(bgp, bgp, afi, safi, new, NULL, 0)) bgp_path_info_set_flag(dest, new, BGP_PATH_VALID); else { if (BGP_DEBUG(nht, NHT)) { @@ -6576,6 +6709,9 @@ static void bgp_aggregate_install( if (!attr) { bgp_aggregate_delete(bgp, p, afi, safi, aggregate); + if (BGP_DEBUG(update_groups, UPDATE_GROUPS)) + zlog_debug("%s: %pFX null attribute", __func__, + p); return; } @@ -7094,6 +7230,13 @@ static void bgp_add_route_to_aggregate(struct bgp *bgp, struct ecommunity *ecommunity = NULL; struct lcommunity *lcommunity = NULL; + /* If the bgp instance is being deleted or self peer is deleted + * then do not create aggregate route + */ + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) + || (bgp->peer_self == NULL)) + return; + /* ORIGIN attribute: If at least one route among routes that are * aggregated has ORIGIN with the value INCOMPLETE, then the * aggregated route must have the ORIGIN attribute with the value @@ -7210,6 +7353,13 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, struct lcommunity *lcommunity = NULL; unsigned long match = 0; + /* If the bgp instance is being deleted or self peer is deleted + * then do not create aggregate route + */ + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) + || (bgp->peer_self == NULL)) + return; + if (BGP_PATH_HOLDDOWN(pi)) return; @@ -7406,6 +7556,13 @@ int bgp_aggregate_unset(struct bgp *bgp, struct prefix *prefix, afi_t afi, struct bgp_dest *dest; struct bgp_aggregate *aggregate; + /* If the bgp instance is being deleted or self peer is deleted + * then do not create aggregate route + */ + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) + || (bgp->peer_self == NULL)) + return 0; + apply_mask(prefix); /* Old configuration check. */ dest = bgp_node_lookup(bgp->aggregate[afi][safi], prefix); @@ -8115,7 +8272,7 @@ bgp_path_selection_reason2str(enum bgp_path_selection_reason reason) case bgp_path_selection_router_id: return "Router ID"; case bgp_path_selection_cluster_length: - return "Cluser length"; + return "Cluster length"; case bgp_path_selection_stale: return "Path Staleness"; case bgp_path_selection_local_configured: @@ -9508,22 +9665,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, inet_ntop(AF_INET, &attr->aggregator_addr, buf, sizeof(buf))); - if (attr->aggregator_as == BGP_AS_ZERO) - json_object_boolean_true_add( - json_path, "aggregatorAsMalformed"); - else - json_object_boolean_false_add( - json_path, "aggregatorAsMalformed"); } else { - if (attr->aggregator_as == BGP_AS_ZERO) - vty_out(vty, - ", (aggregated by %u(malformed) %pI4)", - attr->aggregator_as, - &attr->aggregator_addr); - else - vty_out(vty, ", (aggregated by %u %pI4)", - attr->aggregator_as, - &attr->aggregator_addr); + vty_out(vty, ", (aggregated by %u %pI4)", + attr->aggregator_as, &attr->aggregator_addr); } } @@ -10129,7 +10273,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, } if (path->extra && path->extra->damp_info) - bgp_damp_info_vty(vty, path, afi, safi, json_path); + bgp_damp_info_vty(vty, bgp, path, afi, safi, json_path); /* Remote Label */ if (path->extra && bgp_is_valid_label(&path->extra->label[0]) @@ -10261,6 +10405,24 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, str, label2vni(&attr->label)); } + /* Output some debug about internal state of the dest flags */ + if (json_paths) { + if (CHECK_FLAG(bn->flags, BGP_NODE_PROCESS_SCHEDULED)) + json_object_boolean_true_add(json_path, "processScheduled"); + if (CHECK_FLAG(bn->flags, BGP_NODE_USER_CLEAR)) + json_object_boolean_true_add(json_path, "userCleared"); + if (CHECK_FLAG(bn->flags, BGP_NODE_LABEL_CHANGED)) + json_object_boolean_true_add(json_path, "labelChanged"); + if (CHECK_FLAG(bn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) + json_object_boolean_true_add(json_path, "registeredForLabel"); + if (CHECK_FLAG(bn->flags, BGP_NODE_SELECT_DEFER)) + json_object_boolean_true_add(json_path, "selectDefered"); + if (CHECK_FLAG(bn->flags, BGP_NODE_FIB_INSTALLED)) + json_object_boolean_true_add(json_path, "fibInstalled"); + if (CHECK_FLAG(bn->flags, BGP_NODE_FIB_INSTALL_PENDING)) + json_object_boolean_true_add(json_path, "fibPending"); + } + /* We've constructed the json object for this path, add it to the json * array of paths */ @@ -11163,8 +11325,13 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, vty, use_json, json_paths); - if (use_json && display) - json_object_object_add(json, "paths", json_paths); + if (use_json) { + if (display) + json_object_object_add(json, "paths", + json_paths); + else + json_object_free(json_paths); + } } else { if ((dest = bgp_node_match(rib, &match)) != NULL) { const struct prefix *dest_p = bgp_dest_get_prefix(dest); @@ -11739,10 +11906,6 @@ DEFPY (show_ip_bgp_json, ? AFI_IP : AFI_IP6; FOREACH_SAFI (safi) { - if (strmatch(get_afi_safi_str(afi, safi, true), - "Unknown")) - continue; - if (!bgp_afi_safi_peer_exists(bgp, afi, safi)) continue; @@ -11773,10 +11936,6 @@ DEFPY (show_ip_bgp_json, } else { /* show <ip> bgp all: for each AFI and SAFI*/ FOREACH_AFI_SAFI (afi, safi) { - if (strmatch(get_afi_safi_str(afi, safi, true), - "Unknown")) - continue; - if (!bgp_afi_safi_peer_exists(bgp, afi, safi)) continue; @@ -12148,22 +12307,6 @@ struct bgp_table_stats { double total_space; }; -#if 0 -#define TALLY_SIGFIG 100000 -static unsigned long -ravg_tally (unsigned long count, unsigned long oldavg, unsigned long newval) -{ - unsigned long newtot = (count-1) * oldavg + (newval * TALLY_SIGFIG); - unsigned long res = (newtot * TALLY_SIGFIG) / count; - unsigned long ret = newtot / count; - - if ((res % TALLY_SIGFIG) > (TALLY_SIGFIG/2)) - return ret + 1; - else - return ret; -} -#endif - static void bgp_table_stats_rn(struct bgp_dest *dest, struct bgp_dest *top, struct bgp_table_stats *ts, unsigned int space) { @@ -12178,13 +12321,6 @@ static void bgp_table_stats_rn(struct bgp_dest *dest, struct bgp_dest *top, ts->counts[BGP_STATS_PREFIXES]++; ts->counts[BGP_STATS_TOTPLEN] += rn_p->prefixlen; -#if 0 - ts->counts[BGP_STATS_AVGPLEN] - = ravg_tally (ts->counts[BGP_STATS_PREFIXES], - ts->counts[BGP_STATS_AVGPLEN], - rn_p->prefixlen); -#endif - /* check if the prefix is included by any other announcements */ while (pdest && !bgp_dest_has_bgp_path_info_data(pdest)) pdest = bgp_dest_parent_nolock(pdest); @@ -12221,16 +12357,6 @@ static void bgp_table_stats_rn(struct bgp_dest *dest, struct bgp_dest *top, ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops; ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size; -#if 0 - ts->counts[BGP_STATS_ASPATH_AVGHOPS] - = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], - ts->counts[BGP_STATS_ASPATH_AVGHOPS], - hops); - ts->counts[BGP_STATS_ASPATH_AVGSIZE] - = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], - ts->counts[BGP_STATS_ASPATH_AVGSIZE], - size); -#endif if (highest > ts->counts[BGP_STATS_ASN_HIGHEST]) ts->counts[BGP_STATS_ASN_HIGHEST] = highest; } @@ -12340,15 +12466,6 @@ static int bgp_table_stats_single(struct vty *vty, struct bgp *bgp, afi_t afi, continue; switch (i) { -#if 0 - case BGP_STATS_ASPATH_AVGHOPS: - case BGP_STATS_ASPATH_AVGSIZE: - case BGP_STATS_AVGPLEN: - vty_out (vty, "%-30s: ", table_stats_strs[i]); - vty_out (vty, "%12.2f", - (float)ts.counts[i] / (float)TALLY_SIGFIG); - break; -#endif case BGP_STATS_ASPATH_TOTHOPS: case BGP_STATS_ASPATH_TOTSIZE: if (!json) { @@ -12651,6 +12768,7 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi, "No such neighbor or address family"); vty_out(vty, "%s\n", json_object_to_json_string(json)); json_object_free(json); + json_object_free(json_loop); } else vty_out(vty, "%% No such neighbor or address family\n"); @@ -12903,51 +13021,29 @@ static void show_adj_route_header(struct vty *vty, struct bgp *bgp, } } -static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, - safi_t safi, enum bgp_show_adj_route_type type, - const char *rmap_name, json_object *json, - uint8_t show_flags) +static void +show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, + afi_t afi, safi_t safi, enum bgp_show_adj_route_type type, + const char *rmap_name, json_object *json, json_object *json_ar, + json_object *json_scode, json_object *json_ocode, + uint8_t show_flags, int *header1, int *header2, char *rd_str, + unsigned long *output_count, unsigned long *filtered_count) { - struct bgp_table *table; struct bgp_adj_in *ain; struct bgp_adj_out *adj; - unsigned long output_count = 0; - unsigned long filtered_count = 0; struct bgp_dest *dest; - int header1 = 1; struct bgp *bgp; - int header2 = 1; struct attr attr; int ret; struct update_subgroup *subgrp; - json_object *json_scode = NULL; - json_object *json_ocode = NULL; - json_object *json_ar = NULL; struct peer_af *paf; bool route_filtered; bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); bool wide = CHECK_FLAG(show_flags, BGP_SHOW_OPT_WIDE); - - if (use_json) { - json_scode = json_object_new_object(); - json_ocode = json_object_new_object(); - json_ar = json_object_new_object(); - - json_object_string_add(json_scode, "suppressed", "s"); - json_object_string_add(json_scode, "damped", "d"); - json_object_string_add(json_scode, "history", "h"); - json_object_string_add(json_scode, "valid", "*"); - json_object_string_add(json_scode, "best", ">"); - json_object_string_add(json_scode, "multipath", "="); - json_object_string_add(json_scode, "internal", "i"); - json_object_string_add(json_scode, "ribFailure", "r"); - json_object_string_add(json_scode, "stale", "S"); - json_object_string_add(json_scode, "removed", "R"); - - json_object_string_add(json_ocode, "igp", "i"); - json_object_string_add(json_ocode, "egp", "e"); - json_object_string_add(json_ocode, "incomplete", "?"); - } + bool show_rd = ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) + || (safi == SAFI_EVPN)) + ? true + : false; bgp = peer->bgp; @@ -12961,13 +13057,6 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, return; } - /* labeled-unicast routes live in the unicast table */ - if (safi == SAFI_LABELED_UNICAST) - table = bgp->rib[afi][SAFI_UNICAST]; - else - table = bgp->rib[afi][safi]; - - output_count = filtered_count = 0; subgrp = peer_subgroup(peer, afi, safi); if (type == bgp_show_adj_route_advertised && subgrp @@ -13011,7 +13100,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, vty_out(vty, "Originating default network %s\n\n", (afi == AFI_IP) ? "0.0.0.0/0" : "::/0"); } - header1 = 0; + *header1 = 0; } for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { @@ -13021,9 +13110,23 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, if (ain->peer != peer) continue; - show_adj_route_header( - vty, bgp, table, &header1, &header2, - json, json_scode, json_ocode, wide); + show_adj_route_header(vty, bgp, table, header1, + header2, json, json_scode, + json_ocode, wide); + + if ((safi == SAFI_MPLS_VPN) + || (safi == SAFI_ENCAP) + || (safi == SAFI_EVPN)) { + if (use_json) + json_object_string_add( + json_ar, "rd", rd_str); + else if (show_rd && rd_str) { + vty_out(vty, + "Route Distinguisher: %s\n", + rd_str); + show_rd = false; + } + } attr = *ain->attr; route_filtered = false; @@ -13049,14 +13152,14 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, continue; } - if (type == bgp_show_adj_route_received && - (route_filtered || ret == RMAP_DENY)) - filtered_count++; + if (type == bgp_show_adj_route_received + && (route_filtered || ret == RMAP_DENY)) + (*filtered_count)++; route_vty_out_tmp(vty, rn_p, &attr, safi, use_json, json_ar, wide); bgp_attr_undup(&attr, ain->attr); - output_count++; + (*output_count)++; } } else if (type == bgp_show_adj_route_advertised) { RB_FOREACH (adj, bgp_adj_out_rb, &dest->adj_out) @@ -13064,10 +13167,10 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, if (paf->peer != peer || !adj->attr) continue; - show_adj_route_header( - vty, bgp, table, &header1, - &header2, json, json_scode, - json_ocode, wide); + show_adj_route_header(vty, bgp, table, + header1, header2, + json, json_scode, + json_ocode, wide); const struct prefix *rn_p = bgp_dest_get_prefix(dest); @@ -13078,13 +13181,29 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, rmap_name); if (ret != RMAP_DENY) { + if ((safi == SAFI_MPLS_VPN) + || (safi == SAFI_ENCAP) + || (safi == SAFI_EVPN)) { + if (use_json) + json_object_string_add( + json_ar, + "rd", + rd_str); + else if (show_rd + && rd_str) { + vty_out(vty, + "Route Distinguisher: %s\n", + rd_str); + show_rd = false; + } + } route_vty_out_tmp( vty, rn_p, &attr, safi, use_json, json_ar, wide); - output_count++; + (*output_count)++; } else { - filtered_count++; + (*filtered_count)++; } bgp_attr_undup(&attr, adj->attr); @@ -13092,9 +13211,9 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, } else if (type == bgp_show_adj_route_bestpath) { struct bgp_path_info *pi; - show_adj_route_header(vty, bgp, table, &header1, - &header2, json, json_scode, - json_ocode, wide); + show_adj_route_header(vty, bgp, table, header1, header2, + json, json_scode, json_ocode, + wide); for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { @@ -13108,46 +13227,67 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, bgp_dest_get_prefix(dest), pi->attr, safi, use_json, json_ar, wide); - output_count++; + (*output_count)++; } } } - - if (use_json) { - json_object_object_add(json, "advertisedRoutes", json_ar); - json_object_int_add(json, "totalPrefixCounter", output_count); - json_object_int_add(json, "filteredPrefixCounter", - filtered_count); - - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - - if (!output_count && !filtered_count) { - json_object_free(json_scode); - json_object_free(json_ocode); - } - - json_object_free(json); - } else if (output_count > 0) { - if (filtered_count > 0) - vty_out(vty, - "\nTotal number of prefixes %ld (%ld filtered)\n", - output_count, filtered_count); - else - vty_out(vty, "\nTotal number of prefixes %ld\n", - output_count); - } } static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, enum bgp_show_adj_route_type type, const char *rmap_name, uint8_t show_flags) { + struct bgp *bgp; + struct bgp_table *table; json_object *json = NULL; + json_object *json_scode = NULL; + json_object *json_ocode = NULL; + json_object *json_ar = NULL; bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); - if (use_json) + /* Init BGP headers here so they're only displayed once + * even if 'table' is 2-tier (MPLS_VPN, ENCAP, EVPN). + */ + int header1 = 1; + int header2 = 1; + + /* + * Initialize variables for each RD + * All prefixes under an RD is aggregated within "json_routes" + */ + char rd_str[BUFSIZ] = {0}; + json_object *json_routes = NULL; + + + /* For 2-tier tables, prefix counts need to be + * maintained across multiple runs of show_adj_route() + */ + unsigned long output_count_per_rd; + unsigned long filtered_count_per_rd; + unsigned long output_count = 0; + unsigned long filtered_count = 0; + + if (use_json) { json = json_object_new_object(); + json_ar = json_object_new_object(); + json_scode = json_object_new_object(); + json_ocode = json_object_new_object(); + + json_object_string_add(json_scode, "suppressed", "s"); + json_object_string_add(json_scode, "damped", "d"); + json_object_string_add(json_scode, "history", "h"); + json_object_string_add(json_scode, "valid", "*"); + json_object_string_add(json_scode, "best", ">"); + json_object_string_add(json_scode, "multipath", "="); + json_object_string_add(json_scode, "internal", "i"); + json_object_string_add(json_scode, "ribFailure", "r"); + json_object_string_add(json_scode, "stale", "S"); + json_object_string_add(json_scode, "removed", "R"); + + json_object_string_add(json_ocode, "igp", "i"); + json_object_string_add(json_ocode, "egp", "e"); + json_object_string_add(json_ocode, "incomplete", "?"); + } if (!peer || !peer->afc[afi][safi]) { if (use_json) { @@ -13179,7 +13319,84 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, return CMD_WARNING; } - show_adj_route(vty, peer, afi, safi, type, rmap_name, json, show_flags); + bgp = peer->bgp; + + /* labeled-unicast routes live in the unicast table */ + if (safi == SAFI_LABELED_UNICAST) + table = bgp->rib[afi][SAFI_UNICAST]; + else + table = bgp->rib[afi][safi]; + + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) + || (safi == SAFI_EVPN)) { + + struct bgp_dest *dest; + + for (dest = bgp_table_top(table); dest; + dest = bgp_route_next(dest)) { + table = bgp_dest_get_bgp_table_info(dest); + if (!table) + continue; + + output_count_per_rd = 0; + filtered_count_per_rd = 0; + + if (use_json) + json_routes = json_object_new_object(); + + const struct prefix_rd *prd; + prd = (const struct prefix_rd *)bgp_dest_get_prefix( + dest); + + prefix_rd2str(prd, rd_str, sizeof(rd_str)); + + show_adj_route(vty, peer, table, afi, safi, type, + rmap_name, json, json_routes, json_scode, + json_ocode, show_flags, &header1, + &header2, rd_str, &output_count_per_rd, + &filtered_count_per_rd); + + /* Don't include an empty RD in the output! */ + if (json_routes && (output_count_per_rd > 0)) + json_object_object_add(json_ar, rd_str, + json_routes); + + output_count += output_count_per_rd; + filtered_count += filtered_count_per_rd; + } + } else + show_adj_route(vty, peer, table, afi, safi, type, rmap_name, + json, json_ar, json_scode, json_ocode, + show_flags, &header1, &header2, rd_str, + &output_count, &filtered_count); + + if (use_json) { + json_object_object_add(json, "advertisedRoutes", json_ar); + json_object_int_add(json, "totalPrefixCounter", output_count); + json_object_int_add(json, "filteredPrefixCounter", + filtered_count); + + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + + if (!output_count && !filtered_count) { + json_object_free(json_scode); + json_object_free(json_ocode); + } + + if (json) + json_object_free(json); + + } else if (output_count > 0) { + if (filtered_count > 0) + vty_out(vty, + "\nTotal number of prefixes %ld (%ld filtered)\n", + output_count, filtered_count); + else + vty_out(vty, "\nTotal number of prefixes %ld\n", + output_count); + } return CMD_SUCCESS; } @@ -13318,10 +13535,6 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route, afi = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP) ? AFI_IP : AFI_IP6; FOREACH_SAFI (safi) { - if (strmatch(get_afi_safi_str(afi, safi, true), - "Unknown")) - continue; - if (!bgp_afi_safi_peer_exists(bgp, afi, safi)) continue; @@ -13341,10 +13554,6 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route, } } else { FOREACH_AFI_SAFI (afi, safi) { - if (strmatch(get_afi_safi_str(afi, safi, true), - "Unknown")) - continue; - if (!bgp_afi_safi_peer_exists(bgp, afi, safi)) continue; @@ -14077,7 +14286,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, if (pi->extra && pi->extra->damp_info) { pi_temp = pi->next; bgp_damp_info_free( - pi->extra->damp_info, + &pi->extra->damp_info, + &bgp->damp[afi][safi], 1, afi, safi); pi = pi_temp; } else @@ -14099,7 +14309,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, if (pi->extra && pi->extra->damp_info) { pi_temp = pi->next; bgp_damp_info_free( - pi->extra->damp_info, + &pi->extra->damp_info, + &bgp->damp[afi][safi], 1, afi, safi); pi = pi_temp; } else @@ -14122,7 +14333,9 @@ DEFUN (clear_ip_bgp_dampening, BGP_STR "Clear route flap dampening information\n") { - bgp_damp_info_clean(AFI_IP, SAFI_UNICAST); + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp_damp_info_clean(&bgp->damp[AFI_IP][SAFI_UNICAST], AFI_IP, + SAFI_UNICAST); return CMD_SUCCESS; } |
