diff options
101 files changed, 2592 insertions, 951 deletions
diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index b83c7b1908..f17842366a 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -719,6 +719,7 @@ babel_interface_close_all(void) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp = NULL; + int type; FOR_ALL_INTERFACES(vrf, ifp) { if(!if_up(ifp)) @@ -740,8 +741,14 @@ babel_interface_close_all(void) flushbuf(ifp); usleep(roughly(10000)); gettime(&babel_now); + babel_enable_if_delete(ifp->name); interface_reset(ifp); } + /* Disable babel redistribution */ + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { + zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, AFI_IP, type, 0, VRF_DEFAULT); + zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, AFI_IP6, type, 0, VRF_DEFAULT); + } } /* return "true" if address is one of our ipv6 addresses */ diff --git a/babeld/babeld.c b/babeld/babeld.c index b562f0b70c..1d2f60e3ad 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -304,6 +304,12 @@ void babel_clean_routing_process(void) flush_all_routes(); babel_interface_close_all(); + /* Clean babel config */ + diversity_kind = DIVERSITY_NONE; + diversity_factor = BABEL_DEFAULT_DIVERSITY_FACTOR; + resend_delay = BABEL_DEFAULT_RESEND_DELAY; + change_smoothing_half_life(BABEL_DEFAULT_SMOOTHING_HALF_LIFE); + /* cancel events */ event_cancel(&babel_routing_process->t_read); event_cancel(&babel_routing_process->t_update); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 2280aa9097..d349922c52 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -5406,7 +5406,14 @@ enum bgp_attr_parse_ret bgp_attr_ignore(struct peer *peer, uint8_t type) lookup_msg(attr_str, type, NULL), withdraw ? "treat-as-withdraw" : "discard"); - return withdraw ? BGP_ATTR_PARSE_WITHDRAW : BGP_ATTR_PARSE_PROCEED; + /* We don't increment stat_pfx_withdraw here, because it's done in + * bgp_update_receive(). + */ + if (withdraw) + return BGP_ATTR_PARSE_WITHDRAW; + + peer->stat_pfx_discard++; + return BGP_ATTR_PARSE_PROCEED; } bool route_matches_soo(struct bgp_path_info *pi, struct ecommunity *soo) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 3a4364c5f9..acc49cac94 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -1773,8 +1773,7 @@ static void bmp_stats(struct event *thread) peer->stat_pfx_cluster_loop); bmp_stat_put_u32(s, &count, BMP_STATS_PFX_DUP_WITHDRAW, peer->stat_pfx_dup_withdraw); - bmp_stat_put_u32(s, &count, BMP_STATS_UPD_7606_WITHDRAW, - peer->stat_upd_7606); + bmp_stat_put_u32(s, &count, BMP_STATS_UPD_7606_WITHDRAW, peer->stat_pfx_withdraw); if (bt->stats_send_experimental) bmp_stat_put_u32(s, &count, BMP_STATS_FRR_NH_INVALID, peer->stat_pfx_nh_invalid); @@ -2630,8 +2629,11 @@ DEFPY(bmp_connect, } ba = bmp_active_get(bt, hostname, port); - if (srcif) + if (srcif) { + if (ba->ifsrc) + XFREE(MTYPE_TMP, ba->ifsrc); ba->ifsrc = XSTRDUP(MTYPE_TMP, srcif); + } if (min_retry_str) ba->minretry = min_retry; if (max_retry_str) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 338f5cefee..dc6e0d33c2 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -764,10 +764,9 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi, json_path = json_object_new_array(); if (detail) - route_vty_out_detail( - vty, bgp, bd, bgp_dest_get_prefix(bd), - pi, AFI_L2VPN, SAFI_EVPN, - RPKI_NOT_BEING_USED, json_path); + route_vty_out_detail(vty, bgp, bd, bgp_dest_get_prefix(bd), pi, + AFI_L2VPN, SAFI_EVPN, RPKI_NOT_BEING_USED, + json_path, NULL); else route_vty_out(vty, &bd->rn->p, pi, 0, SAFI_EVPN, json_path, false); @@ -892,10 +891,9 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, json_path = json_object_new_array(); if (detail) - route_vty_out_detail(vty, bgp, dest, &tmp_p, pi, - AFI_L2VPN, SAFI_EVPN, - RPKI_NOT_BEING_USED, - json_path); + route_vty_out_detail(vty, bgp, dest, &tmp_p, pi, AFI_L2VPN, + SAFI_EVPN, RPKI_NOT_BEING_USED, json_path, + NULL); else route_vty_out(vty, &tmp_p, pi, 0, SAFI_EVPN, @@ -2570,9 +2568,8 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), - pi, afi, safi, RPKI_NOT_BEING_USED, - json_path); + route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi, safi, + RPKI_NOT_BEING_USED, json_path, NULL); if (json) json_object_array_add(json_paths, json_path); @@ -2699,9 +2696,8 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, NULL /* ip */); } - route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p, - pi, afi, safi, RPKI_NOT_BEING_USED, - json_path); + route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p, pi, afi, safi, + RPKI_NOT_BEING_USED, json_path, NULL); if (json) json_object_array_add(json_paths, json_path); @@ -2810,9 +2806,8 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), - pi, afi, safi, RPKI_NOT_BEING_USED, - json_path); + route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi, safi, + RPKI_NOT_BEING_USED, json_path, NULL); if (json) json_object_array_add(json_paths, json_path); @@ -2923,9 +2918,8 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out_detail( - vty, bgp, dest, bgp_dest_get_prefix(dest), pi, - afi, safi, RPKI_NOT_BEING_USED, json_path); + route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi, + safi, RPKI_NOT_BEING_USED, json_path, NULL); if (json) json_object_array_add(json_paths, json_path); @@ -3060,9 +3054,8 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out_detail(vty, bgp, dest, p, pi, AFI_L2VPN, - SAFI_EVPN, RPKI_NOT_BEING_USED, - json_path); + route_vty_out_detail(vty, bgp, dest, p, pi, AFI_L2VPN, SAFI_EVPN, + RPKI_NOT_BEING_USED, json_path, NULL); if (json) json_object_array_add(json_paths, json_path); @@ -3115,6 +3108,7 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, afi_t afi; safi_t safi; uint32_t prefix_cnt, path_cnt; + int first = true; afi = AFI_L2VPN; safi = SAFI_EVPN; @@ -3139,8 +3133,15 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, prefix_rd2str((struct prefix_rd *)rd_destp, rd_str, sizeof(rd_str), bgp->asnotation); - if (json) + if (json) { + if (first) { + vty_out(vty, "\"%s\":", rd_str); + first = false; + } else { + vty_out(vty, ",\"%s\":", rd_str); + } json_rd = json_object_new_object(); + } rd_header = 1; @@ -3223,11 +3224,10 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, json_path = json_object_new_array(); if (detail) { - route_vty_out_detail( - vty, bgp, dest, - bgp_dest_get_prefix(dest), pi, - AFI_L2VPN, SAFI_EVPN, - RPKI_NOT_BEING_USED, json_path); + route_vty_out_detail(vty, bgp, dest, + bgp_dest_get_prefix(dest), pi, + AFI_L2VPN, SAFI_EVPN, + RPKI_NOT_BEING_USED, json_path, NULL); } else route_vty_out(vty, p, pi, 0, SAFI_EVPN, json_path, false); @@ -3255,18 +3255,18 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, } if (json) { - if (add_rd_to_json) - json_object_object_add(json, rd_str, json_rd); - else { + if (add_rd_to_json) { + vty_json_no_pretty(vty, json_rd); + } else { + vty_out(vty, "{}"); json_object_free(json_rd); - json_rd = NULL; } } } if (json) { - json_object_int_add(json, "numPrefix", prefix_cnt); - json_object_int_add(json, "numPaths", path_cnt); + vty_out(vty, ",\"numPrefix\":%u", prefix_cnt); + vty_out(vty, ",\"numPaths\":%u", path_cnt); } else { if (prefix_cnt == 0) { vty_out(vty, "No EVPN prefixes %sexist\n", @@ -3284,20 +3284,18 @@ int bgp_evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, { json_object *json = NULL; - if (use_json) + if (use_json) { json = json_object_new_object(); + vty_out(vty, "{\n"); + } evpn_show_all_routes(vty, bgp, type, json, detail, false); - if (use_json) - /* - * We are using no_pretty here because under extremely high - * settings (lots of routes with many different paths) this can - * save several minutes of output when FRR is run on older cpu's - * or more underperforming routers out there. So for route - * scale, we need to use no_pretty json. - */ - vty_json_no_pretty(vty, json); + if (use_json) { + vty_out(vty, "}\n"); + json_object_free(json); + } + return CMD_SUCCESS; } @@ -4948,8 +4946,10 @@ DEFUN(show_bgp_l2vpn_evpn_route, if (!bgp) return CMD_WARNING; - if (uj) + if (uj) { json = json_object_new_object(); + vty_out(vty, "{\n"); + } if (bgp_evpn_cli_parse_type(&type, argv, argc) < 0) return CMD_WARNING; @@ -4962,13 +4962,10 @@ DEFUN(show_bgp_l2vpn_evpn_route, evpn_show_all_routes(vty, bgp, type, json, detail, self_orig); - /* - * This is an extremely expensive operation at scale - * and as such we need to save as much time as is - * possible. - */ - if (uj) - vty_json_no_pretty(vty, json); + if (uj) { + vty_out(vty, "}\n"); + json_object_free(json); + } return CMD_SUCCESS; } @@ -5025,10 +5022,20 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd, if (bgp_evpn_cli_parse_type(&type, argv, argc) < 0) return CMD_WARNING; - if (rd_all) + if (rd_all) { + if (uj) + vty_out(vty, "{\n"); + evpn_show_all_routes(vty, bgp, type, json, 1, false); - else + + if (uj) { + vty_out(vty, "}\n"); + json_object_free(json); + return CMD_SUCCESS; + } + } else { evpn_show_route_rd(vty, bgp, &prd, type, json); + } if (uj) vty_json(vty, json); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 6ad8a2e8de..3d02214ca9 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -491,11 +491,14 @@ static void bgp_connect_timer(struct event *thread) assert(!connection->t_read); if (bgp_debug_neighbor_events(peer)) - zlog_debug("%s [FSM] Timer (connect timer expire)", peer->host); + zlog_debug("%s [FSM] Timer (connect timer (%us) expire)", peer->host, + peer->v_connect); if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) bgp_stop(connection); else { + if (!peer->connect) + peer->v_connect = MIN(BGP_MAX_CONNECT_RETRY, peer->v_connect * 2); EVENT_VAL(thread) = ConnectRetry_timer_expired; bgp_event(thread); /* bgp_event unlocks peer */ } @@ -1224,9 +1227,14 @@ void bgp_fsm_change_status(struct peer_connection *connection, peer_count = bgp->established_peers; - if (status == Established) + if (status == Established) { bgp->established_peers++; - else if ((peer_established(connection)) && (status != Established)) + /* Reset the retry timer if we already established */ + if (peer->connect) + peer->v_connect = peer->connect; + else + peer->v_connect = peer->bgp->default_connect_retry; + } else if ((peer_established(connection)) && (status != Established)) bgp->established_peers--; if (bgp_debug_neighbor_events(peer)) { diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c index 23e0c191dc..54a966e191 100644 --- a/bgpd/bgp_labelpool.c +++ b/bgpd/bgp_labelpool.c @@ -1125,7 +1125,6 @@ static void show_bgp_nexthop_label_afi(struct vty *vty, afi_t afi, struct bgp_path_info *path; struct bgp *bgp_path; struct bgp_table *table; - time_t tbuf; vty_out(vty, "Current BGP label nexthop cache for %s, VRF %s\n", afi2str(afi), bgp->name_pretty); @@ -1146,8 +1145,7 @@ static void show_bgp_nexthop_label_afi(struct vty *vty, afi_t afi, vty_out(vty, " if %s\n", ifindex2ifname(iter->nh->ifindex, iter->nh->vrf_id)); - tbuf = time(NULL) - (monotime(NULL) - iter->last_update); - vty_out(vty, " Last update: %s", ctime_r(&tbuf, buf)); + vty_out(vty, " Last update: %s", time_to_string(iter->last_update, buf)); if (!detail) continue; vty_out(vty, " Paths:\n"); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index ecb78c1ce4..b96c287f86 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -4079,6 +4079,35 @@ void bgp_vpn_leak_export(struct bgp *from_bgp) } } +/* It releases the label from labelpool which + * was previously assigned and unsets the flag based on reset arg + * This also used in vty to release the label and to change the allocation mode as well + */ +void bgp_vpn_release_label(struct bgp *bgp, afi_t afi, bool reset) +{ + if (!CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) + return; + /* + * label has previously been automatically + * assigned by labelpool: release it + * + * NB if tovpn_label == MPLS_LABEL_NONE it + * means the automatic assignment is in flight + * and therefore the labelpool callback must + * detect that the auto label is not needed. + */ + if (bgp->vpn_policy[afi].tovpn_label == MPLS_LABEL_NONE) + return; + if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP)) + return; + + bgp_lp_release(LP_TYPE_VRF, &bgp->vpn_policy[afi], bgp->vpn_policy[afi].tovpn_label); + bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE; + + if (reset) + UNSET_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO); +} + /* The nexthops values are compared to * find in the tree the appropriate cache entry */ @@ -4395,7 +4424,6 @@ static void show_bgp_mplsvpn_nh_label_bind_internal(struct vty *vty, struct bgp_path_info *path; struct bgp *bgp_path; struct bgp_table *table; - time_t tbuf; char buf[32]; vty_out(vty, "Current BGP mpls-vpn nexthop label bind cache, %s\n", @@ -4413,8 +4441,7 @@ static void show_bgp_mplsvpn_nh_label_bind_internal(struct vty *vty, vty_out(vty, " interface %s\n", ifindex2ifname(iter->nh->ifindex, iter->nh->vrf_id)); - tbuf = time(NULL) - (monotime(NULL) - iter->last_update); - vty_out(vty, " Last update: %s", ctime_r(&tbuf, buf)); + vty_out(vty, " Last update: %s", time_to_string(iter->last_update, buf)); if (!detail) continue; vty_out(vty, " Paths:\n"); diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 39fed66781..18639fc69b 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -352,6 +352,7 @@ extern void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw, bool is_config); extern void bgp_vpn_leak_unimport(struct bgp *from_bgp); extern void bgp_vpn_leak_export(struct bgp *from_bgp); +extern void bgp_vpn_release_label(struct bgp *bgp, afi_t afi, bool reset); extern bool bgp_mplsvpn_path_uses_valid_mpls_label(struct bgp_path_info *pi); extern int diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 1ef90a8e38..a1ab9d2d61 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -970,9 +970,8 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, json_object_object_add(json, "nexthops", json_gates); } -static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, - struct bgp_nexthop_cache *bnc, bool specific, - json_object *json) +static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, struct bgp_nexthop_cache *bnc, + bool detail, bool uj) { char buf[PREFIX2STR_BUFFER]; time_t tbuf; @@ -983,10 +982,10 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, peer = (struct peer *)bnc->nht_info; - if (json) + if (uj) json_nexthop = json_object_new_object(); if (bnc->srte_color) { - if (json) + if (uj) json_object_int_add(json_nexthop, "srteColor", bnc->srte_color); else @@ -994,7 +993,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, buf, sizeof(buf)); if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) { - if (json) { + if (uj) { json_object_boolean_true_add(json_nexthop, "valid"); json_object_boolean_true_add(json_nexthop, "complete"); json_object_int_add(json_nexthop, "igpMetric", @@ -1022,7 +1021,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop); } else if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) { - if (json) { + if (uj) { json_object_boolean_true_add(json_nexthop, "valid"); json_object_boolean_false_add(json_nexthop, "complete"); json_object_int_add(json_nexthop, "igpMetric", @@ -1042,7 +1041,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop); } else { - if (json) { + if (uj) { json_object_boolean_false_add(json_nexthop, "valid"); json_object_boolean_false_add(json_nexthop, "complete"); json_object_int_add(json_nexthop, "pathCount", @@ -1074,38 +1073,41 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } } tbuf = time(NULL) - (monotime(NULL) - bnc->last_update); - if (json) { - if (!specific) { + if (uj) { + if (detail) { json_last_update = json_object_new_object(); json_object_int_add(json_last_update, "epoch", tbuf); json_object_string_add(json_last_update, "string", - ctime_r(&tbuf, timebuf)); + time_to_string_json(bnc->last_update, timebuf)); json_object_object_add(json_nexthop, "lastUpdate", json_last_update); } else { json_object_int_add(json_nexthop, "lastUpdate", tbuf); } } else { - vty_out(vty, " Last update: %s", ctime_r(&tbuf, timebuf)); + vty_out(vty, " Last update: %s", time_to_string(bnc->last_update, timebuf)); } /* show paths dependent on nexthop, if needed. */ - if (specific) + if (detail) bgp_show_nexthop_paths(vty, bgp, bnc, json_nexthop); - if (json) - json_object_object_add(json, buf, json_nexthop); + + if (uj) { + vty_out(vty, "\"%s\":", buf); + vty_json_no_pretty(vty, json_nexthop); + } } -static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, - bool import_table, json_object *json, afi_t afi, - bool detail) +static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, bool import_table, bool uj, + afi_t afi, bool detail) { struct bgp_nexthop_cache *bnc; struct bgp_nexthop_cache_head(*tree)[AFI_MAX]; - json_object *json_afi = NULL; bool found = false; + bool firstafi = true; + bool firstnh = true; - if (!json) { + if (!uj) { if (import_table) vty_out(vty, "Current BGP import check cache:\n"); else @@ -1117,34 +1119,42 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, tree = &bgp->nexthop_cache_table; if (afi == AFI_IP || afi == AFI_IP6) { - if (json) - json_afi = json_object_new_object(); + if (uj) + vty_out(vty, "%s:{", (afi == AFI_IP) ? "\"ipv4\"" : "\"ipv6\""); frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) { - bgp_show_nexthop(vty, bgp, bnc, detail, json_afi); + if (uj) + vty_out(vty, "%s", firstnh ? "" : ","); + bgp_show_nexthop(vty, bgp, bnc, detail, uj); found = true; + firstnh = false; } - if (found && json) - json_object_object_add( - json, (afi == AFI_IP) ? "ipv4" : "ipv6", - json_afi); + if (found && uj) + vty_out(vty, "}"); return; } for (afi = AFI_IP; afi < AFI_MAX; afi++) { - if (json && (afi == AFI_IP || afi == AFI_IP6)) - json_afi = json_object_new_object(); - frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) - bgp_show_nexthop(vty, bgp, bnc, detail, json_afi); - if (json && (afi == AFI_IP || afi == AFI_IP6)) - json_object_object_add( - json, (afi == AFI_IP) ? "ipv4" : "ipv6", - json_afi); + if (afi != AFI_IP && afi != AFI_IP6) + continue; + if (uj) + vty_out(vty, "%s%s:{", firstafi ? "" : ",", + (afi == AFI_IP) ? "\"ipv4\"" : "\"ipv6\""); + firstafi = false; + firstnh = true; + frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) { + if (uj) + vty_out(vty, "%s", firstnh ? "" : ","); + bgp_show_nexthop(vty, bgp, bnc, detail, uj); + firstnh = false; + } + + if (uj) + vty_out(vty, "}"); } } -static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, - const char *nhopip_str, bool import_table, - json_object *json, afi_t afi, bool detail) +static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, const char *nhopip_str, + bool import_table, bool uj, afi_t afi, bool detail) { struct bgp *bgp; @@ -1153,7 +1163,7 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, else bgp = bgp_get_default(); if (!bgp) { - if (!json) + if (!uj) vty_out(vty, "%% No such BGP instance exist\n"); return CMD_WARNING; } @@ -1163,61 +1173,57 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, struct bgp_nexthop_cache_head (*tree)[AFI_MAX]; struct bgp_nexthop_cache *bnc; bool found = false; - json_object *json_afi = NULL; if (!str2prefix(nhopip_str, &nhop)) { - if (!json) + if (!uj) vty_out(vty, "nexthop address is malformed\n"); return CMD_WARNING; } tree = import_table ? &bgp->import_check_table : &bgp->nexthop_cache_table; - if (json) - json_afi = json_object_new_object(); + if (uj) + vty_out(vty, "%s:{", + (family2afi(nhop.family) == AFI_IP) ? "\"ipv4\"" : "\"ipv6\""); frr_each (bgp_nexthop_cache, &(*tree)[family2afi(nhop.family)], bnc) { if (prefix_cmp(&bnc->prefix, &nhop)) continue; - bgp_show_nexthop(vty, bgp, bnc, true, json_afi); + bgp_show_nexthop(vty, bgp, bnc, true, uj); found = true; } - if (json) - json_object_object_add( - json, - (family2afi(nhop.family) == AFI_IP) ? "ipv4" - : "ipv6", - json_afi); - if (!found && !json) + if (!found && !uj) vty_out(vty, "nexthop %s does not have entry\n", nhopip_str); + + if (uj) + vty_out(vty, "}"); } else - bgp_show_nexthops(vty, bgp, import_table, json, afi, detail); + bgp_show_nexthops(vty, bgp, import_table, uj, afi, detail); return CMD_SUCCESS; } -static void bgp_show_all_instances_nexthops_vty(struct vty *vty, - json_object *json, afi_t afi, - bool detail) +static void bgp_show_all_instances_nexthops_vty(struct vty *vty, bool uj, afi_t afi, bool detail) { struct listnode *node, *nnode; struct bgp *bgp; const char *inst_name; - json_object *json_instance = NULL; + bool firstinst = true; for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { inst_name = (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) ? VRF_DEFAULT_NAME : bgp->name; - if (json) - json_instance = json_object_new_object(); + if (uj) + vty_out(vty, "%s\"%s\":{", firstinst ? "" : ",", inst_name); + else vty_out(vty, "\nInstance %s:\n", inst_name); - bgp_show_nexthops(vty, bgp, false, json_instance, afi, detail); - - if (json) - json_object_object_add(json, inst_name, json_instance); + bgp_show_nexthops(vty, bgp, false, uj, afi, detail); + firstinst = false; + if (uj) + vty_out(vty, "}"); } } @@ -1241,20 +1247,18 @@ DEFPY (show_ip_bgp_nexthop, JSON_STR) { int rc = 0; - json_object *json = NULL; afi_t afiz = AFI_UNSPEC; if (uj) - json = json_object_new_object(); + vty_out(vty, "{\n"); if (afi) afiz = bgp_vty_afi_from_str(afi); - rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_str, false, json, afiz, - detail); + rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_str, false, uj, afiz, detail); if (uj) - vty_json(vty, json); + vty_out(vty, "}\n"); return rc; } @@ -1271,16 +1275,14 @@ DEFPY (show_ip_bgp_import_check, JSON_STR) { int rc = 0; - json_object *json = NULL; if (uj) - json = json_object_new_object(); + vty_out(vty, "{\n"); - rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, json, AFI_UNSPEC, - detail); + rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, uj, AFI_UNSPEC, detail); if (uj) - vty_json(vty, json); + vty_out(vty, "}\n"); return rc; } @@ -1298,19 +1300,18 @@ DEFPY (show_ip_bgp_instance_all_nexthop, "Show detailed information\n" JSON_STR) { - json_object *json = NULL; afi_t afiz = AFI_UNSPEC; if (uj) - json = json_object_new_object(); + vty_out(vty, "{"); if (afi) afiz = bgp_vty_afi_from_str(afi); - bgp_show_all_instances_nexthops_vty(vty, json, afiz, detail); + bgp_show_all_instances_nexthops_vty(vty, uj, afiz, detail); if (uj) - vty_json(vty, json); + vty_out(vty, "}"); return CMD_SUCCESS; } diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 6a4a02dcc8..5679c215b1 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -82,7 +82,7 @@ struct bgp_nexthop_cache { * L3 unreachable | VALID = 0 | VALID = 0 * | INCOMPLETE = 0 | INCOMPLETE = 0 */ -#define BGP_NEXTHOP_EVPN_INCOMPLETE (1 << 7) +#define BGP_NEXTHOP_EVPN_INCOMPLETE (1 << 8) uint32_t srte_color; diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index e9cc52449b..c5e390b045 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -2411,7 +2411,7 @@ static int bgp_update_receive(struct peer_connection *connection, sizeof(peer->rcvd_attr_str)); if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) { - peer->stat_upd_7606++; + peer->stat_pfx_withdraw++; flog_err( EC_BGP_UPDATE_RCV, "%pBP rcvd UPDATE with errors in attr(s)!! Withdrawing route.", diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 7c3dd234a2..5ac1d26603 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -78,6 +78,9 @@ #include "bgpd/bgp_route_clippy.c" +DEFINE_MTYPE_STATIC(BGPD, BGP_EOIU_MARKER_INFO, "BGP EOIU Marker info"); +DEFINE_MTYPE_STATIC(BGPD, BGP_METAQ, "BGP MetaQ"); + DEFINE_HOOK(bgp_snmp_update_stats, (struct bgp_dest *rn, struct bgp_path_info *pi, bool added), (rn, pi, added)); @@ -3488,14 +3491,6 @@ bool bgp_zebra_has_route_changed(struct bgp_path_info *selected) return false; } -struct bgp_process_queue { - struct bgp *bgp; - STAILQ_HEAD(, bgp_dest) pqueue; -#define BGP_PROCESS_QUEUE_EOIU_MARKER (1 << 0) - unsigned int flags; - unsigned int queued; -}; - static void bgp_process_evpn_route_injection(struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_dest *dest, struct bgp_path_info *new_select, @@ -4043,43 +4038,286 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) &bgp->gr_info[afi][safi].t_route_select); } -static wq_item_status bgp_process_wq(struct work_queue *wq, void *data) +static const char *subqueue2str(enum meta_queue_indexes index) { - struct bgp_process_queue *pqnode = data; - struct bgp *bgp = pqnode->bgp; - struct bgp_table *table; - struct bgp_dest *dest; + switch (index) { + case META_QUEUE_EARLY_ROUTE: + return "Early Route"; + case META_QUEUE_OTHER_ROUTE: + return "Other Route"; + case META_QUEUE_EOIU_MARKER: + return "EOIU Marker"; + } + + return "Unknown"; +} + +/* + * Process a node from the Early route subqueue. + */ +static void process_subq_early_route(struct bgp_dest *dest) +{ + struct bgp_table *table = bgp_dest_table(dest); + + if (bgp_debug_bestpath(dest)) + zlog_debug("%s dequeued from sub-queue %s", bgp_dest_get_prefix_str(dest), + subqueue2str(META_QUEUE_EARLY_ROUTE)); + + /* note, new DESTs may be added as part of processing */ + bgp_process_main_one(table->bgp, dest, table->afi, table->safi); + bgp_dest_unlock_node(dest); + bgp_table_unlock(table); +} + +/* + * Process a node from the other subqueue. + */ +static void process_subq_other_route(struct bgp_dest *dest) +{ + struct bgp_table *table = bgp_dest_table(dest); + + if (bgp_debug_bestpath(dest)) + zlog_debug("%s dequeued from sub-queue %s", bgp_dest_get_prefix_str(dest), + subqueue2str(META_QUEUE_OTHER_ROUTE)); + + /* note, new DESTs may be added as part of processing */ + bgp_process_main_one(table->bgp, dest, table->afi, table->safi); + bgp_dest_unlock_node(dest); + bgp_table_unlock(table); +} + +/* + * Process a node from the eoiu marker subqueue. + */ +static void process_eoiu_marker(struct bgp_dest *dest) +{ + struct bgp_eoiu_info *info = bgp_dest_get_bgp_eoiu_info(dest); + + if (!info || !info->bgp) { + zlog_err("Unable to retrieve BGP instance, can't process EOIU marker"); + return; + } + + if (BGP_DEBUG(update, UPDATE_IN)) + zlog_debug("EOIU Marker dequeued from sub-queue %s", + subqueue2str(META_QUEUE_EOIU_MARKER)); + + bgp_process_main_one(info->bgp, NULL, 0, 0); +} + +/* + * Examine the specified subqueue; process one entry and return 1 if + * there is a node, return 0 otherwise. + */ +static unsigned int process_subq(struct bgp_dest_queue *subq, enum meta_queue_indexes qindex) +{ + struct bgp_dest *dest = STAILQ_FIRST(subq); + + if (!dest) + return 0; + + STAILQ_REMOVE_HEAD(subq, pq); + STAILQ_NEXT(dest, pq) = NULL; /* complete unlink */ + + switch (qindex) { + case META_QUEUE_EARLY_ROUTE: + process_subq_early_route(dest); + break; + case META_QUEUE_OTHER_ROUTE: + process_subq_other_route(dest); + break; + case META_QUEUE_EOIU_MARKER: + process_eoiu_marker(dest); + } + + return 1; +} + +/* Dispatch the meta queue by picking and processing the next node from + * a non-empty sub-queue with lowest priority. wq is equal to bgp->process_queue and + * data is pointed to the meta queue structure. + */ +static wq_item_status meta_queue_process(struct work_queue *dummy, void *data) +{ + struct meta_queue *mq = data; + uint32_t i; + + for (i = 0; i < MQ_SIZE; i++) + if (process_subq(mq->subq[i], i)) { + mq->size--; + break; + } + return mq->size ? WQ_REQUEUE : WQ_SUCCESS; +} + +static int early_route_meta_queue_add(struct meta_queue *mq, void *data) +{ + uint8_t qindex = META_QUEUE_EARLY_ROUTE; + struct bgp_dest *dest = data; + + if (bgp_debug_bestpath(dest)) + zlog_debug("%s queued into sub-queue %s", bgp_dest_get_prefix_str(dest), + subqueue2str(qindex)); + + assert(STAILQ_NEXT(dest, pq) == NULL); + STAILQ_INSERT_TAIL(mq->subq[qindex], dest, pq); + mq->size++; + return 0; +} + +static int other_route_meta_queue_add(struct meta_queue *mq, void *data) +{ + uint8_t qindex = META_QUEUE_OTHER_ROUTE; + struct bgp_dest *dest = data; + + if (bgp_debug_bestpath(dest)) + zlog_debug("%s queued into sub-queue %s", bgp_dest_get_prefix_str(dest), + subqueue2str(qindex)); + + assert(STAILQ_NEXT(dest, pq) == NULL); + STAILQ_INSERT_TAIL(mq->subq[qindex], dest, pq); + mq->size++; + return 0; +} + +static int eoiu_marker_meta_queue_add(struct meta_queue *mq, void *data) +{ + uint8_t qindex = META_QUEUE_EOIU_MARKER; + struct bgp_dest *dest = data; + + if (BGP_DEBUG(update, UPDATE_IN)) + zlog_debug("EOIU Marker queued into sub-queue %s", subqueue2str(qindex)); + + assert(STAILQ_NEXT(dest, pq) == NULL); + STAILQ_INSERT_TAIL(mq->subq[qindex], dest, pq); + mq->size++; + return 0; +} + +static int mq_add_handler(struct bgp *bgp, void *data, + int (*mq_add_func)(struct meta_queue *mq, void *data)) +{ + if (bgp->process_queue == NULL) { + zlog_err("%s: work_queue does not exist!", __func__); + return -1; + } + + if (work_queue_empty(bgp->process_queue)) + work_queue_add(bgp->process_queue, bgp->mq); + + return mq_add_func(bgp->mq, data); +} + +int early_route_process(struct bgp *bgp, struct bgp_dest *dest) +{ + if (!dest) { + zlog_err("%s: early route dest is NULL!", __func__); + return -1; + } + + return mq_add_handler(bgp, dest, early_route_meta_queue_add); +} + +int other_route_process(struct bgp *bgp, struct bgp_dest *dest) +{ + if (!dest) { + zlog_err("%s: other route dest is NULL!", __func__); + return -1; + } + + return mq_add_handler(bgp, dest, other_route_meta_queue_add); +} + +int eoiu_marker_process(struct bgp *bgp, struct bgp_dest *dest) +{ + if (!dest) { + zlog_err("%s: eoiu marker dest is NULL!", __func__); + return -1; + } + + return mq_add_handler(bgp, dest, eoiu_marker_meta_queue_add); +} + +/* Create new meta queue. + A destructor function doesn't seem to be necessary here. + */ +static struct meta_queue *meta_queue_new(void) +{ + struct meta_queue *new; + uint32_t i; + + new = XCALLOC(MTYPE_BGP_METAQ, sizeof(struct meta_queue)); - /* eoiu marker */ - if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)) { - bgp_process_main_one(bgp, NULL, 0, 0); - /* should always have dedicated wq call */ - assert(STAILQ_FIRST(&pqnode->pqueue) == NULL); - return WQ_SUCCESS; + for (i = 0; i < MQ_SIZE; i++) { + new->subq[i] = XCALLOC(MTYPE_BGP_METAQ, sizeof(*(new->subq[i]))); + assert(new->subq[i]); + STAILQ_INIT(new->subq[i]); } - while (!STAILQ_EMPTY(&pqnode->pqueue)) { - dest = STAILQ_FIRST(&pqnode->pqueue); - STAILQ_REMOVE_HEAD(&pqnode->pqueue, pq); + return new; +} + +/* Clean up the early meta-queue list */ +static void early_meta_queue_free(struct meta_queue *mq, struct bgp_dest_queue *l) +{ + struct bgp_dest *dest; + + while (!STAILQ_EMPTY(l)) { + dest = STAILQ_FIRST(l); + STAILQ_REMOVE_HEAD(l, pq); STAILQ_NEXT(dest, pq) = NULL; /* complete unlink */ - table = bgp_dest_table(dest); - /* note, new DESTs may be added as part of processing */ - bgp_process_main_one(bgp, dest, table->afi, table->safi); + mq->size--; + } +} - bgp_dest_unlock_node(dest); - bgp_table_unlock(table); +/* Clean up the other meta-queue list */ +static void other_meta_queue_free(struct meta_queue *mq, struct bgp_dest_queue *l) +{ + struct bgp_dest *dest; + + while (!STAILQ_EMPTY(l)) { + dest = STAILQ_FIRST(l); + STAILQ_REMOVE_HEAD(l, pq); + STAILQ_NEXT(dest, pq) = NULL; /* complete unlink */ + mq->size--; } +} - return WQ_SUCCESS; +/* Clean up the eoiu marker meta-queue list */ +static void eoiu_marker_queue_free(struct meta_queue *mq, struct bgp_dest_queue *l) +{ + struct bgp_dest *dest; + + while (!STAILQ_EMPTY(l)) { + dest = STAILQ_FIRST(l); + XFREE(MTYPE_BGP_EOIU_MARKER_INFO, dest->info); + STAILQ_REMOVE_HEAD(l, pq); + STAILQ_NEXT(dest, pq) = NULL; /* complete unlink */ + mq->size--; + } } -static void bgp_processq_del(struct work_queue *wq, void *data) +void bgp_meta_queue_free(struct meta_queue *mq) { - struct bgp_process_queue *pqnode = data; + enum meta_queue_indexes i; - bgp_unlock(pqnode->bgp); + for (i = 0; i < MQ_SIZE; i++) { + switch (i) { + case META_QUEUE_EARLY_ROUTE: + early_meta_queue_free(mq, mq->subq[i]); + break; + case META_QUEUE_OTHER_ROUTE: + other_meta_queue_free(mq, mq->subq[i]); + break; + case META_QUEUE_EOIU_MARKER: + eoiu_marker_queue_free(mq, mq->subq[i]); + break; + } + + XFREE(MTYPE_BGP_METAQ, mq->subq[i]); + } - XFREE(MTYPE_BGP_PROCESS_QUEUE, pqnode); + XFREE(MTYPE_BGP_METAQ, mq); } void bgp_process_queue_init(struct bgp *bgp) @@ -4091,37 +4329,19 @@ void bgp_process_queue_init(struct bgp *bgp) bgp->process_queue = work_queue_new(bm->master, name); } - bgp->process_queue->spec.workfunc = &bgp_process_wq; - bgp->process_queue->spec.del_item_data = &bgp_processq_del; + bgp->process_queue->spec.workfunc = &meta_queue_process; bgp->process_queue->spec.max_retries = 0; bgp->process_queue->spec.hold = 50; /* Use a higher yield value of 50ms for main queue processing */ bgp->process_queue->spec.yield = 50 * 1000L; -} - -static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp) -{ - struct bgp_process_queue *pqnode; - - pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE, - sizeof(struct bgp_process_queue)); - /* unlocked in bgp_processq_del */ - pqnode->bgp = bgp_lock(bgp); - STAILQ_INIT(&pqnode->pqueue); - - return pqnode; + bgp->mq = meta_queue_new(); } static void bgp_process_internal(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info *pi, afi_t afi, safi_t safi, bool early_process) { -#define ARBITRARY_PROCESS_QLEN 10000 - struct work_queue *wq = bgp->process_queue; - struct bgp_process_queue *pqnode; - int pqnode_reuse = 0; - /* * Indicate that *this* pi is in an unsorted * situation, even if the node is already @@ -4171,39 +4391,16 @@ static void bgp_process_internal(struct bgp *bgp, struct bgp_dest *dest, return; } - if (wq == NULL) - return; - - /* Add route nodes to an existing work queue item until reaching the - limit only if is from the same BGP view and it's not an EOIU marker - */ - if (work_queue_item_count(wq)) { - struct work_queue_item *item = work_queue_last_item(wq); - pqnode = item->data; - - if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) || - (pqnode->queued >= ARBITRARY_PROCESS_QLEN && !early_process)) - pqnode = bgp_processq_alloc(bgp); - else - pqnode_reuse = 1; - } else - pqnode = bgp_processq_alloc(bgp); - /* all unlocked in bgp_process_wq */ + /* all unlocked in process_subq_xxx functions */ bgp_table_lock(bgp_dest_table(dest)); SET_FLAG(dest->flags, BGP_NODE_PROCESS_SCHEDULED); bgp_dest_lock_node(dest); - /* can't be enqueued twice */ - assert(STAILQ_NEXT(dest, pq) == NULL); if (early_process) - STAILQ_INSERT_HEAD(&pqnode->pqueue, dest, pq); + early_route_process(bgp, dest); else - STAILQ_INSERT_TAIL(&pqnode->pqueue, dest, pq); - pqnode->queued++; - - if (!pqnode_reuse) - work_queue_add(wq, pqnode); + other_route_process(bgp, dest); return; } @@ -4222,15 +4419,18 @@ void bgp_process_early(struct bgp *bgp, struct bgp_dest *dest, void bgp_add_eoiu_mark(struct bgp *bgp) { - struct bgp_process_queue *pqnode; - - if (bgp->process_queue == NULL) - return; + /* + * Create a dummy dest as the meta queue expects all its elements to be + * dest's + */ + struct bgp_dest *dummy_dest = XCALLOC(MTYPE_BGP_NODE, sizeof(struct bgp_dest)); - pqnode = bgp_processq_alloc(bgp); + struct bgp_eoiu_info *eoiu_info = XCALLOC(MTYPE_BGP_EOIU_MARKER_INFO, + sizeof(struct bgp_eoiu_info)); + eoiu_info->bgp = bgp; - SET_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER); - work_queue_add(bgp->process_queue, pqnode); + bgp_dest_set_bgp_eoiu_info(dummy_dest, eoiu_info); + eoiu_marker_process(bgp, dummy_dest); } static void bgp_maximum_prefix_restart_timer(struct event *thread) @@ -9361,9 +9561,18 @@ static void route_vty_short_status_out(struct vty *vty, const struct prefix *p, json_object *json_path) { - enum rpki_states rpki_state = RPKI_NOT_BEING_USED; + enum rpki_states rpki_state; + + /* RPKI validation state */ + rpki_state = hook_call(bgp_rpki_prefix_status, path->peer, path->attr, p); if (json_path) { + if (rpki_state == RPKI_VALID) + json_object_boolean_true_add(json_path, "rpkiValid"); + else if (rpki_state == RPKI_INVALID) + json_object_boolean_true_add(json_path, "rpkiInvalid"); + else if (rpki_state == RPKI_NOTFOUND) + json_object_boolean_true_add(json_path, "rpkiNotFound"); /* Route status display. */ if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED)) @@ -9411,10 +9620,6 @@ static void route_vty_short_status_out(struct vty *vty, return; } - /* RPKI validation state */ - rpki_state = - hook_call(bgp_rpki_prefix_status, path->peer, path->attr, p); - if (rpki_state == RPKI_VALID) vty_out(vty, "V"); else if (rpki_state == RPKI_INVALID) @@ -10552,14 +10757,13 @@ static void route_vty_out_detail_es_info(struct vty *vty, } void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, - const struct prefix *p, struct bgp_path_info *path, - afi_t afi, safi_t safi, - enum rpki_states rpki_curr_state, - json_object *json_paths) + const struct prefix *p, struct bgp_path_info *path, afi_t afi, + safi_t safi, enum rpki_states rpki_curr_state, json_object *json_paths, + struct attr *pattr) { char buf[INET6_ADDRSTRLEN]; char vni_buf[30] = {}; - struct attr *attr = path->attr; + struct attr *attr = pattr ? pattr : path->attr; time_t tbuf; char timebuf[32]; json_object *json_bestpath = NULL; @@ -11284,6 +11488,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_path, "community", bgp_attr_get_community(attr)->json); } else { + if (!bgp_attr_get_community(attr)->str) + community_str(bgp_attr_get_community(attr), true, true); vty_out(vty, " Community: %s\n", bgp_attr_get_community(attr)->str); } @@ -11291,6 +11497,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, /* Line 5 display Extended-community */ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { + if (!bgp_attr_get_ecommunity(attr)->str) + ecommunity_str(bgp_attr_get_ecommunity(attr)); + if (json_paths) { json_ext_community = json_object_new_object(); json_object_string_add( @@ -11305,6 +11514,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES))) { + if (!bgp_attr_get_ipv6_ecommunity(attr)->str) + ecommunity_str(bgp_attr_get_ipv6_ecommunity(attr)); + if (json_paths) { json_ext_ipv6_community = json_object_new_object(); json_object_string_add(json_ext_ipv6_community, "string", @@ -11330,6 +11542,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_path, "largeCommunity", bgp_attr_get_lcommunity(attr)->json); } else { + if (!bgp_attr_get_lcommunity(attr)->str) + lcommunity_str(bgp_attr_get_lcommunity(attr), true, true); vty_out(vty, " Large Community: %s\n", bgp_attr_get_lcommunity(attr)->str); } @@ -11512,11 +11726,11 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_last_update = json_object_new_object(); json_object_int_add(json_last_update, "epoch", tbuf); json_object_string_add(json_last_update, "string", - ctime_r(&tbuf, timebuf)); + time_to_string_json(path->uptime, timebuf)); json_object_object_add(json_path, "lastUpdate", json_last_update); } else - vty_out(vty, " Last update: %s", ctime_r(&tbuf, timebuf)); + vty_out(vty, " Last update: %s", time_to_string(path->uptime, timebuf)); /* Line 10 display PMSI tunnel attribute, if present */ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) { @@ -11761,14 +11975,13 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa continue; } - if (type == bgp_show_type_rpki) { - if (dest_p->family == AF_INET - || dest_p->family == AF_INET6) - rpki_curr_state = hook_call( - bgp_rpki_prefix_status, - pi->peer, pi->attr, dest_p); - if (rpki_target_state != RPKI_NOT_BEING_USED - && rpki_curr_state != rpki_target_state) + if ((dest_p->family == AF_INET || dest_p->family == AF_INET6) && + (detail_routes || detail_json || type == bgp_show_type_rpki)) { + rpki_curr_state = hook_call(bgp_rpki_prefix_status, pi->peer, + pi->attr, dest_p); + if (type == bgp_show_type_rpki && + rpki_target_state != RPKI_NOT_BEING_USED && + rpki_curr_state != rpki_target_state) continue; } @@ -11997,11 +12210,9 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa prd, table->afi, safi, NULL, false, false); - route_vty_out_detail( - vty, bgp, dest, dest_p, pi, - family2afi(dest_p->family), - safi, RPKI_NOT_BEING_USED, - json_paths); + route_vty_out_detail(vty, bgp, dest, dest_p, pi, + family2afi(dest_p->family), safi, + rpki_curr_state, json_paths, NULL); } else { route_vty_out(vty, dest_p, pi, display, safi, json_paths, wide); @@ -12114,8 +12325,13 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa } if (is_last) { unsigned long i; - for (i = 0; i < *json_header_depth; ++i) + for (i = 0; i < *json_header_depth; ++i) { vty_out(vty, " } "); + /* Put this information before closing the last `}` */ + if (i == *json_header_depth - 2) + vty_out(vty, ", \"totalRoutes\": %ld, \"totalPaths\": %ld", + output_count, total_count); + } if (!all) vty_out(vty, "\n"); } @@ -12511,11 +12727,10 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, } } -static void bgp_show_path_info(const struct prefix_rd *pfx_rd, - struct bgp_dest *bgp_node, struct vty *vty, - struct bgp *bgp, afi_t afi, safi_t safi, - json_object *json, enum bgp_path_type pathtype, - int *display, enum rpki_states rpki_target_state) +static void bgp_show_path_info(const struct prefix_rd *pfx_rd, struct bgp_dest *bgp_node, + struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, + json_object *json, enum bgp_path_type pathtype, int *display, + enum rpki_states rpki_target_state, struct attr *attr) { struct bgp_path_info *pi; int header = 1; @@ -12558,10 +12773,8 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd, || (pathtype == BGP_PATH_SHOW_MULTIPATH && (CHECK_FLAG(pi->flags, BGP_PATH_MULTIPATH) || CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)))) - route_vty_out_detail(vty, bgp, bgp_node, - bgp_dest_get_prefix(bgp_node), pi, - afi, safi, rpki_curr_state, - json_paths); + route_vty_out_detail(vty, bgp, bgp_node, bgp_dest_get_prefix(bgp_node), pi, + afi, safi, rpki_curr_state, json_paths, attr); } if (json && json_paths) { @@ -12648,9 +12861,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, continue; } - bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, - bgp, afi, safi, json, pathtype, - &display, rpki_target_state); + bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, + json, pathtype, &display, rpki_target_state, NULL); bgp_dest_unlock_node(rm); } @@ -12709,9 +12921,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, rm = longest_pfx; bgp_dest_lock_node(rm); - bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, - bgp, afi, safi, json, pathtype, - &display, rpki_target_state); + bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, + json, pathtype, &display, rpki_target_state, NULL); bgp_dest_unlock_node(rm); } @@ -12737,9 +12948,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, const struct prefix *dest_p = bgp_dest_get_prefix(dest); if (!prefix_check || dest_p->prefixlen == match.prefixlen) { - bgp_show_path_info(NULL, dest, vty, bgp, afi, - safi, json, pathtype, - &display, rpki_target_state); + bgp_show_path_info(NULL, dest, vty, bgp, afi, safi, json, pathtype, + &display, rpki_target_state, NULL); } bgp_dest_unlock_node(dest); @@ -14633,10 +14843,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (use_json) json_net = json_object_new_object(); - bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, - afi, safi, json_net, - BGP_PATH_SHOW_ALL, &display, - RPKI_NOT_BEING_USED); + bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, safi, json_net, + BGP_PATH_SHOW_ALL, &display, RPKI_NOT_BEING_USED, NULL); if (use_json) json_object_object_addf(json_ar, json_net, "%pFX", rn_p); @@ -14770,11 +14978,9 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, pass_in = &buildit; } else pass_in = dest; - bgp_show_path_info( - NULL, pass_in, vty, bgp, afi, - safi, json_net, - BGP_PATH_SHOW_ALL, &display, - RPKI_NOT_BEING_USED); + bgp_show_path_info(NULL, pass_in, vty, bgp, afi, safi, + json_net, BGP_PATH_SHOW_ALL, &display, + RPKI_NOT_BEING_USED, NULL); if (use_json) json_object_object_addf( json_ar, json_net, @@ -14800,9 +15006,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, bgp_dest_get_prefix(dest); attr = *adj->attr; - ret = bgp_output_modifier( - peer, rn_p, &attr, afi, safi, - rmap_name); + ret = bgp_output_modifier(peer, rn_p, &attr, afi, safi, + rmap_name); if (ret == RMAP_DENY) { (*filtered_count)++; @@ -14826,7 +15031,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, json_net = json_object_new_object(); bgp_show_path_info(NULL, dest, vty, bgp, afi, safi, json_net, BGP_PATH_SHOW_ALL, - &display, RPKI_NOT_BEING_USED); + &display, RPKI_NOT_BEING_USED, + adj->attr); if (use_json) json_object_object_addf(json_ar, json_net, "%pFX", rn_p); @@ -14839,7 +15045,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, */ if (use_json) { route_vty_out_tmp(vty, bgp, dest, rn_p, - &attr, safi, use_json, + adj->attr, safi, use_json, json_ar, wide); } else { for (bpi = bgp_dest_get_bgp_path_info(dest); @@ -14872,11 +15078,9 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (use_json) json_net = json_object_new_object(); - bgp_show_path_info( - NULL /* prefix_rd */, dest, vty, - bgp, afi, safi, json_net, - BGP_PATH_SHOW_BESTPATH, - &display, RPKI_NOT_BEING_USED); + bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, + safi, json_net, BGP_PATH_SHOW_BESTPATH, + &display, RPKI_NOT_BEING_USED, NULL); if (use_json) json_object_object_addf( json_ar, json_net, @@ -14902,6 +15106,8 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, json_object *json = NULL; json_object *json_ar = NULL; bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); + bool first = true; + struct update_subgroup *subgrp; /* Init BGP headers here so they're only displayed once * even if 'table' is 2-tier (MPLS_VPN, ENCAP, EVPN). @@ -14970,6 +15176,28 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, else table = bgp->rib[afi][safi]; + subgrp = peer_subgroup(peer, afi, safi); + if (use_json) { + if (type == bgp_show_adj_route_advertised || type == bgp_show_adj_route_received) { + if (header1) { + int version = table ? table->version : 0; + vty_out(vty, "\"bgpTableVersion\":%d", version); + vty_out(vty, ",\"bgpLocalRouterId\":\"%pI4\"", &bgp->router_id); + vty_out(vty, ",\"defaultLocPrf\":%u", bgp->default_local_pref); + vty_out(vty, ",\"localAS\":%u", bgp->as); + if (type == bgp_show_adj_route_advertised && subgrp && + CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE)) + vty_out(vty, ",\"bgpOriginatingDefaultNetwork\":\"%s\"", + (afi == AFI_IP) ? "0.0.0.0/0" : "::/0"); + } + + if (type == bgp_show_adj_route_advertised) + vty_out(vty, ",\"advertisedRoutes\": "); + if (type == bgp_show_adj_route_received) + vty_out(vty, ",\"receivedRoutes\": "); + } + } + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN)) { @@ -14988,6 +15216,7 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, json_routes = json_object_new_object(); const struct prefix_rd *prd; + prd = (const struct prefix_rd *)bgp_dest_get_prefix( dest); @@ -15001,34 +15230,56 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, &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); + if (json_routes && (output_count_per_rd > 0) && use_json) { + if (type == bgp_show_adj_route_advertised || + type == bgp_show_adj_route_received) { + if (first) { + vty_out(vty, "\"%s\":", rd_str); + first = false; + } else { + vty_out(vty, ",\"%s\":", rd_str); + } + vty_json_no_pretty(vty, json_routes); + } else { + json_object_object_add(json_ar, rd_str, json_routes); + } + } output_count += output_count_per_rd; filtered_count += filtered_count_per_rd; } - } else + } else { show_adj_route(vty, peer, table, afi, safi, type, rmap_name, json, json_ar, show_flags, &header1, &header2, rd_str, match, &output_count, &filtered_count); + if (use_json) { + if (type == bgp_show_adj_route_advertised || + type == bgp_show_adj_route_received) { + vty_json_no_pretty(vty, json_ar); + } + } + } + if (use_json) { - if (type == bgp_show_adj_route_advertised) - json_object_object_add(json, "advertisedRoutes", - json_ar); - else + if (type == bgp_show_adj_route_advertised || type == bgp_show_adj_route_received) { + vty_out(vty, ",\"totalPrefixCounter\":%lu", output_count); + vty_out(vty, ",\"filteredPrefixCounter\":%lu", filtered_count); + json_object_free(json); + } else { + /* for bgp_show_adj_route_filtered & bgp_show_adj_route_bestpath type */ json_object_object_add(json, "receivedRoutes", json_ar); - json_object_int_add(json, "totalPrefixCounter", output_count); - json_object_int_add(json, "filteredPrefixCounter", - filtered_count); - - /* - * This is an extremely expensive operation at scale - * and non-pretty reduces memory footprint significantly. - */ - vty_json_no_pretty(vty, json); - } else if (output_count > 0) { + json_object_int_add(json, "totalPrefixCounter", output_count); + json_object_int_add(json, "filteredPrefixCounter", filtered_count); + } + + /* + * This is an extremely expensive operation at scale + * and non-pretty reduces memory footprint significantly. + */ + if ((type != bgp_show_adj_route_advertised) && (type != bgp_show_adj_route_received)) + vty_json_no_pretty(vty, json); + } else if (output_count > 0) { if (!match && filtered_count > 0) vty_out(vty, "\nTotal number of prefixes %ld (%ld filtered)\n", @@ -15131,6 +15382,7 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route, uint16_t show_flags = 0; struct listnode *node; struct bgp *abgp; + int ret; if (detail || prefix_str) SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL); @@ -15172,9 +15424,22 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route, else if (argv_find(argv, argc, "filtered-routes", &idx)) type = bgp_show_adj_route_filtered; - if (!all) - return peer_adj_routes(vty, peer, afi, safi, type, route_map, - prefix_str ? prefix : NULL, show_flags); + if (!all) { + if (uj) + if (type == bgp_show_adj_route_advertised || + type == bgp_show_adj_route_received) + vty_out(vty, "{\n"); + + ret = peer_adj_routes(vty, peer, afi, safi, type, route_map, + prefix_str ? prefix : NULL, show_flags); + if (uj) + if (type == bgp_show_adj_route_advertised || + type == bgp_show_adj_route_received) + vty_out(vty, "}\n"); + + return ret; + } + if (uj) vty_out(vty, "{\n"); @@ -15573,6 +15838,28 @@ static int bgp_distance_unset(struct vty *vty, const char *distance_str, return CMD_SUCCESS; } +void bgp_address_family_distance_delete(void) +{ + afi_t afi = AFI_UNSPEC; + safi_t safi = SAFI_UNSPEC; + struct bgp_dest *dest = NULL; + struct bgp_distance *bdistance = NULL; + + FOREACH_AFI_SAFI (afi, safi) { + for (dest = bgp_table_top(bgp_distance_table[afi][safi]); dest; + dest = bgp_route_next(dest)) { + if (!bgp_dest_has_bgp_path_info_data(dest)) + continue; + bdistance = bgp_dest_get_bgp_distance_info(dest); + XFREE(MTYPE_AS_LIST, bdistance->access_list); + bgp_distance_free(bdistance); + + bgp_dest_set_bgp_distance_info(dest, NULL); + bgp_dest_unlock_node(dest); + } + } +} + /* Apply BGP information to distance method. */ uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo, afi_t afi, safi_t safi, struct bgp *bgp) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 1df0ffd300..474e229575 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -589,6 +589,42 @@ enum bgp_path_type { BGP_PATH_SHOW_MULTIPATH }; +/* meta-queue structure: + * sub-queue 0: soo routes + * sub-queue 1: other routes + */ +#define MQ_SIZE 3 + +/* For checking that an object has already queued in some sub-queue */ +#define MQ_BIT_MASK ((1 << MQ_SIZE) - 1) + +struct meta_queue { + STAILQ_HEAD(bgp_dest_queue, bgp_dest) * subq[MQ_SIZE]; + uint32_t size; /* sum of lengths of all subqueues */ +}; + +/* + * When the update-delay expires, BGP inserts an EOIU (End-Of-Initial-Update) marker + * into the BGP_PROCESS_QUEUE_EOIU_MARKER meta queue. This meta queue holds only + * bgp_dest structures. To process the EOIU marker, we need to call bgp_process_main_one() + * on the corresponding BGP instance. Since the marker itself isn't a real route + * (a dummy dest is created for this) and doesn't inherently carry the BGP instance pointer, + * we store the struct bgp pointer in the dest->info field. This ensures that, when processing + * the EOIU marker, we have the necessary context (the relevant BGP instance) available. + */ +struct bgp_eoiu_info { + struct bgp *bgp; +}; + +/* + * Meta Q's specific names + */ +enum meta_queue_indexes { + META_QUEUE_EARLY_ROUTE, + META_QUEUE_OTHER_ROUTE, + META_QUEUE_EOIU_MARKER, +}; + static inline void bgp_bump_version(struct bgp_dest *dest) { dest->version = bgp_table_next_version(bgp_dest_table(dest)); @@ -795,6 +831,7 @@ extern void bgp_redistribute_withdraw(struct bgp *, afi_t, int, unsigned short); extern void bgp_static_add(struct bgp *); extern void bgp_static_delete(struct bgp *); +extern void bgp_address_family_distance_delete(void); extern void bgp_static_redo_import_check(struct bgp *); extern void bgp_purge_static_redist_routes(struct bgp *bgp); extern void bgp_static_update(struct bgp *bgp, const struct prefix *p, @@ -932,11 +969,10 @@ extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, safi_t safi, json_object *json, bool incremental_print, bool local_table); -extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, - struct bgp_dest *bn, const struct prefix *p, - struct bgp_path_info *path, afi_t afi, - safi_t safi, enum rpki_states, - json_object *json_paths); +extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, + const struct prefix *p, struct bgp_path_info *path, afi_t afi, + safi_t safi, enum rpki_states, json_object *json_paths, + struct attr *attr); extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, @@ -973,4 +1009,8 @@ extern int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, #define bgp_path_info_add(A, B) \ bgp_path_info_add_with_caller(__func__, (A), (B)) #define bgp_path_info_free(B) bgp_path_info_free_with_caller(__func__, (B)) +extern void bgp_meta_queue_free(struct meta_queue *mq); +extern int early_route_process(struct bgp *bgp, struct bgp_dest *dest); +extern int other_route_process(struct bgp *bgp, struct bgp_dest *dest); +extern int eoiu_marker_process(struct bgp *bgp, struct bgp_dest *dest); #endif /* _QUAGGA_BGP_ROUTE_H */ diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 347c5d02a1..04a709b350 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -155,7 +155,6 @@ static enum route_map_cmd_result_t route_match(void *rule, void *object); static void *route_match_compile(const char *arg); static void revalidate_bgp_node(struct bgp_dest *dest, afi_t afi, safi_t safi); -static void revalidate_all_routes(struct rpki_vrf *rpki_vrf); static bool rpki_debug_conf, rpki_debug_term; @@ -586,48 +585,10 @@ static void rpki_revalidate_prefix(struct event *thread) XFREE(MTYPE_BGP_RPKI_REVALIDATE, rrp); } -static void bgpd_sync_callback(struct event *thread) +static void revalidate_single_prefix(struct vrf *vrf, struct prefix prefix, afi_t afi) { struct bgp *bgp; struct listnode *node; - struct prefix prefix; - struct pfx_record rec; - struct rpki_vrf *rpki_vrf = EVENT_ARG(thread); - struct vrf *vrf = NULL; - - event_add_read(bm->master, bgpd_sync_callback, rpki_vrf, - rpki_vrf->rpki_sync_socket_bgpd, NULL); - - if (atomic_load_explicit(&rpki_vrf->rtr_update_overflow, - memory_order_seq_cst)) { - while (read(rpki_vrf->rpki_sync_socket_bgpd, &rec, - sizeof(struct pfx_record)) != -1) - ; - - atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 0, - memory_order_seq_cst); - revalidate_all_routes(rpki_vrf); - return; - } - - int retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec, - sizeof(struct pfx_record)); - if (retval != sizeof(struct pfx_record)) { - RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd"); - return; - } - pfx_record_to_prefix(&rec, &prefix); - - afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6; - - if (rpki_vrf->vrfname) { - vrf = vrf_lookup_by_name(rpki_vrf->vrfname); - if (!vrf) { - zlog_err("%s(): vrf for rpki %s not found", __func__, - rpki_vrf->vrfname); - return; - } - } for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { safi_t safi; @@ -655,101 +616,76 @@ static void bgpd_sync_callback(struct event *thread) } } -static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi, - safi_t safi) +static void bgpd_sync_callback(struct event *thread) { - struct bgp_adj_in *ain; - mpls_label_t *label; - uint8_t num_labels; - - for (ain = bgp_dest->adj_in; ain; ain = ain->next) { - struct bgp_path_info *path = - bgp_dest_get_bgp_path_info(bgp_dest); - - num_labels = BGP_PATH_INFO_NUM_LABELS(path); - label = num_labels ? path->extra->labels->label : NULL; - - (void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest), - ain->addpath_rx_id, ain->attr, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, - num_labels, 1, NULL); - } -} - -/* - * The act of a soft reconfig in revalidation is really expensive - * coupled with the fact that the download of a full rpki state - * from a rpki server can be expensive, let's break up the revalidation - * to a point in time in the future to allow other bgp events - * to take place too. - */ -struct rpki_revalidate_peer { + struct prefix prefix; + struct pfx_record rec; + struct rpki_vrf *rpki_vrf = EVENT_ARG(thread); + struct vrf *vrf = NULL; afi_t afi; - safi_t safi; - struct peer *peer; -}; + int retval; -static void bgp_rpki_revalidate_peer(struct event *thread) -{ - struct rpki_revalidate_peer *rvp = EVENT_ARG(thread); - - /* - * Here's the expensive bit of gnomish deviousness - */ - bgp_soft_reconfig_in(rvp->peer, rvp->afi, rvp->safi); - - XFREE(MTYPE_BGP_RPKI_REVALIDATE, rvp); -} - -static void revalidate_all_routes(struct rpki_vrf *rpki_vrf) -{ - struct bgp *bgp; - struct listnode *node; - struct vrf *vrf = NULL; + event_add_read(bm->master, bgpd_sync_callback, rpki_vrf, rpki_vrf->rpki_sync_socket_bgpd, + NULL); if (rpki_vrf->vrfname) { vrf = vrf_lookup_by_name(rpki_vrf->vrfname); if (!vrf) { - zlog_err("%s(): vrf for rpki %s not found", __func__, - rpki_vrf->vrfname); + zlog_err("%s(): vrf for rpki %s not found", __func__, rpki_vrf->vrfname); return; } } - for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { - struct peer *peer; - struct listnode *peer_listnode; + if (atomic_load_explicit(&rpki_vrf->rtr_update_overflow, memory_order_seq_cst)) { + ssize_t size = 0; - if (!vrf && bgp->vrf_id != VRF_DEFAULT) - continue; - if (vrf && bgp->vrf_id != vrf->vrf_id) - continue; + retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record)); + while (retval != -1) { + if (retval != sizeof(struct pfx_record)) + break; - for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) { - afi_t afi; - safi_t safi; + size += retval; + pfx_record_to_prefix(&rec, &prefix); + afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6; + revalidate_single_prefix(vrf, prefix, afi); - FOREACH_AFI_SAFI (afi, safi) { - struct rpki_revalidate_peer *rvp; + retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec, + sizeof(struct pfx_record)); + } - if (!bgp->rib[afi][safi]) - continue; + RPKI_DEBUG("Socket overflow detected (%zu), revalidating affected prefixes", size); - if (!peer_established(peer->connection)) - continue; + atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 0, memory_order_seq_cst); + return; + } - rvp = XCALLOC(MTYPE_BGP_RPKI_REVALIDATE, - sizeof(*rvp)); - rvp->peer = peer; - rvp->afi = afi; - rvp->safi = safi; + retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record)); + if (retval != sizeof(struct pfx_record)) { + RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd"); + return; + } + pfx_record_to_prefix(&rec, &prefix); - event_add_event( - bm->master, bgp_rpki_revalidate_peer, - rvp, 0, - &peer->t_revalidate_all[afi][safi]); - } - } + afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6; + + revalidate_single_prefix(vrf, prefix, afi); +} + +static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi, safi_t safi) +{ + struct bgp_adj_in *ain; + mpls_label_t *label; + uint8_t num_labels; + + for (ain = bgp_dest->adj_in; ain; ain = ain->next) { + struct bgp_path_info *path = bgp_dest_get_bgp_path_info(bgp_dest); + + num_labels = BGP_PATH_INFO_NUM_LABELS(path); + label = num_labels ? path->extra->labels->label : NULL; + + (void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest), ain->addpath_rx_id, + ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, + label, num_labels, 1, NULL); } } diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 782b5354fa..88276de848 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -391,6 +391,16 @@ static inline void bgp_dest_set_bgp_path_info(struct bgp_dest *dest, dest->info = bi; } +static inline struct bgp_eoiu_info *bgp_dest_get_bgp_eoiu_info(struct bgp_dest *dest) +{ + return dest ? dest->info : NULL; +} + +static inline void bgp_dest_set_bgp_eoiu_info(struct bgp_dest *dest, struct bgp_eoiu_info *eoiu_info) +{ + dest->info = eoiu_info; +} + static inline struct bgp_table * bgp_dest_get_bgp_table_info(struct bgp_dest *dest) { diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index ef03606707..35ddfc34ff 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -757,7 +757,7 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) json_time = json_object_new_object(); json_object_int_add(json_time, "epoch", epoch_tbuf); json_object_string_add(json_time, "epochString", - ctime_r(&epoch_tbuf, timebuf)); + time_to_string_json(updgrp->uptime, timebuf)); json_object_object_add(json_updgrp, "groupCreateTime", json_time); json_object_string_add(json_updgrp, "afi", @@ -766,8 +766,7 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) safi2str(updgrp->safi)); } else { vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id); - vty_out(vty, " Created: %s", - timestamp_string(updgrp->uptime, timebuf)); + vty_out(vty, " Created: %s", time_to_string(updgrp->uptime, timebuf)); } filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi]; @@ -835,15 +834,14 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) json_object_int_add(json_subgrp_time, "epoch", epoch_tbuf); json_object_string_add(json_subgrp_time, "epochString", - ctime_r(&epoch_tbuf, timebuf)); + time_to_string_json(subgrp->uptime, timebuf)); json_object_object_add(json_subgrp, "groupCreateTime", json_subgrp_time); } else { vty_out(vty, "\n"); vty_out(vty, " Update-subgroup %" PRIu64 ":\n", subgrp->id); - vty_out(vty, " Created: %s", - timestamp_string(subgrp->uptime, timebuf)); + vty_out(vty, " Created: %s", time_to_string(subgrp->uptime, timebuf)); } if (subgrp->split_from.update_group_id diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 2fc5dc847f..40b2847c6f 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -95,15 +95,15 @@ FRR_CFG_DEFAULT_BOOL(BGP_DETERMINISTIC_MED, ); FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY, { .val_ulong = 10, .match_profile = "datacenter", }, - { .val_ulong = 120 }, + { .val_ulong = BGP_DEFAULT_CONNECT_RETRY }, ); FRR_CFG_DEFAULT_ULONG(BGP_HOLDTIME, { .val_ulong = 9, .match_profile = "datacenter", }, - { .val_ulong = 180 }, + { .val_ulong = BGP_DEFAULT_KEEPALIVE }, ); FRR_CFG_DEFAULT_ULONG(BGP_KEEPALIVE, { .val_ulong = 3, .match_profile = "datacenter", }, - { .val_ulong = 60 }, + { .val_ulong = BGP_DEFAULT_KEEPALIVE }, ); FRR_CFG_DEFAULT_BOOL(BGP_EBGP_REQUIRES_POLICY, { .val_bool = false, .match_profile = "datacenter", }, @@ -9806,6 +9806,8 @@ DEFPY (af_rd_vpn_export, bgp_get_default(), bgp); if (yes) { + if (bgp->vpn_policy[afi].tovpn_rd_pretty) + XFREE(MTYPE_BGP_NAME, bgp->vpn_policy[afi].tovpn_rd_pretty); bgp->vpn_policy[afi].tovpn_rd_pretty = XSTRDUP(MTYPE_BGP_NAME, rd_str); bgp->vpn_policy[afi].tovpn_rd = prd; @@ -9946,26 +9948,9 @@ DEFPY (af_label_vpn_export, UNSET_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG); - } else if (CHECK_FLAG(bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) { + } else if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) /* release any previous auto label */ - if (bgp->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE) { - - /* - * label has previously been automatically - * assigned by labelpool: release it - * - * NB if tovpn_label == MPLS_LABEL_NONE it - * means the automatic assignment is in flight - * and therefore the labelpool callback must - * detect that the auto label is not needed. - */ - - bgp_lp_release(LP_TYPE_VRF, - &bgp->vpn_policy[afi], - bgp->vpn_policy[afi].tovpn_label); - } - } + bgp_vpn_release_label(bgp, afi, false); if (yes) { if (label_auto) { @@ -11491,6 +11476,72 @@ DEFPY (show_bgp_vrfs, return CMD_SUCCESS; } +DEFPY(show_bgp_router, + show_bgp_router_cmd, + "show bgp router [json]", + SHOW_STR + BGP_STR + "Overall BGP information\n" + JSON_STR) +{ + char timebuf[MONOTIME_STRLEN]; + time_t unix_timestamp; + bool uj = use_json(argc, argv); + json_object *json = NULL; + + if (uj) + json = json_object_new_object(); + + time_to_string(bm->start_time, timebuf); + + if (uj) { + unix_timestamp = time(NULL) - (monotime(NULL) - bm->start_time); + json_object_int_add(json, "bgpStartedAt", unix_timestamp); + json_object_boolean_add(json, "bgpStartedGracefully", + CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART)); + } + + if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART)) { + if (!uj) + vty_out(vty, "BGP started gracefully at %s", timebuf); + else + json_object_boolean_add(json, "grComplete", + CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)); + + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)) { + time_to_string(bm->gr_completion_time, timebuf); + if (uj) { + unix_timestamp = time(NULL) - + (monotime(NULL) - bm->gr_completion_time); + json_object_int_add(json, "grCompletedAt", unix_timestamp); + } else + vty_out(vty, "Graceful restart completed at %s", timebuf); + } else { + if (!uj) + vty_out(vty, "Graceful restart is in progress\n"); + } + } else { + if (!uj) + vty_out(vty, "BGP started at %s", timebuf); + } + + if (uj) { + json_object_boolean_add(json, "bgpInMaintenanceMode", + (CHECK_FLAG(bm->flags, BM_FLAG_MAINTENANCE_MODE))); + json_object_int_add(json, "bgpInstanceCount", listcount(bm->bgp)); + + vty_json(vty, json); + } else { + if (CHECK_FLAG(bm->flags, BM_FLAG_MAINTENANCE_MODE)) + vty_out(vty, "BGP is in Maintenance mode (BGP GSHUT is in effect)\n"); + + vty_out(vty, "Number of BGP instances (including default): %d\n", + listcount(bm->bgp)); + } + + return CMD_SUCCESS; +} + DEFUN (show_bgp_mac_hash, show_bgp_mac_hash_cmd, "show bgp mac hash", @@ -15479,9 +15530,12 @@ CPP_NOTICE("Remove `gracefulRestartCapability` JSON field") if (use_json) { json_object *json_stat = NULL; + json_object *json_pfx_stat = NULL; + json_stat = json_object_new_object(); - /* Packet counts. */ + json_pfx_stat = json_object_new_object(); + /* Packet counts. */ atomic_size_t outq_count, inq_count; outq_count = atomic_load_explicit(&p->connection->obuf->count, memory_order_relaxed); @@ -15531,6 +15585,16 @@ CPP_NOTICE("Remove `gracefulRestartCapability` JSON field") json_object_int_add(json_stat, "totalSent", PEER_TOTAL_TX(p)); json_object_int_add(json_stat, "totalRecv", PEER_TOTAL_RX(p)); json_object_object_add(json_neigh, "messageStats", json_stat); + + /* Prefix statistics */ + json_object_int_add(json_pfx_stat, "inboundFiltered", p->stat_pfx_filter); + json_object_int_add(json_pfx_stat, "aspathLoop", p->stat_pfx_aspath_loop); + json_object_int_add(json_pfx_stat, "originatorLoop", p->stat_pfx_originator_loop); + json_object_int_add(json_pfx_stat, "clusterLoop", p->stat_pfx_cluster_loop); + json_object_int_add(json_pfx_stat, "invalidNextHop", p->stat_pfx_nh_invalid); + json_object_int_add(json_pfx_stat, "withdrawn", p->stat_pfx_withdraw); + json_object_int_add(json_pfx_stat, "attributesDiscarded", p->stat_pfx_discard); + json_object_object_add(json_neigh, "prefixStats", json_pfx_stat); } else { atomic_size_t outq_count, inq_count, open_out, open_in, notify_out, notify_in, update_out, update_in, @@ -15582,8 +15646,18 @@ CPP_NOTICE("Remove `gracefulRestartCapability` JSON field") refresh_in); vty_out(vty, " Capability: %10zu %10zu\n", dynamic_cap_out, dynamic_cap_in); - vty_out(vty, " Total: %10u %10u\n", - (uint32_t)PEER_TOTAL_TX(p), (uint32_t)PEER_TOTAL_RX(p)); + vty_out(vty, " Total: %10u %10u\n\n", (uint32_t)PEER_TOTAL_TX(p), + (uint32_t)PEER_TOTAL_RX(p)); + + /* Prefix statistics */ + vty_out(vty, " Prefix statistics:\n"); + vty_out(vty, " Inbound filtered: %u\n", p->stat_pfx_filter); + vty_out(vty, " AS-PATH loop: %u\n", p->stat_pfx_aspath_loop); + vty_out(vty, " Originator loop: %u\n", p->stat_pfx_originator_loop); + vty_out(vty, " Cluster loop: %u\n", p->stat_pfx_cluster_loop); + vty_out(vty, " Invalid next-hop: %u\n", p->stat_pfx_nh_invalid); + vty_out(vty, " Withdrawn: %u\n", p->stat_pfx_withdraw); + vty_out(vty, " Attributes discarded: %u\n\n", p->stat_pfx_discard); } if (use_json) { @@ -18781,7 +18855,11 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, /* enforce-first-as */ if (CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS)) { - if (!peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) + /* The `no` form is printed because by default this enforcing + * is enabled, thus we need to print it inverted. + * See peer_new(). + */ + if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) vty_out(vty, " no neighbor %s enforce-first-as\n", addr); } else { if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) @@ -21915,6 +21993,9 @@ void bgp_vty_init(void) /* "show [ip] bgp vrfs" commands. */ install_element(VIEW_NODE, &show_bgp_vrfs_cmd); + /* Some overall BGP information */ + install_element(VIEW_NODE, &show_bgp_router_cmd); + /* Community-list. */ community_list_vty(); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index e414039348..e3465feda8 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -421,11 +421,10 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) if (addr->family == AF_INET) continue; - if (!IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) - && memcmp(&peer->nexthop.v6_global, - &addr->u.prefix6, 16) - == 0) { - memset(&peer->nexthop.v6_global, 0, 16); + if (!IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) && + memcmp(&peer->nexthop.v6_global, &addr->u.prefix6, IPV6_MAX_BYTELEN) == + 0) { + memset(&peer->nexthop.v6_global, 0, IPV6_MAX_BYTELEN); FOREACH_AFI_SAFI (afi, safi) bgp_announce_route(peer, afi, safi, true); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d580da4e1a..eda6bc31d2 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1227,8 +1227,6 @@ static void peer_free(struct peer *peer) bgp_reads_off(peer->connection); bgp_writes_off(peer->connection); event_cancel_event_ready(bm->master, peer->connection); - FOREACH_AFI_SAFI (afi, safi) - EVENT_OFF(peer->t_revalidate_all[afi][safi]); assert(!peer->connection->t_write); assert(!peer->connection->t_read); @@ -1562,8 +1560,13 @@ struct peer *peer_new(struct bgp *bgp) SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); - if (CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS)) - peer_flag_set(peer, PEER_FLAG_ENFORCE_FIRST_AS); + /* By default this is enabled, thus we need to mark it as + * inverted in order to display correctly in the configuration. + */ + if (CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS)) { + SET_FLAG(peer->flags_invert, PEER_FLAG_ENFORCE_FIRST_AS); + SET_FLAG(peer->flags, PEER_FLAG_ENFORCE_FIRST_AS); + } if (CHECK_FLAG(bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY)) peer_flag_set(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION); @@ -2676,8 +2679,6 @@ int peer_delete(struct peer *peer) bgp_reads_off(peer->connection); bgp_writes_off(peer->connection); event_cancel_event_ready(bm->master, peer->connection); - FOREACH_AFI_SAFI (afi, safi) - EVENT_OFF(peer->t_revalidate_all[afi][safi]); assert(!CHECK_FLAG(peer->connection->thread_flags, PEER_THREAD_WRITES_ON)); assert(!CHECK_FLAG(peer->connection->thread_flags, @@ -4036,6 +4037,9 @@ int bgp_delete(struct bgp *bgp) bgp_vpn_leak_unimport(bgp); + bgp_vpn_release_label(bgp, AFI_IP, true); + bgp_vpn_release_label(bgp, AFI_IP6, true); + hook_call(bgp_inst_delete, bgp); FOREACH_AFI_SAFI (afi, safi) @@ -4236,6 +4240,14 @@ int bgp_delete(struct bgp *bgp) } } + /* Clean BGP address family parameters */ + bgp_mh_info->ead_evi_rx = BGP_EVPN_MH_EAD_EVI_RX_DEF; + bgp_evpn_switch_ead_evi_rx(); + bgp_mh_info->ead_evi_tx = BGP_EVPN_MH_EAD_EVI_TX_DEF; + bgp_mh_info->evi_per_es_frag = BGP_EVPN_MAX_EVI_PER_ES_FRAG; + + bgp_address_family_distance_delete(); + return 0; } @@ -4317,6 +4329,9 @@ void bgp_free(struct bgp *bgp) XFREE(MTYPE_BGP_NAME, bgp->snmp_stats); XFREE(MTYPE_BGP_CONFED_LIST, bgp->confed_peers); + bgp_meta_queue_free(bgp->mq); + bgp->mq = NULL; + XFREE(MTYPE_BGP, bgp); } @@ -6671,7 +6686,7 @@ int peer_allowas_in_set(struct peer *peer, afi_t afi, safi_t safi, SET_FLAG(member->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN); member->allowas_in[afi][safi] = 0; - peer_on_policy_change(peer, afi, safi, 0); + peer_on_policy_change(member, afi, safi, 0); } } else { if (member->allowas_in[afi][safi] != allow_num @@ -6680,7 +6695,7 @@ int peer_allowas_in_set(struct peer *peer, afi_t afi, safi_t safi, UNSET_FLAG(member->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN); member->allowas_in[afi][safi] = allow_num; - peer_on_policy_change(peer, afi, safi, 0); + peer_on_policy_change(member, afi, safi, 0); } } } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index f66b41abe9..47214e52e5 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -842,6 +842,9 @@ struct bgp { /* Process Queue for handling routes */ struct work_queue *process_queue; + /* Meta Queue Information */ + struct meta_queue *mq; + bool fast_convergence; /* BGP Conditional advertisement */ @@ -1670,7 +1673,6 @@ struct peer { /* Threads. */ struct event *t_llgr_stale[AFI_MAX][SAFI_MAX]; - struct event *t_revalidate_all[AFI_MAX][SAFI_MAX]; struct event *t_refresh_stalepath; /* Thread flags. */ @@ -1726,7 +1728,8 @@ struct peer { uint32_t stat_pfx_cluster_loop; uint32_t stat_pfx_nh_invalid; uint32_t stat_pfx_dup_withdraw; - uint32_t stat_upd_7606; /* RFC7606: treat-as-withdraw */ + uint32_t stat_pfx_withdraw; /* RFC7606: treat-as-withdraw */ + uint32_t stat_pfx_discard; /* The number of prefixes with discarded attributes */ uint64_t stat_pfx_loc_rib; /* RFC7854 : Number of routes in Loc-RIB */ uint64_t stat_pfx_adj_rib_in; /* RFC7854 : Number of routes in Adj-RIBs-In */ @@ -2121,7 +2124,8 @@ struct bgp_nlri { */ #define BGP_DEFAULT_HOLDTIME 180 #define BGP_DEFAULT_KEEPALIVE 60 -#define BGP_DEFAULT_CONNECT_RETRY 120 +#define BGP_DEFAULT_CONNECT_RETRY 30 +#define BGP_MAX_CONNECT_RETRY 120 #define BGP_DEFAULT_EBGP_ROUTEADV 0 #define BGP_DEFAULT_IBGP_ROUTEADV 0 @@ -2711,14 +2715,6 @@ static inline int peer_group_af_configured(struct peer_group *group) return 0; } -static inline char *timestamp_string(time_t ts, char *timebuf) -{ - time_t tbuf; - - tbuf = time(NULL) - (monotime(NULL) - ts); - return ctime_r(&tbuf, timebuf); -} - static inline bool peer_established(struct peer_connection *connection) { return connection->status == Established; diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index dafcac7c84..3642681765 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -4350,6 +4350,10 @@ displays IPv6 routing table. If ``detail`` option is specified after ``json``, more verbose JSON output will be displayed. +.. clicmd:: show bgp router [json] + + This command displays information related BGP router and Graceful Restart. + Some other commands provide additional options for filtering the output. .. clicmd:: show [ip] bgp regexp LINE diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 46eddfe05d..ac29b1c7d4 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -926,7 +926,7 @@ and this section also helps that case. Create a new locator. If the name of an existing locator is specified, move to specified locator's configuration node to change the settings it. -.. clicmd:: prefix X:X::X:X/M [func-bits (0-64)] [block-len 40] [node-len 24] +.. clicmd:: prefix X:X::X:X/M [block-len (16-64)] [node-len (16-64)] [func-bits (0-64)] Set the ipv6 prefix block of the locator. SRv6 locator is defined by RFC8986. The actual routing protocol specifies the locator and allocates a diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 9a967bc1e3..9ea2cfd0a1 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1008,45 +1008,40 @@ void isis_circuit_print_json(struct isis_circuit *circuit, circuit_t2string(level)); if (circuit->area->newmetric) json_object_int_add(level_json, "metric", - circuit->te_metric[0]); + circuit->te_metric[level - 1]); else json_object_int_add(level_json, "metric", - circuit->metric[0]); + circuit->metric[level - 1]); if (!circuit->is_passive) { - json_object_int_add(level_json, - "active-neighbors", - circuit->upadjcount[0]); - json_object_int_add(level_json, - "hello-interval", - circuit->hello_interval[0]); + json_object_int_add(level_json, "active-neighbors", + circuit->upadjcount[level - 1]); + json_object_int_add(level_json, "hello-interval", + circuit->hello_interval[level - 1]); hold_json = json_object_new_object(); json_object_object_add(level_json, "holddown", hold_json); - json_object_int_add( - hold_json, "count", - circuit->hello_multiplier[0]); + json_object_int_add(hold_json, "count", + circuit->hello_multiplier[level - 1]); json_object_string_add( hold_json, "pad", isis_hello_padding2string( circuit->pad_hellos)); json_object_int_add(level_json, "cnsp-interval", - circuit->csnp_interval[0]); + circuit->csnp_interval[level - 1]); json_object_int_add(level_json, "psnp-interval", - circuit->psnp_interval[0]); + circuit->psnp_interval[level - 1]); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { lan_prio_json = json_object_new_object(); json_object_object_add(level_json, "lan", lan_prio_json); - json_object_int_add( - lan_prio_json, "priority", - circuit->priority[0]); - json_object_string_add( - lan_prio_json, "is-dis", - (circuit->u.bc.is_dr[0] - ? "yes" - : "no")); + json_object_int_add(lan_prio_json, "priority", + circuit->priority[level - 1]); + json_object_string_add(lan_prio_json, "is-dis", + (circuit->u.bc.is_dr[level - 1] + ? "yes" + : "no")); } } json_object_array_add(levels_json, level_json); diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 93f7bbf753..652efee89a 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -2065,12 +2065,6 @@ void cli_show_isis_srv6_locator(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, " locator %s\n", yang_dnode_get_string(dnode, NULL)); } -void cli_show_isis_srv6_locator_end(struct vty *vty, - const struct lyd_node *dnode) -{ - vty_out(vty, " exit\n"); -} - /* * XPath: /frr-isisd:isis/instance/segment-routing-srv6/enabled */ @@ -2118,6 +2112,11 @@ void cli_show_isis_srv6_enabled(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, " segment-routing srv6\n"); } +void cli_show_isis_srv6_end(struct vty *vty, const struct lyd_node *dnode) +{ + vty_out(vty, " exit\n"); +} + /* * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd */ @@ -2248,6 +2247,11 @@ void cli_show_isis_srv6_node_msd(struct vty *vty, const struct lyd_node *dnode, yang_dnode_get_uint8(dnode, "max-end-d")); } +void cli_show_isis_srv6_node_msd_end(struct vty *vty, const struct lyd_node *dnode) +{ + vty_out(vty, " exit\n"); +} + /* * XPath: /frr-isisd:isis/instance/segment-routing-srv6/interface */ diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index 8608d2b9bd..3024bb57ea 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -861,6 +861,12 @@ const struct frr_yang_module_info frr_isisd_info = { }, }, { + .xpath = "/frr-isisd:isis/instance/segment-routing-srv6", + .cbs = { + .cli_show_end = cli_show_isis_srv6_end, + }, + }, + { .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/enabled", .cbs = { .modify = isis_instance_segment_routing_srv6_enabled_modify, @@ -873,7 +879,6 @@ const struct frr_yang_module_info frr_isisd_info = { .modify = isis_instance_segment_routing_srv6_locator_modify, .destroy = isis_instance_segment_routing_srv6_locator_destroy, .cli_show = cli_show_isis_srv6_locator, - .cli_show_end = cli_show_isis_srv6_locator_end, }, }, { @@ -904,6 +909,7 @@ const struct frr_yang_module_info frr_isisd_info = { .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd", .cbs = { .cli_show = cli_show_isis_srv6_node_msd, + .cli_show_end = cli_show_isis_srv6_node_msd_end, }, }, { diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index 1bf95e3db3..10b3bd4009 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -322,6 +322,7 @@ int isis_instance_flex_algo_affinity_mapping_value_modify( struct nb_cb_modify_args *args); int isis_instance_flex_algo_affinity_mapping_value_destroy( struct nb_cb_destroy_args *args); +void cli_show_isis_srv6_end(struct vty *vty, const struct lyd_node *dnode); int isis_instance_segment_routing_srv6_enabled_modify( struct nb_cb_modify_args *args); void cli_show_isis_srv6_enabled(struct vty *vty, const struct lyd_node *dnode, @@ -332,8 +333,6 @@ int isis_instance_segment_routing_srv6_locator_destroy( struct nb_cb_destroy_args *args); void cli_show_isis_srv6_locator(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_srv6_locator_end(struct vty *vty, - const struct lyd_node *dnode); int isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_modify( struct nb_cb_modify_args *args); int isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_modify( @@ -344,6 +343,7 @@ int isis_instance_segment_routing_srv6_msd_node_msd_max_end_d_modify( struct nb_cb_modify_args *args); void cli_show_isis_srv6_node_msd(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +void cli_show_isis_srv6_node_msd_end(struct vty *vty, const struct lyd_node *dnode); int isis_instance_segment_routing_srv6_interface_modify( struct nb_cb_modify_args *args); void cli_show_isis_srv6_interface(struct vty *vty, const struct lyd_node *dnode, diff --git a/lib/darr.c b/lib/darr.c index 7a01274104..0cffa64425 100644 --- a/lib/darr.c +++ b/lib/darr.c @@ -8,6 +8,7 @@ #include <zebra.h> #include "darr.h" #include "memory.h" +#include "printfrr.h" DEFINE_MTYPE(LIB, DARR, "Dynamic Array"); DEFINE_MTYPE(LIB, DARR_STR, "Dynamic Array String"); @@ -70,7 +71,7 @@ char *__darr_in_vsprintf(char **sp, bool concat, const char *fmt, va_list ap) *darr_append(*sp) = 0; again: va_copy(ap_copy, ap); - len = vsnprintf(darr_last(*sp), darr_avail(*sp) + 1, fmt, ap_copy); + len = vsnprintfrr(darr_last(*sp), darr_avail(*sp) + 1, fmt, ap_copy); va_end(ap_copy); if (len < 0) darr_in_strcat(*sp, fmt); diff --git a/lib/darr.h b/lib/darr.h index 2b9a0a0c02..121e3dd14e 100644 --- a/lib/darr.h +++ b/lib/darr.h @@ -272,10 +272,10 @@ void *__darr_resize(void *a, uint count, size_t esize, struct memtype *mt); */ #define darr_ensure_avail_mt(A, S, MT) \ ({ \ - ssize_t need = (ssize_t)(S) - \ - (ssize_t)(darr_cap(A) - darr_len(A)); \ - if (need > 0) \ - _darr_resize_mt((A), darr_cap(A) + need, MT); \ + ssize_t __dea_need = (ssize_t)(S) - \ + (ssize_t)(darr_cap(A) - darr_len(A)); \ + if (__dea_need > 0) \ + _darr_resize_mt((A), darr_cap(A) + __dea_need, MT); \ (A); \ }) #define darr_ensure_avail(A, S) darr_ensure_avail_mt(A, S, MTYPE_DARR) @@ -301,9 +301,9 @@ void *__darr_resize(void *a, uint count, size_t esize, struct memtype *mt); #define darr_ensure_cap_mt(A, C, MT) \ ({ \ /* Cast to avoid warning when C == 0 */ \ - uint _c = (C) > 0 ? (C) : 1; \ - if ((size_t)darr_cap(A) < _c) \ - _darr_resize_mt((A), _c, MT); \ + uint __dec_c = (C) > 0 ? (C) : 1; \ + if ((size_t)darr_cap(A) < __dec_c) \ + _darr_resize_mt((A), __dec_c, MT); \ (A); \ }) #define darr_ensure_cap(A, C) darr_ensure_cap_mt(A, C, MTYPE_DARR) @@ -428,12 +428,12 @@ void *__darr_resize(void *a, uint count, size_t esize, struct memtype *mt); #define _darr_append_n(A, N, Z, MT) \ ({ \ - uint __len = darr_len(A); \ - darr_ensure_cap_mt(A, __len + (N), MT); \ - _darr_len(A) = __len + (N); \ + uint __da_len = darr_len(A); \ + darr_ensure_cap_mt(A, __da_len + (N), MT); \ + _darr_len(A) = __da_len + (N); \ if (Z) \ - memset(&(A)[__len], 0, (N)*_darr_esize(A)); \ - &(A)[__len]; \ + memset(&(A)[__da_len], 0, (N)*_darr_esize(A)); \ + &(A)[__da_len]; \ }) /** * Extending the array's length by N. diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h index ef03b66edc..587a002801 100644 --- a/lib/mgmt_msg_native.h +++ b/lib/mgmt_msg_native.h @@ -554,8 +554,8 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn, */ #define mgmt_msg_native_alloc_msg(msg_type, var_len, mem_type) \ ({ \ - uint8_t *buf = NULL; \ - (msg_type *)darr_append_nz_mt(buf, \ + uint8_t *__nam_buf = NULL; \ + (msg_type *)darr_append_nz_mt(__nam_buf, \ sizeof(msg_type) + (var_len), \ mem_type); \ }) @@ -590,10 +590,10 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn, */ #define mgmt_msg_native_append(msg, data, len) \ ({ \ - uint8_t **darrp = mgmt_msg_native_get_darrp(msg); \ - uint8_t *p = darr_append_n(*darrp, len); \ - memcpy(p, data, len); \ - p; \ + uint8_t **__na_darrp = mgmt_msg_native_get_darrp(msg); \ + uint8_t *__na_p = darr_append_n(*__na_darrp, len); \ + memcpy(__na_p, data, len); \ + __na_p; \ }) /** @@ -611,8 +611,8 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn, */ #define mgmt_msg_native_add_str(msg, s) \ do { \ - int __len = strlen(s) + 1; \ - mgmt_msg_native_append(msg, s, __len); \ + int __nas_len = strlen(s) + 1; \ + mgmt_msg_native_append(msg, s, __nas_len); \ } while (0) /** diff --git a/lib/monotime.h b/lib/monotime.h index f7ae1bbbe1..5e1bfe754e 100644 --- a/lib/monotime.h +++ b/lib/monotime.h @@ -129,6 +129,22 @@ static inline char *time_to_string(time_t ts, char *buf) return ctime_r(&tbuf, buf); } +/* A wrapper for time_to_string() which removes newline at the end. + * This is needed for JSON outputs, where newline is not expected. + */ +static inline char *time_to_string_json(time_t ts, char *buf) +{ + size_t len; + + time_to_string(ts, buf); + len = strlen(buf); + + if (len && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + return buf; +} + /* Convert interval to human-friendly string, used in cli output e.g. */ static inline const char *frrtime_to_interval(time_t t, char *buf, size_t buflen) diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index f9794bee3c..b199dd61f8 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -83,6 +83,7 @@ static int nb_cli_classic_commit(struct vty *vty) static void nb_cli_pending_commit_clear(struct vty *vty) { vty->pending_commit = 0; + vty->buffer_cmd_count = 0; XFREE(MTYPE_TMP, vty->pending_cmds_buf); vty->pending_cmds_buflen = 0; vty->pending_cmds_bufpos = 0; @@ -102,12 +103,19 @@ int nb_cli_pending_commit_check(struct vty *vty) static int nb_cli_schedule_command(struct vty *vty) { - /* Append command to dynamically sized buffer of scheduled commands. */ + /* Append command to dynamically sized buffer of scheduled commands. + * vty->buf -Incoming config + * vty->pending_cmds_buf - Pending buffer where incoming configs are + * accumulated for later processing + * vty->pending_cmds_bufpos - length of the pending buffer + * + */ if (!vty->pending_cmds_buf) { vty->pending_cmds_buflen = 4096; vty->pending_cmds_buf = XCALLOC(MTYPE_TMP, vty->pending_cmds_buflen); } + if ((strlen(vty->buf) + 3) > (vty->pending_cmds_buflen - vty->pending_cmds_bufpos)) { vty->pending_cmds_buflen *= 2; @@ -121,6 +129,9 @@ static int nb_cli_schedule_command(struct vty *vty) /* Schedule the commit operation. */ vty->pending_commit = 1; + vty->buffer_cmd_count++; + if (vty->buffer_cmd_count == NB_CMD_BATCH_SIZE) + nb_cli_pending_commit_check(vty); return CMD_SUCCESS; } diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h index 4c8dc50bd2..43c40f49e1 100644 --- a/lib/northbound_cli.h +++ b/lib/northbound_cli.h @@ -20,6 +20,9 @@ enum nb_cfg_format { NB_CFG_FMT_XML, }; +/* Maximum config commands in a batch*/ +#define NB_CMD_BATCH_SIZE 5000 + extern struct nb_config *vty_shared_candidate_config; /* diff --git a/lib/route_types.txt b/lib/route_types.txt index 93cbc36e97..b5f8b6fdf3 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -88,7 +88,7 @@ ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP", vr ZEBRA_ROUTE_NHG, zebra, none, '-', 0, 0, 0, "Nexthop Group", none ZEBRA_ROUTE_SRTE, srte, none, '-', 0, 0, 0, "SR-TE", none ZEBRA_ROUTE_TABLE_DIRECT, table-direct, zebra, 't', 1, 1, 1, "Table-Direct", zebra -ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-", none +ZEBRA_ROUTE_ALL, any, none, '-', 0, 0, 0, "-", none ## help strings @@ -149,6 +149,7 @@ struct vty { struct nb_config *candidate_config_base; /* Dynamic transaction information. */ + size_t buffer_cmd_count; bool pending_allowed; bool pending_commit; char *pending_cmds_buf; diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c index 93c9bcac44..45e154d83b 100644 --- a/mgmtd/mgmt_be_adapter.c +++ b/mgmtd/mgmt_be_adapter.c @@ -83,7 +83,7 @@ static const char *const zebra_oper_xpaths[] = { NULL, }; -#if HAVE_RIPD +#ifdef HAVE_RIPD static const char *const ripd_config_xpaths[] = { "/frr-filter:lib", "/frr-interface:lib/interface", @@ -104,7 +104,7 @@ static const char *const ripd_rpc_xpaths[] = { }; #endif -#if HAVE_RIPNGD +#ifdef HAVE_RIPNGD static const char *const ripngd_config_xpaths[] = { "/frr-filter:lib", "/frr-interface:lib/interface", @@ -123,7 +123,7 @@ static const char *const ripngd_rpc_xpaths[] = { }; #endif -#if HAVE_STATICD +#ifdef HAVE_STATICD static const char *const staticd_config_xpaths[] = { "/frr-vrf:lib", "/frr-interface:lib", diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c index 32f28a5774..7f7a5d9a8e 100644 --- a/mgmtd/mgmt_fe_adapter.c +++ b/mgmtd/mgmt_fe_adapter.c @@ -190,7 +190,7 @@ static void mgmt_fe_cleanup_session(struct mgmt_fe_session_ctx **sessionp) assert(session->adapter->refcount > 1); mgmt_fe_adapter_unlock(&session->adapter); } - + darr_free_free(session->notify_xpaths); hash_release(mgmt_fe_sessions, session); XFREE(MTYPE_MGMTD_FE_SESSION, session); *sessionp = NULL; diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index 93779991b5..eed1bfcb30 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -1823,7 +1823,7 @@ static void ospf_abr_nssa_type7_default_create(struct ospf *ospf, "Announcing Type-7 default route into NSSA area %pI4", &area->area_id); - /* Prepare the extrenal_info for aggregator */ + /* Prepare the external_info for aggregator */ memset(&ei, 0, sizeof(struct external_info)); ei.p.family = AF_INET; ei.p.prefixlen = 0; diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 738ac6d8cf..aa11467027 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -492,7 +492,7 @@ static void ospf_aggr_handle_external_info(void *data) ei->to_be_processed = true; if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR)) - zlog_debug("%s: Handle extrenal route(%pI4/%d)", __func__, + zlog_debug("%s: Handle external route(%pI4/%d)", __func__, &ei->p.prefix, ei->p.prefixlen); assert(ospf); @@ -571,7 +571,7 @@ static void ospf_external_aggr_delete(struct ospf *ospf, struct route_node *rn) } struct ospf_external_aggr_rt * -ospf_extrenal_aggregator_lookup(struct ospf *ospf, struct prefix_ipv4 *p) +ospf_external_aggregator_lookup(struct ospf *ospf, struct prefix_ipv4 *p) { struct route_node *rn; struct ospf_external_aggr_rt *summary_rt = NULL; @@ -617,7 +617,7 @@ void ospf_unlink_ei_from_aggr(struct ospf *ospf, { if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR)) zlog_debug( - "%s: Unlinking extrenal route(%pI4/%d) from aggregator(%pI4/%d), external route count:%ld", + "%s: Unlinking external route(%pI4/%d) from aggregator(%pI4/%d), external route count:%ld", __func__, &ei->p.prefix, ei->p.prefixlen, &aggr->p.prefix, aggr->p.prefixlen, OSPF_EXTERNAL_RT_COUNT(aggr)); @@ -648,7 +648,7 @@ static void ospf_link_ei_to_aggr(struct ospf_external_aggr_rt *aggr, { if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR)) zlog_debug( - "%s: Linking extrenal route(%pI4/%d) to aggregator(%pI4/%d)", + "%s: Linking external route(%pI4/%d) to aggregator(%pI4/%d)", __func__, &ei->p.prefix, ei->p.prefixlen, &aggr->p.prefix, aggr->p.prefixlen); (void)hash_get(aggr->match_extnl_hash, ei, hash_alloc_intern); @@ -703,7 +703,7 @@ struct ospf_lsa *ospf_originate_summary_lsa(struct ospf *ospf, return NULL; } - /* Prepare the extrenal_info for aggregator */ + /* Prepare the external_info for aggregator */ memset(&ei_aggr, 0, sizeof(ei_aggr)); ei_aggr.p = aggr->p; ei_aggr.tag = aggr->tag; @@ -1063,7 +1063,7 @@ static void ospf_handle_external_aggr_update(struct ospf *ospf) aggr->action = OSPF_ROUTE_AGGR_NONE; - /* Prepare the extrenal_info for aggregator */ + /* Prepare the external_info for aggregator */ memset(&ei_aggr, 0, sizeof(ei_aggr)); ei_aggr.p = aggr->p; ei_aggr.tag = aggr->tag; @@ -1176,7 +1176,7 @@ int ospf_asbr_external_aggregator_set(struct ospf *ospf, struct prefix_ipv4 *p, { struct ospf_external_aggr_rt *aggregator; - aggregator = ospf_extrenal_aggregator_lookup(ospf, p); + aggregator = ospf_external_aggregator_lookup(ospf, p); if (aggregator) { if (CHECK_FLAG(aggregator->flags, @@ -1236,7 +1236,7 @@ int ospf_asbr_external_rt_no_advertise(struct ospf *ospf, struct prefix_ipv4 *p) struct ospf_external_aggr_rt *aggr; route_tag_t tag = 0; - aggr = ospf_extrenal_aggregator_lookup(ospf, p); + aggr = ospf_external_aggregator_lookup(ospf, p); if (aggr) { if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE)) return OSPF_SUCCESS; diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index 648a5a11ae..0b3b695f3e 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -144,7 +144,7 @@ extern int ospf_external_aggregator_timer_set(struct ospf *ospf, extern void ospf_external_aggrigator_free(struct ospf_external_aggr_rt *aggr); extern struct ospf_external_aggr_rt * -ospf_extrenal_aggregator_lookup(struct ospf *ospf, struct prefix_ipv4 *p); +ospf_external_aggregator_lookup(struct ospf *ospf, struct prefix_ipv4 *p); void ospf_unset_all_aggr_flag(struct ospf *ospf); diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index e3398af74b..bcb35315d8 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -325,7 +325,7 @@ static void ospf_process_self_originated_lsa(struct ospf *ospf, LSA_REFRESH_FORCE, false); } else { aggr = (struct ospf_external_aggr_rt *) - ospf_extrenal_aggregator_lookup(ospf, &p); + ospf_external_aggregator_lookup(ospf, &p); if (aggr) { struct external_info ei_aggr; diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 7354223397..ac53f3a19f 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -4064,7 +4064,7 @@ struct ospf_lsa *ospf_lsa_refresh(struct ospf *ospf, struct ospf_lsa *lsa) ospf, lsa, ei, LSA_REFRESH_FORCE, false); else { aggr = (struct ospf_external_aggr_rt *) - ospf_extrenal_aggregator_lookup(ospf, &p); + ospf_external_aggregator_lookup(ospf, &p); if (aggr) { struct external_info ei_aggr; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index d72afec1e4..90330d368d 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -843,7 +843,7 @@ static void ospf_finish_final(struct ospf *ospf) ospf_distance_reset(ospf); route_table_finish(ospf->distance_table); - /* Release extrenal Aggregator table */ + /* Release external Aggregator table */ for (rn = route_top(ospf->rt_aggr_tbl); rn; rn = route_next(rn)) { struct ospf_external_aggr_rt *aggr; diff --git a/pathd/path_pcep_debug.c b/pathd/path_pcep_debug.c index 7bff9c7b9c..89e7574324 100644 --- a/pathd/path_pcep_debug.c +++ b/pathd/path_pcep_debug.c @@ -1321,8 +1321,7 @@ void _format_pcep_event(int ps, pcep_event *event) PATHD_FORMAT("\n"); PATHD_FORMAT("%*sevent_type: %s\n", ps2, "", pcep_event_type_name(event->event_type)); - PATHD_FORMAT("%*sevent_time: %s", ps2, "", - ctime_r(&event->event_time, buf)); + PATHD_FORMAT("%*sevent_time: %s", ps2, "", time_to_string(event->event_time, buf)); if (event->session == NULL) { PATHD_FORMAT("%*ssession: NULL\n", ps2, ""); } else { diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 17e9c3f268..4fd19b5dbe 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -960,8 +960,9 @@ void pim_rp_setup(struct pim_instance *pim) if (!pim_nht_lookup_ecmp(pim, &rp_info->rp.source_nexthop, nht_p, &rp_info->group, true)) { if (PIM_DEBUG_PIM_NHT_RP) - zlog_debug( - "Unable to lookup nexthop for rp specified"); + zlog_debug("%s: unable to lookup nexthop for rp %pPA", __func__, + &rp_info->rp.rpf_addr); + pim_nht_rp_del(rp_info); } } @@ -1107,7 +1108,12 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group) __func__, &nht_p, &rp_info->group); pim_nht_find_or_track(pim, nht_p, NULL, rp_info, NULL); pim_rpf_set_refresh_time(pim); - pim_nht_lookup_ecmp(pim, &rp_info->rp.source_nexthop, nht_p, &rp_info->group, true); + if (!pim_nht_lookup_ecmp(pim, &rp_info->rp.source_nexthop, nht_p, &rp_info->group, + true)) + if (PIM_DEBUG_PIM_NHT_RP) + zlog_debug("%s: unable to lookup nexthop for rp %pPA", __func__, + &rp_info->rp.rpf_addr); + return (&rp_info->rp); } diff --git a/pimd/pim_tib.c b/pimd/pim_tib.c index e9992691a5..d067abf45a 100644 --- a/pimd/pim_tib.c +++ b/pimd/pim_tib.c @@ -35,7 +35,11 @@ tib_sg_oil_setup(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif) up = pim_upstream_find(pim, &sg); if (up) { memcpy(&nexthop, &up->rpf.source_nexthop, sizeof(struct pim_nexthop)); - pim_nht_lookup_ecmp(pim, &nexthop, vif_source, &grp, false); + if (!pim_nht_lookup_ecmp(pim, &nexthop, vif_source, &grp, false)) + if (PIM_DEBUG_PIM_NHT_RP) + zlog_debug("%s: Nexthop Lookup failed vif_src:%pPA, sg.src:%pPA, sg.grp:%pPA", + __func__, &vif_source, &sg.src, &sg.grp); + if (nexthop.interface) input_iface_vif_index = pim_if_find_vifindex_by_ifindex( pim, nexthop.interface->ifindex); diff --git a/staticd/static_nht.c b/staticd/static_nht.c index 6be598434d..06d27c6f59 100644 --- a/staticd/static_nht.c +++ b/staticd/static_nht.c @@ -21,6 +21,7 @@ static void static_nht_update_path(struct static_path *pn, struct prefix *nhp, uint32_t nh_num, vrf_id_t nh_vrf_id) { struct static_nexthop *nh; + bool route_changed = false; frr_each(static_nexthop_list, &pn->nexthop_list, nh) { if (nh->nh_vrf_id != nh_vrf_id) @@ -42,8 +43,10 @@ static void static_nht_update_path(struct static_path *pn, struct prefix *nhp, nh->nh_valid = !!nh_num; if (nh->state == STATIC_START) - static_zebra_route_add(pn, true); + route_changed = true; } + if (route_changed) + static_zebra_route_add(pn, true); } static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp, diff --git a/tests/helpers/python/frrtest.py b/tests/helpers/python/frrtest.py index 3faa2a6f13..4682bd8786 100644 --- a/tests/helpers/python/frrtest.py +++ b/tests/helpers/python/frrtest.py @@ -163,8 +163,8 @@ class TestRefMismatch(Exception): difflib.unified_diff( self.reftext.splitlines(), self.outtext.splitlines(), - "outtext", "reftext", + "outtext", lineterm="", ) ) diff --git a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py index 3d17a2b709..e58b53728b 100644 --- a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py +++ b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py @@ -73,7 +73,9 @@ def test_bgp_addpath_best_selected(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) + r1 = tgen.gears["r1"] r2 = tgen.gears["r2"] + r7 = tgen.gears["r7"] def _bgp_converge(): output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 172.16.16.254/32 json")) @@ -111,78 +113,67 @@ def test_bgp_addpath_best_selected(): _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, "Can't converge initially" - def check_bgp_advertised_routes_to_r1(): + def r1_check_bgp_received_routes_from_r2(): output = json.loads( - r2.vtysh_cmd( - "show bgp ipv4 neighbors 192.168.1.1 advertised-routes detail json" - ) + r1.vtysh_cmd("show bgp ipv4 neighbors 192.168.1.2 routes json") ) expected = { - "advertisedRoutes": { - "172.16.16.254/32": { - "paths": [ - { - "aspath": { - "string": "65005", - } - }, - { - "aspath": { - "string": "65006", - } - }, - ] - } + "routes": { + "172.16.16.254/32": [ + { + "valid": True, + "path": "65002 65005", + }, + { + "valid": True, + "path": "65002 65006", + }, + ] }, - "totalPrefixCounter": 2, + "totalRoutes": 1, + "totalPaths": 2, } return topotest.json_cmp(output, expected) - test_func = functools.partial(check_bgp_advertised_routes_to_r1) + test_func = functools.partial(r1_check_bgp_received_routes_from_r2) _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None - ), "Received more/less Add-Path best paths, but should be only 1+1 (real best path)" + ), "Received more/less Add-Path best paths, but should be ONLY 1+1 (real best path)" - def check_bgp_advertised_routes_to_r7(): + def r7_check_bgp_received_routes_from_r2(): output = json.loads( - r2.vtysh_cmd( - "show bgp ipv4 neighbors 192.168.7.7 advertised-routes detail json" - ) + r7.vtysh_cmd("show bgp ipv4 neighbors 192.168.7.2 routes json") ) expected = { - "advertisedRoutes": { - "172.16.16.254/32": { - "paths": [ - { - "aspath": { - "string": "65004", - } - }, - { - "aspath": { - "string": "65005", - } - }, - { - "aspath": { - "string": "65006", - } - }, - ] - } + "routes": { + "172.16.16.254/32": [ + { + "valid": True, + "path": "65002 65004", + }, + { + "valid": True, + "path": "65002 65005", + }, + { + "valid": True, + "path": "65002 65006", + }, + ] }, - "totalPrefixCounter": 3, + "totalRoutes": 1, + "totalPaths": 3, } return topotest.json_cmp(output, expected) - test_func = functools.partial(check_bgp_advertised_routes_to_r7) + test_func = functools.partial(r7_check_bgp_received_routes_from_r2) _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None - ), "Received more/less Add-Path best paths, but should be only 2+1 (real best path)" + ), "Received more/less Add-Path best paths, but should be ONLY 2+1 (real best path)" if __name__ == "__main__": diff --git a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py index 5d8338d6eb..7e39b83d8f 100644 --- a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py +++ b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py @@ -187,6 +187,16 @@ def test_bgp_administrative_reset_gr(): """ ) + def _bgp_verify_show_bgp_router_json(): + output = json.loads(r1.vtysh_cmd("show bgp router json")) + expected = { + "bgpStartedAt": "*", + "bgpStartedGracefully": False, + "bgpInMaintenanceMode": False, + "bgpInstanceCount": 1, + } + return topotest.json_cmp(output, expected) + step("Initial BGP converge") test_func = functools.partial(_bgp_converge) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) @@ -205,6 +215,11 @@ def test_bgp_administrative_reset_gr(): _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to send Administrative Reset notification from R2" + step("Check show bgp router json") + test_func = functools.partial(_bgp_verify_show_bgp_router_json) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Invalid BGP router details" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py index c9ff2ffc7e..d2d6a40ae8 100755 --- a/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py +++ b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py @@ -76,7 +76,7 @@ def test_bgp_minimum_holdtime(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_neighbor_check_if_notification_sent) - _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, "Failed to send notification message\n" diff --git a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py index adc92f59fe..c6f1b6193b 100644 --- a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py +++ b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py @@ -142,6 +142,27 @@ def test_bgp_path_attribute_discard(): result is None ), "Failed to discard path attributes (atomic-aggregate, community)" + def _bgp_check_attributes_discarded_stats(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "10.0.0.254": { + "prefixStats": { + "inboundFiltered": 0, + "aspathLoop": 0, + "originatorLoop": 0, + "clusterLoop": 0, + "invalidNextHop": 0, + "withdrawn": 0, + "attributesDiscarded": 3, + } + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_attributes_discarded_stats) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Discarded path attributes count is not as expected" + def _bgp_check_if_aigp_invalid_attribute_discarded(): output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast json detail")) expected = { diff --git a/tests/topotests/bgp_path_attribute_treat_as_withdraw/test_bgp_path_attribute_treat_as_withdraw.py b/tests/topotests/bgp_path_attribute_treat_as_withdraw/test_bgp_path_attribute_treat_as_withdraw.py index a9d678a42d..4f6472f3c5 100644 --- a/tests/topotests/bgp_path_attribute_treat_as_withdraw/test_bgp_path_attribute_treat_as_withdraw.py +++ b/tests/topotests/bgp_path_attribute_treat_as_withdraw/test_bgp_path_attribute_treat_as_withdraw.py @@ -134,6 +134,27 @@ def test_bgp_path_attribute_treat_as_withdraw(): _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to withdraw prefixes with atomic-aggregate attribute" + def _bgp_check_attributes_withdrawn_stats(): + output = json.loads(r2.vtysh_cmd("show bgp neighbor json")) + expected = { + "10.0.0.1": { + "prefixStats": { + "inboundFiltered": 0, + "aspathLoop": 0, + "originatorLoop": 0, + "clusterLoop": 0, + "invalidNextHop": 0, + "withdrawn": 1, + "attributesDiscarded": 0, + } + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_attributes_withdrawn_stats) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Withdrawn prefix count is not as expected" + def test_memory_leak(): "Run the memory leak test and report results." diff --git a/tests/topotests/bgp_route_server_client/r1/bgpd.conf b/tests/topotests/bgp_route_server_client/r1/bgpd.conf index d379f7df45..5cbb7956be 100644 --- a/tests/topotests/bgp_route_server_client/r1/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r1/bgpd.conf @@ -2,10 +2,12 @@ router bgp 65001 bgp router-id 10.10.10.1 no bgp ebgp-requires-policy - no bgp enforce-first-as - neighbor 2001:db8:1::1 remote-as external - neighbor 2001:db8:1::1 timers 3 10 - neighbor 2001:db8:1::1 timers connect 1 + neighbor pg peer-group + neighbor pg remote-as external + neighbor pg timers 1 3 + neighbor pg timers connect 1 + no neighbor pg enforce-first-as + neighbor 2001:db8:1::1 peer-group pg address-family ipv6 unicast redistribute connected neighbor 2001:db8:1::1 activate diff --git a/tests/topotests/bgp_rpki_topo1/r2/bgp_rpki_valid.json b/tests/topotests/bgp_rpki_topo1/r2/bgp_rpki_valid.json new file mode 100644 index 0000000000..016c019d10 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r2/bgp_rpki_valid.json @@ -0,0 +1,70 @@ +{ + "vrfId": 0, + "vrfName": "default", + "tableVersion": 3, + "routerId": "192.0.2.2", + "defaultLocPrf": 100, + "localAS": 65002, + "routes": { + "198.51.100.0/24": [ + { + "origin": "IGP", + "metric": 0, + "valid": true, + "version": 2, + "rpkiValidationState": "valid", + "bestpath": { + "overall": true, + "selectionReason": "First path received" + }, + "nexthops": [ + { + "ip": "192.0.2.1", + "hostname": "r1", + "afi": "ipv4", + "metric": 0, + "accessible": true, + "used": true + } + ], + "peer": { + "peerId": "192.0.2.1", + "routerId": "192.0.2.1", + "hostname": "r1", + "type": "external" + } + } + ], + "203.0.113.0/24": [ + { + "origin": "IGP", + "metric": 0, + "valid": true, + "version": 3, + "rpkiValidationState": "valid", + "bestpath": { + "overall": true, + "selectionReason": "First path received" + }, + "nexthops": [ + { + "ip": "192.0.2.1", + "hostname": "r1", + "afi": "ipv4", + "metric": 0, + "accessible": true, + "used": true + } + ], + "peer": { + "peerId": "192.0.2.1", + "routerId": "192.0.2.1", + "hostname": "r1", + "type": "external" + } + } + ] + }, + "totalRoutes": 3, + "totalPaths": 3 +}
\ No newline at end of file diff --git a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py index 7b40bbdae8..5b775aa6cb 100644 --- a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py +++ b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py @@ -101,6 +101,16 @@ def show_rpki_prefixes(rname, expected, vrf=None): return topotest.json_cmp(output, expected) +def show_rpki_valid(rname, expected, vrf=None): + tgen = get_topogen() + + cmd = "show bgp ipv4 detail json" + + output = json.loads(tgen.gears[rname].vtysh_cmd(cmd)) + + return topotest.json_cmp(output, expected) + + def show_bgp_ipv4_table_rpki(rname, rpki_state, expected, vrf=None): tgen = get_topogen() @@ -123,6 +133,25 @@ def show_bgp_ipv4_table_rpki(rname, rpki_state, expected, vrf=None): return topotest.json_cmp(output, expected) +def test_show_bgp_rpki_prefixes_valid(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["r1", "r3"]: + logger.info("{}: checking if rtrd is running".format(rname)) + if rtrd_process[rname].poll() is not None: + pytest.skip(tgen.errors) + + rname = "r2" + expected = open(os.path.join(CWD, "{}/bgp_rpki_valid.json".format(rname))).read() + expected_json = json.loads(expected) + test_func = functools.partial(show_rpki_valid, rname, expected_json) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see RPKI on {}".format(rname) + + def test_show_bgp_rpki_prefixes(): tgen = get_topogen() diff --git a/tests/topotests/bgp_show_advertised_routes_detail/__init__.py b/tests/topotests/bgp_show_advertised_routes_detail/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_show_advertised_routes_detail/__init__.py diff --git a/tests/topotests/bgp_show_advertised_routes_detail/r1/frr.conf b/tests/topotests/bgp_show_advertised_routes_detail/r1/frr.conf new file mode 100644 index 0000000000..c9710eb5e8 --- /dev/null +++ b/tests/topotests/bgp_show_advertised_routes_detail/r1/frr.conf @@ -0,0 +1,13 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as auto + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + network 10.10.10.1/32 + exit-address-family +! diff --git a/tests/topotests/bgp_show_advertised_routes_detail/r2/frr.conf b/tests/topotests/bgp_show_advertised_routes_detail/r2/frr.conf new file mode 100644 index 0000000000..30b4ba539f --- /dev/null +++ b/tests/topotests/bgp_show_advertised_routes_detail/r2/frr.conf @@ -0,0 +1,29 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +int r2-eth1 + ip address 192.168.2.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + neighbor 192.168.2.3 remote-as auto + neighbor 192.168.2.3 timers 1 3 + neighbor 192.168.2.3 timers connect 1 + address-family ipv4 unicast + neighbor 192.168.2.3 route-map r3 out + exit-address-family + ! +! +ip prefix-list p1 permit 10.10.10.1/32 +! +route-map r3 permit 10 + match ip address prefix-list p1 + set large-community 65001:65002:65003 + set community 65001:65002 + set extcommunity bandwidth 100 +exit +! diff --git a/tests/topotests/bgp_show_advertised_routes_detail/r3/frr.conf b/tests/topotests/bgp_show_advertised_routes_detail/r3/frr.conf new file mode 100644 index 0000000000..11333d481f --- /dev/null +++ b/tests/topotests/bgp_show_advertised_routes_detail/r3/frr.conf @@ -0,0 +1,11 @@ +! +int r3-eth0 + ip address 192.168.2.3/24 +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as auto + neighbor 192.168.2.2 timers 1 3 + neighbor 192.168.2.2 timers connect 1 + ! +! diff --git a/tests/topotests/bgp_show_advertised_routes_detail/test_bgp_show_advertised_routes_detail.py b/tests/topotests/bgp_show_advertised_routes_detail/test_bgp_show_advertised_routes_detail.py new file mode 100644 index 0000000000..fda7ec601d --- /dev/null +++ b/tests/topotests/bgp_show_advertised_routes_detail/test_bgp_show_advertised_routes_detail.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +import os +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2"), "s2": ("r2", "r3")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_show_advertised_routes_detail(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads( + r2.vtysh_cmd( + "show bgp ipv4 unicast neighbor 192.168.2.3 advertised-routes detail json" + ) + ) + expected = { + "advertisedRoutes": { + "10.10.10.1/32": { + "paths": [ + { + "community": { + "string": "65001:65002", + }, + "extendedCommunity": { + "string": "LB:65002:12500000 (100.000 Mbps)" + }, + "largeCommunity": { + "string": "65001:65002:65003", + }, + } + ], + } + }, + "totalPrefixCounter": 1, + "filteredPrefixCounter": 0, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py index 3932c29b98..ee7e00b323 100644 --- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py +++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py @@ -232,6 +232,20 @@ def test_local_vs_non_local(): assert False, "Route 60.0.0.0/24 should not have fibPending" +def test_ip_protocol_any_fib_filter(): + # "Filtered route of source protocol any should not get installed in fib" + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + r2.vtysh_cmd("conf\nno ip protocol bgp") + r2.vtysh_cmd("conf\nip protocol any route-map LIMIT") + test_bgp_route() + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/__init__.py b/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/__init__.py diff --git a/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/r1/frr.conf b/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/r1/frr.conf new file mode 100644 index 0000000000..7daf335aab --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/r1/frr.conf @@ -0,0 +1,117 @@ +interface r1-eth1 vrf vrf1 + ip address 173.31.1.1/32 +! +interface r1-eth2 vrf vrf2 + ip address 173.31.1.2/32 +! +interface r1-eth3 vrf vrf3 + ip address 173.31.1.3/32 +! +interface r1-eth4 vrf vrf4 + ip address 173.31.1.4/32 +! +interface r1-eth5 vrf vrf5 + ip address 173.31.1.5/32 +! + +interface r1-eth0 + ip address 192.168.0.1/24 +! + +interface r1-eth6 + ip address 193.170.0.1/24 + +interface lo + ip address 11.11.11.11/32 +! +router ospf + ospf router-id 11.11.11.11 + network 193.170.0.0/24 area 0.0.0.0 + network 11.11.11.11/32 area 0.0.0.0 + redistribute connected +exit +! +mpls ldp + router-id 11.11.11.11 + ! + address-family ipv4 + discovery transport-address 11.11.11.11 + ! + interface r1-eth6 + exit + ! + exit-address-family + ! +exit +! +bgp route-map delay-timer 1 +router bgp 65500 + bgp router-id 192.0.2.1 + no bgp ebgp-requires-policy + neighbor 192.168.0.2 remote-as 65501 + address-family ipv4 unicast + no neighbor 192.168.0.2 activate + exit-address-family + address-family ipv4 vpn + neighbor 192.168.0.2 activate + exit-address-family +! +router bgp 65500 vrf vrf1 + bgp router-id 192.0.2.1 + address-family ipv4 unicast + redistribute connected + label vpn export auto + rd vpn export 445:1 + rt vpn both 53:1 + export vpn + import vpn + exit-address-family +! +router bgp 65500 vrf vrf2 + bgp router-id 192.0.2.1 + address-family ipv4 unicast + redistribute connected + label vpn export auto + rd vpn export 445:2 + rt vpn both 53:2 + export vpn + import vpn + exit-address-family +! +router bgp 65500 vrf vrf3 + bgp router-id 192.0.2.1 + address-family ipv4 unicast + redistribute connected + label vpn export auto + rd vpn export 445:3 + rt vpn both 53:3 + export vpn + import vpn + exit-address-family +! +router bgp 65500 vrf vrf4 + bgp router-id 192.0.2.1 + address-family ipv4 unicast + redistribute connected + label vpn export auto + rd vpn export 445:4 + rt vpn both 53:4 + export vpn + import vpn + exit-address-family +! +router bgp 65500 vrf vrf5 + bgp router-id 192.0.2.1 + address-family ipv4 unicast + redistribute connected + label vpn export auto + rd vpn export 445:5 + rt vpn both 53:5 + export vpn + import vpn + exit-address-family +! + +interface r1-eth0 + mpls bgp forwarding +!
\ No newline at end of file diff --git a/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/r2/frr.conf b/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/r2/frr.conf new file mode 100644 index 0000000000..6facebe40e --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/r2/frr.conf @@ -0,0 +1,88 @@ +interface r2-eth1 vrf vrf1 + ip address 173.31.0.1/32 +! +interface r2-eth2 vrf vrf2 + ip address 173.31.0.2/32 +! +interface r2-eth3 vrf vrf3 + ip address 173.31.0.3/32 +! +interface r2-eth4 vrf vrf4 + ip address 173.31.0.4/32 +! +interface r2-eth5 vrf vrf5 + ip address 173.31.0.5/32 +! +interface r2-eth0 + ip address 192.168.0.2/24 +! +router bgp 65501 + bgp router-id 192.0.2.2 + no bgp ebgp-requires-policy + neighbor 192.168.0.1 remote-as 65500 + address-family ipv4 unicast + no neighbor 192.168.0.1 activate + exit-address-family + address-family ipv4 vpn + neighbor 192.168.0.1 activate + exit-address-family +! +router bgp 65501 vrf vrf1 + bgp router-id 192.0.2.2 + address-family ipv4 unicast + redistribute connected + label vpn export auto + rd vpn export 445:1 + rt vpn both 53:1 + export vpn + import vpn + exit-address-family +! +router bgp 65501 vrf vrf2 + bgp router-id 192.0.2.2 + address-family ipv4 unicast + redistribute connected + label vpn export auto + rd vpn export 445:2 + rt vpn both 53:2 + export vpn + import vpn + exit-address-family +! +router bgp 65501 vrf vrf3 + bgp router-id 192.0.2.2 + address-family ipv4 unicast + redistribute connected + label vpn export auto + rd vpn export 445:3 + rt vpn both 53:3 + export vpn + import vpn + exit-address-family +! +router bgp 65501 vrf vrf4 + bgp router-id 192.0.2.2 + address-family ipv4 unicast + redistribute connected + label vpn export auto + rd vpn export 445:4 + rt vpn both 53:4 + export vpn + import vpn + exit-address-family +! +router bgp 65501 vrf vrf5 + bgp router-id 192.0.2.2 + address-family ipv4 unicast + redistribute connected + label vpn export auto + rd vpn export 445:5 + rt vpn both 53:5 + export vpn + import vpn + exit-address-family +! + +interface r2-eth0 + mpls bgp forwarding +! diff --git a/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/r3/frr.conf b/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/r3/frr.conf new file mode 100644 index 0000000000..8f49cdfe0c --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/r3/frr.conf @@ -0,0 +1,32 @@ +interface r3-eth0 + ip address 193.170.0.2/24 +! +interface lo + ip address 33.33.33.33/32 +! +interface r3-eth1 + ip address 180.170.0.2/32 +! +interface r3-eth2 + ip address 180.170.0.3/32 +! +router ospf + ospf router-id 33.33.33.33 + network 193.170.0.0/24 area 0.0.0.0 + network 33.33.33.33/32 area 0.0.0.0 + redistribute connected +exit +! +mpls ldp + router-id 33.33.33.33 + ! + address-family ipv4 + discovery transport-address 33.33.33.33 + ! + interface r3-eth0 + exit + ! + exit-address-family + ! +exit +!
\ No newline at end of file diff --git a/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/test_bgp_vpnv4_vpn_auto.py b/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/test_bgp_vpnv4_vpn_auto.py new file mode 100644 index 0000000000..ed3cdca2f9 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp_vpn_auto/test_bgp_vpnv4_vpn_auto.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_bgp_vpnv4_vpn_auto.py +# +# Copyright (c) 2024 by Varun Hegde +# + +""" + test_bgp_vpnv4_vpn_auto.py: Test the FRR BGP daemon with BGP VPN session with label export auto +""" + +import os +import sys +import json +import functools +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.bgpcheck import ( + check_show_bgp_vpn_prefix_found, + check_show_bgp_vpn_prefix_not_found, +) +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + "Build function" + + # Create 3 routers. + tgen.add_router("r1") + tgen.add_router("r2") + tgen.add_router("r3") + + + for i in range(6): + switch = tgen.add_switch("s{0}".format(i)) + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + #create a singiluar link between R2 -- R3 + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + for i in range(7, 9): + switch = tgen.add_switch("s{0}".format(i)) + switch.add_link(tgen.gears["r3"]) + + + +def _populate_iface(): + tgen = get_topogen() + cmds_list = [ + "ip link add vrf{} type vrf table {}", + "ip link set dev vrf{} up", + "ip link set dev r1-eth{} master vrf{}", + "echo 1 > /proc/sys/net/mpls/conf/r1-eth{}/input", + ] + cmds_list2 = [ + "ip link add vrf{} type vrf table {}", + "ip link set dev vrf{} up", + "ip link set dev r2-eth{} master vrf{}", + "echo 1 > /proc/sys/net/mpls/conf/r2-eth{}/input", + ] + + for i in range(1, 6): + for cmd in cmds_list: + input = cmd.format(i, i) + logger.info("input: " + cmd) + output = tgen.net["r1"].cmd(cmd.format(i, i)) + logger.info("output: " + output) + + for cmd in cmds_list2: + input = cmd.format(i, i) + logger.info("input: " + cmd) + output = tgen.net["r2"].cmd(cmd.format(i, i)) + logger.info("output: " + output) + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + _populate_iface() + + for rname, router in router_list.items(): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + + tgen.stop_topology() + + +def test_labelpool_release(): + """ + Check that once we remove BGP VPN sesson + label pool structure ( allocated_map ) gets released properly or not + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Just waiting for BGP VPN session to converge + logger.info("Waiting for BGP VPN sessions to converge and label pools to get initialised") + router = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads( + router.vtysh_cmd("show bgp labelpool summary json") + ) + expected = {"ledger":5,"inUse":5,"requests":0,"labelChunks":1,"pending":0,"reconnects":1} + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see BGP Labelpool initialised" + + + # checking the initial label pool chunk's free labels + logger.info("checking the initial label pool chunk's free labels") + expected = [{"first":80,"last":207,"size":128,"numberFree":123}] + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show bgp label chunks json", + expected, + ) + + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + + # Test case : check whether label got released or not + logger.info( + "Remove multiple vpn session and check whether label got released or no" + ) + router.vtysh_cmd( + """ + configure terminal + no router bgp 65500 vrf vrf1 + no router bgp 65500 vrf vrf2 + """ + ) + expected = [{"first":80,"last":207,"size":128,"numberFree":125}] + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show bgp label chunks json", + expected, + ) + + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py index 6237decfc3..ee84e375fb 100644 --- a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py +++ b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py @@ -140,6 +140,10 @@ def router_json_cmp_exact_filter(router, cmd, expected): # filter out tableVersion, version and nhVrfID json_output.pop("tableVersion") + if "totalRoutes" in json_output: + json_output.pop("totalRoutes") + if "totalPaths" in json_output: + json_output.pop("totalPaths") for rd, data in json_output["routes"]["routeDistinguishers"].items(): for _, attrs in data.items(): for attr in attrs: @@ -163,12 +167,18 @@ def router_vrf_json_cmp_exact_filter(router, cmd, expected): json_output = json.loads(output) + print(json_output) + # filter out tableVersion, version, nhVrfId and vrfId for vrf, data in json_output.items(): if "vrfId" in data: data.pop("vrfId") if "tableVersion" in data: data.pop("tableVersion") + if "totalRoutes" in data: + data.pop("totalRoutes") + if "totalPaths" in data: + data.pop("totalPaths") if "routes" not in data: continue for _, attrs in data["routes"].items(): @@ -203,7 +213,7 @@ def check_show_bgp_ipv4_vpn(rname, json_file): "show bgp ipv4 vpn json", expected, ) - _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg @@ -224,7 +234,7 @@ def check_show_bgp_vrf_ipv4(rname, json_file): "show bgp vrf all ipv4 unicast json", expected, ) - _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg @@ -248,7 +258,7 @@ def test_protocols_convergence_step0(): "show bgp ipv4 vpn summary json", expected, ) - _, result = topotest.run_and_expect(test_func, None, count=20, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json index 948f4e6c23..da2d8e3625 100644 --- a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json +++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json @@ -39,7 +39,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -68,7 +68,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -97,7 +97,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -126,7 +126,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -238,7 +238,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -250,7 +252,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -265,7 +267,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -277,7 +281,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -292,7 +296,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -304,7 +310,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -319,7 +325,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -331,7 +339,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -369,7 +377,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -398,7 +406,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -427,7 +435,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -456,7 +464,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -480,7 +488,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -492,7 +502,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -507,7 +517,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -519,7 +531,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -534,7 +546,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -546,7 +560,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -561,7 +575,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -573,7 +589,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -589,3 +605,4 @@ ] } } + diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json index 30daecf16e..b4abdde465 100644 --- a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json +++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json @@ -38,8 +38,8 @@ "gateway": "", "interface": "r1-eth0", "active": [null], - "fib": [null], - "weight":1 + "fib": [null], + "weight": 1 } ] } @@ -67,8 +67,8 @@ "gateway": "", "interface": "r1-eth0", "active": [null], - "fib": [null], - "weight":1 + "fib": [null], + "weight": 1 } ] } @@ -96,8 +96,8 @@ "gateway": "", "interface": "r1-eth1", "active": [null], - "fib": [null], - "weight":1 + "fib": [null], + "weight": 1 } ] } @@ -125,8 +125,8 @@ "gateway": "", "interface": "r1-eth1", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -238,7 +238,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -249,8 +251,8 @@ "gateway": "", "interface": "r1-eth0", "active": [null], - "fib": [null], - "weight":1 + "fib": [null], + "weight": 1 } ] } @@ -265,7 +267,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -276,8 +280,8 @@ "gateway": "", "interface": "r1-eth0", "active": [null], - "fib": [null], - "weight":1 + "fib": [null], + "weight": 1 } ] } @@ -292,7 +296,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -303,8 +309,8 @@ "gateway": "", "interface": "r1-eth1", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -319,7 +325,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -330,8 +338,8 @@ "gateway": "", "interface": "r1-eth1", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -368,8 +376,8 @@ "gateway": "", "interface": "r1-eth0", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -397,8 +405,8 @@ "gateway": "", "interface": "r1-eth0", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -426,8 +434,8 @@ "gateway": "", "interface": "r1-eth1", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -455,8 +463,8 @@ "gateway": "", "interface": "r1-eth1", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -480,7 +488,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -491,8 +501,8 @@ "gateway": "", "interface": "r1-eth0", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -507,7 +517,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -518,8 +530,8 @@ "gateway": "", "interface": "r1-eth0", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -534,7 +546,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -545,8 +559,8 @@ "gateway": "", "interface": "r1-eth1", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -561,7 +575,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -572,8 +588,8 @@ "gateway": "", "interface": "r1-eth1", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -623,8 +639,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -652,8 +668,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -681,8 +697,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -710,8 +726,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -823,7 +839,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -834,8 +852,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -850,7 +868,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -861,8 +881,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -877,7 +897,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -888,8 +910,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -904,7 +926,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -915,8 +939,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -953,8 +977,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -982,8 +1006,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -1011,8 +1035,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -1040,8 +1064,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -1065,7 +1089,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -1076,8 +1102,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -1092,7 +1118,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -1103,8 +1131,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -1119,7 +1147,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -1130,8 +1160,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } @@ -1146,7 +1176,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -1157,8 +1189,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null], - "weight": 1 + "fib": [null], + "weight": 1 } ] } diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-red.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-red.json index cfabd49c45..5d61b9865f 100644 --- a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-red.json +++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-red.json @@ -38,7 +38,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -66,7 +67,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -94,7 +96,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -122,7 +125,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -234,7 +238,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -245,7 +251,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -260,7 +267,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -271,7 +280,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -286,7 +296,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -297,7 +309,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -312,7 +325,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -323,7 +338,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -360,7 +376,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -388,7 +405,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -416,7 +434,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -444,7 +463,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -468,7 +488,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -479,7 +501,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -494,7 +517,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -505,7 +530,8 @@ "gateway": "", "interface": "r1-eth2", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -520,7 +546,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -531,7 +559,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } @@ -546,7 +575,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -557,7 +588,8 @@ "gateway": "", "interface": "r1-eth3", "active": [null], - "fib": [null] + "fib": [null], + "weight": 1 } ] } diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json index b1124bd7bb..86e67a9e23 100644 --- a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json +++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json @@ -35,7 +35,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -64,7 +64,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -93,7 +93,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -122,7 +122,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -234,7 +234,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -246,7 +248,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -261,7 +263,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -273,7 +277,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -288,7 +292,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -300,7 +306,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -315,7 +321,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -327,7 +335,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -365,7 +373,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -394,7 +402,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -423,7 +431,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -452,7 +460,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -476,7 +484,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -488,7 +498,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -503,7 +513,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -515,7 +527,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -530,7 +542,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -542,7 +556,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -557,7 +571,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -569,7 +585,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json index 70c8798b31..86e67a9e23 100644 --- a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json +++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json @@ -234,7 +234,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -261,7 +263,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -288,7 +292,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -315,7 +321,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -476,7 +484,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -503,7 +513,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -530,7 +542,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -557,7 +571,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib.json b/tests/topotests/mgmt_oper/oper-results/result-lib.json index 0b2a9fa427..b4abdde465 100644 --- a/tests/topotests/mgmt_oper/oper-results/result-lib.json +++ b/tests/topotests/mgmt_oper/oper-results/result-lib.json @@ -39,7 +39,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -68,7 +68,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -97,7 +97,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -126,7 +126,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -238,7 +238,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -250,7 +252,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -265,7 +267,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -277,7 +281,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -292,7 +296,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -304,7 +310,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -319,7 +325,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -331,7 +339,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -369,7 +377,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -398,7 +406,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -427,7 +435,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -456,7 +464,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -480,7 +488,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -492,7 +502,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -507,7 +517,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -519,7 +531,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -534,7 +546,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -546,7 +560,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -561,7 +575,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -573,7 +589,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -624,7 +640,7 @@ "interface": "r1-eth2", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -653,7 +669,7 @@ "interface": "r1-eth2", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -682,7 +698,7 @@ "interface": "r1-eth3", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -711,7 +727,7 @@ "interface": "r1-eth3", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -823,7 +839,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -835,7 +853,7 @@ "interface": "r1-eth2", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -850,7 +868,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -862,7 +882,7 @@ "interface": "r1-eth2", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -877,7 +897,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -889,7 +911,7 @@ "interface": "r1-eth3", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -904,7 +926,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -916,7 +940,7 @@ "interface": "r1-eth3", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -954,7 +978,7 @@ "interface": "r1-eth2", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -983,7 +1007,7 @@ "interface": "r1-eth2", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -1012,7 +1036,7 @@ "interface": "r1-eth3", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -1041,7 +1065,7 @@ "interface": "r1-eth3", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -1065,7 +1089,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -1077,7 +1103,7 @@ "interface": "r1-eth2", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -1092,7 +1118,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -1104,7 +1132,7 @@ "interface": "r1-eth2", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -1119,7 +1147,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -1131,7 +1161,7 @@ "interface": "r1-eth3", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -1146,7 +1176,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -1158,7 +1190,7 @@ "interface": "r1-eth3", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } diff --git a/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json index 769c1f73a5..e313a158a3 100644 --- a/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json +++ b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json @@ -35,7 +35,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -64,7 +64,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -93,7 +93,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -122,7 +122,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } diff --git a/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json index c740f592f7..86e67a9e23 100644 --- a/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json +++ b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json @@ -35,7 +35,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -64,7 +64,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -93,7 +93,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -122,7 +122,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -234,7 +234,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -246,7 +248,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -261,7 +263,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -273,7 +277,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -288,7 +292,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -300,7 +306,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -315,7 +321,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -327,7 +335,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -365,7 +373,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -394,7 +402,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -423,7 +431,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -476,7 +484,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -488,7 +498,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -503,7 +513,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -515,7 +527,7 @@ "interface": "r1-eth0", "active": [null], "fib": [null], - "weight": 1 + "weight": 1 } ] } @@ -530,7 +542,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -542,7 +556,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } @@ -557,7 +571,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -569,7 +585,7 @@ "interface": "r1-eth1", "active": [null], "fib": [null], - "weight":1 + "weight": 1 } ] } diff --git a/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-route-nokey.json b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-route-nokey.json new file mode 100644 index 0000000000..e313a158a3 --- /dev/null +++ b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-route-nokey.json @@ -0,0 +1,229 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.0.0.0/8", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "blackhole", + "vrf": "rubout", + "gateway": "", + "interface": " ", + "bh-type": "null", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "12.12.12.12/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "2.2.2.2", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/oper.py b/tests/topotests/mgmt_oper/oper.py index f54e64ae18..bca452d011 100644 --- a/tests/topotests/mgmt_oper/oper.py +++ b/tests/topotests/mgmt_oper/oper.py @@ -77,7 +77,13 @@ def _do_oper_test(tgen, qr, seconds_left=None): # Don't use this for now. dd_json_cmp = None - expected = open(qr[1], encoding="ascii").read() + if isinstance(qr[1], str): + expected = open(qr[1], encoding="ascii").read() + expected_alt = None + else: + expected = open(qr[1][0], encoding="ascii").read() + expected_alt = open(qr[1][1], encoding="ascii").read() + output = r1.cmd_nostatus(qcmd.format(qr[0], qr[2] if len(qr) > 2 else "")) diag = logging.debug if seconds_left else logging.warning @@ -90,6 +96,7 @@ def _do_oper_test(tgen, qr, seconds_left=None): try: ejson = json.loads(expected) + ejson_alt = json.loads(expected_alt) if expected_alt is not None else None except json.decoder.JSONDecodeError as error: logging.error( "Error decoding json exp result: %s\noutput:\n%s", error, expected @@ -99,6 +106,8 @@ def _do_oper_test(tgen, qr, seconds_left=None): if dd_json_cmp: cmpout = json_cmp(ojson, ejson, exact_match=True) + if cmpout and ejson_alt is not None: + cmpout = json_cmp(ojson, ejson_alt, exact_match=True) if cmpout: diag( "-------DIFF---------\n%s\n---------DIFF----------", @@ -106,6 +115,8 @@ def _do_oper_test(tgen, qr, seconds_left=None): ) else: cmpout = tt_json_cmp(ojson, ejson, exact=True) + if cmpout and ejson_alt is not None: + cmpout = tt_json_cmp(ojson, ejson_alt, exact=True) if cmpout: diag( "-------EXPECT--------\n%s\n------END-EXPECT------", @@ -118,6 +129,7 @@ def _do_oper_test(tgen, qr, seconds_left=None): diag("----diff---\n{}".format(cmpout)) diag("Command: {}".format(qcmd.format(qr[0], qr[2] if len(qr) > 2 else ""))) diag("File: {}".format(qr[1])) + cmpout = str(cmpout) return cmpout @@ -127,7 +139,8 @@ def do_oper_test(tgen, query_results): step(f"Perform query '{qr[0]}'", reset=reset) if reset: reset = False - _do_oper_test(tgen, qr) + ret = _do_oper_test(tgen, qr) + assert ret is None, "Unexpected diff: " + str(ret) def get_ip_networks(super_prefix, count): diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim-empty-label.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim-empty-label.json new file mode 100644 index 0000000000..efd7e8c684 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim-empty-label.json @@ -0,0 +1,3 @@ +{ + "frr-zebra:evpn-mh": {} +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim.json index efd7e8c684..2c63c08510 100644 --- a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim.json +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim.json @@ -1,3 +1,2 @@ { - "frr-zebra:evpn-mh": {} } diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json index f85b163bd6..19295870d5 100644 --- a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json +++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json @@ -121,7 +121,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -148,7 +150,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json index e2cfec9724..f0bde048f2 100644 --- a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json +++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json @@ -121,7 +121,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -148,7 +150,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -282,7 +286,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -309,7 +315,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json index 3567f35a34..8b632bac66 100644 --- a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json +++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json @@ -92,7 +92,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -119,7 +121,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json index d9ca58d25d..678a80ab97 100644 --- a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json +++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json @@ -117,7 +117,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -144,7 +146,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json index d9ca58d25d..678a80ab97 100644 --- a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json +++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json @@ -117,7 +117,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -144,7 +146,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib.json b/tests/topotests/mgmt_oper/simple-results/result-lib.json index e2cfec9724..f0bde048f2 100644 --- a/tests/topotests/mgmt_oper/simple-results/result-lib.json +++ b/tests/topotests/mgmt_oper/simple-results/result-lib.json @@ -121,7 +121,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -148,7 +150,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -282,7 +286,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -309,7 +315,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", diff --git a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json index d9ca58d25d..678a80ab97 100644 --- a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json +++ b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json @@ -117,7 +117,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", @@ -144,7 +146,9 @@ "distance": 0, "metric": 0, "selected": [null], + "installed": [null], "internal-flags": 8, + "internal-status": 16, "uptime": "rubout", "nexthop-group": { "id": "rubout", diff --git a/tests/topotests/mgmt_oper/test_oper.py b/tests/topotests/mgmt_oper/test_oper.py index e4ceabf352..23529bc75e 100644 --- a/tests/topotests/mgmt_oper/test_oper.py +++ b/tests/topotests/mgmt_oper/test_oper.py @@ -107,6 +107,7 @@ vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ri for f in ${resdir}/result-*; do sed -i -e 's/"uptime": ".*"/"uptime": "rubout"/;s/"id": [0-9][0-9]*/"id": "rubout"/' $f + sed -i -e 's/"phy-address": ".*"/"phy-address": "rubout"/' $f sed -i -e 's/"if-index": [0-9][0-9]*/"if-index": "rubout"/' $f sed -i -e 's,"vrf": "[0-9]*","vrf": "rubout",' $f done diff --git a/tests/topotests/mgmt_oper/test_simple.py b/tests/topotests/mgmt_oper/test_simple.py index 2b3d6ff6a5..237f7d57d5 100644 --- a/tests/topotests/mgmt_oper/test_simple.py +++ b/tests/topotests/mgmt_oper/test_simple.py @@ -154,7 +154,11 @@ def test_oper_simple(tgen): ), ( '/frr-interface:lib/interface[name="r1-eth0"]/frr-zebra:zebra/evpn-mh', - "simple-results/result-intf-eth0-wd-trim.json", + ( + # Output is different between libyang2 and libyang3+ + "simple-results/result-intf-eth0-wd-trim.json", + "simple-results/result-intf-eth0-wd-trim-empty-label.json", + ), "with-config exact with-defaults trim", ), ( @@ -181,7 +185,7 @@ vtysh -c 'show mgmt get-data /frr-vrf:lib' > ${resdir}/result-lib.json vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf' > ${resdir}/result-lib-vrf-nokey.json vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]' > ${resdir}/result-lib-vrf-default.json vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="red"]' > ${resdir}/result-lib-vrf-red.json -vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra' > ${resdir}/result-lib-vrf-ebra.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra' > ${resdir}/result-lib-vrf-zebra.json vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs' > ${resdir}/result-lib-vrf-zebra-ribs.json vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib' > ${resdir}/result-ribs-rib-nokeys.json vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]' > ${resdir}/result-ribs-rib-ipv4-unicast.json diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route_static.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route_static.json new file mode 100644 index 0000000000..628a556c62 --- /dev/null +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route_static.json @@ -0,0 +1,50 @@ +{ + "10.48.48.0/24":[ + { + "prefix":"10.48.48.0/24", + "prefixLen":24, + "protocol":"ospf", + "vrfId":0, + "vrfName":"default", + "distance":20, + "metric":134, + "table":254, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"r1-eth0", + "active":true, + "weight":1 + } + ] + }, + { + "prefix":"10.48.48.0/24", + "prefixLen":24, + "protocol":"bgp", + "vrfId":0, + "vrfName":"default", + "selected":true, + "destSelected":true, + "distance":20, + "metric":34, + "installed":true, + "table":254, + "nexthops":[ + { + "flags":3, + "fib":true, + "ip":"10.0.10.5", + "afi":"ipv4", + "interfaceName":"r1-eth1", + "vrf":"blue", + "active":true, + "weight":1 + } + ] + } + ] +}
\ No newline at end of file diff --git a/tests/topotests/ospf_metric_propagation/r4/frr.conf b/tests/topotests/ospf_metric_propagation/r4/frr.conf index b02ae18fc1..d9832d80b8 100644 --- a/tests/topotests/ospf_metric_propagation/r4/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r4/frr.conf @@ -1,6 +1,10 @@ ! hostname r4 ! +vrf green + ip route 10.48.48.0/24 10.0.94.2 +exit + interface r4-eth0 ip address 10.0.3.4/24 ip ospf cost 100 @@ -59,6 +63,7 @@ router bgp 99 vrf green address-family ipv4 unicast redistribute connected redistribute ospf + redistribute static import vrf route-map rmap import vrf default import vrf blue diff --git a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py index b97b86bff9..4639a1e26b 100644 --- a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py +++ b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py @@ -190,6 +190,25 @@ def test_all_links_up(): assert result is None, assertmsg +def test_static_remote(): + "Test static route at R1 configured on R4" + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + r1 = tgen.gears["r1"] + json_file = "{}/r1/show_ip_route_static.json".format(CWD) + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, r1, "show ip route 10.48.48.2 json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + + assertmsg = "r1 JSON output mismatches" + assert result is None, assertmsg + + def test_link_1_down(): "Test path R1 -> R2 -> Ra -> Rb -> R4" tgen = get_topogen() diff --git a/tests/topotests/srv6_static_route/test_srv6_route.py b/tests/topotests/srv6_static_route/test_srv6_route.py index f23e199d4a..e26775daf7 100755 --- a/tests/topotests/srv6_static_route/test_srv6_route.py +++ b/tests/topotests/srv6_static_route/test_srv6_route.py @@ -27,7 +27,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -pytestmark = [pytest.mark.bgpd, pytest.mark.sharpd] +pytestmark = [pytest.mark.staticd] def open_json_file(filename): diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 2bb364f32b..dba50b3c53 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -270,7 +270,7 @@ ctx_keywords = { "mpls ldp": {"address-family ": {"interface ": {}}}, "l2vpn ": {"member pseudowire ": {}}, "key chain ": {"key ": {}}, - "vrf ": {}, + "vrf ": {"rpki": {}}, "interface ": {"link-params": {}}, "pseudowire ": {}, "segment-routing": { @@ -279,7 +279,11 @@ ctx_keywords = { "policy ": {"candidate-path ": {}}, "pcep": {"pcc": {}, "pce ": {}, "pce-config ": {}}, }, - "srv6": {"locators": {"locator ": {}}, "encapsulation": {}}, + "srv6": { + "locators": {"locator ": {}}, + "encapsulation": {}, + "formats": {"format": {}}, + }, }, "nexthop-group ": {}, "route-map ": {}, diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c index 046dc9e99e..516743acab 100644 --- a/tools/gen_northbound_callbacks.c +++ b/tools/gen_northbound_callbacks.c @@ -11,6 +11,7 @@ #include <unistd.h> +#include "darr.h" #include "yang.h" #include "northbound.h" @@ -19,7 +20,7 @@ static bool static_cbs; static void __attribute__((noreturn)) usage(int status) { extern const char *__progname; - fprintf(stderr, "usage: %s [-h] [-s] [-p path] MODULE\n", __progname); + fprintf(stderr, "usage: %s [-h] [-s] [-p path]* MODULE\n", __progname); exit(status); } @@ -408,7 +409,8 @@ static int generate_nb_nodes(const struct lysc_node *snode, void *arg) int main(int argc, char *argv[]) { - const char *search_path = NULL; + char **search_paths = NULL; + char **iter = NULL; struct yang_module *module; char module_name_underscores[64]; struct stat st; @@ -433,7 +435,7 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - search_path = optarg; + *darr_append(search_paths) = darr_strdup(optarg); break; case 's': static_cbs = true; @@ -450,8 +452,11 @@ int main(int argc, char *argv[]) yang_init(false, true, false); - if (search_path) - ly_ctx_set_searchdir(ly_native_ctx, search_path); + darr_foreach_p (search_paths, iter) { + ly_ctx_set_searchdir(ly_native_ctx, *iter); + darr_free(*iter); + } + darr_free(search_paths); /* Load all FRR native models to ensure all augmentations are loaded. */ yang_module_load_all(); diff --git a/zebra/dpdk/zebra_dplane_dpdk.c b/zebra/dpdk/zebra_dplane_dpdk.c index ae1a3743ce..0a898c1923 100644 --- a/zebra/dpdk/zebra_dplane_dpdk.c +++ b/zebra/dpdk/zebra_dplane_dpdk.c @@ -330,14 +330,11 @@ static void zd_dpdk_rule_update(struct zebra_dplane_ctx *ctx) op = dplane_ctx_get_op(ctx); - switch (op) { - case DPLANE_OP_RULE_ADD: + if (op == DPLANE_OP_RULE_ADD) { atomic_fetch_add_explicit(&dpdk_stat->rule_adds, 1, memory_order_relaxed); zd_dpdk_rule_add(ctx); - break; - - case DPLANE_OP_RULE_UPDATE: + } else if (op == DPLANE_OP_RULE_UPDATE) { /* delete old rule and install new one */ atomic_fetch_add_explicit(&dpdk_stat->rule_adds, 1, memory_order_relaxed); @@ -346,62 +343,12 @@ static void zd_dpdk_rule_update(struct zebra_dplane_ctx *ctx) zd_dpdk_rule_del(ctx, dplane_ctx_rule_get_ifname(ctx), in_ifindex, dp_flow_ptr); zd_dpdk_rule_add(ctx); - break; - - case DPLANE_OP_RULE_DELETE: + } else if (op == DPLANE_OP_RULE_DELETE) { atomic_fetch_add_explicit(&dpdk_stat->rule_dels, 1, memory_order_relaxed); in_ifindex = dplane_ctx_get_ifindex(ctx); dp_flow_ptr = dplane_ctx_rule_get_dp_flow_ptr(ctx); - zd_dpdk_rule_del(ctx, dplane_ctx_rule_get_ifname(ctx), - in_ifindex, dp_flow_ptr); - break; - - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_BR_PORT_UPDATE: - case DPLANE_OP_IPTABLE_ADD: - case DPLANE_OP_IPTABLE_DELETE: - case DPLANE_OP_IPSET_ADD: - case DPLANE_OP_IPSET_DELETE: - case DPLANE_OP_IPSET_ENTRY_ADD: - case DPLANE_OP_IPSET_ENTRY_DELETE: - case DPLANE_OP_NEIGH_IP_INSTALL: - case DPLANE_OP_NEIGH_IP_DELETE: - case DPLANE_OP_NEIGH_TABLE_UPDATE: - case DPLANE_OP_GRE_SET: - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: - case DPLANE_OP_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_VLAN_INSTALL, - break; + zd_dpdk_rule_del(ctx, dplane_ctx_rule_get_ifname(ctx), in_ifindex, dp_flow_ptr); } } @@ -410,62 +357,13 @@ static void zd_dpdk_rule_update(struct zebra_dplane_ctx *ctx) */ static void zd_dpdk_process_update(struct zebra_dplane_ctx *ctx) { - switch (dplane_ctx_get_op(ctx)) { + enum dplane_op_e op; - case DPLANE_OP_RULE_ADD: - case DPLANE_OP_RULE_UPDATE: - case DPLANE_OP_RULE_DELETE: + op = dplane_ctx_get_op(ctx); + if (op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE || op == DPLANE_OP_RULE_DELETE) zd_dpdk_rule_update(ctx); - break; - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_BR_PORT_UPDATE: - case DPLANE_OP_IPTABLE_ADD: - case DPLANE_OP_IPTABLE_DELETE: - case DPLANE_OP_IPSET_ADD: - case DPLANE_OP_IPSET_DELETE: - case DPLANE_OP_IPSET_ENTRY_ADD: - case DPLANE_OP_IPSET_ENTRY_DELETE: - case DPLANE_OP_NEIGH_IP_INSTALL: - case DPLANE_OP_NEIGH_IP_DELETE: - case DPLANE_OP_NEIGH_TABLE_UPDATE: - case DPLANE_OP_GRE_SET: - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: - case DPLANE_OP_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_VLAN_INSTALL, - atomic_fetch_add_explicit(&dpdk_stat->ignored_updates, 1, - memory_order_relaxed); - - break; - } + else + atomic_fetch_add_explicit(&dpdk_stat->ignored_updates, 1, memory_order_relaxed); } diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index f9009dabb7..3fd84b5257 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -1323,6 +1323,7 @@ int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr, uint32_t flags, bool force) { int state = ZEBRA_NEIGH_ACTIVE; + struct zebra_vrf *zvrf; if (!force) { if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE) && @@ -1330,12 +1331,14 @@ int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr, /* the host was not advertised - nothing to delete */ return 0; - /* MAC is LOCAL and DUP_DETECTED, this local mobility event - * is not known to bgpd. Upon receiving local delete - * ask bgp to reinstall the best route (remote entry). + /* Duplicate detect action is freeze enabled and + * Local MAC is duplicate deteced, this local + * mobility event is not known to bgpd. + * Upon receiving local delete ask bgp to reinstall + * the best route (remote entry). */ - if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL) && - CHECK_FLAG(flags, ZEBRA_MAC_DUPLICATE)) + zvrf = zebra_vrf_get_evpn(); + if (zvrf && zvrf->dad_freeze && CHECK_FLAG(flags, ZEBRA_MAC_DUPLICATE)) state = ZEBRA_NEIGH_INACTIVE; } diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c index ec151360bd..d99010547f 100644 --- a/zebra/zebra_nb_config.c +++ b/zebra/zebra_nb_config.c @@ -3358,10 +3358,7 @@ int lib_vrf_zebra_filter_protocol_create(struct nb_cb_create_args *args) const char *proto = yang_dnode_get_string(args->dnode, "protocol"); int rtype; - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); + rtype = proto_name2num(proto); if (args->event == NB_EV_VALIDATE) if (rtype < 0) { @@ -3387,10 +3384,7 @@ int lib_vrf_zebra_filter_protocol_destroy(struct nb_cb_destroy_args *args) yang_afi_safi_identity2value(afi_safi, &afi, &safi); - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); + rtype = proto_name2num(proto); /* deleting an existing entry, it can't be invalid */ assert(rtype >= 0); @@ -3418,10 +3412,7 @@ void lib_vrf_zebra_filter_protocol_apply_finish( yang_afi_safi_identity2value(afi_safi, &afi, &safi); - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); + rtype = proto_name2num(proto); /* finishing apply for a validated entry, it can't be invalid */ assert(rtype >= 0); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index e61c158ca9..a32fc2bb14 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1056,6 +1056,7 @@ static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, struct nh_g static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe, bool valid) { struct nhg_connected *rb_node_dep; + bool dependent_valid = valid; if (valid) SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); @@ -1071,6 +1072,7 @@ static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe, bool valid) /* Update validity of nexthops depending on it */ frr_each (nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) { + dependent_valid = valid; if (!valid) { /* * Grab the first nexthop from the depending nexthop group @@ -1080,16 +1082,22 @@ static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe, bool valid) struct nexthop *nexthop = rb_node_dep->nhe->nhg.nexthop; while (nexthop) { - if (nexthop_same(nexthop, nhe->nhg.nexthop)) - break; - + if (nexthop_same(nexthop, nhe->nhg.nexthop)) { + /* Invalid Nexthop */ + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } else { + /* + * If other nexthops in the nexthop + * group are valid then we can continue + * to use this nexthop group as valid + */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + dependent_valid = true; + } nexthop = nexthop->next; } - - if (nexthop) - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); } - zebra_nhg_set_valid(rb_node_dep->nhe, valid); + zebra_nhg_set_valid(rb_node_dep->nhe, dependent_valid); } } diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 29bbf6023d..73ffa09c16 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -114,11 +114,6 @@ static void show_vrf_proto_rm(struct vty *vty, struct zebra_vrf *zvrf, vty_out(vty, "%-24s : none\n", zebra_route_string(i)); } - if (PROTO_RM_NAME(zvrf, af_type, i)) - vty_out(vty, "%-24s : %-10s\n", "any", - PROTO_RM_NAME(zvrf, af_type, i)); - else - vty_out(vty, "%-24s : none\n", "any"); } static void show_vrf_nht_rm(struct vty *vty, struct zebra_vrf *zvrf, @@ -1222,8 +1217,8 @@ route_map_result_t zebra_route_map_check(afi_t family, struct route_entry *re, return RMAP_DENYMATCH; } if (!rmap) { - rm_name = PROTO_RM_NAME(zvrf, family, ZEBRA_ROUTE_MAX); - rmap = PROTO_RM_MAP(zvrf, family, ZEBRA_ROUTE_MAX); + rm_name = PROTO_RM_NAME(zvrf, family, ZEBRA_ROUTE_ALL); + rmap = PROTO_RM_MAP(zvrf, family, ZEBRA_ROUTE_ALL); if (rm_name && !rmap) return RMAP_DENYMATCH; diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 5a80524149..6867b1bbb6 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -338,10 +338,6 @@ DEFUN_NOSH (srv6_locator, } locator = srv6_locator_alloc(argv[1]->arg); - if (!locator) { - vty_out(vty, "%% Alloc failed\n"); - return CMD_WARNING_CONFIG_FAILED; - } locator->status_up = true; VTY_PUSH_CONTEXT(SRV6_LOC_NODE, locator); |
