diff options
Diffstat (limited to 'bgpd/bgp_route.c')
| -rw-r--r-- | bgpd/bgp_route.c | 493 |
1 files changed, 383 insertions, 110 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 063cc24dc1..31243c899d 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -434,7 +434,8 @@ void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf) static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, struct bgp_path_info *exist, int *paths_eq, struct bgp_maxpaths_cfg *mpath_cfg, int debug, - char *pfx_buf, afi_t afi, safi_t safi) + char *pfx_buf, afi_t afi, safi_t safi, + enum bgp_path_selection_reason *reason) { struct attr *newattr, *existattr; bgp_peer_sort_t new_sort; @@ -463,6 +464,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, /* 0. Null check. */ if (new == NULL) { + *reason = bgp_path_selection_none; if (debug) zlog_debug("%s: new is NULL", pfx_buf); return 0; @@ -472,6 +474,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, bgp_path_info_path_with_addpath_rx_str(new, new_buf); if (exist == NULL) { + *reason = bgp_path_selection_first; if (debug) zlog_debug("%s: %s is the initial bestpath", pfx_buf, new_buf); @@ -514,6 +517,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (newattr->sticky && !existattr->sticky) { + *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( "%s: %s wins over %s due to sticky MAC flag", @@ -522,6 +526,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (!newattr->sticky && existattr->sticky) { + *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( "%s: %s loses to %s due to sticky MAC flag", @@ -534,6 +539,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, exist_mm_seq = mac_mobility_seqnum(existattr); if (new_mm_seq > exist_mm_seq) { + *reason = bgp_path_selection_evpn_seq; if (debug) zlog_debug( "%s: %s wins over %s due to MM seq %u > %u", @@ -543,6 +549,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (new_mm_seq < exist_mm_seq) { + *reason = bgp_path_selection_evpn_seq; if (debug) zlog_debug( "%s: %s loses to %s due to MM seq %u < %u", @@ -557,6 +564,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, */ nh_cmp = bgp_path_info_nexthop_cmp(new, exist); if (nh_cmp < 0) { + *reason = bgp_path_selection_evpn_lower_ip; if (debug) zlog_debug( "%s: %s wins over %s due to same MM seq %u and lower IP %s", @@ -565,6 +573,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, return 1; } if (nh_cmp > 0) { + *reason = bgp_path_selection_evpn_lower_ip; if (debug) zlog_debug( "%s: %s loses to %s due to same MM seq %u and higher IP %s", @@ -579,6 +588,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, exist_weight = existattr->weight; if (new_weight > exist_weight) { + *reason = bgp_path_selection_weight; if (debug) zlog_debug("%s: %s wins over %s due to weight %d > %d", pfx_buf, new_buf, exist_buf, new_weight, @@ -587,6 +597,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (new_weight < exist_weight) { + *reason = bgp_path_selection_weight; if (debug) zlog_debug("%s: %s loses to %s due to weight %d < %d", pfx_buf, new_buf, exist_buf, new_weight, @@ -603,6 +614,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, exist_pref = existattr->local_pref; if (new_pref > exist_pref) { + *reason = bgp_path_selection_local_pref; if (debug) zlog_debug( "%s: %s wins over %s due to localpref %d > %d", @@ -612,6 +624,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (new_pref < exist_pref) { + *reason = bgp_path_selection_local_pref; if (debug) zlog_debug( "%s: %s loses to %s due to localpref %d < %d", @@ -627,6 +640,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, */ if (!(new->sub_type == BGP_ROUTE_NORMAL || new->sub_type == BGP_ROUTE_IMPORTED)) { + *reason = bgp_path_selection_local_route; if (debug) zlog_debug( "%s: %s wins over %s due to preferred BGP_ROUTE type", @@ -636,6 +650,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (!(exist->sub_type == BGP_ROUTE_NORMAL || exist->sub_type == BGP_ROUTE_IMPORTED)) { + *reason = bgp_path_selection_local_route; if (debug) zlog_debug( "%s: %s loses to %s due to preferred BGP_ROUTE type", @@ -655,6 +670,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, aspath_hops += aspath_count_confeds(newattr->aspath); if (aspath_hops < (exist_hops + exist_confeds)) { + *reason = bgp_path_selection_confed_as_path; if (debug) zlog_debug( "%s: %s wins over %s due to aspath (with confeds) hopcount %d < %d", @@ -665,6 +681,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (aspath_hops > (exist_hops + exist_confeds)) { + *reason = bgp_path_selection_confed_as_path; if (debug) zlog_debug( "%s: %s loses to %s due to aspath (with confeds) hopcount %d > %d", @@ -677,6 +694,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, int newhops = aspath_count_hops(newattr->aspath); if (newhops < exist_hops) { + *reason = bgp_path_selection_as_path; if (debug) zlog_debug( "%s: %s wins over %s due to aspath hopcount %d < %d", @@ -686,6 +704,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (newhops > exist_hops) { + *reason = bgp_path_selection_as_path; if (debug) zlog_debug( "%s: %s loses to %s due to aspath hopcount %d > %d", @@ -698,6 +717,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, /* 5. Origin check. */ if (newattr->origin < existattr->origin) { + *reason = bgp_path_selection_origin; if (debug) zlog_debug("%s: %s wins over %s due to ORIGIN %s < %s", pfx_buf, new_buf, exist_buf, @@ -707,6 +727,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (newattr->origin > existattr->origin) { + *reason = bgp_path_selection_origin; if (debug) zlog_debug("%s: %s loses to %s due to ORIGIN %s > %s", pfx_buf, new_buf, exist_buf, @@ -732,6 +753,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, exist_med = bgp_med_value(exist->attr, bgp); if (new_med < exist_med) { + *reason = bgp_path_selection_med; if (debug) zlog_debug( "%s: %s wins over %s due to MED %d < %d", @@ -741,6 +763,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (new_med > exist_med) { + *reason = bgp_path_selection_med; if (debug) zlog_debug( "%s: %s loses to %s due to MED %d > %d", @@ -756,6 +779,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (new_sort == BGP_PEER_EBGP && (exist_sort == BGP_PEER_IBGP || exist_sort == BGP_PEER_CONFED)) { + *reason = bgp_path_selection_peer; if (debug) zlog_debug( "%s: %s wins over %s due to eBGP peer > iBGP peer", @@ -765,6 +789,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (exist_sort == BGP_PEER_EBGP && (new_sort == BGP_PEER_IBGP || new_sort == BGP_PEER_CONFED)) { + *reason = bgp_path_selection_peer; if (debug) zlog_debug( "%s: %s loses to %s due to iBGP peer < eBGP peer", @@ -834,6 +859,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { if (new_sort == BGP_PEER_CONFED && exist_sort == BGP_PEER_IBGP) { + *reason = bgp_path_selection_confed; if (debug) zlog_debug( "%s: %s wins over %s due to confed-external peer > confed-internal peer", @@ -843,6 +869,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (exist_sort == BGP_PEER_CONFED && new_sort == BGP_PEER_IBGP) { + *reason = bgp_path_selection_confed; if (debug) zlog_debug( "%s: %s loses to %s due to confed-internal peer < confed-external peer", @@ -918,6 +945,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, "%s: %s loses to %s after IGP metric comparison", pfx_buf, new_buf, exist_buf); } + *reason = bgp_path_selection_igp_metric; return ret; } @@ -928,6 +956,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (!bgp_flag_check(bgp, BGP_FLAG_COMPARE_ROUTER_ID) && new_sort == BGP_PEER_EBGP && exist_sort == BGP_PEER_EBGP) { if (CHECK_FLAG(new->flags, BGP_PATH_SELECTED)) { + *reason = bgp_path_selection_older; if (debug) zlog_debug( "%s: %s wins over %s due to oldest external", @@ -936,6 +965,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (CHECK_FLAG(exist->flags, BGP_PATH_SELECTED)) { + *reason = bgp_path_selection_older; if (debug) zlog_debug( "%s: %s loses to %s due to oldest external", @@ -959,6 +989,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, exist_id.s_addr = exist->peer->remote_id.s_addr; if (ntohl(new_id.s_addr) < ntohl(exist_id.s_addr)) { + *reason = bgp_path_selection_router_id; if (debug) zlog_debug( "%s: %s wins over %s due to Router-ID comparison", @@ -967,6 +998,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (ntohl(new_id.s_addr) > ntohl(exist_id.s_addr)) { + *reason = bgp_path_selection_router_id; if (debug) zlog_debug( "%s: %s loses to %s due to Router-ID comparison", @@ -979,6 +1011,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, exist_cluster = BGP_CLUSTER_LIST_LENGTH(exist->attr); if (new_cluster < exist_cluster) { + *reason = bgp_path_selection_cluster_length; if (debug) zlog_debug( "%s: %s wins over %s due to CLUSTER_LIST length %d < %d", @@ -988,6 +1021,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (new_cluster > exist_cluster) { + *reason = bgp_path_selection_cluster_length; if (debug) zlog_debug( "%s: %s loses to %s due to CLUSTER_LIST length %d > %d", @@ -1001,6 +1035,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, * valid peer information (as the connection may or may not be up). */ if (CHECK_FLAG(exist->flags, BGP_PATH_STALE)) { + *reason = bgp_path_selection_stale; if (debug) zlog_debug( "%s: %s wins over %s due to latter path being STALE", @@ -1009,6 +1044,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (CHECK_FLAG(new->flags, BGP_PATH_STALE)) { + *reason = bgp_path_selection_stale; if (debug) zlog_debug( "%s: %s loses to %s due to former path being STALE", @@ -1017,14 +1053,19 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } /* locally configured routes to advertise do not have su_remote */ - if (new->peer->su_remote == NULL) + if (new->peer->su_remote == NULL) { + *reason = bgp_path_selection_local_configured; return 0; - if (exist->peer->su_remote == NULL) + } + if (exist->peer->su_remote == NULL) { + *reason = bgp_path_selection_local_configured; return 1; + } ret = sockunion_cmp(new->peer->su_remote, exist->peer->su_remote); if (ret == 1) { + *reason = bgp_path_selection_neighbor_ip; if (debug) zlog_debug( "%s: %s loses to %s due to Neighor IP comparison", @@ -1033,6 +1074,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (ret == -1) { + *reason = bgp_path_selection_neighbor_ip; if (debug) zlog_debug( "%s: %s wins over %s due to Neighor IP comparison", @@ -1040,6 +1082,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, return 1; } + *reason = bgp_path_selection_default; if (debug) zlog_debug("%s: %s wins over %s due to nothing left to compare", pfx_buf, new_buf, exist_buf); @@ -1053,12 +1096,13 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, * This version is compatible with */ int bgp_path_info_cmp_compatible(struct bgp *bgp, struct bgp_path_info *new, struct bgp_path_info *exist, char *pfx_buf, - afi_t afi, safi_t safi) + afi_t afi, safi_t safi, + enum bgp_path_selection_reason *reason) { int paths_eq; int ret; ret = bgp_path_info_cmp(bgp, new, exist, &paths_eq, NULL, 0, pfx_buf, - afi, safi); + afi, safi, reason); if (paths_eq) ret = 0; @@ -1219,20 +1263,6 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p, } } - /* RFC 8212 to prevent route leaks. - * This specification intends to improve this situation by requiring the - * explicit configuration of both BGP Import and Export Policies for any - * External BGP (EBGP) session such as customers, peers, or - * confederation boundaries for all enabled address families. Through - * codification of the aforementioned requirement, operators will - * benefit from consistent behavior across different BGP - * implementations. - */ - if (peer->bgp->ebgp_requires_policy - == DEFAULT_EBGP_POLICY_ENABLED) - if (!bgp_inbound_policy_exists(peer, filter)) - return RMAP_DENY; - /* Route map apply. */ if (rmap) { memset(&rmap_path, 0, sizeof(struct bgp_path_info)); @@ -1781,6 +1811,10 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, peer->rmap_type = 0; if (ret == RMAP_DENYMATCH) { + if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) + zlog_debug("%s [Update:SEND] %s is filtered by route-map", + peer->host, prefix2str(p, buf, sizeof(buf))); + bgp_attr_flush(attr); return 0; } @@ -1854,13 +1888,28 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, * Note: 3rd party nexthop currently implemented for * IPv4 only. */ - if (!bgp_subgrp_multiaccess_check_v4(piattr->nexthop, - subgrp)) + if ((p->family == AF_INET) && + (!bgp_subgrp_multiaccess_check_v4( + piattr->nexthop, + subgrp))) subgroup_announce_reset_nhop( (peer_cap_enhe(peer, afi, safi) ? AF_INET6 : p->family), - attr); + attr); + + if ((p->family == AF_INET6) && + (!bgp_subgrp_multiaccess_check_v6( + piattr->mp_nexthop_global, + subgrp))) + subgroup_announce_reset_nhop( + (peer_cap_enhe(peer, afi, safi) + ? AF_INET6 + : p->family), + attr); + + + } else if (CHECK_FLAG(pi->flags, BGP_PATH_ANNC_NH_SELF)) { /* * This flag is used for leaked vpn-vrf routes @@ -1965,7 +2014,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn, if (bgp_path_info_cmp( bgp, pi2, new_select, &paths_eq, mpath_cfg, debug, - pfx_buf, afi, safi)) { + pfx_buf, afi, safi, + &rn->reason)) { bgp_path_info_unset_flag( rn, new_select, BGP_PATH_DMED_SELECTED); @@ -2038,7 +2088,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn, bgp_path_info_unset_flag(rn, pi, BGP_PATH_DMED_CHECK); if (bgp_path_info_cmp(bgp, pi, new_select, &paths_eq, mpath_cfg, - debug, pfx_buf, afi, safi)) { + debug, pfx_buf, afi, safi, &rn->reason)) { new_select = pi; } } @@ -2094,7 +2144,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn, } bgp_path_info_cmp(bgp, pi, new_select, &paths_eq, - mpath_cfg, debug, pfx_buf, afi, safi); + mpath_cfg, debug, pfx_buf, afi, safi, + &rn->reason); if (paths_eq) { if (debug) @@ -3049,6 +3100,22 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, goto filtered; } + /* RFC 8212 to prevent route leaks. + * This specification intends to improve this situation by requiring the + * explicit configuration of both BGP Import and Export Policies for any + * External BGP (EBGP) session such as customers, peers, or + * confederation boundaries for all enabled address families. Through + * codification of the aforementioned requirement, operators will + * benefit from consistent behavior across different BGP + * implementations. + */ + if (peer->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED) + if (!bgp_inbound_policy_exists(peer, + &peer->filter[afi][safi])) { + reason = "inbound policy missing"; + goto filtered; + } + bgp_attr_dup(&new_attr, attr); /* Apply incoming route-map. @@ -6863,6 +6930,13 @@ static void route_vty_short_status_out(struct vty *vty, vty_out(vty, " "); } +static char *bgp_nexthop_fqdn(struct peer *peer) +{ + if (peer->hostname && bgp_flag_check(peer->bgp, BGP_FLAG_SHOW_HOSTNAME)) + return peer->hostname; + return NULL; +} + /* called from terminal list command */ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_path_info *path, int display, safi_t safi, @@ -6879,6 +6953,7 @@ void route_vty_out(struct vty *vty, struct prefix *p, bool nexthop_othervrf = false; vrf_id_t nexthop_vrfid = VRF_DEFAULT; const char *nexthop_vrfname = VRF_DEFAULT_NAME; + char *nexthop_fqdn = bgp_nexthop_fqdn(path->peer); if (json_paths) json_path = json_object_new_object(); @@ -6974,42 +7049,58 @@ void route_vty_out(struct vty *vty, struct prefix *p, if (json_paths) { json_nexthop_global = json_object_new_object(); - json_object_string_add(json_nexthop_global, "afi", - (af == AF_INET) ? "ip" : "ipv6"); - json_object_string_add(json_nexthop_global, - (af == AF_INET) ? "ip" : "ipv6", - nexthop); + json_object_string_add( + json_nexthop_global, "afi", + nexthop_fqdn ? "fqdn" + : (af == AF_INET) ? "ip" : "ipv6"); + json_object_string_add( + json_nexthop_global, + nexthop_fqdn ? "fqdn" + : (af == AF_INET) ? "ip" : "ipv6", + nexthop_fqdn ? nexthop_fqdn : nexthop); json_object_boolean_true_add(json_nexthop_global, "used"); } else - vty_out(vty, "%s%s", nexthop, vrf_id_str); + vty_out(vty, "%s%s", + nexthop_fqdn ? nexthop_fqdn : nexthop, + vrf_id_str); } else if (safi == SAFI_EVPN) { if (json_paths) { json_nexthop_global = json_object_new_object(); - json_object_string_add(json_nexthop_global, "ip", - inet_ntoa(attr->nexthop)); + json_object_string_add( + json_nexthop_global, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn ? nexthop_fqdn + : inet_ntoa(attr->nexthop)); json_object_string_add(json_nexthop_global, "afi", "ipv4"); json_object_boolean_true_add(json_nexthop_global, "used"); } else - vty_out(vty, "%-16s%s", inet_ntoa(attr->nexthop), + vty_out(vty, "%-16s%s", + nexthop_fqdn ?: inet_ntoa(attr->nexthop), vrf_id_str); } else if (safi == SAFI_FLOWSPEC) { if (attr->nexthop.s_addr != 0) { if (json_paths) { json_nexthop_global = json_object_new_object(); json_object_string_add( - json_nexthop_global, "ip", - inet_ntoa(attr->nexthop)); + json_nexthop_global, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntoa(attr->nexthop)); json_object_string_add(json_nexthop_global, "afi", "ipv4"); json_object_boolean_true_add( json_nexthop_global, "used"); } else { - vty_out(vty, "%-16s", inet_ntoa(attr->nexthop)); + vty_out(vty, "%-16s", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntoa(attr->nexthop)); } } } else if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { @@ -7018,12 +7109,19 @@ void route_vty_out(struct vty *vty, struct prefix *p, if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) json_object_string_add( - json_nexthop_global, "ip", - inet_ntoa(attr->mp_nexthop_global_in)); + json_nexthop_global, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntoa( + attr->mp_nexthop_global_in)); else json_object_string_add( - json_nexthop_global, "ip", - inet_ntoa(attr->nexthop)); + json_nexthop_global, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntoa(attr->nexthop)); json_object_string_add(json_nexthop_global, "afi", "ipv4"); @@ -7033,7 +7131,9 @@ void route_vty_out(struct vty *vty, struct prefix *p, char buf[BUFSIZ]; snprintf(buf, sizeof(buf), "%s%s", - inet_ntoa(attr->nexthop), vrf_id_str); + nexthop_fqdn ? nexthop_fqdn + : inet_ntoa(attr->nexthop), + vrf_id_str); vty_out(vty, "%-16s", buf); } } @@ -7046,9 +7146,13 @@ void route_vty_out(struct vty *vty, struct prefix *p, if (json_paths) { json_nexthop_global = json_object_new_object(); json_object_string_add( - json_nexthop_global, "ip", - inet_ntop(AF_INET6, &attr->mp_nexthop_global, - buf, BUFSIZ)); + json_nexthop_global, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntop(AF_INET6, + &attr->mp_nexthop_global, + buf, BUFSIZ)); json_object_string_add(json_nexthop_global, "afi", "ipv6"); json_object_string_add(json_nexthop_global, "scope", @@ -7060,10 +7164,14 @@ void route_vty_out(struct vty *vty, struct prefix *p, || (path->peer->conf_if)) { json_nexthop_ll = json_object_new_object(); json_object_string_add( - json_nexthop_ll, "ip", - inet_ntop(AF_INET6, - &attr->mp_nexthop_local, buf, - BUFSIZ)); + json_nexthop_ll, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntop( + AF_INET6, + &attr->mp_nexthop_local, + buf, BUFSIZ)); json_object_string_add(json_nexthop_ll, "afi", "ipv6"); json_object_string_add(json_nexthop_ll, "scope", @@ -7102,10 +7210,12 @@ void route_vty_out(struct vty *vty, struct prefix *p, } else { len = vty_out( vty, "%s%s", - inet_ntop( - AF_INET6, - &attr->mp_nexthop_local, - buf, BUFSIZ), + nexthop_fqdn + ? nexthop_fqdn + : inet_ntop( + AF_INET6, + &attr->mp_nexthop_local, + buf, BUFSIZ), vrf_id_str); len = 16 - len; @@ -7117,10 +7227,13 @@ void route_vty_out(struct vty *vty, struct prefix *p, } else { len = vty_out( vty, "%s%s", - inet_ntop(AF_INET6, - &attr->mp_nexthop_global, buf, - BUFSIZ), - vrf_id_str); + nexthop_fqdn + ? nexthop_fqdn + : inet_ntop( + AF_INET6, + &attr->mp_nexthop_global, + buf, BUFSIZ), + vrf_id_str); len = 16 - len; if (len < 1) @@ -7519,21 +7632,26 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p, json_object *json_paths) { struct attr *attr; - char buf[BUFSIZ]; + char buf[BUFSIZ] = {0}; json_object *json_path = NULL; - - if (json_paths) - json_path = json_object_new_object(); + json_object *json_nexthop = NULL; + json_object *json_overlay = NULL; if (!path->extra) return; + if (json_paths) { + json_path = json_object_new_object(); + json_overlay = json_object_new_object(); + json_nexthop = json_object_new_object(); + } + /* short status lead text */ route_vty_short_status_out(vty, path, json_path); /* print prefix and mask */ if (!display) - route_vty_out_route(p, vty, NULL); + route_vty_out_route(p, vty, json_path); else vty_out(vty, "%*s", 17, " "); @@ -7545,35 +7663,69 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p, switch (af) { case AF_INET: - vty_out(vty, "%-16s", - inet_ntop(af, &attr->mp_nexthop_global_in, buf, - BUFSIZ)); + inet_ntop(af, &attr->mp_nexthop_global_in, buf, BUFSIZ); + if (!json_path) { + vty_out(vty, "%-16s", buf); + } else { + json_object_string_add(json_nexthop, "ip", buf); + + json_object_string_add(json_nexthop, "afi", + "ipv4"); + + json_object_object_add(json_path, "nexthop", + json_nexthop); + } break; case AF_INET6: - vty_out(vty, "%s(%s)", - inet_ntop(af, &attr->mp_nexthop_global, buf, - BUFSIZ), - inet_ntop(af, &attr->mp_nexthop_local, buf1, - BUFSIZ)); + inet_ntop(af, &attr->mp_nexthop_global, buf, BUFSIZ); + inet_ntop(af, &attr->mp_nexthop_local, buf1, BUFSIZ); + if (!json_path) { + vty_out(vty, "%s(%s)", buf, buf1); + } else { + json_object_string_add(json_nexthop, + "ipv6Global", buf); + + json_object_string_add(json_nexthop, + "ipv6LinkLocal", buf1); + + json_object_string_add(json_nexthop, "afi", + "ipv6"); + + json_object_object_add(json_path, "nexthop", + json_nexthop); + } break; default: - vty_out(vty, "?"); + if (!json_path) { + vty_out(vty, "?"); + } else { + json_object_string_add(json_nexthop, "Error", + "Unsupported address-family"); + } } char *str = esi2str(&(attr->evpn_overlay.eth_s_id)); - vty_out(vty, "%s", str); + if (!json_path) + vty_out(vty, "%s", str); + else + json_object_string_add(json_overlay, "esi", str); + XFREE(MTYPE_TMP, str); if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)p)) { - vty_out(vty, "/%s", - inet_ntoa(attr->evpn_overlay.gw_ip.ipv4)); + inet_ntop(AF_INET, &(attr->evpn_overlay.gw_ip.ipv4), + buf, BUFSIZ); } else if (is_evpn_prefix_ipaddr_v6((struct prefix_evpn *)p)) { - vty_out(vty, "/%s", - inet_ntop(AF_INET6, - &(attr->evpn_overlay.gw_ip.ipv6), buf, - BUFSIZ)); + inet_ntop(AF_INET6, &(attr->evpn_overlay.gw_ip.ipv6), + buf, BUFSIZ); } + + if (!json_path) + vty_out(vty, "/%s", buf); + else + json_object_string_add(json_overlay, "gw", buf); + if (attr->ecommunity) { char *mac = NULL; struct ecommunity_val *routermac = ecommunity_lookup( @@ -7582,13 +7734,25 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p, if (routermac) mac = ecom_mac2str((char *)routermac->val); if (mac) { - vty_out(vty, "/%s", (char *)mac); + if (!json_path) { + vty_out(vty, "/%s", (char *)mac); + } else { + json_object_string_add(json_overlay, + "rmac", mac); + } XFREE(MTYPE_TMP, mac); } } - vty_out(vty, "\n"); - } + if (!json_path) { + vty_out(vty, "\n"); + } else { + json_object_object_add(json_path, "overlay", + json_overlay); + + json_object_array_add(json_paths, json_path); + } + } } /* dampening route */ @@ -7816,9 +7980,83 @@ static void route_vty_out_tx_ids(struct vty *vty, } } -void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, - struct bgp_path_info *path, afi_t afi, safi_t safi, - json_object *json_paths) +static const char *bgp_path_selection_reason2str( + enum bgp_path_selection_reason reason) +{ + switch (reason) { + case bgp_path_selection_none: + return "Nothing to Select"; + break; + case bgp_path_selection_first: + return "First path received"; + break; + case bgp_path_selection_evpn_sticky_mac: + return "EVPN Sticky Mac"; + break; + case bgp_path_selection_evpn_seq: + return "EVPN sequence number"; + break; + case bgp_path_selection_evpn_lower_ip: + return "EVPN lower IP"; + break; + case bgp_path_selection_weight: + return "Weight"; + break; + case bgp_path_selection_local_pref: + return "Local Pref"; + break; + case bgp_path_selection_local_route: + return "Local Route"; + break; + case bgp_path_selection_confed_as_path: + return "Confederation based AS Path"; + break; + case bgp_path_selection_as_path: + return "AS Path"; + break; + case bgp_path_selection_origin: + return "Origin"; + break; + case bgp_path_selection_med: + return "MED"; + break; + case bgp_path_selection_peer: + return "Peer Type"; + break; + case bgp_path_selection_confed: + return "Confed Peer Type"; + break; + case bgp_path_selection_igp_metric: + return "IGP Metric"; + break; + case bgp_path_selection_older: + return "Older Path"; + break; + case bgp_path_selection_router_id: + return "Router ID"; + break; + case bgp_path_selection_cluster_length: + return "Cluser length"; + break; + case bgp_path_selection_stale: + return "Path Staleness"; + break; + case bgp_path_selection_local_configured: + return "Locally configured route"; + break; + case bgp_path_selection_neighbor_ip: + return "Neighbor IP"; + break; + case bgp_path_selection_default: + return "Nothing left to compare"; + break; + } + return "Invalid (internal error)"; +} + +void route_vty_out_detail(struct vty *vty, struct bgp *bgp, + struct bgp_node *bn, struct bgp_path_info *path, + afi_t afi, safi_t safi, json_object *json_paths) { char buf[INET6_ADDRSTRLEN]; char buf1[BUFSIZ]; @@ -7848,6 +8086,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, bool nexthop_self = CHECK_FLAG(path->flags, BGP_PATH_ANNC_NH_SELF) ? true : false; int i; + char *nexthop_fqdn = bgp_nexthop_fqdn(path->peer); if (json_paths) { json_path = json_object_new_object(); @@ -7858,7 +8097,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, if (!json_paths && safi == SAFI_EVPN) { char tag_buf[30]; - bgp_evpn_route2str((struct prefix_evpn *)p, buf2, sizeof(buf2)); + bgp_evpn_route2str((struct prefix_evpn *)&bn->p, + buf2, sizeof(buf2)); vty_out(vty, " Route %s", buf2); tag_buf[0] = '\0'; if (path->extra && path->extra->num_labels) { @@ -7973,8 +8213,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, /* Line2 display Next-hop, Neighbor, Router-id */ /* Display the nexthop */ - if ((p->family == AF_INET || p->family == AF_ETHERNET - || p->family == AF_EVPN) + if ((bn->p.family == AF_INET || bn->p.family == AF_ETHERNET + || bn->p.family == AF_EVPN) && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { @@ -7982,21 +8222,33 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, || safi == SAFI_EVPN) { if (json_paths) json_object_string_add( - json_nexthop_global, "ip", - inet_ntoa( - attr->mp_nexthop_global_in)); + json_nexthop_global, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntoa( + attr->mp_nexthop_global_in)); else vty_out(vty, " %s", - inet_ntoa( - attr->mp_nexthop_global_in)); + nexthop_fqdn + ? nexthop_fqdn + : inet_ntoa( + attr->mp_nexthop_global_in)); } else { if (json_paths) json_object_string_add( - json_nexthop_global, "ip", - inet_ntoa(attr->nexthop)); + json_nexthop_global, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntoa( + attr->nexthop)); else vty_out(vty, " %s", - inet_ntoa(attr->nexthop)); + nexthop_fqdn + ? nexthop_fqdn + : inet_ntoa( + attr->nexthop)); } if (json_paths) @@ -8005,19 +8257,28 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, } else { if (json_paths) { json_object_string_add( - json_nexthop_global, "ip", - inet_ntop(AF_INET6, - &attr->mp_nexthop_global, buf, - INET6_ADDRSTRLEN)); + json_nexthop_global, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntop( + AF_INET6, + &attr->mp_nexthop_global, + buf, + INET6_ADDRSTRLEN)); json_object_string_add(json_nexthop_global, "afi", "ipv6"); json_object_string_add(json_nexthop_global, "scope", "global"); } else { vty_out(vty, " %s", - inet_ntop(AF_INET6, - &attr->mp_nexthop_global, buf, - INET6_ADDRSTRLEN)); + nexthop_fqdn + ? nexthop_fqdn + : inet_ntop( + AF_INET6, + &attr->mp_nexthop_global, + buf, + INET6_ADDRSTRLEN)); } } @@ -8056,7 +8317,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, if (path->peer == bgp->peer_self) { if (safi == SAFI_EVPN - || (p->family == AF_INET + || (bn->p.family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { if (json_paths) json_object_string_add( @@ -8199,10 +8460,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, if (json_paths) { json_nexthop_ll = json_object_new_object(); json_object_string_add( - json_nexthop_ll, "ip", - inet_ntop(AF_INET6, - &attr->mp_nexthop_local, buf, - INET6_ADDRSTRLEN)); + json_nexthop_ll, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntop( + AF_INET6, + &attr->mp_nexthop_local, + buf, + INET6_ADDRSTRLEN)); json_object_string_add(json_nexthop_ll, "afi", "ipv6"); json_object_string_add(json_nexthop_ll, "scope", @@ -8410,8 +8676,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, json_object_new_object(); json_object_boolean_true_add(json_bestpath, "overall"); - } else + json_object_string_add(json_bestpath, + "selectionReason", + bgp_path_selection_reason2str(bn->reason)); + } else { vty_out(vty, ", best"); + vty_out(vty, " (%s)", + bgp_path_selection_reason2str(bn->reason)); + } } if (json_bestpath) @@ -9012,6 +9284,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, unsigned long i; for (i = 0; i < *json_header_depth; ++i) vty_out(vty, " } "); + vty_out(vty, "\n"); } } else { if (is_last) { @@ -9422,7 +9695,7 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, BGP_PATH_MULTIPATH) || CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)))) - route_vty_out_detail(vty, bgp, &rm->p, + route_vty_out_detail(vty, bgp, rm, pi, AFI_IP, safi, json_paths); } @@ -9466,7 +9739,7 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, pi->flags, BGP_PATH_SELECTED)))) route_vty_out_detail( - vty, bgp, &rn->p, pi, + vty, bgp, rn, pi, afi, safi, json_paths); } } |
