diff options
42 files changed, 1091 insertions, 358 deletions
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index acc49cac94..036bece359 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -28,6 +28,7 @@ #include "bgpd/bgp_table.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" +#include "bgpd/bgp_nht.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_errors.h" @@ -1708,6 +1709,26 @@ static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi, return 0; } +static int bmp_nht_path_valid(struct bgp *bgp, struct bgp_path_info *path, bool valid) +{ + struct bgp_dest *dest = path->net; + struct bgp_table *table; + + if (frrtrace_enabled(frr_bgp, bmp_nht_path_valid)) { + char pfxprint[PREFIX2STR_BUFFER]; + + prefix2str(&dest->rn->p, pfxprint, sizeof(pfxprint)); + frrtrace(4, frr_bgp, bmp_nht_path_valid, bgp, pfxprint, path, valid); + } + if (bgp->peer_self == path->peer) + /* self declared networks or redistributed networks are not relevant for bmp */ + return 0; + + table = bgp_dest_table(dest); + + return bmp_process(bgp, table->afi, table->safi, dest, path->peer, !valid); +} + static void bmp_stat_put_u32(struct stream *s, size_t *cnt, uint16_t type, uint32_t value) { @@ -2013,11 +2034,16 @@ static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp) size_t open_len = stream_get_endp(s); bbpeer->open_rx_len = open_len; + if (bbpeer->open_rx) + XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx); bbpeer->open_rx = XMALLOC(MTYPE_BMP_OPEN, open_len); memcpy(bbpeer->open_rx, s->data, open_len); bbpeer->open_tx_len = open_len; - bbpeer->open_tx = bbpeer->open_rx; + if (bbpeer->open_tx) + XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx); + bbpeer->open_tx = XMALLOC(MTYPE_BMP_OPEN, open_len); + memcpy(bbpeer->open_tx, s->data, open_len); stream_free(s); } @@ -2057,6 +2083,7 @@ bool bmp_bgp_update_vrf_status(struct bmp_bgp *bmpbgp, enum bmp_vrf_state force) } else { bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid); if (bbpeer) { + XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx); XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx); bmp_peerh_del(&bmp_peerh, bbpeer); XFREE(MTYPE_BMP_PEER, bbpeer); @@ -3090,11 +3117,14 @@ static int bmp_route_update(struct bgp *bgp, afi_t afi, safi_t safi, return 0; } - struct bmp_bgp *bmpbgp = bmp_bgp_get(bgp); + struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp); struct peer *peer = updated_route->peer; struct bmp_targets *bt; struct bmp *bmp; + if (!bmpbgp) + return 0; + frr_each (bmp_targets, &bmpbgp->targets, bt) { if (CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB)) { is_locribmon_enabled = true; @@ -3149,6 +3179,37 @@ static int bgp_bmp_early_fini(void) return 0; } +/* called when the routerid of an instance changes */ +static int bmp_bgp_attribute_updated(struct bgp *bgp, bool withdraw) +{ + struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp); + + if (!bmpbgp) + return 0; + + bmp_bgp_update_vrf_status(bmpbgp, vrf_state_unknown); + + if (bmpbgp->vrf_state == vrf_state_down) + /* do not send peer events, router id will not be enough to set state to up + */ + return 0; + + /* vrf_state is up: trigger a peer event + */ + bmp_send_all_safe(bmpbgp, bmp_peerstate(bgp->peer_self, withdraw)); + return 1; +} + +static int bmp_routerid_update(struct bgp *bgp, bool withdraw) +{ + return bmp_bgp_attribute_updated(bgp, withdraw); +} + +static int bmp_route_distinguisher_update(struct bgp *bgp, afi_t afi, bool preconfig) +{ + return bmp_bgp_attribute_updated(bgp, preconfig); +} + /* called when a bgp instance goes up/down, implying that the underlying VRF * has been created or deleted in zebra */ @@ -3194,6 +3255,7 @@ static int bgp_bmp_module_init(void) hook_register(peer_status_changed, bmp_peer_status_changed); hook_register(peer_backward_transition, bmp_peer_backward); hook_register(bgp_process, bmp_process); + hook_register(bgp_nht_path_update, bmp_nht_path_valid); hook_register(bgp_inst_config_write, bmp_config_write); hook_register(bgp_inst_delete, bmp_bgp_del); hook_register(frr_late_init, bgp_bmp_init); @@ -3201,6 +3263,8 @@ static int bgp_bmp_module_init(void) hook_register(frr_early_fini, bgp_bmp_early_fini); hook_register(bgp_instance_state, bmp_vrf_state_changed); hook_register(bgp_vrf_status_changed, bmp_vrf_itf_state_changed); + hook_register(bgp_routerid_update, bmp_routerid_update); + hook_register(bgp_route_distinguisher_update, bmp_route_distinguisher_update); return 0; } diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index d9dfc4c5eb..dc6e0d33c2 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3108,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; @@ -3132,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; @@ -3247,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", @@ -3276,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; } @@ -4940,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; @@ -4954,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; } @@ -5017,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_io.c b/bgpd/bgp_io.c index 9e9251c854..5d0f14cc5c 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -199,7 +199,7 @@ static int read_ibuf_work(struct peer_connection *connection) assert(ringbuf_get(ibw, pkt->data, pktsize) == pktsize); stream_set_endp(pkt, pktsize); - frrtrace(2, frr_bgp, packet_read, connection->peer, pkt); + frrtrace(2, frr_bgp, packet_read, connection, pkt); frr_with_mutex (&connection->io_mtx) { stream_fifo_push(connection->ibuf, pkt); } diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 5fda5701f3..ed689c8bac 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -869,6 +869,9 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, ? bnc->ifindex_ipv6_ll : nexthop->ifindex, bgp->vrf_id)); + json_object_int_add(json_gate, "ifindex", + bnc->ifindex_ipv6_ll ? bnc->ifindex_ipv6_ll + : nexthop->ifindex); break; case NEXTHOP_TYPE_IPV4: json_object_string_addf(json_gate, "ip", "%pI4", @@ -882,6 +885,9 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, ? bnc->ifindex_ipv6_ll : nexthop->ifindex, bgp->vrf_id)); + json_object_int_add(json_gate, "ifindex", + bnc->ifindex_ipv6_ll ? bnc->ifindex_ipv6_ll + : nexthop->ifindex); break; case NEXTHOP_TYPE_IPV4_IFINDEX: json_object_string_addf(json_gate, "ip", "%pI4", @@ -893,6 +899,9 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, ? bnc->ifindex_ipv6_ll : nexthop->ifindex, bgp->vrf_id)); + json_object_int_add(json_gate, "ifindex", + bnc->ifindex_ipv6_ll ? bnc->ifindex_ipv6_ll + : nexthop->ifindex); break; case NEXTHOP_TYPE_BLACKHOLE: json_object_boolean_true_add(json_gate, @@ -926,13 +935,13 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, vty_out(vty, " gate %pI6", &nexthop->gate.ipv6); if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX && bnc->ifindex_ipv6_ll) - vty_out(vty, ", if %s\n", - ifindex2ifname(bnc->ifindex_ipv6_ll, - bgp->vrf_id)); + vty_out(vty, ", if %s, ifindex %d\n", + ifindex2ifname(bnc->ifindex_ipv6_ll, bgp->vrf_id), + bnc->ifindex_ipv6_ll); else if (nexthop->ifindex) - vty_out(vty, ", if %s\n", - ifindex2ifname(nexthop->ifindex, - bgp->vrf_id)); + vty_out(vty, ", if %s, ifindex %d\n", + ifindex2ifname(nexthop->ifindex, bgp->vrf_id), + nexthop->ifindex); else vty_out(vty, "\n"); break; @@ -941,22 +950,22 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, vty_out(vty, " gate %pI4", &nexthop->gate.ipv4); if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX && bnc->ifindex_ipv6_ll) - vty_out(vty, ", if %s\n", - ifindex2ifname(bnc->ifindex_ipv6_ll, - bgp->vrf_id)); + vty_out(vty, ", if %s, ifindex %d\n", + ifindex2ifname(bnc->ifindex_ipv6_ll, bgp->vrf_id), + bnc->ifindex_ipv6_ll); else if (nexthop->ifindex) - vty_out(vty, ", if %s\n", - ifindex2ifname(nexthop->ifindex, - bgp->vrf_id)); + vty_out(vty, ", if %s, ifindex %d\n", + ifindex2ifname(nexthop->ifindex, bgp->vrf_id), + nexthop->ifindex); else vty_out(vty, "\n"); break; case NEXTHOP_TYPE_IFINDEX: - vty_out(vty, " if %s\n", - ifindex2ifname(bnc->ifindex_ipv6_ll - ? bnc->ifindex_ipv6_ll - : nexthop->ifindex, - bgp->vrf_id)); + vty_out(vty, " if %s, ifindex %d\n", + ifindex2ifname(bnc->ifindex_ipv6_ll ? bnc->ifindex_ipv6_ll + : nexthop->ifindex, + bgp->vrf_id), + bnc->ifindex_ipv6_ll ? bnc->ifindex_ipv6_ll : nexthop->ifindex); break; case NEXTHOP_TYPE_BLACKHOLE: vty_out(vty, " blackhole\n"); @@ -970,9 +979,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 +991,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 +1002,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 +1030,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 +1050,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,8 +1082,8 @@ 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", @@ -1090,22 +1098,25 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } /* 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 +1128,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 +1172,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 +1182,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 +1256,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 +1284,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 +1309,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_nht.c b/bgpd/bgp_nht.c index ed83757ea3..164e2300c0 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -41,6 +41,9 @@ static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc); static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p); static void bgp_nht_ifp_initial(struct event *thread); +DEFINE_HOOK(bgp_nht_path_update, (struct bgp *bgp, struct bgp_path_info *pi, bool valid), + (bgp, pi, valid)); + static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc) { return (bgp_zebra_num_connects() == 0 @@ -1449,6 +1452,9 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc) } } + if (path_valid != bnc_is_valid_nexthop) + hook_call(bgp_nht_path_update, bgp_path, path, bnc_is_valid_nexthop); + bgp_process(bgp_path, dest, path, afi, safi); } diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index e7c6fdc281..345089ac5a 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -83,4 +83,9 @@ extern void bgp_nht_ifp_up(struct interface *ifp); extern void bgp_nht_ifp_down(struct interface *ifp); extern void bgp_nht_interface_events(struct peer *peer); + +/* called when a path becomes valid or invalid, because of nexthop tracking */ +DECLARE_HOOK(bgp_nht_path_update, (struct bgp *bgp, struct bgp_path_info *pi, bool valid), + (bgp, pi, valid)); + #endif /* _BGP_NHT_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0f899d9617..f519534192 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -649,7 +649,7 @@ static bool use_bgp_med_value(struct attr *attr, struct bgp *bgp) /* Get MED value. If MED value is missing and "bgp bestpath missing-as-worst" is specified, treat it as the worst value. */ -static uint32_t bgp_med_value(struct attr *attr, struct bgp *bgp) +uint32_t bgp_med_value(struct attr *attr, struct bgp *bgp) { if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) return attr->med; @@ -15106,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). @@ -15174,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)) { @@ -15192,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); @@ -15205,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", @@ -15335,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); @@ -15376,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"); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 474e229575..c071120de9 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -1013,4 +1013,5 @@ 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); +extern uint32_t bgp_med_value(struct attr *attr, struct bgp *bgp); #endif /* _QUAGGA_BGP_ROUTE_H */ diff --git a/bgpd/bgp_trace.h b/bgpd/bgp_trace.h index a77a25e435..43bc7a5a17 100644 --- a/bgpd/bgp_trace.h +++ b/bgpd/bgp_trace.h @@ -211,6 +211,24 @@ TRACEPOINT_EVENT( TRACEPOINT_LOGLEVEL(frr_bgp, bmp_process, TRACE_DEBUG) /* + * BMP is hooked for a nexthop tracking event + */ +TRACEPOINT_EVENT( + frr_bgp, + bmp_nht_path_valid, + TP_ARGS(struct bgp *, bgp, char *, pfx, struct bgp_path_info *, + path, bool, valid), + TP_FIELDS( + ctf_string(bgp, bgp->name_pretty) + ctf_string(prefix, pfx) + ctf_string(path, PEER_HOSTNAME(path->peer)) + ctf_integer(bool, valid, valid) + ) +) + +TRACEPOINT_LOGLEVEL(frr_bgp, bmp_nht_path_valid, TRACE_DEBUG) + +/* * bgp_dest_lock/bgp_dest_unlock */ TRACEPOINT_EVENT( diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index a1bf9a4c61..8f816eb30d 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -228,64 +228,67 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg) afi2str(afi), safi2str(safi), ctx->dest); UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) { - /* withdraw stale addpath without waiting for the coalesce timer timeout. - * Otherwise, since adj->addpath_tx_id is overwritten, the code never - * notice anymore it has to do a withdrawal. - */ - if (addpath_capable) - subgrp_withdraw_stale_addpath(ctx, subgrp); - /* - * Skip the subgroups that have coalesce timer running. We will - * walk the entire prefix table for those subgroups when the - * coalesce timer fires. - */ - if (!subgrp->t_coalesce) { - - /* An update-group that uses addpath */ - if (addpath_capable) { - subgrp_announce_addpath_best_selected(ctx->dest, - subgrp); + /* An update-group that uses addpath */ + if (addpath_capable) { + /* Send withdrawals without waiting for coalesting timer + * to expire. + */ + if (subgrp->t_coalesce) { + subgrp_withdraw_stale_addpath(ctx, subgrp); - /* Process the bestpath last so the "show [ip] - * bgp neighbor x.x.x.x advertised" - * output shows the attributes from the bestpath - */ - if (ctx->pi) - subgroup_process_announce_selected( - subgrp, ctx->pi, ctx->dest, afi, - safi, - bgp_addpath_id_for_peer( - peer, afi, safi, - &ctx->pi->tx_addpath)); + goto done; } - /* An update-group that does not use addpath */ - else { - if (ctx->pi) { - subgroup_process_announce_selected( - subgrp, ctx->pi, ctx->dest, afi, - safi, - bgp_addpath_id_for_peer( - peer, afi, safi, - &ctx->pi->tx_addpath)); - } else { - /* Find the addpath_tx_id of the path we - * had advertised and - * send a withdraw */ - RB_FOREACH_SAFE (adj, bgp_adj_out_rb, - &ctx->dest->adj_out, + + subgrp_withdraw_stale_addpath(ctx, subgrp); + subgrp_announce_addpath_best_selected(ctx->dest, subgrp); + + /* Process the bestpath last so the + * "show [ip] bgp neighbor x.x.x.x advertised" output shows + * the attributes from the bestpath. + */ + if (ctx->pi) + subgroup_process_announce_selected( + subgrp, ctx->pi, ctx->dest, afi, safi, + bgp_addpath_id_for_peer(peer, afi, safi, + &ctx->pi->tx_addpath)); + } else { + /* Send withdrawals without waiting for coalesting timer + * to expire. + */ + if (subgrp->t_coalesce) { + if (!ctx->pi || CHECK_FLAG(ctx->pi->flags, BGP_PATH_UNUSEABLE)) { + RB_FOREACH_SAFE (adj, bgp_adj_out_rb, &ctx->dest->adj_out, adj_next) { if (adj->subgroup == subgrp) { subgroup_process_announce_selected( - subgrp, NULL, - ctx->dest, afi, - safi, + subgrp, NULL, ctx->dest, afi, safi, adj->addpath_tx_id); } } } + + goto done; + } + + if (ctx->pi) { + subgroup_process_announce_selected( + subgrp, ctx->pi, ctx->dest, afi, safi, + bgp_addpath_id_for_peer(peer, afi, safi, + &ctx->pi->tx_addpath)); + } else { + RB_FOREACH_SAFE (adj, bgp_adj_out_rb, &ctx->dest->adj_out, + adj_next) { + if (adj->subgroup == subgrp) { + subgroup_process_announce_selected(subgrp, NULL, + ctx->dest, afi, + safi, + adj->addpath_tx_id); + } + } } } +done: /* Notify BGP Conditional advertisement */ bgp_notify_conditional_adv_scanner(subgrp); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 550adf93db..c6b09481b6 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -141,6 +141,8 @@ DEFINE_HOOK(bgp_inst_config_write, DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp)); DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp)); DEFINE_HOOK(bgp_snmp_traps_config_write, (struct vty * vty), (vty)); +DEFINE_HOOK(bgp_route_distinguisher_update, (struct bgp *bgp, afi_t afi, bool preconfig), + (bgp, afi, preconfig)); static struct peer_group *listen_range_exists(struct bgp *bgp, struct prefix *range, int exact); @@ -9805,6 +9807,14 @@ DEFPY (af_rd_vpn_export, vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi, bgp_get_default(), bgp); + if (!bgp->vpn_policy[afi].tovpn_rd_pretty && !rd_str) + return CMD_SUCCESS; + + if (yes && bgp->vpn_policy[afi].tovpn_rd_pretty && rd_str && + strmatch(rd_str, bgp->vpn_policy[afi].tovpn_rd_pretty)) + return CMD_SUCCESS; + + hook_call(bgp_route_distinguisher_update, bgp, afi, true); if (yes) { if (bgp->vpn_policy[afi].tovpn_rd_pretty) XFREE(MTYPE_BGP_NAME, bgp->vpn_policy[afi].tovpn_rd_pretty); @@ -9815,9 +9825,11 @@ DEFPY (af_rd_vpn_export, BGP_VPN_POLICY_TOVPN_RD_SET); } else { XFREE(MTYPE_BGP_NAME, bgp->vpn_policy[afi].tovpn_rd_pretty); + bgp->vpn_policy[afi].tovpn_rd_pretty = NULL; UNSET_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_RD_SET); } + hook_call(bgp_route_distinguisher_update, bgp, afi, false); /* post-change: re-export vpn routes */ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi, @@ -11476,6 +11488,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", @@ -21927,6 +22005,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 e3465feda8..7ad9ce4726 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1339,7 +1339,7 @@ static void bgp_zebra_announce_parse_nexthop( * overridden on 1st nexthop */ if (mpinfo == info) { if (metric) - *metric = mpinfo_cp->attr->med; + *metric = bgp_med_value(mpinfo_cp->attr, bgp); if (tag) *tag = mpinfo_cp->attr->tag; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 2f234e3a5a..05bc804db4 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -86,6 +86,7 @@ DEFINE_QOBJ_TYPE(bgp); DEFINE_QOBJ_TYPE(peer); DEFINE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp)); DEFINE_HOOK(bgp_instance_state, (struct bgp *bgp), (bgp)); +DEFINE_HOOK(bgp_routerid_update, (struct bgp *bgp, bool withdraw), (bgp, withdraw)); /* BGP process wide configuration. */ static struct bgp_master bgp_master; @@ -301,6 +302,8 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id, vpn_handle_router_id_update(bgp, true, is_config); + hook_call(bgp_routerid_update, bgp, true); + IPV4_ADDR_COPY(&bgp->router_id, id); /* Set all peer's local identifier with this value. */ @@ -318,6 +321,7 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id, vpn_handle_router_id_update(bgp, false, is_config); + hook_call(bgp_routerid_update, bgp, false); return 0; } @@ -6686,7 +6690,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 @@ -6695,7 +6699,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 47214e52e5..65b268c4ea 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -907,6 +907,9 @@ DECLARE_HOOK(bgp_config_end, (struct bgp *bgp), (bgp)); DECLARE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled), (vrf, enabled)); DECLARE_HOOK(bgp_instance_state, (struct bgp *bgp), (bgp)); +DECLARE_HOOK(bgp_routerid_update, (struct bgp *bgp, bool withdraw), (bgp, withdraw)); +DECLARE_HOOK(bgp_route_distinguisher_update, (struct bgp *bgp, afi_t afi, bool preconfig), + (bgp, afi, preconfig)); /* Thread callback information */ struct afi_safi_info { diff --git a/doc/developer/building-frr-for-alpine.rst b/doc/developer/building-frr-for-alpine.rst index 68e58c9d76..a5ce636ebb 100644 --- a/doc/developer/building-frr-for-alpine.rst +++ b/doc/developer/building-frr-for-alpine.rst @@ -47,11 +47,11 @@ Build apk packages ./docker/alpine/build.sh -This will put the apk packages in: +This will put the apk packages into the architecture folder in: :: - ./docker/pkgs/apk/x86_64/ + ./docker/alpine/pkgs/apk/ Usage ----- 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/isisd/isis_cli.c b/isisd/isis_cli.c index 652efee89a..735e39a377 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -626,10 +626,17 @@ DEFPY_YANG(domain_passwd, domain_passwd_cmd, } DEFPY_YANG(no_area_passwd, no_area_passwd_cmd, - "no <area-password|domain-password>$cmd", + "no <area-password|domain-password>$cmd [<clear|md5>$pwd_type WORD$pwd [authenticate snp <send-only|validate>$snp]]", NO_STR "Configure the authentication password for an area\n" - "Set the authentication password for a routing domain\n") + "Set the authentication password for a routing domain\n" + "Clear-text authentication type\n" + "MD5 authentication type\n" + "Level-wide password\n" + "Authentication\n" + "SNP PDUs\n" + "Send but do not check PDUs on receiving\n" + "Send and check PDUs on receiving\n") { nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); @@ -1649,90 +1649,90 @@ static int lib_interface_description_destroy(struct nb_cb_destroy_args *args) return NB_OK; } -/* - * XPath: /frr-interface:lib/interface/vrf - */ -static struct yang_data * -lib_interface_vrf_get_elem(struct nb_cb_get_elem_args *args) +static enum nb_error __return_ok(const struct nb_node *nb_node, const void *list_entry, + struct lyd_node *parent) { - const struct interface *ifp = args->list_entry; - - return yang_data_new_string(args->xpath, ifp->vrf->name); + return NB_OK; } /* - * XPath: /frr-interface:lib/interface/state/if-index + * XPath: /frr-interface:lib/interface/vrf */ -static struct yang_data * -lib_interface_state_if_index_get_elem(struct nb_cb_get_elem_args *args) +static enum nb_error lib_interface_vrf_get(const struct nb_node *nb_node, const void *list_entry, + struct lyd_node *parent) { - const struct interface *ifp = args->list_entry; + const struct lysc_node *snode = nb_node->snode; + const struct interface *ifp = list_entry; - return yang_data_new_int32(args->xpath, ifp->ifindex); + if (lyd_new_term(parent, snode->module, snode->name, ifp->vrf->name, LYD_NEW_PATH_UPDATE, + NULL)) + return NB_ERR_RESOURCE; + return NB_OK; } /* - * XPath: /frr-interface:lib/interface/state/mtu + * XPath: /frr-interface:lib/interface/state/if-index */ -static struct yang_data * -lib_interface_state_mtu_get_elem(struct nb_cb_get_elem_args *args) +static enum nb_error lib_interface_state_if_index_get(const struct nb_node *nb_node, + const void *list_entry, + struct lyd_node *parent) { - const struct interface *ifp = args->list_entry; + const struct lysc_node *snode = nb_node->snode; + const struct interface *ifp = list_entry; + int32_t value = ifp->ifindex; - return yang_data_new_uint32(args->xpath, ifp->mtu); + if (lyd_new_term_bin(parent, snode->module, snode->name, &value, sizeof(value), + LYD_NEW_PATH_UPDATE, NULL)) + return NB_ERR_RESOURCE; + return NB_OK; } /* - * XPath: /frr-interface:lib/interface/state/mtu6 + * XPath: /frr-interface:lib/interface/state/mtu[6] */ -static struct yang_data * -lib_interface_state_mtu6_get_elem(struct nb_cb_get_elem_args *args) +static enum nb_error lib_interface_state_mtu_get(const struct nb_node *nb_node, + const void *list_entry, struct lyd_node *parent) { - const struct interface *ifp = args->list_entry; + const struct lysc_node *snode = nb_node->snode; + const struct interface *ifp = list_entry; + uint32_t value = ifp->mtu; - return yang_data_new_uint32(args->xpath, ifp->mtu6); + if (lyd_new_term_bin(parent, snode->module, snode->name, &value, sizeof(value), + LYD_NEW_PATH_UPDATE, NULL)) + return NB_ERR_RESOURCE; + return NB_OK; } /* * XPath: /frr-interface:lib/interface/state/speed */ -static struct yang_data * -lib_interface_state_speed_get_elem(struct nb_cb_get_elem_args *args) +static enum nb_error lib_interface_state_speed_get(const struct nb_node *nb_node, + const void *list_entry, struct lyd_node *parent) { - const struct interface *ifp = args->list_entry; + const struct lysc_node *snode = nb_node->snode; + const struct interface *ifp = list_entry; + uint32_t value = ifp->speed; - return yang_data_new_uint32(args->xpath, ifp->speed); + if (lyd_new_term_bin(parent, snode->module, snode->name, &value, sizeof(value), + LYD_NEW_PATH_UPDATE, NULL)) + return NB_ERR_RESOURCE; + return NB_OK; } /* * XPath: /frr-interface:lib/interface/state/metric */ -static struct yang_data * -lib_interface_state_metric_get_elem(struct nb_cb_get_elem_args *args) +static enum nb_error lib_interface_state_metric_get(const struct nb_node *nb_node, + const void *list_entry, struct lyd_node *parent) { - const struct interface *ifp = args->list_entry; - - return yang_data_new_uint32(args->xpath, ifp->metric); -} + const struct lysc_node *snode = nb_node->snode; + const struct interface *ifp = list_entry; + uint32_t value = ifp->metric; -/* - * XPath: /frr-interface:lib/interface/state/flags - */ -static struct yang_data * -lib_interface_state_flags_get_elem(struct nb_cb_get_elem_args *args) -{ - /* TODO: implement me. */ - return NULL; -} - -/* - * XPath: /frr-interface:lib/interface/state/type - */ -static struct yang_data * -lib_interface_state_type_get_elem(struct nb_cb_get_elem_args *args) -{ - /* TODO: implement me. */ - return NULL; + if (lyd_new_term_bin(parent, snode->module, snode->name, &value, sizeof(value), + LYD_NEW_PATH_UPDATE, NULL)) + return NB_ERR_RESOURCE; + return NB_OK; } /* @@ -1779,49 +1779,49 @@ const struct frr_yang_module_info frr_interface_info = { { .xpath = "/frr-interface:lib/interface/vrf", .cbs = { - .get_elem = lib_interface_vrf_get_elem, + .get = lib_interface_vrf_get, } }, { .xpath = "/frr-interface:lib/interface/state/if-index", .cbs = { - .get_elem = lib_interface_state_if_index_get_elem, + .get = lib_interface_state_if_index_get, } }, { .xpath = "/frr-interface:lib/interface/state/mtu", .cbs = { - .get_elem = lib_interface_state_mtu_get_elem, + .get = lib_interface_state_mtu_get, } }, { .xpath = "/frr-interface:lib/interface/state/mtu6", .cbs = { - .get_elem = lib_interface_state_mtu6_get_elem, + .get = lib_interface_state_mtu_get, } }, { .xpath = "/frr-interface:lib/interface/state/speed", .cbs = { - .get_elem = lib_interface_state_speed_get_elem, + .get = lib_interface_state_speed_get, } }, { .xpath = "/frr-interface:lib/interface/state/metric", .cbs = { - .get_elem = lib_interface_state_metric_get_elem, + .get = lib_interface_state_metric_get, } }, { .xpath = "/frr-interface:lib/interface/state/flags", .cbs = { - .get_elem = lib_interface_state_flags_get_elem, + .get = __return_ok, } }, { .xpath = "/frr-interface:lib/interface/state/type", .cbs = { - .get_elem = lib_interface_state_type_get_elem, + .get = __return_ok, } }, { diff --git a/lib/mgmt_be_client.c b/lib/mgmt_be_client.c index f03006ad0e..05949fd62d 100644 --- a/lib/mgmt_be_client.c +++ b/lib/mgmt_be_client.c @@ -312,11 +312,11 @@ static int be_client_send_error(struct mgmt_be_client *client, uint64_t txn_id, return ret; } -static int mgmt_be_send_notification(void *__be_client, const char *xpath, - const struct lyd_node *tree) +static int __send_notification(struct mgmt_be_client *client, const char *xpath, + const struct lyd_node *tree, uint8_t op) { - struct mgmt_be_client *client = __be_client; struct mgmt_msg_notify_data *msg = NULL; + // LYD_FORMAT format = LYD_LYB; LYD_FORMAT format = LYD_JSON; uint8_t **darrp; LY_ERR err; @@ -324,37 +324,91 @@ static int mgmt_be_send_notification(void *__be_client, const char *xpath, assert(tree); - debug_be_client("%s: sending YANG notification: %s", __func__, - tree->schema->name); + debug_be_client("%s: sending %sYANG %snotification: %s", __func__, + op == NOTIFY_OP_DS_DELETE ? "delete " + : op == NOTIFY_OP_DS_REPLACE ? "replace " + : op == NOTIFY_OP_DS_PATCH ? "patch " + : "", + op == NOTIFY_OP_NOTIFICATION ? "" : "DS ", xpath ?: tree->schema->name); /* * Allocate a message and append the data to it using `format` */ - msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_notify_data, 0, - MTYPE_MSG_NATIVE_NOTIFY); + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_notify_data, 0, MTYPE_MSG_NATIVE_NOTIFY); msg->code = MGMT_MSG_CODE_NOTIFY; msg->result_type = format; + msg->op = op; mgmt_msg_native_xpath_encode(msg, xpath); - darrp = mgmt_msg_native_get_darrp(msg); - err = yang_print_tree_append(darrp, tree, format, - (LYD_PRINT_SHRINK | LYD_PRINT_WD_EXPLICIT | - LYD_PRINT_WITHSIBLINGS)); - if (err) { - flog_err(EC_LIB_LIBYANG, - "%s: error creating notification data: %s", __func__, - ly_strerrcode(err)); - ret = 1; - goto done; + if (tree) { + darrp = mgmt_msg_native_get_darrp(msg); + err = yang_print_tree_append(darrp, tree, format, + (LYD_PRINT_SHRINK | LYD_PRINT_WD_EXPLICIT | + LYD_PRINT_WITHSIBLINGS)); + if (err) { + flog_err(EC_LIB_LIBYANG, "%s: error creating notification data: %s", + __func__, ly_strerrcode(err)); + ret = 1; + goto done; + } } - (void)be_client_send_native_msg(client, msg, - mgmt_msg_native_get_msg_len(msg), false); + ret = be_client_send_native_msg(client, msg, mgmt_msg_native_get_msg_len(msg), false); done: mgmt_msg_native_free_msg(msg); return ret; } +/** + * mgmt_be_send_ds_delete_notification() - Send DS notification to mgmtd + */ +int mgmt_be_send_ds_delete_notification(const char *path) +{ + if (!__be_client) { + debug_be_client("%s: No mgmtd connection for DS delete notification: %s", __func__, + path); + return 1; + } + return __send_notification(__be_client, path, NULL, NOTIFY_OP_DS_DELETE); +} + +/** + * mgmt_be_send_ds_patch_notification() - Send a YANG patch DS notification to mgmtd + */ +int mgmt_be_send_ds_patch_notification(const char *path, const struct lyd_node *patch) +{ + if (!__be_client) { + debug_be_client("%s: No mgmtd connection for DS delete notification: %s", __func__, + path); + return 1; + } + return __send_notification(__be_client, path, patch, NOTIFY_OP_DS_PATCH); +} + +/** + * mgmt_be_send_ds_replace_notification() - Send a replace DS notification to mgmtd + */ +int mgmt_be_send_ds_replace_notification(const char *path, const struct lyd_node *tree) +{ + if (!__be_client) { + debug_be_client("%s: No mgmtd connection for DS delete notification: %s", __func__, + path); + return 1; + } + return __send_notification(__be_client, path, tree, NOTIFY_OP_DS_REPLACE); +} + +/** + * mgmt_be_send_notification() - Send notification to mgmtd + * + * This function is attached to the northbound notification hook. + */ +static int mgmt_be_send_notification(void *__client, const char *path, const struct lyd_node *tree) +{ + __send_notification(__client, path, tree, NOTIFY_OP_NOTIFICATION); + return 0; +} + static int mgmt_be_send_txn_reply(struct mgmt_be_client *client_ctx, uint64_t txn_id, bool create) { diff --git a/lib/mgmt_be_client.h b/lib/mgmt_be_client.h index 6ed8c2a39f..a3e3896d52 100644 --- a/lib/mgmt_be_client.h +++ b/lib/mgmt_be_client.h @@ -112,6 +112,22 @@ extern struct mgmt_be_client * mgmt_be_client_create(const char *name, struct mgmt_be_client_cbs *cbs, uintptr_t user_data, struct event_loop *event_loop); + +/** + * mgmt_be_send_ds_delete_notification() - Send a datastore delete notification. + */ +extern int mgmt_be_send_ds_delete_notification(const char *path); + +/** + * mgmt_be_send_ds_patch_notification() - Send a datastore YANG patch notification. + */ +extern int mgmt_be_send_ds_patch_notification(const char *path, const struct lyd_node *tree); + +/** + * mgmt_be_send_ds_replace_notification() - Send a datastore replace notification. + */ +extern int mgmt_be_send_ds_replace_notification(const char *path, const struct lyd_node *tree); + /* * Initialize library vty (adds debug support). * diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h index 587a002801..4076977a22 100644 --- a/lib/mgmt_msg_native.h +++ b/lib/mgmt_msg_native.h @@ -323,22 +323,29 @@ _Static_assert(sizeof(struct mgmt_msg_get_data) == offsetof(struct mgmt_msg_get_data, xpath), "Size mismatch"); + +#define NOTIFY_OP_NOTIFICATION 0 +#define NOTIFY_OP_DS_REPLACE 1 +#define NOTIFY_OP_DS_DELETE 2 +#define NOTIFY_OP_DS_PATCH 3 + /** * struct mgmt_msg_notify_data - Message carrying notification data. * * @result_type: ``LYD_FORMAT`` for format of the @result value. * @data: The xpath string of the notification followed by the tree data in * @result_type format. + * @op: notify operation type. */ struct mgmt_msg_notify_data { struct mgmt_msg_header; uint8_t result_type; - uint8_t resv2[7]; + uint8_t op; + uint8_t resv2[6]; alignas(8) char data[]; }; -_Static_assert(sizeof(struct mgmt_msg_notify_data) == - offsetof(struct mgmt_msg_notify_data, data), +_Static_assert(sizeof(struct mgmt_msg_notify_data) == offsetof(struct mgmt_msg_notify_data, data), "Size mismatch"); #define EDIT_FLAG_IMPLICIT_LOCK 0x01 diff --git a/lib/northbound.c b/lib/northbound.c index a385cc9ece..c67ed924a9 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -273,9 +273,11 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node) error += nb_node_validate_cb(nb_node, NB_CB_APPLY_FINISH, !!nb_node->cbs.apply_finish, true); error += nb_node_validate_cb(nb_node, NB_CB_GET_ELEM, - !!nb_node->cbs.get_elem, false); + (nb_node->cbs.get_elem || nb_node->cbs.get), false); error += nb_node_validate_cb(nb_node, NB_CB_GET_NEXT, - !!nb_node->cbs.get_next, false); + (nb_node->cbs.get_next || + (nb_node->snode->nodetype == LYS_LEAFLIST && nb_node->cbs.get)), + false); error += nb_node_validate_cb(nb_node, NB_CB_GET_KEYS, !!nb_node->cbs.get_keys, false); error += nb_node_validate_cb(nb_node, NB_CB_LOOKUP_ENTRY, diff --git a/lib/northbound.h b/lib/northbound.h index 97a1d31e57..42f763c3ef 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -21,6 +21,7 @@ extern "C" { /* Forward declaration(s). */ struct vty; struct debug; +struct nb_node; struct nb_yang_xpath_tag { uint32_t ns; @@ -102,6 +103,20 @@ enum nb_cb_operation { NB_CB_NOTIFY, }; +/* Northbound error codes. */ +enum nb_error { + NB_OK = 0, + NB_ERR, + NB_ERR_NO_CHANGES, + NB_ERR_NOT_FOUND, + NB_ERR_EXISTS, + NB_ERR_LOCKED, + NB_ERR_VALIDATION, + NB_ERR_RESOURCE, + NB_ERR_INCONSISTENCY, + NB_YIELD, +}; + union nb_resource { int fd; void *ptr; @@ -426,6 +441,25 @@ struct nb_callbacks { void (*apply_finish)(struct nb_cb_apply_finish_args *args); /* + * Operational data callback (new direct tree add method). + * + * The callback function should create a new lyd_node (leaf) or + * lyd_node's (leaf list) for the value and attach to parent. + * + * nb_node + * The node representing the leaf or leaf list + * list_entry + * List entry from get_next (or NULL). + * parent + * The parent lyd_node to attach the leaf data to. + * + * Returns: + * Returns an nb_error if the data could not be added to the tree. + */ + enum nb_error (*get)(const struct nb_node *nb_node, const void *list_entry, + struct lyd_node *parent); + + /* * Operational data callback. * * The callback function should return the value of a specific leaf, @@ -672,20 +706,6 @@ struct frr_yang_module_info { #endif }; -/* Northbound error codes. */ -enum nb_error { - NB_OK = 0, - NB_ERR, - NB_ERR_NO_CHANGES, - NB_ERR_NOT_FOUND, - NB_ERR_EXISTS, - NB_ERR_LOCKED, - NB_ERR_VALIDATION, - NB_ERR_RESOURCE, - NB_ERR_INCONSISTENCY, - NB_YIELD, -}; - /* Default priority. */ #define NB_DFLT_PRIORITY (UINT32_MAX / 2) @@ -814,8 +834,9 @@ extern struct debug nb_dbg_libyang; extern struct nb_config *running_config; /* Wrappers for the northbound callbacks. */ -extern struct yang_data *nb_callback_get_elem(const struct nb_node *nb_node, - const char *xpath, +extern struct yang_data *nb_callback_has_new_get_elem(const struct nb_node *nb_node); + +extern struct yang_data *nb_callback_get_elem(const struct nb_node *nb_node, const char *xpath, const void *list_entry); extern const void *nb_callback_get_next(const struct nb_node *nb_node, const void *parent_list_entry, diff --git a/lib/northbound_oper.c b/lib/northbound_oper.c index 2c72d8ecef..0364870486 100644 --- a/lib/northbound_oper.c +++ b/lib/northbound_oper.c @@ -654,6 +654,10 @@ static enum nb_error nb_op_iter_leaf(struct nb_op_yield_state *ys, if (lysc_is_key(snode)) return NB_OK; + /* Check for new simple get */ + if (nb_node->cbs.get) + return nb_node->cbs.get(nb_node, ni->list_entry, ni->inner); + data = nb_callback_get_elem(nb_node, xpath, ni->list_entry); if (data == NULL) return NB_OK; @@ -687,6 +691,10 @@ static enum nb_error nb_op_iter_leaflist(struct nb_op_yield_state *ys, if (CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return NB_OK; + /* Check for new simple get */ + if (nb_node->cbs.get) + return nb_node->cbs.get(nb_node, ni->list_entry, ni->inner); + do { struct yang_data *data; 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 diff --git a/ospfclient/ospfclient.py b/ospfclient/ospfclient.py index 7477ef8191..588c1c9fdd 100755 --- a/ospfclient/ospfclient.py +++ b/ospfclient/ospfclient.py @@ -306,7 +306,7 @@ class OspfApiClient: self._s = None self._as = None self._ls = None - self._ar = self._r = self._w = None + self._ar = self._r = self._aw = self._w = None self.server = server self.handlers = handlers if handlers is not None else dict() self.write_lock = Lock() @@ -345,7 +345,7 @@ class OspfApiClient: logging.debug("%s: success", self) self._r, self._w = await asyncio.open_connection(sock=self._s) - self._ar, _ = await asyncio.open_connection(sock=self._as) + self._ar, self._aw = await asyncio.open_connection(sock=self._as) self._seq = 1 async def connect(self): diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 27528f6594..95e8b179d8 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -10258,8 +10258,10 @@ DEFUN (ospf_external_route_aggregation, tag = strtoul(argv[idx + 2]->arg, NULL, 10); ret = ospf_asbr_external_aggregator_set(ospf, &p, tag); - if (ret == OSPF_INVALID) - vty_out(vty, "Invalid configuration!!\n"); + if (ret == OSPF_FAILURE) { + vty_out(vty, "%% Failed to set summary-address!\n"); + return CMD_WARNING_CONFIG_FAILED; + } return CMD_SUCCESS; } @@ -10611,8 +10613,10 @@ DEFUN (ospf_external_route_aggregation_no_adrvertise, } ret = ospf_asbr_external_rt_no_advertise(ospf, &p); - if (ret == OSPF_INVALID) - vty_out(vty, "Invalid configuration!!\n"); + if (ret == OSPF_FAILURE) { + vty_out(vty, "%% Failed to set summary-address!\n"); + return CMD_WARNING_CONFIG_FAILED; + } return CMD_SUCCESS; } diff --git a/tests/lib/northbound/test_oper_data.c b/tests/lib/northbound/test_oper_data.c index 3d700d8a19..0b334c6522 100644 --- a/tests/lib/northbound/test_oper_data.c +++ b/tests/lib/northbound/test_oper_data.c @@ -120,6 +120,26 @@ static const void *frr_test_module_vrfs_vrf_interfaces_interface_get_next( } /* + * XPath: /frr-test-module:frr-test-module/vrfs/vrf/interfaces/interface-new + */ +static enum nb_error frr_test_module_vrfs_vrf_interfaces_interface_new_get( + const struct nb_node *nb_node, const void *parent_list_entry, struct lyd_node *parent) +{ + const struct lysc_node *snode = nb_node->snode; + const struct tvrf *vrf; + struct listnode *node; + const char *interface; + LY_ERR err; + + vrf = listgetdata((struct listnode *)parent_list_entry); + for (ALL_LIST_ELEMENTS_RO(vrf->interfaces, node, interface)) { + err = lyd_new_term(parent, snode->module, snode->name, interface, false, NULL); + assert(err == LY_SUCCESS); + } + return NB_OK; +} + +/* * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route */ static const void * @@ -228,10 +248,19 @@ frr_test_module_c1value_get_elem(struct nb_cb_get_elem_args *args) /* * XPath: /frr-test-module:frr-test-module/c2cont/c2value */ -static struct yang_data * -frr_test_module_c2cont_c2value_get_elem(struct nb_cb_get_elem_args *args) +static enum nb_error frr_test_module_c2cont_c2value_get(const struct nb_node *nb_node, + const void *parent_list_entry, + struct lyd_node *parent) { - return yang_data_new_uint32(args->xpath, 0xAB010203); + const struct lysc_node *snode = nb_node->snode; + uint32_t value = 0xAB010203; + LY_ERR err; + + err = lyd_new_term_bin(parent, snode->module, snode->name, &value, sizeof(value), + LYD_NEW_PATH_UPDATE, NULL); + assert(err == LY_SUCCESS); + + return NB_OK; } /* clang-format off */ @@ -254,6 +283,10 @@ const struct frr_yang_module_info frr_test_module_info = { .cbs.get_next = frr_test_module_vrfs_vrf_interfaces_interface_get_next, }, { + .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/interfaces/interface-new", + .cbs.get = frr_test_module_vrfs_vrf_interfaces_interface_new_get, + }, + { .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route", .cbs.get_next = frr_test_module_vrfs_vrf_routes_route_get_next, }, @@ -287,7 +320,7 @@ const struct frr_yang_module_info frr_test_module_info = { }, { .xpath = "/frr-test-module:frr-test-module/c2cont/c2value", - .cbs.get_elem = frr_test_module_c2cont_c2value_get_elem, + .cbs.get = frr_test_module_c2cont_c2value_get, }, { .xpath = NULL, diff --git a/tests/lib/northbound/test_oper_data.refout b/tests/lib/northbound/test_oper_data.refout index 77e8562525..2536e0306b 100644 --- a/tests/lib/northbound/test_oper_data.refout +++ b/tests/lib/northbound/test_oper_data.refout @@ -11,6 +11,12 @@ test# show yang operational-data /frr-test-module:frr-test-module "eth1",
"eth2",
"eth3"
+ ],
+ "interface-new": [
+ "eth0",
+ "eth1",
+ "eth2",
+ "eth3"
]
},
"routes": {
@@ -65,6 +71,12 @@ test# show yang operational-data /frr-test-module:frr-test-module "eth1",
"eth2",
"eth3"
+ ],
+ "interface-new": [
+ "eth0",
+ "eth1",
+ "eth2",
+ "eth3"
]
},
"routes": {
diff --git a/tests/topotests/bgp_bmp/bgpbmp.py b/tests/topotests/bgp_bmp/bgpbmp.py index eac78a63f7..acbc405aa4 100644 --- a/tests/topotests/bgp_bmp/bgpbmp.py +++ b/tests/topotests/bgp_bmp/bgpbmp.py @@ -187,12 +187,19 @@ def bmp_check_for_prefixes( def bmp_check_for_peer_message( - expected_peers, bmp_log_type, bmp_collector, bmp_log_file, is_rd_instance=False + expected_peers, + bmp_log_type, + bmp_collector, + bmp_log_file, + is_rd_instance=False, + peer_bgp_id=None, + peer_distinguisher=None, ): """ Check for the presence of a peer up message for the peer """ global SEQ + last_seq = SEQ # we care only about the new messages messages = [ @@ -208,6 +215,10 @@ def bmp_check_for_peer_message( for m in messages: if is_rd_instance and m["peer_distinguisher"] == "0:0": continue + if peer_distinguisher and m["peer_distinguisher"] != peer_distinguisher: + continue + if peer_bgp_id and m["peer_bgp_id"] != peer_bgp_id: + continue if ( "peer_ip" in m.keys() and m["peer_ip"] != "0.0.0.0" @@ -215,16 +226,23 @@ def bmp_check_for_peer_message( ): if is_rd_instance and m["peer_type"] != "route distinguisher instance": continue - peers.append(m["peer_ip"]) + peers.append((m["peer_ip"], m["seq"])) elif m["policy"] == "loc-rib" and m["bmp_log_type"] == bmp_log_type: - peers.append("0.0.0.0") + peers.append(("0.0.0.0", m["seq"])) # check for prefixes for ep in expected_peers: - if ep not in peers: + for _ip, _seq in peers: + if ep == _ip: + msg = "The peer {} is present in the {} log messages." + logger.debug(msg.format(ep, bmp_log_type)) + if _seq > last_seq: + last_seq = _seq + break + else: msg = "The peer {} is not present in the {} log messages." logger.debug(msg.format(ep, bmp_log_type)) return False - SEQ = messages[-1]["seq"] + SEQ = last_seq return True diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py index f16ff2b445..e0b9a0f607 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py @@ -252,6 +252,169 @@ def test_peer_down(): assert success, "Checking the updated prefixes has been failed !." +def test_bgp_instance_flapping(): + """ + Checking for BGP loc-rib up messages + """ + tgen = get_topogen() + + # create flapping at BMP + tgen.net["r1vrf"].cmd("ip link set dev vrf1 down") + + peers = ["0.0.0.0"] + logger.info("checking for BMP peer down LOC-RIB message.") + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer down", + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + is_rd_instance=True, + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert success, "Checking the BMP peer down LOC-RIB message failed !." + + tgen.net["r1vrf"].cmd("ip link set dev vrf1 up") + + logger.info("checking for BMP peer up LOC-RIB message.") + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer up", + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + is_rd_instance=True, + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert success, "Checking the BMP peer up LOC-RIB message failed !." + + +def test_bgp_routerid_changed(): + """ + Checking for BGP loc-rib up messages with new router-id + """ + tgen = get_topogen() + + tgen.gears["r1vrf"].vtysh_cmd( + """ + configure terminal + router bgp 65501 vrf vrf1 + bgp router-id 192.168.1.77 + """ + ) + + peers = ["0.0.0.0"] + + logger.info( + "checking for BMP peer down LOC-RIB message with router-id set to 192.168.0.1." + ) + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer down", + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + is_rd_instance=True, + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert ( + success + ), "Checking the BMP peer down LOC-RIB message with router-id set to 192.168.0.1 failed !." + + logger.info( + "checking for BMP peer up LOC-RIB message with router-id set to 192.168.1.77." + ) + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer up", + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + is_rd_instance=True, + peer_bgp_id="192.168.1.77", + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert ( + success + ), "Checking the BMP peer up LOC-RIB message with router-id set to 192.168.1.77 failed !." + + +def test_reconfigure_route_distinguisher_vrf1(): + """ + Checking for BMP peers down messages + """ + tgen = get_topogen() + + bmp_update_seq( + tgen.gears["bmp1vrf"], os.path.join(tgen.logdir, "bmp1vrf", "bmp.log") + ) + peers = ["0.0.0.0"] + + tgen.gears["r1vrf"].vtysh_cmd( + """ + configure terminal + router bgp 65501 vrf vrf1 + address-family ipv4 unicast + rd vpn export 666:22 + exit-address-family + address-family ipv6 unicast + rd vpn export 666:22 + """ + ) + logger.info( + "checking for BMP peer down LOC-RIB message with route-distinguisher set to 444:1" + ) + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer down", + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + is_rd_instance=True, + peer_distinguisher="444:1", + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert ( + success + ), "Checking the BMP peer down LOC-RIB message with route-distinguisher set to 444:1 failed !." + + logger.info( + "checking for BMP peer up LOC-RIB messages with route-distinguisher set to 666:22" + ) + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer up", + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + is_rd_instance=True, + peer_bgp_id="192.168.1.77", + peer_distinguisher="666:22", + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert ( + success + ), "Checking the BMP peer up LOC-RIB message with route-distinguisher set to 666:22 failed !." + + logger.info( + "checking for BMP peer up messages with route-distinguisher set to 666:22" + ) + peers = ["192.168.0.2", "192:168::2"] + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer up", + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + is_rd_instance=True, + peer_distinguisher="666:22", + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert ( + success + ), "Checking the BMP peer up messages with route-distinguisher set to 666:22 failed !." + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) 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_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/lib/bmp_collector/bgp/update/rd.py b/tests/topotests/lib/bmp_collector/bgp/update/rd.py index 3f08de5ae9..d44060bf2f 100644 --- a/tests/topotests/lib/bmp_collector/bgp/update/rd.py +++ b/tests/topotests/lib/bmp_collector/bgp/update/rd.py @@ -4,6 +4,7 @@ # Authored by Farid Mihoub <farid.mihoub@6wind.com> # import ipaddress +import socket import struct @@ -45,9 +46,11 @@ class RouteDistinguisher: self.repr_str = f"{self.as_number}:{self.assigned_sp}" elif rd_type == 1: - (self.admin_ipv4, self.assigned_sp) = struct.unpack_from("!IH", self.rd[2:]) - ipv4 = str(ipaddress.IPv4Address(self.admin_ipv4)) - self.repr_str = f"{self.as_number}:{self.assigned_sp}" + (self.admin_ipv4, self.assigned_sp) = struct.unpack_from( + "!4sH", self.rd[2:] + ) + ipv4_str = socket.inet_ntoa(self.admin_ipv4) + self.repr_str = f"{ipv4_str}:{self.assigned_sp}" elif rd_type == 2: (self.four_bytes_as, self.assigned_sp) = struct.unpack_from( diff --git a/tests/topotests/lib/fe_client.py b/tests/topotests/lib/fe_client.py index 784f7d17eb..078df8cb33 100755 --- a/tests/topotests/lib/fe_client.py +++ b/tests/topotests/lib/fe_client.py @@ -78,8 +78,13 @@ GET_DATA_FLAG_STATE = 0x1 GET_DATA_FLAG_CONFIG = 0x2 GET_DATA_FLAG_EXACT = 0x4 -MSG_NOTIFY_FMT = "=B7x" +MSG_NOTIFY_FMT = "=BB6x" NOTIFY_FIELD_RESULT_TYPE = 0 +NOTIFY_FIELD_OP = 1 +NOTIFY_OP_NOTIFICATION = 0 +NOTIFY_OP_REPLACE = 1 +NOTIFY_OP_DELETE = 2 +NOTIFY_OP_PATCH = 3 MSG_NOTIFY_SELECT_FMT = "=B7x" @@ -363,10 +368,12 @@ class Session: raise Exception(f"Received NON-NOTIFY Message: {mfixed}: {mdata}") vsplit = mhdr[HDR_FIELD_VSPLIT] + result_type = mfixed[0] + op = mfixed[1] assert mdata[vsplit - 1] == 0 assert mdata[-1] == 0 - # xpath = mdata[: vsplit - 1].decode("utf-8") - return mdata[vsplit:-1].decode("utf-8") + xpath = mdata[: vsplit - 1].decode("utf-8") + return result_type, op, xpath, mdata[vsplit:-1].decode("utf-8") else: raise TimeoutError("Timeout waiting for notifications") @@ -390,6 +397,9 @@ def __parse_args(): "-c", "--config-only", action="store_true", help="return config only" ) parser.add_argument( + "--datastore", action="store_true", help="listen for datastore notifications" + ) + parser.add_argument( "-q", "--query", nargs="+", metavar="XPATH", help="xpath[s] to query" ) parser.add_argument("-s", "--server", default=MPATH, help="path to server socket") @@ -434,9 +444,31 @@ def __main(): if args.listen is not None: i = args.notify_count + if args.listen: + sess.add_notify_select(True, args.listen) while i > 0 or args.notify_count == 0: - notif = sess.recv_notify(args.listen) - print(notif) + result_type, op, xpath, notif = sess.recv_notify() + if op == NOTIFY_OP_NOTIFICATION: + if args.datastore: + logging.warning("ignoring non-datastore notification: %s", notif) + else: + print(notif) + elif not args.datastore: + logging.warning( + "ignoring datastore notification op: %s xpath: %s data: %s", + op, + xpath, + notif, + ) + elif op == NOTIFY_OP_PATCH: + print(f"#OP=PATCH: {xpath}") + print(notif) + elif op == NOTIFY_OP_REPLACE: + print(f"#OP=REPLACE: {xpath}") + print(notif) + elif op == NOTIFY_OP_DELETE: + print(f"#OP=DELETE: {xpath}") + assert len(notif) == 0 i -= 1 diff --git a/tests/topotests/mgmt_oper/oper.py b/tests/topotests/mgmt_oper/oper.py index bca452d011..6e1866382b 100644 --- a/tests/topotests/mgmt_oper/oper.py +++ b/tests/topotests/mgmt_oper/oper.py @@ -62,7 +62,7 @@ def disable_debug(router): router.vtysh_cmd("no debug northbound callbacks configuration") -@retry(retry_timeout=30, initial_wait=1) +@retry(retry_timeout=30, initial_wait=0.1) def _do_oper_test(tgen, qr, seconds_left=None): r1 = tgen.gears["r1"].net @@ -113,6 +113,7 @@ def _do_oper_test(tgen, qr, seconds_left=None): "-------DIFF---------\n%s\n---------DIFF----------", pprint.pformat(cmpout), ) + cmpout = str(cmpout) else: cmpout = tt_json_cmp(ojson, ejson, exact=True) if cmpout and ejson_alt is not None: @@ -186,6 +187,20 @@ def addrgen(a, count, step=1): @retry(retry_timeout=30, initial_wait=0.1) +def check_kernel_net(r1, net, vrf): + addr = ipaddress.ip_network(net) + vrfstr = f" vrf {vrf}" if vrf else "" + if addr.version == 6: + kernel = r1.cmd_raises(f"ip -6 route show{vrfstr}") + else: + kernel = r1.cmd_raises(f"ip -4 route show{vrfstr}") + + nentries = len(re.findall("\n", kernel)) + logging.info("checking kernel routing table%s: (%s entries)", vrfstr, nentries) + assert str(net) in kernel, f"Failed to find '{net}' in {nentries} entries" + + +@retry(retry_timeout=30, initial_wait=0.1) def check_kernel_32(r1, start_addr, count, vrf, step=1): start = ipaddress.ip_address(start_addr) vrfstr = f" vrf {vrf}" if vrf else "" diff --git a/tests/topotests/mgmt_oper/test_oper.py b/tests/topotests/mgmt_oper/test_oper.py index 23529bc75e..0d346b5b7c 100644 --- a/tests/topotests/mgmt_oper/test_oper.py +++ b/tests/topotests/mgmt_oper/test_oper.py @@ -15,7 +15,7 @@ import math import pytest from lib.topogen import Topogen -from oper import check_kernel_32, do_oper_test +from oper import check_kernel_32, check_kernel_net, do_oper_test pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] @@ -85,10 +85,17 @@ def test_oper(tgen): ] r1 = tgen.gears["r1"].net + check_kernel_32(r1, "11.11.11.11", 1, "") check_kernel_32(r1, "12.12.12.12", 1, "") check_kernel_32(r1, "13.13.13.13", 1, "red") check_kernel_32(r1, "14.14.14.14", 1, "red") + + check_kernel_net(r1, "2001:1111::/64", "") + check_kernel_net(r1, "2002:2222::/64", "") + check_kernel_net(r1, "2003:333::/64", "red") + check_kernel_net(r1, "2004:4444::/64", "red") + do_oper_test(tgen, query_results) diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c index 516743acab..019404d7cc 100644 --- a/tools/gen_northbound_callbacks.c +++ b/tools/gen_northbound_callbacks.c @@ -15,12 +15,13 @@ #include "yang.h" #include "northbound.h" -static bool static_cbs; +static bool f_static_cbs; +static bool f_new_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] [-n] [-s] [-p path]* MODULE\n", __progname); exit(status); } @@ -111,6 +112,14 @@ static struct nb_callback_info nb_config_write = { .arguments = "struct vty *vty, const struct lyd_node *dnode, bool show_defaults", }; +static struct nb_callback_info nb_oper_get = { + .operation = NB_CB_GET_ELEM, + .return_type = "enum nb_error ", + .return_value = "NB_OK", + .arguments = + "const struct nb_node *nb_node, const void *parent_list_entry, struct lyd_node *parent", +}; + static void replace_hyphens_by_underscores(char *str) { char *p; @@ -120,6 +129,14 @@ static void replace_hyphens_by_underscores(char *str) *p++ = '_'; } +static const char *__operation_name(enum nb_cb_operation operation) +{ + if (f_new_cbs && operation == NB_CB_GET_ELEM) + return "get"; + else + return nb_cb_operation_name(operation); +} + static void generate_callback_name(const struct lysc_node *snode, enum nb_cb_operation operation, char *buffer, size_t size) @@ -143,7 +160,7 @@ static void generate_callback_name(const struct lysc_node *snode, strlcat(buffer, snode->name, size); strlcat(buffer, "_", size); } - strlcat(buffer, nb_cb_operation_name(operation), size); + strlcat(buffer, __operation_name(operation), size); list_delete(&snodes); replace_hyphens_by_underscores(buffer); @@ -208,17 +225,25 @@ static int generate_prototypes(const struct lysc_node *snode, void *arg) return YANG_ITER_CONTINUE; } - for (struct nb_callback_info *cb = &nb_callbacks[0]; - cb->operation != -1; cb++) { + for (struct nb_callback_info *cb = &nb_callbacks[0]; cb->operation != -1; cb++) { char cb_name[BUFSIZ]; if (cb->optional || !nb_cb_operation_is_valid(cb->operation, snode)) continue; + if (f_new_cbs && cb->operation == NB_CB_GET_NEXT && snode->nodetype == LYS_LEAFLIST) + continue; + generate_callback_name(snode, cb->operation, cb_name, sizeof(cb_name)); - generate_prototype(cb, cb_name); + + if (cb->operation == NB_CB_GET_ELEM) { + if (f_new_cbs) + generate_prototype(&nb_oper_get, cb_name); + else + generate_prototype(cb, cb_name); + } if (cb->need_config_write && need_config_write) { generate_config_write_cb_name(snode, cb_name, @@ -236,8 +261,8 @@ static int generate_prototypes(const struct lysc_node *snode, void *arg) static void generate_callback(const struct nb_callback_info *ncinfo, const char *cb_name) { - printf("%s%s%s(%s)\n{\n", static_cbs ? "static " : "", - ncinfo->return_type, cb_name, ncinfo->arguments); + printf("%s%s%s(%s)\n{\n", f_static_cbs ? "static " : "", ncinfo->return_type, cb_name, + ncinfo->arguments); switch (ncinfo->operation) { case NB_CB_CREATE: @@ -266,8 +291,8 @@ static void generate_callback(const struct nb_callback_info *ncinfo, static void generate_config_write_callback(const struct nb_callback_info *ncinfo, const char *cb_name) { - printf("%s%s%s(%s)\n{\n", static_cbs ? "static " : "", - ncinfo->return_type, cb_name, ncinfo->arguments); + printf("%s%s%s(%s)\n{\n", f_static_cbs ? "static " : "", ncinfo->return_type, cb_name, + ncinfo->arguments); /* Add a comment, since these callbacks may not all be needed. */ printf("\t/* TODO: this cli callback is optional; the cli output may not need to be done at each node. */\n"); @@ -313,9 +338,18 @@ static int generate_callbacks(const struct lysc_node *snode, void *arg) first = false; } + if (f_new_cbs && cb->operation == NB_CB_GET_NEXT && snode->nodetype == LYS_LEAFLIST) + continue; + generate_callback_name(snode, cb->operation, cb_name, sizeof(cb_name)); - generate_callback(cb, cb_name); + + if (cb->operation == NB_CB_GET_ELEM) { + if (f_new_cbs) + generate_callback(&nb_oper_get, cb_name); + else + generate_callback(cb, cb_name); + } if (cb->need_config_write && need_config_write) { generate_config_write_cb_name(snode, cb_name, @@ -371,12 +405,13 @@ static int generate_nb_nodes(const struct lysc_node *snode, void *arg) printf("\t\t\t.cbs = {\n"); first = false; } + if (f_new_cbs && cb->operation == NB_CB_GET_NEXT && + snode->nodetype == LYS_LEAFLIST) + continue; generate_callback_name(snode, cb->operation, cb_name, sizeof(cb_name)); - printf("\t\t\t\t.%s = %s,\n", - nb_cb_operation_name(cb->operation), - cb_name); + printf("\t\t\t\t.%s = %s,\n", __operation_name(cb->operation), cb_name); } else if (cb->need_config_write && need_config_write) { if (first) { yang_snode_get_path(snode, @@ -417,11 +452,14 @@ int main(int argc, char *argv[]) int opt; bool config_pass; - while ((opt = getopt(argc, argv, "hp:s")) != -1) { + while ((opt = getopt(argc, argv, "hnp:s")) != -1) { switch (opt) { case 'h': usage(EXIT_SUCCESS); /* NOTREACHED */ + case 'n': + f_new_cbs = true; + break; case 'p': if (stat(optarg, &st) == -1) { fprintf(stderr, @@ -438,7 +476,7 @@ int main(int argc, char *argv[]) *darr_append(search_paths) = darr_strdup(optarg); break; case 's': - static_cbs = true; + f_static_cbs = true; break; default: usage(EXIT_FAILURE); @@ -477,7 +515,7 @@ int main(int argc, char *argv[]) printf("// SPDX-" "License-Identifier: GPL-2.0-or-later\n\n"); /* Generate callback prototypes. */ - if (!static_cbs) { + if (!f_static_cbs) { printf("/* prototypes */\n"); yang_snodes_iterate(module->info, generate_prototypes, 0, NULL); printf("\n"); diff --git a/yang/frr-test-module.yang b/yang/frr-test-module.yang index dcf204a956..90086d05a2 100644 --- a/yang/frr-test-module.yang +++ b/yang/frr-test-module.yang @@ -60,6 +60,9 @@ module frr-test-module { leaf-list interface { type frr-interface:interface-ref; } + leaf-list interface-new { + type frr-interface:interface-ref; + } } container routes { list route { 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_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; |
