summaryrefslogtreecommitdiff
path: root/bgpd/bgp_route.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_route.c')
-rw-r--r--bgpd/bgp_route.c493
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);
}
}