diff options
75 files changed, 2422 insertions, 704 deletions
diff --git a/.github/workflows/build-test-docker.yml b/.github/workflows/build-test-docker.yml index de9f620c9..3f53f32d3 100644 --- a/.github/workflows/build-test-docker.yml +++ b/.github/workflows/build-test-docker.yml @@ -68,11 +68,13 @@ jobs: - name: Run topotests run: | uname -a - sudo apt-get install -y linux-modules-extra-azure || true - sudo apt-get install -y python3-xmltodict || true + MODPKGVER=$(uname -r) + sudo apt-get update -y + # Github is running old kernels but installing newer packages :( + sudo apt-get install -y linux-modules-extra-azure linux-modules-${MODPKGVER} linux-modules-extra-${MODPKGVER} python3-xmltodict sudo modprobe vrf || true - sudo modprobe mpls-iptunnel || true - sudo modprobe mpls-router || true + sudo modprobe mpls-iptunnel + sudo modprobe mpls-router docker load --input /tmp/frr-ubuntu22.tar if ! grep CONFIG_IP_MROUTE_MULTIPLE_TABLES=y /boot/config*; then diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index d519749f6..d5c7e1887 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -163,7 +163,7 @@ bool bgp_adj_out_lookup(struct peer *peer, struct bgp_dest *dest, void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr, - uint32_t addpath_id) + uint32_t addpath_id, struct bgp_labels *labels) { struct bgp_adj_in *adj; @@ -173,6 +173,10 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr, bgp_attr_unintern(&adj->attr); adj->attr = bgp_attr_intern(attr); } + if (!bgp_labels_cmp(adj->labels, labels)) { + bgp_labels_unintern(&adj->labels); + adj->labels = bgp_labels_intern(labels); + } return; } } @@ -181,6 +185,7 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr, adj->attr = bgp_attr_intern(attr); adj->uptime = monotime(NULL); adj->addpath_rx_id = addpath_id; + adj->labels = bgp_labels_intern(labels); BGP_ADJ_IN_ADD(dest, adj); peer->stat_pfx_adj_rib_in++; bgp_dest_lock_node(dest); @@ -189,6 +194,7 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr, void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai) { bgp_attr_unintern(&bai->attr); + bgp_labels_unintern(&bai->labels); if (bai->peer) bai->peer->stat_pfx_adj_rib_in--; BGP_ADJ_IN_DEL(*dest, bai); diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index 49821061b..8c831892b 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -75,6 +75,9 @@ struct bgp_adj_out { /* Advertised attribute. */ struct attr *attr; + /* VPN label information */ + struct bgp_labels *labels; + /* Advertisement information. */ struct bgp_advertise *adv; }; @@ -95,6 +98,9 @@ struct bgp_adj_in { /* Received attribute. */ struct attr *attr; + /* VPN label information */ + struct bgp_labels *labels; + /* timestamp (monotime) */ time_t uptime; @@ -135,7 +141,8 @@ struct bgp_synchronize { extern bool bgp_adj_out_lookup(struct peer *peer, struct bgp_dest *dest, uint32_t addpath_tx_id); extern void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, - struct attr *attr, uint32_t addpath_id); + struct attr *attr, uint32_t addpath_id, + struct bgp_labels *labels); extern bool bgp_adj_in_unset(struct bgp_dest **dest, struct peer *peer, uint32_t addpath_id); extern void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 71f02a7f8..da4701d06 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -4158,7 +4158,7 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, const struct prefix *p, const struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, bool addpath_capable, + uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *attr) { switch (safi) { @@ -4434,7 +4434,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from, struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct bgp_path_info *bpi) { @@ -4963,7 +4963,7 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi) void bgp_packet_mpunreach_prefix(struct stream *s, const struct prefix *p, afi_t afi, safi_t safi, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *attr) { diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index a8ba36d2d..f353e7691 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -393,7 +393,7 @@ extern bgp_size_t bgp_packet_attribute( struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from, struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, bool addpath_capable, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct bgp_path_info *bpi); extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi, const struct prefix *p); @@ -451,7 +451,7 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, const struct prefix *p, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *); extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, @@ -462,7 +462,7 @@ extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi); extern void bgp_packet_mpunreach_prefix( struct stream *s, const struct prefix *p, afi_t afi, safi_t safi, - const struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels, + const struct prefix_rd *prd, mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *attr); extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt); diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index bf08e3050..43f8006e2 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -38,6 +38,7 @@ #include "bgpd/bgp_vty.h" #include "bgpd/bgp_trace.h" #include "bgpd/bgp_network.h" +#include "bgpd/bgp_label.h" static void bmp_close(struct bmp *bmp); static struct bmp_bgp *bmp_bgp_find(struct bgp *bgp); @@ -1046,6 +1047,7 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) { + uint8_t bpi_num_labels; afi_t afi; safi_t safi; @@ -1219,14 +1221,16 @@ afibreak: (safi == SAFI_MPLS_VPN)) prd = (struct prefix_rd *)bgp_dest_get_prefix(bmp->syncrdpos); + bpi_num_labels = bgp_path_info_num_labels(bpi); + if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED) && CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_LOC_RIB)) { bmp_monitor(bmp, bpi->peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, bn_p, prd, bpi->attr, afi, safi, bpi && bpi->extra ? bpi->extra->bgp_rib_uptime : (time_t)(-1L), - bpi->extra ? bpi->extra->label : NULL, - bpi->extra ? bpi->extra->num_labels : 0); + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); } if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_VALID) && @@ -1234,8 +1238,8 @@ afibreak: bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd, bpi->attr, afi, safi, bpi->uptime, - bpi->extra ? bpi->extra->label : NULL, - bpi->extra ? bpi->extra->num_labels : 0); + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); if (adjin) /* TODO: set label here when adjin supports labels */ @@ -1292,6 +1296,7 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr) struct peer *peer; struct bgp_dest *bn = NULL; bool written = false; + uint8_t bpi_num_labels; bqe = bmp_pull_locrib(bmp); if (!bqe) @@ -1351,12 +1356,14 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr) break; } + bpi_num_labels = bgp_path_info_num_labels(bpi); + bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, &bqe->p, prd, bpi ? bpi->attr : NULL, afi, safi, bpi && bpi->extra ? bpi->extra->bgp_rib_uptime : (time_t)(-1L), - (bpi && bpi->extra) ? bpi->extra->label : NULL, - (bpi && bpi->extra) ? bpi->extra->num_labels : 0); + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); written = true; out: @@ -1375,6 +1382,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) struct peer *peer; struct bgp_dest *bn = NULL; bool written = false; + uint8_t bpi_num_labels; bqe = bmp_pull(bmp); if (!bqe) @@ -1426,12 +1434,14 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) break; } + bpi_num_labels = bgp_path_info_num_labels(bpi); + bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd, bpi ? bpi->attr : NULL, afi, safi, bpi ? bpi->uptime : monotime(NULL), - (bpi && bpi->extra) ? bpi->extra->label : NULL, - (bpi && bpi->extra) ? bpi->extra->num_labels : 0); + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); written = true; } diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index b4651ad0b..6228432bd 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -2713,7 +2713,7 @@ bool bgp_debug_zebra(const struct prefix *p) const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, const struct prefix_rd *prd, union prefixconstptr pu, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, int addpath_valid, uint32_t addpath_id, struct bgp_route_evpn *overlay_index, char *str, int size) diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 673926f24..061d966dc 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -175,7 +175,7 @@ extern bool bgp_debug_zebra(const struct prefix *p); extern const char *bgp_debug_rdpfxpath2str( afi_t afi, safi_t safi, const struct prefix_rd *prd, - union prefixconstptr pu, mpls_label_t *label, uint32_t num_labels, + union prefixconstptr pu, mpls_label_t *label, uint8_t num_labels, int addpath_valid, uint32_t addpath_id, struct bgp_route_evpn *overlay_index, char *str, int size); const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data, diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index ce9666d61..5ce5b19b1 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1602,7 +1602,7 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, { struct attr *attr_new = NULL; struct bgp_path_info *pi = NULL; - mpls_label_t label = MPLS_INVALID_LABEL; + struct bgp_labels bgp_labels = {}; struct bgp_path_info *local_pi = NULL; struct bgp_path_info *tmp_pi = NULL; @@ -1630,9 +1630,14 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, /* Type-5 routes advertise the L3-VNI */ bgp_path_info_extra_get(pi); - vni2label(bgp_vrf->l3vni, &label); - memcpy(&pi->extra->label, &label, sizeof(label)); - pi->extra->num_labels = 1; + vni2label(bgp_vrf->l3vni, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; + if (!bgp_path_info_labels_same(pi, &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&pi->extra->labels); + pi->extra->labels = bgp_labels_intern(&bgp_labels); + } + /* add the route entry to route node*/ bgp_path_info_add(dest, pi); @@ -1930,15 +1935,13 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct bgp_path_info *local_pi; struct attr *attr_new; struct attr local_attr; - mpls_label_t label[BGP_MAX_LABELS]; - uint32_t num_labels = 1; + struct bgp_labels bgp_labels = {}; int route_change = 1; uint8_t sticky = 0; const struct prefix_evpn *evp; *pi = NULL; evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest); - memset(&label, 0, sizeof(label)); /* See if this is an update of an existing route, or a new add. */ local_pi = bgp_evpn_route_get_local_path(bgp, dest); @@ -1980,7 +1983,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, bgp_path_info_extra_get(tmp_pi); /* The VNI goes into the 'label' field of the route */ - vni2label(vpn->vni, &label[0]); + vni2label(vpn->vni, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; /* Type-2 routes may carry a second VNI - the L3-VNI. * Only attach second label if we are advertising two labels for @@ -1992,13 +1996,16 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, l3vni = bgpevpn_get_l3vni(vpn); if (l3vni) { - vni2label(l3vni, &label[1]); - num_labels++; + vni2label(l3vni, &bgp_labels.label[1]); + bgp_labels.num_labels++; } } - memcpy(&tmp_pi->extra->label, label, sizeof(label)); - tmp_pi->extra->num_labels = num_labels; + if (!bgp_path_info_labels_same(tmp_pi, &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&tmp_pi->extra->labels); + tmp_pi->extra->labels = bgp_labels_intern(&bgp_labels); + } if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { if (mac) @@ -2022,7 +2029,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * The attributes have changed, type-2 routes needs to * be advertised with right labels. */ - vni2label(vpn->vni, &label[0]); + vni2label(vpn->vni, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) { @@ -2030,12 +2038,17 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, l3vni = bgpevpn_get_l3vni(vpn); if (l3vni) { - vni2label(l3vni, &label[1]); - num_labels++; + vni2label(l3vni, &bgp_labels.label[1]); + bgp_labels.num_labels++; } } - memcpy(&tmp_pi->extra->label, label, sizeof(label)); - tmp_pi->extra->num_labels = num_labels; + if (!bgp_path_info_labels_same(tmp_pi, + &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&tmp_pi->extra->labels); + tmp_pi->extra->labels = + bgp_labels_intern(&bgp_labels); + } if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { if (mac) @@ -2983,12 +2996,11 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi, sizeof(struct bgp_path_info_extra_vrfleak)); pi->extra->vrfleak->parent = bgp_path_info_lock(parent_pi); bgp_dest_lock_node((struct bgp_dest *)parent_pi->net); - if (parent_pi->extra) { - memcpy(&pi->extra->label, &parent_pi->extra->label, - sizeof(pi->extra->label)); - pi->extra->num_labels = parent_pi->extra->num_labels; + if (parent_pi->extra) pi->extra->igpmetric = parent_pi->extra->igpmetric; - } + + if (bgp_path_info_num_labels(parent_pi)) + pi->extra->labels = bgp_labels_intern(parent_pi->extra->labels); bgp_path_info_add(dest, pi); @@ -4676,7 +4688,7 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, uint8_t macaddr_len; /* holds the VNI(s) as in packet */ mpls_label_t label[BGP_MAX_LABELS] = {}; - uint32_t num_labels = 0; + uint8_t num_labels = 0; uint32_t eth_tag; int ret = 0; @@ -5019,7 +5031,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, struct attr *attr) { int len; @@ -5809,7 +5821,7 @@ int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn) /* * TODO: Hardcoded for a maximum of 2 VNIs right now */ -char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels, char *buf, +char *bgp_evpn_label2str(mpls_label_t *label, uint8_t num_labels, char *buf, int len) { vni_t vni1, vni2; @@ -5893,7 +5905,7 @@ void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json) */ void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p, const struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, struct attr *attr, + uint8_t num_labels, struct attr *attr, bool addpath_capable, uint32_t addpath_tx_id) { struct prefix_evpn *evp = (struct prefix_evpn *)p; @@ -7737,7 +7749,7 @@ void bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket, * */ mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels, - uint32_t num_labels) + uint8_t num_labels) { if (!labels) return NULL; @@ -7756,8 +7768,10 @@ vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi) if (!pi->extra) return 0; - return label2vni(bgp_evpn_path_info_labels_get_l3vni( - pi->extra->label, pi->extra->num_labels)); + return label2vni( + bgp_evpn_path_info_labels_get_l3vni(pi->extra->labels->label, + pi->extra->labels + ->num_labels)); } /* diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 11a6f45dd..223f18a17 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -115,12 +115,12 @@ extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi); extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf); extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw); -extern char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels, +extern char *bgp_evpn_label2str(mpls_label_t *label, uint8_t num_labels, char *buf, int len); extern void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json); extern void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, struct attr *attr, bool addpath_capable, uint32_t addpath_tx_id); extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, @@ -177,7 +177,7 @@ extern void bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket, void *arg); extern mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels, - uint32_t num_labels); + uint8_t num_labels); extern vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi); extern bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf, struct bgp_path_info *mpinfo); diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index d63e01156..d723a2b1b 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -358,6 +358,7 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es, struct bgp_path_info *tmp_pi = NULL; struct bgp_path_info *local_pi = NULL; /* local route entry if any */ struct bgp_path_info *remote_pi = NULL; /* remote route entry if any */ + struct bgp_labels bgp_labels = {}; struct attr *attr_new = NULL; struct prefix_evpn *evp; @@ -404,11 +405,16 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es, if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) { bgp_path_info_extra_get(tmp_pi); - tmp_pi->extra->num_labels = 1; + bgp_labels.num_labels = 1; if (vpn) - vni2label(vpn->vni, &tmp_pi->extra->label[0]); - else - tmp_pi->extra->label[0] = 0; + vni2label(vpn->vni, &bgp_labels.label[0]); + if (!bgp_path_info_labels_same(tmp_pi, + &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&tmp_pi->extra->labels); + tmp_pi->extra->labels = + bgp_labels_intern(&bgp_labels); + } } /* add the newly created path to the route-node */ @@ -2455,7 +2461,7 @@ static void bgp_evpn_es_frag_show_detail(struct vty *vty, } static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es, - uint8_t vtep_str_size) + size_t vtep_str_size) { char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ]; struct listnode *node; @@ -3956,7 +3962,7 @@ void bgp_evpn_vni_es_cleanup(struct bgpevpn *vpn) static char *bgp_evpn_es_evi_vteps_str(char *vtep_str, struct bgp_evpn_es_evi *es_evi, - uint8_t vtep_str_size) + size_t vtep_str_size) { char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ]; struct listnode *node; diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 68104967b..839437e12 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -15,6 +15,7 @@ #include "memory.h" #include "nexthop.h" #include "mpls.h" +#include "jhash.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -27,6 +28,124 @@ extern struct zclient *zclient; + +/* MPLS Labels hash routines. */ +static struct hash *labels_hash; + +static void *bgp_labels_hash_alloc(void *p) +{ + const struct bgp_labels *labels = p; + struct bgp_labels *new; + uint8_t i; + + new = XMALLOC(MTYPE_BGP_LABELS, sizeof(struct bgp_labels)); + + new->num_labels = labels->num_labels; + for (i = 0; i < labels->num_labels; i++) + new->label[i] = labels->label[i]; + + return new; +} + +static uint32_t bgp_labels_hash_key_make(const void *p) +{ + const struct bgp_labels *labels = p; + uint32_t key = 0; + + if (labels->num_labels) + key = jhash(&labels->label, + labels->num_labels * sizeof(mpls_label_t), key); + + return key; +} + +static bool bgp_labels_hash_cmp(const void *p1, const void *p2) +{ + return bgp_labels_cmp(p1, p2); +} + +void bgp_labels_init(void) +{ + labels_hash = hash_create(bgp_labels_hash_key_make, bgp_labels_hash_cmp, + "BGP Labels hash"); +} + +/* + * special for hash_clean below + */ +static void bgp_labels_free(void *labels) +{ + XFREE(MTYPE_BGP_LABELS, labels); +} + +void bgp_labels_finish(void) +{ + hash_clean_and_free(&labels_hash, bgp_labels_free); +} + +struct bgp_labels *bgp_labels_intern(struct bgp_labels *labels) +{ + struct bgp_labels *find; + + if (!labels) + return NULL; + + if (!labels->num_labels) + /* do not intern void labels structure */ + return NULL; + + find = (struct bgp_labels *)hash_get(labels_hash, labels, + bgp_labels_hash_alloc); + find->refcnt++; + + return find; +} + +void bgp_labels_unintern(struct bgp_labels **plabels) +{ + struct bgp_labels *labels = *plabels; + struct bgp_labels *ret; + + if (!*plabels) + return; + + /* Decrement labels reference. */ + labels->refcnt--; + + /* If reference becomes zero then free labels object. */ + if (labels->refcnt == 0) { + ret = hash_release(labels_hash, labels); + assert(ret != NULL); + bgp_labels_free(labels); + *plabels = NULL; + } +} + +bool bgp_labels_cmp(const struct bgp_labels *labels1, + const struct bgp_labels *labels2) +{ + uint8_t i; + + if (!labels1 && !labels2) + return true; + + if (!labels1 && labels2) + return false; + + if (labels1 && !labels2) + return false; + + if (labels1->num_labels != labels2->num_labels) + return false; + + for (i = 0; i < labels1->num_labels; i++) { + if (labels1->label[i] != labels2->label[i]) + return false; + } + + return true; +} + int bgp_parse_fec_update(void) { struct stream *s; @@ -89,7 +208,9 @@ mpls_label_t bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi, if (!dest || !pi || !to) return MPLS_INVALID_LABEL; - remote_label = pi->extra ? pi->extra->label[0] : MPLS_INVALID_LABEL; + remote_label = bgp_path_info_num_labels(pi) + ? pi->extra->labels->label[0] + : MPLS_INVALID_LABEL; from = pi->peer; reflect = ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP)); @@ -471,8 +592,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, return BGP_NLRI_PARSE_OK; } -bool bgp_labels_same(const mpls_label_t *tbl_a, const uint32_t num_labels_a, - const mpls_label_t *tbl_b, const uint32_t num_labels_b) +bool bgp_labels_same(const mpls_label_t *tbl_a, const uint8_t num_labels_a, + const mpls_label_t *tbl_b, const uint8_t num_labels_b) { uint32_t i; diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h index b54403ee8..2ffd5b699 100644 --- a/bgpd/bgp_label.h +++ b/bgpd/bgp_label.h @@ -15,6 +15,26 @@ struct bgp_dest; struct bgp_path_info; struct peer; +/* Maximum number of labels we can process or send with a prefix. We + * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN. + */ +#define BGP_MAX_LABELS 2 + +/* MPLS label(s) - VNI(s) for EVPN-VxLAN */ +struct bgp_labels { + mpls_label_t label[BGP_MAX_LABELS]; + uint8_t num_labels; + + unsigned long refcnt; +}; + +extern void bgp_labels_init(void); +extern void bgp_labels_finish(void); +extern struct bgp_labels *bgp_labels_intern(struct bgp_labels *labels); +extern void bgp_labels_unintern(struct bgp_labels **plabels); +extern bool bgp_labels_cmp(const struct bgp_labels *labels1, + const struct bgp_labels *labels2); + extern int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, bool allocated); extern void bgp_reg_dereg_for_label(struct bgp_dest *dest, @@ -27,9 +47,9 @@ extern mpls_label_t bgp_adv_label(struct bgp_dest *dest, extern int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, struct bgp_nlri *packet); extern bool bgp_labels_same(const mpls_label_t *tbl_a, - const uint32_t num_labels_a, + const uint8_t num_labels_a, const mpls_label_t *tbl_b, - const uint32_t num_labels_b); + const uint8_t num_labels_b); static inline int bgp_labeled_safi(safi_t safi) { diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c index e629732c7..31e84d13c 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -14,6 +14,7 @@ #include "bgpd/bgpd.h" #include "bgpd/bgp_mac.h" #include "bgpd/bgp_memory.h" +#include "bgpd/bgp_label.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_rd.h" @@ -125,6 +126,8 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, { struct bgp_dest *pdest, *dest; struct bgp_path_info *pi; + uint8_t num_labels; + mpls_label_t *label_pnt; for (pdest = bgp_table_top(table); pdest; pdest = bgp_route_next(pdest)) { @@ -140,8 +143,6 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, const struct prefix *p = bgp_dest_get_prefix(dest); struct prefix_evpn *pevpn = (struct prefix_evpn *)dest; struct prefix_rd prd; - uint32_t num_labels = 0; - mpls_label_t *label_pnt = NULL; struct bgp_route_evpn *evpn; if (pevpn->family == AF_EVPN @@ -169,10 +170,9 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, && !dest_affected) continue; - if (pi->extra) - num_labels = pi->extra->num_labels; - if (num_labels) - label_pnt = &pi->extra->label[0]; + num_labels = bgp_path_info_num_labels(pi); + label_pnt = num_labels ? &pi->extra->labels->label[0] + : NULL; prd.family = AF_UNSPEC; prd.prefixlen = 64; diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 2bbd3a4b1..97658d340 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -225,6 +225,9 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) /* reverse bgp_attr_init */ bgp_attr_finish(); + /* reverse bgp_labels_init */ + bgp_labels_finish(); + /* stop pthreads */ bgp_pthreads_finish(); diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 53c03d810..c1804fb70 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -102,6 +102,8 @@ DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information"); DEFINE_MTYPE(BGPD, BGP_DUMP_STR, "BGP Dump String Information"); DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV"); +DEFINE_MTYPE(BGPD, BGP_LABELS, "BGP LABELS"); + DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options"); DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 865c5880d..4ae49a2c1 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -98,6 +98,8 @@ DECLARE_MTYPE(BGP_FILTER_NAME); DECLARE_MTYPE(BGP_DUMP_STR); DECLARE_MTYPE(ENCAP_TLV); +DECLARE_MTYPE(BGP_LABELS); + DECLARE_MTYPE(BGP_TEA_OPTIONS); DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 39f8f84a0..90881621b 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -964,50 +964,6 @@ void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset, } } -static bool labels_same(struct bgp_path_info *bpi, mpls_label_t *label, - uint32_t n) -{ - if (!bpi->extra) { - if (!n) - return true; - else - return false; - } - - return bgp_labels_same((const mpls_label_t *)bpi->extra->label, - bpi->extra->num_labels, - (const mpls_label_t *)label, n); -} - -/* - * make encoded route labels match specified encoded label set - */ -static void setlabels(struct bgp_path_info *bpi, - mpls_label_t *label, /* array of labels */ - uint32_t num_labels) -{ - if (num_labels) - assert(label); - assert(num_labels <= BGP_MAX_LABELS); - - if (!num_labels) { - if (bpi->extra) - bpi->extra->num_labels = 0; - return; - } - - struct bgp_path_info_extra *extra = bgp_path_info_extra_get(bpi); - uint32_t i; - - for (i = 0; i < num_labels; ++i) { - extra->label[i] = label[i]; - if (!bgp_is_valid_label(&label[i])) { - bgp_set_valid_label(&extra->label[i]); - } - } - extra->num_labels = num_labels; -} - static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, struct attr *new_attr, afi_t afi, safi_t safi, @@ -1086,7 +1042,7 @@ static struct bgp_path_info * leak_update(struct bgp *to_bgp, struct bgp_dest *bn, struct attr *new_attr, /* already interned */ afi_t afi, safi_t safi, struct bgp_path_info *source_bpi, - mpls_label_t *label, uint32_t num_labels, struct bgp *bgp_orig, + mpls_label_t *label, uint8_t num_labels, struct bgp *bgp_orig, struct prefix *nexthop_orig, int nexthop_self_flag, int debug) { const struct prefix *p = bgp_dest_get_prefix(bn); @@ -1094,6 +1050,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, struct bgp_path_info *new; struct bgp_path_info_extra *extra; struct bgp_path_info *parent = source_bpi; + struct bgp_labels bgp_labels = {}; + bool labelssame; + uint8_t i; if (debug) zlog_debug( @@ -1128,8 +1087,15 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, break; } + bgp_labels.num_labels = num_labels; + for (i = 0; i < num_labels; i++) { + bgp_labels.label[i] = label[i]; + bgp_set_valid_label(&bgp_labels.label[i]); + } + if (bpi) { - bool labelssame = labels_same(bpi, label, num_labels); + labelssame = bgp_path_info_labels_same(bpi, bgp_labels.label, + bgp_labels.num_labels); if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED) && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { @@ -1187,11 +1153,13 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, bpi->uptime = monotime(NULL); /* - * rewrite labels + * update labels */ - if (!labelssame) - setlabels(bpi, label, num_labels); - + if (!labelssame) { + bgp_path_info_extra_get(bpi); + bgp_labels_unintern(&bpi->extra->labels); + bpi->extra->labels = bgp_labels_intern(&bgp_labels); + } if (nexthop_self_flag) bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF); @@ -1249,8 +1217,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN)) bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN); - if (num_labels) - setlabels(new, label, num_labels); + if (bgp_labels.num_labels) + new->extra->labels = bgp_labels_intern(&bgp_labels); new->extra->vrfleak->parent = bgp_path_info_lock(parent); bgp_dest_lock_node( @@ -2102,8 +2070,8 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ safi_t safi = SAFI_UNICAST; const char *debugmsg; struct prefix nexthop_orig; - mpls_label_t *pLabels = NULL; - uint32_t num_labels = 0; + mpls_label_t *label_pnt = NULL; + uint8_t num_labels = 0; int nexthop_self_flag = 1; struct bgp_path_info *bpi_ultimate = NULL; struct bgp_path_info *bpi; @@ -2349,21 +2317,16 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ origin_local = 1; } - /* copy labels */ - if (!origin_local && path_vpn->extra - && path_vpn->extra->num_labels) { - num_labels = path_vpn->extra->num_labels; - if (num_labels > BGP_MAX_LABELS) - num_labels = BGP_MAX_LABELS; - pLabels = path_vpn->extra->label; - } + num_labels = origin_local ? 0 + : bgp_path_info_num_labels(path_vpn); + label_pnt = num_labels ? path_vpn->extra->labels->label : NULL; } if (debug) zlog_debug("%s: pfx %pBD: num_labels %d", __func__, path_vpn->net, num_labels); - if (!leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, pLabels, + if (!leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, label_pnt, num_labels, src_vrf, &nexthop_orig, nexthop_self_flag, debug)) bgp_dest_unlock_node(bn); @@ -3995,7 +3958,7 @@ static void bgp_mplsvpn_nh_label_bind_send_nexthop_label( struct bgp_mplsvpn_nh_label_bind_cache *bmnc, int cmd) { struct prefix pfx_nh, *p = NULL; - uint32_t num_labels = 0, lsp_num_labels; + uint8_t num_labels = 0, lsp_num_labels; mpls_label_t label[MPLS_MAX_LABELS]; struct nexthop *nh; ifindex_t ifindex = IFINDEX_INTERNAL; @@ -4130,7 +4093,7 @@ bool bgp_mplsvpn_path_uses_valid_mpls_label(struct bgp_path_info *pi) /* prefix_sid attribute */ return false; - if (!pi->extra || !bgp_is_valid_label(&pi->extra->label[0])) + if (!bgp_path_info_has_valid_label(pi)) /* invalid MPLS label */ return false; return true; @@ -4237,14 +4200,17 @@ void bgp_mplsvpn_nh_label_bind_register_local_label(struct bgp *bgp, { struct bgp_mplsvpn_nh_label_bind_cache *bmnc; struct bgp_mplsvpn_nh_label_bind_cache_head *tree; + mpls_label_t label; + + label = bgp_path_info_num_labels(pi) + ? decode_label(&pi->extra->labels->label[0]) + : MPLS_INVALID_LABEL; tree = &bgp->mplsvpn_nh_label_bind; - bmnc = bgp_mplsvpn_nh_label_bind_find( - tree, &pi->nexthop->prefix, decode_label(&pi->extra->label[0])); + bmnc = bgp_mplsvpn_nh_label_bind_find(tree, &pi->nexthop->prefix, label); if (!bmnc) { - bmnc = bgp_mplsvpn_nh_label_bind_new( - tree, &pi->nexthop->prefix, - decode_label(&pi->extra->label[0])); + bmnc = bgp_mplsvpn_nh_label_bind_new(tree, &pi->nexthop->prefix, + label); bmnc->bgp_vpn = bgp; bmnc->allocation_in_progress = true; bgp_lp_get(LP_TYPE_BGP_L3VPN_BIND, bmnc, diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 79f62ef60..8ce45558e 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -499,8 +499,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) return 1; else if (safi == SAFI_UNICAST && pi && - pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra && - pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop) + pi->sub_type == BGP_ROUTE_IMPORTED && + bgp_path_info_num_labels(pi) && !bnc->is_evpn_gwip_nexthop) return bgp_isvalid_nexthop_for_l3vpn(bnc, pi); else if (safi == SAFI_MPLS_VPN && pi && pi->sub_type != BGP_ROUTE_IMPORTED) @@ -1301,10 +1301,10 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc) bool bnc_is_valid_nexthop = false; bool path_valid = false; - if (safi == SAFI_UNICAST && path->sub_type == BGP_ROUTE_IMPORTED - && path->extra && path->extra->num_labels - && (path->attr->evpn_overlay.type - != OVERLAY_INDEX_GATEWAY_IP)) { + if (safi == SAFI_UNICAST && + path->sub_type == BGP_ROUTE_IMPORTED && + bgp_path_info_num_labels(path) && + (path->attr->evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP)) { bnc_is_valid_nexthop = bgp_isvalid_nexthop_for_l3vpn(bnc, path) ? true diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 2309b710e..94c21e186 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -235,8 +235,6 @@ static struct bgp_path_info_extra *bgp_path_info_extra_new(void) struct bgp_path_info_extra *new; new = XCALLOC(MTYPE_BGP_ROUTE_EXTRA, sizeof(struct bgp_path_info_extra)); - new->label[0] = MPLS_INVALID_LABEL; - new->num_labels = 0; new->flowspec = NULL; return new; } @@ -307,6 +305,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) XFREE(MTYPE_BGP_ROUTE_EXTRA_VNC, e->vnc); #endif + if (e->labels) + bgp_labels_unintern(&e->labels); + XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra); } @@ -324,6 +325,41 @@ struct bgp_path_info_extra *bgp_path_info_extra_get(struct bgp_path_info *pi) return pi->extra; } +bool bgp_path_info_has_valid_label(const struct bgp_path_info *path) +{ + if (!bgp_path_info_num_labels(path)) + return false; + + return bgp_is_valid_label(&path->extra->labels->label[0]); +} + +bool bgp_path_info_labels_same(const struct bgp_path_info *bpi, + const mpls_label_t *label, uint32_t n) +{ + uint8_t bpi_num_labels; + const mpls_label_t *bpi_label; + + bpi_num_labels = bgp_path_info_num_labels(bpi); + bpi_label = bpi_num_labels ? bpi->extra->labels->label : NULL; + + return bgp_labels_same(bpi_label, bpi_num_labels, + (const mpls_label_t *)label, n); +} + +uint8_t bgp_path_info_num_labels(const struct bgp_path_info *pi) +{ + if (!pi) + return 0; + + if (!pi->extra) + return 0; + + if (!pi->extra->labels) + return 0; + + return pi->extra->labels->num_labels; +} + /* Free bgp route information. */ void bgp_path_info_free_with_caller(const char *name, struct bgp_path_info *path) @@ -1359,25 +1395,18 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, /* If one path has a label but the other does not, do not treat * them as equals for multipath */ - int newl, existl; - - newl = existl = 0; - - if (new->extra) - newl = new->extra->num_labels; - if (exist->extra) - existl = exist->extra->num_labels; - if (((new->extra &&bgp_is_valid_label(&new->extra->label[0])) != - (exist->extra && - bgp_is_valid_label(&exist->extra->label[0]))) || - (newl != existl)) { + bool new_label_valid, exist_label_valid; + + new_label_valid = bgp_path_info_has_valid_label(new); + exist_label_valid = bgp_path_info_has_valid_label(exist); + + if (new_label_valid != exist_label_valid) { if (debug) zlog_debug( "%s: %s and %s cannot be multipath, one has a label while the other does not", pfx_buf, new_buf, exist_buf); } else if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { - /* * For the two paths, all comparison steps till IGP * metric @@ -1843,11 +1872,12 @@ static bool bgp_check_role_applicability(afi_t afi, safi_t safi) static int bgp_input_modifier(struct peer *peer, const struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, const char *rmap_name, mpls_label_t *label, - uint32_t num_labels, struct bgp_dest *dest) + uint8_t num_labels, struct bgp_dest *dest) { struct bgp_filter *filter; struct bgp_path_info rmap_path = { 0 }; struct bgp_path_info_extra extra = { 0 }; + struct bgp_labels bgp_labels = {}; route_map_result_t ret; struct route_map *rmap = NULL; @@ -1879,11 +1909,12 @@ static int bgp_input_modifier(struct peer *peer, const struct prefix *p, rmap_path.attr = attr; rmap_path.extra = &extra; rmap_path.net = dest; + extra.labels = &bgp_labels; - extra.num_labels = num_labels; + bgp_labels.num_labels = num_labels; if (label && num_labels && num_labels <= BGP_MAX_LABELS) - memcpy(extra.label, label, - num_labels * sizeof(mpls_label_t)); + memcpy(bgp_labels.label, label, + num_labels * sizeof(mpls_label_t)); SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN); @@ -2218,8 +2249,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * off box as that the RT and RD created are localy * significant and globaly useless. */ - if (safi == SAFI_MPLS_VPN && pi->extra && pi->extra->num_labels - && pi->extra->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) + if (safi == SAFI_MPLS_VPN && bgp_path_info_num_labels(pi) && + pi->extra->labels->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) return false; /* If it's labeled safi, make sure the route has a valid label. */ @@ -3455,8 +3486,7 @@ static bool bgp_lu_need_null_label(struct bgp *bgp, || new_select->sub_type == BGP_ROUTE_AGGREGATE || new_select->sub_type == BGP_ROUTE_REDISTRIBUTE) goto need_null_label; - else if (new_select->extra && - bgp_is_valid_label(&new_select->extra->label[0])) + else if (bgp_path_info_has_valid_label(new_select)) return false; need_null_label: if (label == NULL) @@ -4506,7 +4536,7 @@ static bool bgp_accept_own(struct peer *peer, afi_t afi, safi_t safi, void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, int soft_reconfig, + uint8_t num_labels, int soft_reconfig, struct bgp_route_evpn *evpn) { int ret; @@ -4517,16 +4547,16 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct attr *attr_new; struct bgp_path_info *pi; struct bgp_path_info *new = NULL; - struct bgp_path_info_extra *extra; const char *reason; char pfx_buf[BGP_PRD_PATH_STRLEN]; int connected = 0; int do_loop_check = 1; - int has_valid_label = 0; afi_t nh_afi; bool force_evpn_import = false; safi_t orig_safi = safi; int allowas_in = 0; + struct bgp_labels bgp_labels = {}; + uint8_t i; if (frrtrace_enabled(frr_bgp, process_update)) { char pfxprint[PREFIX2STR_BUFFER]; @@ -4548,15 +4578,12 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, bgp = peer->bgp; dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd); - /* TODO: Check to see if we can get rid of "is_valid_label" */ - if (afi == AFI_L2VPN && safi == SAFI_EVPN) - has_valid_label = (num_labels > 0) ? 1 : 0; - else - has_valid_label = bgp_is_valid_label(label); - - if (has_valid_label) - assert(label != NULL); + if ((afi == AFI_L2VPN && safi == SAFI_EVPN) || + bgp_is_valid_label(&label[0])) + bgp_labels.num_labels = num_labels; + for (i = 0; i < bgp_labels.num_labels; i++) + bgp_labels.label[i] = label[i]; /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ @@ -4573,7 +4600,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, memcpy(&attr->evpn_overlay, evpn, sizeof(struct bgp_route_evpn)); } - bgp_adj_in_set(dest, peer, attr, addpath_id); + bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels); } /* Update permitted loop count */ @@ -4850,11 +4877,9 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, /* Same attribute comes in. */ if (!CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) && same_attr && - (!has_valid_label || - (bgp_path_info_extra_get(pi) && - bgp_labels_same((const mpls_label_t *)pi->extra->label, - pi->extra->num_labels, label, - num_labels)))) { + (!bgp_labels.num_labels || + bgp_path_info_labels_same(pi, bgp_labels.label, + bgp_labels.num_labels))) { if (get_active_bdc_from_pi(pi, afi, safi) && peer->sort == BGP_PEER_EBGP && CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) { @@ -5036,17 +5061,11 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, pi->attr = attr_new; /* Update MPLS label */ - if (has_valid_label) { - extra = bgp_path_info_extra_get(pi); - if (!bgp_labels_same((const mpls_label_t *)extra->label, - extra->num_labels, label, - num_labels)) { - memcpy(&extra->label, label, - num_labels * sizeof(mpls_label_t)); - extra->num_labels = num_labels; - } - if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) - bgp_set_valid_label(&extra->label[0]); + if (!bgp_path_info_labels_same(pi, &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_path_info_extra_get(pi); + bgp_labels_unintern(&pi->extra->labels); + pi->extra->labels = bgp_labels_intern(&bgp_labels); } #ifdef ENABLE_BGP_VNC @@ -5237,17 +5256,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, new = info_make(type, sub_type, 0, peer, attr_new, dest); /* Update MPLS label */ - if (has_valid_label) { - extra = bgp_path_info_extra_get(new); - if (!bgp_labels_same((const mpls_label_t *)extra->label, - extra->num_labels, label, num_labels)) { - memcpy(&extra->label, label, - num_labels * sizeof(mpls_label_t)); - extra->num_labels = num_labels; - } - if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) - bgp_set_valid_label(&extra->label[0]); - } + bgp_path_info_extra_get(new); + new->extra->labels = bgp_labels_intern(&bgp_labels); /* Nexthop reachability check. */ if (((afi == AFI_IP || afi == AFI_IP6) && @@ -5428,7 +5438,7 @@ filtered: void bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, struct bgp_route_evpn *evpn) + uint8_t num_labels, struct bgp_route_evpn *evpn) { struct bgp *bgp; char pfx_buf[BGP_PRD_PATH_STRLEN]; @@ -5655,18 +5665,16 @@ static void bgp_soft_reconfig_table_update(struct peer *peer, safi_t safi, struct prefix_rd *prd) { struct bgp_path_info *pi; - uint32_t num_labels = 0; - mpls_label_t *label_pnt = NULL; + uint8_t num_labels; + mpls_label_t *label_pnt; struct bgp_route_evpn evpn; for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (pi->peer == peer) break; - if (pi && pi->extra) - num_labels = pi->extra->num_labels; - if (num_labels) - label_pnt = &pi->extra->label[0]; + num_labels = ain->labels ? ain->labels->num_labels : 0; + label_pnt = num_labels ? &ain->labels->label[0] : NULL; if (pi) memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr), sizeof(evpn)); @@ -6678,10 +6686,11 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, route_map_result_t ret; #ifdef ENABLE_BGP_VNC int vnc_implicit_withdraw = 0; - mpls_label_t label = 0; + mpls_label_t label = MPLS_INVALID_LABEL; #endif - uint32_t num_labels = 0; + uint8_t num_labels = 0; struct bgp *bgp_nexthop = bgp; + struct bgp_labels labels = {}; assert(bgp_static); @@ -6831,9 +6840,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, bgp, p, pi); } } else { - if (pi->extra) + if (bgp_path_info_num_labels(pi)) label = decode_label( - &pi->extra->label[0]); + &pi->extra->labels->label[0]); } #endif if (pi->extra && pi->extra->vrfleak->bgp_orig) @@ -6882,8 +6891,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, SET_FLAG(new->flags, BGP_PATH_VALID); bgp_path_info_extra_get(new); if (num_labels) { - new->extra->label[0] = bgp_static->label; - new->extra->num_labels = num_labels; + labels.num_labels = num_labels; + labels.label[0] = bgp_static->label; + new->extra->labels = bgp_labels_intern(&labels); } #ifdef ENABLE_BGP_VNC label = decode_label(&bgp_static->label); @@ -10069,8 +10079,8 @@ void route_vty_out_tag(struct vty *vty, const struct prefix *p, } } - if (bgp_is_valid_label(&path->extra->label[0])) { - label = decode_label(&path->extra->label[0]); + if (bgp_path_info_has_valid_label(path)) { + label = decode_label(&path->extra->labels->label[0]); if (json) { json_object_int_add(json_out, "notag", label); json_object_array_add(json, json_out); @@ -10460,7 +10470,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object *json_paths) { char buf[INET6_ADDRSTRLEN]; - char tag_buf[30]; + char vni_buf[30] = {}; struct attr *attr = path->attr; time_t tbuf; char timebuf[32]; @@ -10493,7 +10503,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, uint32_t bos = 0; uint32_t exp = 0; mpls_label_t label = MPLS_INVALID_LABEL; - tag_buf[0] = '\0'; struct bgp_path_info *bpi_ultimate = bgp_get_imported_bpi_ultimate(path); @@ -10503,26 +10512,22 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_nexthop_global = json_object_new_object(); } + if (bgp_path_info_num_labels(path)) { + bgp_evpn_label2str(path->extra->labels->label, + path->extra->labels->num_labels, vni_buf, + sizeof(vni_buf)); + } + if (safi == SAFI_EVPN) { if (!json_paths) vty_out(vty, " Route %pFX", p); - } - if (path->extra) { - if (path->extra && path->extra->num_labels) { - bgp_evpn_label2str(path->extra->label, - path->extra->num_labels, tag_buf, - sizeof(tag_buf)); - } - if (safi == SAFI_EVPN) { - if (!json_paths) { - if (tag_buf[0] != '\0') - vty_out(vty, " VNI %s", tag_buf); - } else { - if (tag_buf[0]) - json_object_string_add(json_path, "vni", - tag_buf); - } + if (vni_buf[0]) { + if (json_paths) + json_object_string_add(json_path, "vni", + vni_buf); + else + vty_out(vty, " VNI %s", vni_buf); } } @@ -10562,7 +10567,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, ":%pFX, VNI %s", (struct prefix_evpn *) bgp_dest_get_prefix(dest), - tag_buf); + vni_buf); if (CHECK_FLAG(attr->es_flags, ATTR_ES_L3_NHG)) vty_out(vty, ", L3NHG %s", CHECK_FLAG( @@ -11274,10 +11279,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, bgp_damp_info_vty(vty, bgp, path, afi, safi, json_path); /* Remote Label */ - if (path->extra && bgp_is_valid_label(&path->extra->label[0]) - && (safi != SAFI_EVPN && !is_route_parent_evpn(path))) { - mpls_lse_decode(path->extra->label[0], &label, &ttl, &exp, - &bos); + if (bgp_path_info_has_valid_label(path) && + (safi != SAFI_EVPN && !is_route_parent_evpn(path))) { + mpls_lse_decode(path->extra->labels->label[0], &label, &ttl, + &exp, &bos); if (json_paths) json_object_int_add(json_path, "remoteLabel", label); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 25fc327a1..89449ac5b 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -69,11 +69,6 @@ enum bgp_show_adj_route_type { #define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n" #define BGP_SHOW_HEADER_WIDE " Network Next Hop Metric LocPrf Weight Path\n" -/* Maximum number of labels we can process or send with a prefix. We - * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN. - */ -#define BGP_MAX_LABELS 2 - /* Maximum number of sids we can process or send with a prefix. */ #define BGP_MAX_SIDS 6 @@ -237,8 +232,7 @@ struct bgp_path_info_extra { uint32_t igpmetric; /* MPLS label(s) - VNI(s) for EVPN-VxLAN */ - mpls_label_t label[BGP_MAX_LABELS]; - uint32_t num_labels; + struct bgp_labels *labels; /* timestamp of the rib installation */ time_t bgp_rib_uptime; @@ -753,12 +747,16 @@ extern void bgp_path_info_delete(struct bgp_dest *dest, struct bgp_path_info *pi); extern struct bgp_path_info_extra * bgp_path_info_extra_get(struct bgp_path_info *path); +extern bool bgp_path_info_has_valid_label(const struct bgp_path_info *path); +extern uint8_t bgp_path_info_num_labels(const struct bgp_path_info *pi); extern void bgp_path_info_set_flag(struct bgp_dest *dest, struct bgp_path_info *path, uint32_t flag); extern void bgp_path_info_unset_flag(struct bgp_dest *dest, struct bgp_path_info *path, uint32_t flag); extern void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf, size_t buf_len); +extern bool bgp_path_info_labels_same(const struct bgp_path_info *bpi, + const mpls_label_t *label, uint32_t n); extern int bgp_nlri_parse_ip(struct peer *, struct attr *, struct bgp_nlri *); @@ -795,12 +793,12 @@ extern void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, int soft_reconfig, + uint8_t num_labels, int soft_reconfig, struct bgp_route_evpn *evpn); extern void bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, struct bgp_route_evpn *evpn); /* for bgp_nexthop and bgp_damp */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index dc26a1f5d..9b0ca72e4 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1056,7 +1056,7 @@ static enum route_map_cmd_result_t route_match_vni(void *rule, const struct prefix *prefix, void *object) { vni_t vni = 0; - unsigned int label_cnt = 0; + unsigned int label_cnt; struct bgp_path_info *path = NULL; struct prefix_evpn *evp = (struct prefix_evpn *) prefix; @@ -1081,13 +1081,10 @@ route_match_vni(void *rule, const struct prefix *prefix, void *object) && evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE)) return RMAP_NOOP; - if (path->extra == NULL) - return RMAP_NOMATCH; - - for (; - label_cnt < BGP_MAX_LABELS && label_cnt < path->extra->num_labels; + for (label_cnt = 0; label_cnt < BGP_MAX_LABELS && + label_cnt < bgp_path_info_num_labels(path); label_cnt++) { - if (vni == label2vni(&path->extra->label[label_cnt])) + if (vni == label2vni(&path->extra->labels->label[label_cnt])) return RMAP_MATCH; } diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index f5508a0a7..a487f49e6 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -29,6 +29,7 @@ #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgp_advertise.h" +#include "bgp_label.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" @@ -656,17 +657,16 @@ 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); - mpls_label_t *label = NULL; - uint32_t num_labels = 0; - if (path && path->extra) { - label = path->extra->label; - num_labels = path->extra->num_labels; - } + 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, diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 0a852c75d..250378af6 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -78,6 +78,8 @@ static inline struct bgp_adj_out *adj_lookup(struct bgp_dest *dest, static void adj_free(struct bgp_adj_out *adj) { + bgp_labels_unintern(&adj->labels); + TAILQ_REMOVE(&(adj->subgroup->adjq), adj, subgrp_adj_train); SUBGRP_DECR_STAT(adj->subgroup, adj_count); @@ -572,7 +574,9 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest, attr_hash = attrhash_key_make(attr); if (!CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES) && - attr_hash && adj->attr_hash == attr_hash) { + attr_hash && adj->attr_hash == attr_hash && + bgp_labels_cmp(path->extra ? path->extra->labels : NULL, + adj->labels)) { if (BGP_DEBUG(update, UPDATE_OUT)) { char attr_str[BUFSIZ] = {0}; @@ -614,6 +618,10 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest, adv->baa = bgp_advertise_attr_intern(subgrp->hash, attr); adv->adj = adj; adj->attr_hash = attr_hash; + if (path->extra) + adj->labels = bgp_labels_intern(path->extra->labels); + else + adj->labels = NULL; /* Add new advertisement to advertisement attribute list. */ bgp_advertise_add(adv->baa, adv); diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 1f691b6a9..6e30d4f84 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -667,7 +667,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) uint32_t addpath_tx_id = 0; struct prefix_rd *prd = NULL; mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL; - uint32_t num_labels = 0; + uint8_t num_labels = 0; if (!subgrp) return NULL; @@ -814,9 +814,12 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) path); label_pnt = &label; num_labels = 1; - } else if (path && path->extra) { - label_pnt = &path->extra->label[0]; - num_labels = path->extra->num_labels; + } else { + num_labels = bgp_path_info_num_labels(path); + label_pnt = + num_labels + ? &path->extra->labels->label[0] + : NULL; } if (stream_empty(snlri)) @@ -1083,7 +1086,7 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp, struct bpacket_attr_vec_arr vecarr; bool addpath_capable = false; mpls_label_t label = MPLS_LABEL_IMPLICIT_NULL; - uint32_t num_labels = 0; + uint8_t num_labels = 0; if (DISABLE_BGP_ANNOUNCE) return; diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 1c2f08465..8fab0d1c0 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1273,7 +1273,7 @@ static void bgp_zebra_announce_parse_nexthop( struct bgp_path_info local_info; struct bgp_path_info *mpinfo_cp = &local_info; mpls_label_t *labels; - uint32_t num_labels = 0; + uint8_t num_labels = 0; mpls_label_t nh_label; int nh_othervrf = 0; bool nh_updated = false; @@ -1301,8 +1301,6 @@ static void bgp_zebra_announce_parse_nexthop( } for (; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) { - labels = NULL; - num_labels = 0; uint64_t nh_weight; bool is_evpn; bool is_parent_evpn; @@ -1341,15 +1339,14 @@ static void bgp_zebra_announce_parse_nexthop( api_nh->srte_color = bgp_attr_get_color(info->attr); if (bgp_debug_zebra(&api->prefix)) { - if (mpinfo->extra) { + if (bgp_path_info_num_labels(mpinfo)) { zlog_debug("%s: p=%pFX, bgp_is_valid_label: %d", __func__, p, bgp_is_valid_label( - &mpinfo->extra->label[0])); + &mpinfo->extra->labels + ->label[0])); } else { - zlog_debug( - "%s: p=%pFX, extra is NULL, no label", - __func__, p); + zlog_debug("%s: p=%pFX, no label", __func__, p); } } @@ -1415,13 +1412,10 @@ static void bgp_zebra_announce_parse_nexthop( mpinfo->peer->sort == BGP_PEER_CONFED)) *allow_recursion = true; - if (mpinfo->extra) { - labels = mpinfo->extra->label; - num_labels = mpinfo->extra->num_labels; - } + num_labels = bgp_path_info_num_labels(mpinfo); + labels = num_labels ? mpinfo->extra->labels->label : NULL; - if (labels && (num_labels > 0) && - (is_evpn || bgp_is_valid_label(&labels[0]))) { + if (num_labels && (is_evpn || bgp_is_valid_label(&labels[0]))) { enum lsp_types_t nh_label_type = ZEBRA_LSP_NONE; if (is_evpn) { @@ -4112,8 +4106,7 @@ int bgp_zebra_srv6_manager_release_locator_chunk(const char *name) void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, ifindex_t ifindex, vrf_id_t vrf_id, enum lsp_types_t ltype, struct prefix *p, - uint32_t num_labels, - mpls_label_t out_labels[]) + uint8_t num_labels, mpls_label_t out_labels[]) { struct zapi_labels zl = {}; struct zapi_nexthop *znh; diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index ef296b963..55a4185bd 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -120,7 +120,7 @@ extern int bgp_zebra_srv6_manager_release_locator_chunk(const char *name); extern void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, ifindex_t index, vrf_id_t vrfid, enum lsp_types_t ltype, - struct prefix *p, uint32_t num_labels, + struct prefix *p, uint8_t num_labels, mpls_label_t out_labels[]); extern bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size, bool label_auto); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d8eba0ab2..81506f441 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3620,10 +3620,13 @@ struct bgp *bgp_lookup_by_name(const char *name) struct bgp *bgp; struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; if ((bgp->name == NULL && name == NULL) || (bgp->name && name && strcmp(bgp->name, name) == 0)) return bgp; + } return NULL; } @@ -8547,6 +8550,7 @@ void bgp_init(unsigned short instance) /* BGP inits. */ bgp_attr_init(); + bgp_labels_init(); bgp_debug_init(); bgp_community_alias_init(); bgp_dump_init(); diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index ae899daf8..23e3eb482 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -549,6 +549,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ int flags) { afi_t afi; /* of the VN address */ + struct bgp_labels bgp_labels = {}; struct bgp_path_info *new; struct bgp_path_info *bpi; struct bgp_dest *bn; @@ -592,7 +593,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ } } - if (label) + if (label && *label != MPLS_INVALID_LABEL) label_val = *label; else label_val = MPLS_LABEL_IMPLICIT_NULL; @@ -1020,7 +1021,10 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ new->extra->vnc = XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VNC, sizeof(struct bgp_path_info_extra_vnc)); new->extra->vnc->vnc.export.rfapi_handle = (void *)rfd; - encode_label(label_val, &new->extra->label[0]); + + encode_label(label_val, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; + new->extra->labels = bgp_labels_intern(&bgp_labels); /* debug */ diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 168b8e4c1..2afcb2f45 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -442,6 +442,7 @@ static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr, uint32_t *label) { struct bgp_path_info *new; + struct bgp_labels bgp_labels = {}; new = info_make(type, sub_type, 0, peer, attr, NULL); @@ -454,8 +455,11 @@ static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr, new->extra->vnc->vnc.import.rd = *prd; new->extra->vnc->vnc.import.create_time = monotime(NULL); } - if (label) - encode_label(*label, &new->extra->label[0]); + if (label && *label != MPLS_INVALID_LABEL) { + encode_label(*label, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; + new->extra->labels = bgp_labels_intern(&bgp_labels); + } peer_lock(peer); @@ -1267,7 +1271,10 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, bpi->extra->vnc->vnc.import.rd.val[1]; /* label comes from MP_REACH_NLRI label */ - vo->v.l2addr.label = decode_label(&bpi->extra->label[0]); + vo->v.l2addr.label = + bgp_path_info_num_labels(bpi) + ? decode_label(&bpi->extra->labels->label[0]) + : MPLS_INVALID_LABEL; new->vn_options = vo; @@ -4154,15 +4161,16 @@ static void rfapiBgpTableFilteredImport(struct bgp *bgp, for (bpi = bgp_dest_get_bgp_path_info(dest2); bpi; bpi = bpi->next) { - uint32_t label = 0; + uint32_t label = MPLS_INVALID_LABEL; if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) continue; - if (bpi->extra) + if (bgp_path_info_num_labels(bpi)) label = decode_label( - &bpi->extra->label[0]); + &bpi->extra->labels + ->label[0]); (*rfapiBgpInfoFilteredImportFunction( safi))( it, /* which import table */ diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 316904e45..a0bdf4961 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -691,7 +691,10 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, bpi->extra->vnc->vnc.import.rd.val[1]; /* label comes from MP_REACH_NLRI label */ - vo->v.l2addr.label = decode_label(&bpi->extra->label[0]); + vo->v.l2addr.label = + bgp_path_info_num_labels(bpi) + ? decode_label(&bpi->extra->labels->label[0]) + : MPLS_INVALID_LABEL; rfapi_vn_options_free( ri->vn_options); /* maybe free old version */ diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 5da99dbc4..9bfb6c4b4 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -413,12 +413,12 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p, XFREE(MTYPE_ECOMMUNITY_STR, s); } - if (bpi->extra != NULL) { - if (bpi->extra->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) + if (bgp_path_info_num_labels(bpi)) { + if (bpi->extra->labels->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) vty_out(vty, " label=VRF2VRF"); else vty_out(vty, " label=%u", - decode_label(&bpi->extra->label[0])); + decode_label(&bpi->extra->labels->label[0])); } if (bpi->attr->srv6_l3vpn || bpi->attr->srv6_vpn) { @@ -1052,8 +1052,8 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, snprintf(buf_un, sizeof(buf_un), "%s", inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop, sizeof(buf_ntop))); - if (bpi->extra) { - uint32_t l = decode_label(&bpi->extra->label[0]); + if (bgp_path_info_num_labels(bpi)) { + uint32_t l = decode_label(&bpi->extra->labels->label[0]); snprintf(buf_vn, sizeof(buf_vn), "Label: %d", l); } else /* should never happen */ { @@ -1161,8 +1161,8 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, } } } - if (tun_type != BGP_ENCAP_TYPE_MPLS && bpi->extra) { - uint32_t l = decode_label(&bpi->extra->label[0]); + if (tun_type != BGP_ENCAP_TYPE_MPLS && bgp_path_info_num_labels(bpi)) { + uint32_t l = decode_label(&bpi->extra->labels->label[0]); if (!MPLS_LABEL_IS_NULL(l)) { fp(out, " Label: %d", l); diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c index c067b7a61..2bb7c1b16 100644 --- a/bgpd/rfapi/vnc_import_bgp.c +++ b/bgpd/rfapi/vnc_import_bgp.c @@ -414,7 +414,7 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi( uint32_t lifetime; uint32_t *plifetime; struct bgp_attr_encap_subtlv *encaptlvs; - uint32_t label = 0; + uint32_t label; struct rfapi_un_option optary[3]; struct rfapi_un_option *opt = NULL; @@ -470,16 +470,19 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi( if (bgp_attr_get_ecommunity(bpi->attr)) ecommunity_merge(new_ecom, bgp_attr_get_ecommunity(bpi->attr)); - if (bpi->extra) - label = decode_label(&bpi->extra->label[0]); + if (bgp_path_info_num_labels(bpi)) + label = decode_label(&bpi->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; add_vnc_route(&vncHDResolveNve, bgp, SAFI_MPLS_VPN, - prefix, /* unicast route prefix */ + prefix, /* unicast route prefix */ prd, &nexthop_h, /* new nexthop */ local_pref, plifetime, (struct bgp_tea_options *)encaptlvs, /* RFP options */ opt, NULL, new_ecom, med, /* NULL => don't set med */ - (label ? &label : NULL), /* NULL= default */ + ((label != MPLS_INVALID_LABEL) ? &label + : NULL), /* NULL= default */ ZEBRA_ROUTE_BGP_DIRECT, BGP_ROUTE_REDISTRIBUTE, RFAPI_AHR_RFPOPT_IS_VNCTLV); /* flags */ @@ -1678,7 +1681,7 @@ static void vnc_import_bgp_exterior_add_route_it( bpi_interior = bpi_interior->next) { struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; if (!is_usable_interior_route(bpi_interior)) continue; @@ -1695,14 +1698,19 @@ static void vnc_import_bgp_exterior_add_route_it( */ have_usable_route = 1; - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc .import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(new_attr)); new_attr = *bpi_interior->attr; @@ -1851,7 +1859,7 @@ void vnc_import_bgp_exterior_del_route( for (bpi_interior = rn->info; bpi_interior; bpi_interior = bpi_interior->next) { struct prefix_rd *prd; - uint32_t label = 0; + uint32_t label; if (!is_usable_interior_route(bpi_interior)) continue; @@ -1864,14 +1872,19 @@ void vnc_import_bgp_exterior_del_route( */ have_usable_route = 1; - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc .import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; + rfapiBgpInfoFilteredImportVPN( it, FIF_ACTION_KILL, bpi_interior->peer, NULL, /* rfd */ @@ -2007,18 +2020,22 @@ void vnc_import_bgp_exterior_add_route_interior( struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; assert(bpi_exterior); assert(pfx_exterior); - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc.import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); new_attr = *bpi_interior->attr; @@ -2097,7 +2114,7 @@ void vnc_import_bgp_exterior_add_route_interior( struct bgp_path_info *bpi; struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; /* do pull-down */ @@ -2124,15 +2141,19 @@ void vnc_import_bgp_exterior_add_route_interior( * parent routes. */ for (bpi = par->info; bpi; bpi = bpi->next) { - - if (bpi->extra) { + if (bpi->extra) prd = &bpi->extra->vnc->vnc .import.rd; - label = decode_label( - &bpi->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi)) + label = decode_label( + &bpi->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; + rfapiBgpInfoFilteredImportVPN( it, FIF_ACTION_KILL, bpi->peer, NULL, /* rfd */ @@ -2147,14 +2168,19 @@ void vnc_import_bgp_exterior_add_route_interior( * Add constructed exterior routes based on * the new interior route at longer prefix. */ - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc .import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); new_attr = *bpi_interior->attr; @@ -2237,7 +2263,7 @@ void vnc_import_bgp_exterior_add_route_interior( struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; /* do pull-down */ @@ -2266,13 +2292,17 @@ void vnc_import_bgp_exterior_add_route_interior( * Add constructed exterior routes based on the * new interior route at the longer prefix. */ - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc.import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); new_attr = *bpi_interior->attr; @@ -2372,14 +2402,19 @@ void vnc_import_bgp_exterior_del_route_interior( &cursor)) { struct prefix_rd *prd; - uint32_t label = 0; + uint32_t label; - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc.import.rd; - label = decode_label(&bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + rfapiBgpInfoFilteredImportVPN( it, FIF_ACTION_KILL, bpi_interior->peer, NULL, /* rfd */ pfx_exterior, NULL, afi, prd, bpi_interior->attr, @@ -2446,18 +2481,22 @@ void vnc_import_bgp_exterior_del_route_interior( struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; if (bpi->type == ZEBRA_ROUTE_BGP_DIRECT_EXT) continue; - if (bpi->extra) { + if (bpi->extra) prd = &bpi->extra->vnc->vnc.import.rd; - label = decode_label( - &bpi->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi)) + label = decode_label( + &bpi->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(new_attr)); new_attr = *bpi->attr; diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 58fdbf969..150a915e3 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -4102,6 +4102,10 @@ The following are available in the top level *enable* mode: Clear all peers. +.. clicmd:: clear bgp ipv4|ipv6 ASNUM + + Clear peers with the AS number in plain or dotted format. + .. clicmd:: clear bgp ipv4|ipv6 \* Clear all peers with this address-family activated. diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile index d136538c7..b317b0598 100644 --- a/docker/debian/Dockerfile +++ b/docker/debian/Dockerfile @@ -24,5 +24,5 @@ RUN chown -R frr:frr /etc/frr /var/run/frr ENTRYPOINT ["/usr/bin/tini", "--"] # Default CMD starts watchfrr -COPY docker-start /usr/lib/frr/docker-start +COPY --chmod=0755 docker-start /usr/lib/frr/docker-start CMD ["/usr/lib/frr/docker-start"] diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 9e875ff6e..c98cee06a 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -705,6 +705,10 @@ void lsp_print_common(struct isis_lsp *lsp, struct vty *vty, struct json_object } } +#if CONFDATE > 20240916 +CPP_NOTICE("Remove JSON in '-' format") +#endif + void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, char dynhost, struct isis *isis) { @@ -718,10 +722,20 @@ void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, own_json = json_object_new_object(); json_object_object_add(json, "lsp", own_json); json_object_string_add(own_json, "id", LSPid); +#if CONFDATE > 20240916 + CPP_NOTICE("remove own key") +#endif json_object_string_add(own_json, "own", lsp->own_lsp ? "*" : " "); + if (lsp->own_lsp) + json_object_boolean_add(own_json, "ownLSP", true); json_object_int_add(json, "pdu-len", lsp->hdr.pdu_len); + json_object_int_add(json, "pduLen", lsp->hdr.pdu_len); snprintfrr(buf, sizeof(buf), "0x%08x", lsp->hdr.seqno); +#if CONFDATE > 20240916 + CPP_NOTICE("remove seq-number key") +#endif json_object_string_add(json, "seq-number", buf); + json_object_string_add(json, "seqNumber", buf); snprintfrr(buf, sizeof(buf), "0x%04hx", lsp->hdr.checksum); json_object_string_add(json, "chksum", buf); if (lsp->hdr.rem_lifetime == 0) { @@ -731,8 +745,13 @@ void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, } else { json_object_int_add(json, "holdtime", lsp->hdr.rem_lifetime); } +#if CONFDATE > 20240916 + CPP_NOTICE("remove att-p-ol key") +#endif json_object_string_add( json, "att-p-ol", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b))); + json_object_string_add(json, "attPOl", + lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b))); } void lsp_print_vty(struct isis_lsp *lsp, struct vty *vty, diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 93ae8c6cb..3bb8a4824 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -348,9 +348,120 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid) } static void format_item_asla_subtlvs(struct isis_asla_subtlvs *asla, + struct json_object *ext_json, struct sbuf *buf, int indent) { char admin_group_buf[ADMIN_GROUP_PRINT_MAX_SIZE]; + struct json_object *json; + char cnt_buf[255]; + size_t i; + int j; + + if (ext_json) { + json = json_object_new_object(); + json_object_object_add(ext_json, "asla", json); + json_object_boolean_add(json, "legacyFlag", asla->legacy); + json_object_string_addf(json, "standardApp", "0x%02x", + asla->standard_apps); + if (IS_SUBTLV(asla, EXT_ADM_GRP)) + json_object_string_addf(json, "adminGroup", "0x%x", + asla->admin_group); + if (IS_SUBTLV(asla, EXT_EXTEND_ADM_GRP) && + admin_group_nb_words(&asla->ext_admin_group) != 0) { + struct json_object *ext_adm_grp_json; + + ext_adm_grp_json = json_object_new_object(); + json_object_object_add(json, "extendedAdminGroup", + ext_adm_grp_json); + for (i = 0; + i < admin_group_nb_words(&asla->ext_admin_group); + i++) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%lu", + (unsigned long)i); + json_object_string_addf(ext_adm_grp_json, + cnt_buf, "0x%x", + asla->ext_admin_group + .bitmap.data[i]); + } + } + if (IS_SUBTLV(asla, EXT_MAX_BW)) + json_object_string_addf(json, "maxBandwithBytesSec", + "%g", asla->max_bw); + if (IS_SUBTLV(asla, EXT_MAX_RSV_BW)) + json_object_string_addf(json, "maxResBandwithBytesSec", + "%g", asla->max_rsv_bw); + if (IS_SUBTLV(asla, EXT_UNRSV_BW)) { + struct json_object *unrsv_json = + json_object_new_object(); + + json_object_object_add(json, "unrsvBandwithBytesSec", + unrsv_json); + for (j = 0; j < MAX_CLASS_TYPE; j += 1) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", j); + json_object_string_addf(unrsv_json, cnt_buf, + "%g", asla->unrsv_bw[j]); + } + } + if (IS_SUBTLV(asla, EXT_TE_METRIC)) + json_object_int_add(json, "teMetric", asla->te_metric); + + /* Extended metrics */ + if (IS_SUBTLV(asla, EXT_DELAY)) { + struct json_object *avg_json; + + avg_json = json_object_new_object(); + json_object_object_add(json, "avgDelay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(asla->delay) + ? "Anomalous" + : "Normal"); + json_object_int_add(avg_json, "microSec", asla->delay); + } + if (IS_SUBTLV(asla, EXT_MM_DELAY)) { + struct json_object *avg_json; + + avg_json = json_object_new_object(); + json_object_object_add(json, "maxMinDelay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(asla->min_delay) + ? "Anomalous" + : "Normal"); + json_object_string_addf(avg_json, "microSec", "%u / %u", + asla->min_delay & TE_EXT_MASK, + asla->max_delay & TE_EXT_MASK); + } + if (IS_SUBTLV(asla, EXT_DELAY_VAR)) + json_object_int_add(json, "delayVariationMicroSec", + asla->delay_var & TE_EXT_MASK); + if (IS_SUBTLV(asla, EXT_PKT_LOSS)) { + struct json_object *link_json; + + link_json = json_object_new_object(); + json_object_object_add(json, "linkPacketLoss", + link_json); + json_object_string_add(link_json, "loss", + IS_ANORMAL(asla->pkt_loss) + ? "Anomalous" + : "Normal"); + json_object_string_addf(link_json, "percentage", "%g", + (float)((asla->pkt_loss & + TE_EXT_MASK) * + LOSS_PRECISION)); + } + if (IS_SUBTLV(asla, EXT_RES_BW)) + json_object_string_addf(json, + "unidirResidualBandBytesSec", + "%g", (asla->res_bw)); + if (IS_SUBTLV(asla, EXT_AVA_BW)) + json_object_string_addf(json, + "unidirAvailableBandBytesSec", + "%g", (asla->ava_bw)); + if (IS_SUBTLV(asla, EXT_USE_BW)) + json_object_string_addf(json, + "unidirUtilizedBandBytesSec", + "%g", (asla->use_bw)); + return; + } sbuf_push(buf, indent, "Application Specific Link Attributes:\n"); sbuf_push(buf, indent + 2, @@ -454,6 +565,10 @@ static void format_item_asla_subtlvs(struct isis_asla_subtlvs *asla, asla->use_bw); } +#if CONFDATE > 20240916 +CPP_NOTICE("Remove JSON in '-' format") +#endif + /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct sbuf *buf, struct json_object *json, @@ -470,7 +585,11 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "0x%x", exts->adm_group); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "adm-group", aux_buf); + json_object_string_add(json, "admGroup", aux_buf); } else { sbuf_push(buf, indent, "Admin Group: 0x%08x\n", exts->adm_group); @@ -484,8 +603,23 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_EXTEND_ADM_GRP) && admin_group_nb_words(&exts->ext_admin_group) != 0) { - if (!json) { - /* TODO json after fix show database detail json */ + if (json) { + struct json_object *ext_adm_grp_json; + size_t i; + ext_adm_grp_json = json_object_new_object(); + json_object_object_add(json, "extendedAdminGroup", + ext_adm_grp_json); + for (i = 0; + i < admin_group_nb_words(&exts->ext_admin_group); + i++) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%lu", + (unsigned long)i); + json_object_string_addf(ext_adm_grp_json, + cnt_buf, "0x%x", + exts->ext_admin_group + .bitmap.data[i]); + } + } else { sbuf_push(buf, indent, "Ext Admin Group: %s\n", admin_group_string( admin_group_buf, @@ -505,10 +639,17 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } if (IS_SUBTLV(exts, EXT_LLRI)) { if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_int_add(json, "link-local-id", exts->local_llri); json_object_int_add(json, "link-remote-id", exts->remote_llri); + json_object_int_add(json, "linkLocalId", + exts->local_llri); + json_object_int_add(json, "linkRemoteId", + exts->remote_llri); } else { sbuf_push(buf, indent, "Link Local ID: %u\n", exts->local_llri); @@ -520,7 +661,11 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET, &exts->local_addr, aux_buf, sizeof(aux_buf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "local-iface-ip", aux_buf); + json_object_string_add(json, "localIfaceIp", aux_buf); } else sbuf_push(buf, indent, "Local Interface IP Address(es): %pI4\n", @@ -530,8 +675,12 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET, &exts->neigh_addr, aux_buf, sizeof(aux_buf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "remote-iface-ip", aux_buf); + json_object_string_add(json, "remoteIfaceIp", aux_buf); } else sbuf_push(buf, indent, "Remote Interface IP Address(es): %pI4\n", @@ -541,8 +690,12 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET6, &exts->local_addr6, aux_buf, sizeof(aux_buf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "local-iface-ipv6", aux_buf); + json_object_string_add(json, "localIfaceIpv6", aux_buf); } else sbuf_push(buf, indent, "Local Interface IPv6 Address(es): %pI6\n", @@ -552,8 +705,12 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET6, &exts->neigh_addr6, aux_buf, sizeof(aux_buf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "remote-iface-ipv6", aux_buf); + json_object_string_add(json, "remoteIfaceIpv6", aux_buf); } else sbuf_push(buf, indent, "Remote Interface IPv6 Address(es): %pI6\n", @@ -563,8 +720,13 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", exts->max_bw); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "max-bandwith-bytes-sec", aux_buf); + json_object_string_add(json, "maxBandwithBytesSec", + aux_buf); } else sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", @@ -574,8 +736,13 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", exts->max_rsv_bw); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add( json, "max-res-bandwith-bytes-sec", aux_buf); + json_object_string_add(json, "maxResBandwithBytesSec", + aux_buf); } else sbuf_push( buf, indent, @@ -585,6 +752,22 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_UNRSV_BW)) { if (json) { struct json_object *unrsv_json; + + unrsv_json = json_object_new_object(); + json_object_object_add(json, "unrsvBandwithBytesSec", + unrsv_json); + for (int j = 0; j < MAX_CLASS_TYPE; j += 1) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", j); + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + exts->unrsv_bw[j]); + json_object_string_add(unrsv_json, cnt_buf, + aux_buf); + } + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ unrsv_json = json_object_new_object(); json_object_object_add(json, "unrsv-bandwith-bytes-sec", unrsv_json); @@ -595,6 +778,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, json_object_string_add(unrsv_json, cnt_buf, aux_buf); } + /* end old deprecated key format */ } else { sbuf_push(buf, indent, "Unreserved Bandwidth:\n"); for (int j = 0; j < MAX_CLASS_TYPE; j += 2) { @@ -608,7 +792,11 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } if (IS_SUBTLV(exts, EXT_TE_METRIC)) { if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_int_add(json, "te-metric", exts->te_metric); + json_object_int_add(json, "teMetric", exts->te_metric); } else sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", @@ -616,8 +804,13 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } if (IS_SUBTLV(exts, EXT_RMT_AS)) { if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_int_add(json, "inter-as-te-remote-as", exts->remote_as); + json_object_int_add(json, "interAsTeRemoteAs", + exts->remote_as); } else sbuf_push(buf, indent, "Inter-AS TE Remote AS number: %u\n", @@ -627,8 +820,13 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET6, &exts->remote_ip, aux_buf, sizeof(aux_buf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add( json, "inter-as-te-remote-asbr-ip", aux_buf); + json_object_string_add(json, "interAsTeRemoteAsbrIp", + aux_buf); } else sbuf_push(buf, indent, "Inter-AS TE Remote ASBR IP address: %pI4\n", @@ -639,12 +837,23 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { struct json_object *avg_json; avg_json = json_object_new_object(); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_object_add(json, "avg-delay", avg_json); json_object_string_add(avg_json, "delay", IS_ANORMAL(exts->delay) ? "Anomalous" : "Normal"); json_object_int_add(avg_json, "micro-sec", exts->delay); + + avg_json = json_object_new_object(); + json_object_object_add(json, "avgDelay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(exts->delay) + ? "Anomalous" + : "Normal"); + json_object_int_add(avg_json, "microSec", exts->delay); } else sbuf_push(buf, indent, "%s Average Link Delay: %u (micro-sec)\n", @@ -656,6 +865,9 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { struct json_object *avg_json; avg_json = json_object_new_object(); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_object_add(json, "max-min-delay", avg_json); json_object_string_add(avg_json, "delay", IS_ANORMAL(exts->min_delay) @@ -666,6 +878,17 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, exts->max_delay & TE_EXT_MASK); json_object_string_add(avg_json, "micro-sec", aux_buf); + avg_json = json_object_new_object(); + json_object_object_add(json, "maxMinDelay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(exts->min_delay) + ? "Anomalous" + : "Normal"); + snprintfrr(aux_buf, sizeof(aux_buf), "%u / %u", + exts->min_delay & TE_EXT_MASK, + exts->max_delay & TE_EXT_MASK); + json_object_string_add(avg_json, "microSec", aux_buf); + } else sbuf_push( buf, indent, @@ -677,8 +900,13 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } if (IS_SUBTLV(exts, EXT_DELAY_VAR)) { if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_int_add(json, "delay-variation-micro-sec", exts->delay_var & TE_EXT_MASK); + json_object_int_add(json, "delayVariationMicroSec", + exts->delay_var & TE_EXT_MASK); } else sbuf_push(buf, indent, "Delay Variation: %u (micro-sec)\n", @@ -690,6 +918,10 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, (float)((exts->pkt_loss & TE_EXT_MASK) * LOSS_PRECISION)); struct json_object *link_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif link_json = json_object_new_object(); json_object_object_add(json, "link-packet-loss", link_json); @@ -697,8 +929,18 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, IS_ANORMAL(exts->pkt_loss) ? "Anomalous" : "Normal"); + /* typo */ json_object_string_add(link_json, "percentaje", aux_buf); + + link_json = json_object_new_object(); + json_object_object_add(json, "linkPacketLoss", + link_json); + json_object_string_add(link_json, "loss", + IS_ANORMAL(exts->pkt_loss) + ? "Anomalous" + : "Normal"); + json_object_string_add(link_json, "percentage", aux_buf); } else sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n", IS_ANORMAL(exts->pkt_loss) ? "Anomalous" @@ -710,9 +952,15 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", (exts->res_bw)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "unidir-residual-band-bytes-sec", aux_buf); + json_object_string_add(json, + "unidirResidualBandBytesSec", + aux_buf); } else sbuf_push( buf, indent, @@ -723,9 +971,15 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", (exts->ava_bw)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add( json, "unidir-available-band-bytes-sec", aux_buf); + json_object_string_add(json, + "unidirAvailableBandBytesSec", + aux_buf); } else sbuf_push( buf, indent, @@ -739,6 +993,12 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, json_object_string_add(json, "unidir-utilized-band-bytes-sec", aux_buf); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + json_object_string_add(json, + "unidirUtilizedBandBytesSec", + aux_buf); } else sbuf_push( buf, indent, @@ -751,6 +1011,11 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { struct json_object *arr_adj_json, *flags_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ arr_adj_json = json_object_new_array(); json_object_object_add(json, "adj-sid", arr_adj_json); for (adj = (struct isis_adj_sid *)exts->adj_sid.head; @@ -794,6 +1059,44 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, : "0"); json_object_array_add(arr_adj_json, flags_json); } + /* end old deprecated key format */ + + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "adjSid", arr_adj_json); + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; + adj; adj = adj->next) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", + adj->sid); + flags_json = json_object_new_object(); + json_object_int_add(flags_json, "sid", adj->sid); + json_object_int_add(flags_json, "weight", + adj->weight); + json_object_boolean_add(flags_json, "flagF", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? true + : false); + json_object_boolean_add(flags_json, "flagB", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? true + : false); + json_object_boolean_add(flags_json, "flagV", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? true + : false); + json_object_boolean_add(flags_json, "flagL", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? true + : false); + json_object_boolean_add(flags_json, "flagS", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? true + : false); + json_object_boolean_add(flags_json, "flagP", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? true + : false); + json_object_array_add(arr_adj_json, flags_json); + } } else for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj; adj = adj->next) { @@ -826,6 +1129,11 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_lan_adj_sid *lan; if (json) { struct json_object *arr_adj_json, *flags_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ arr_adj_json = json_object_new_array(); json_object_object_add(json, "lan-adj-sid", arr_adj_json); @@ -876,6 +1184,49 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, : "0"); json_object_array_add(arr_adj_json, flags_json); } + /* end old deprecated key format */ + + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "lanAdjSid", arr_adj_json); + for (lan = (struct isis_lan_adj_sid *)exts->adj_sid.head; + lan; lan = lan->next) { + if (((mtid == ISIS_MT_IPV4_UNICAST) && + (lan->family != AF_INET)) || + ((mtid == ISIS_MT_IPV6_UNICAST) && + (lan->family != AF_INET6))) + continue; + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", + lan->sid); + flags_json = json_object_new_object(); + json_object_int_add(flags_json, "sid", lan->sid); + json_object_int_add(flags_json, "weight", + lan->weight); + json_object_boolean_add(flags_json, "flagF", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? true + : false); + json_object_boolean_add(flags_json, "flagB", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? true + : false); + json_object_boolean_add(flags_json, "flagV", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? true + : false); + json_object_boolean_add(flags_json, "flagL", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? true + : false); + json_object_boolean_add(flags_json, "flagS", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? true + : false); + json_object_boolean_add(flags_json, "flagP", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? true + : false); + json_object_array_add(arr_adj_json, flags_json); + } } else for (lan = (struct isis_lan_adj_sid *) @@ -918,6 +1269,11 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { struct json_object *arr_adj_json, *flags_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ arr_adj_json = json_object_new_array(); json_object_object_add(json, "srv6-endx-sid", arr_adj_json); @@ -955,7 +1311,47 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, json_object_array_add(arr_adj_json, flags_json); if (adj->subsubtlvs) isis_format_subsubtlvs(adj->subsubtlvs, - NULL, json, + NULL, + arr_adj_json, + indent + 4); + } + /* end old deprecated key format */ + + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "srv6EndSID", arr_adj_json); + for (adj = (struct isis_srv6_endx_sid_subtlv *) + exts->srv6_endx_sid.head; + adj; adj = adj->next) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", + &adj->sid); + flags_json = json_object_new_object(); + json_object_string_addf(flags_json, "sid", + "%pI6", &adj->sid); + json_object_string_add(flags_json, "algorithm", + sr_algorithm_string( + adj->algorithm)); + json_object_int_add(flags_json, "weight", + adj->weight); + json_object_string_add(flags_json, "behavior", + seg6local_action2str( + adj->behavior)); + json_object_boolean_add( + flags_json, "flagB", + !!(adj->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); + json_object_boolean_add( + flags_json, "flagS", + !!(adj->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); + json_object_boolean_add( + flags_json, "flagP", + !!(adj->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); + json_object_array_add(arr_adj_json, flags_json); + if (adj->subsubtlvs) + isis_format_subsubtlvs(adj->subsubtlvs, + NULL, + arr_adj_json, indent + 4); } } else @@ -989,6 +1385,11 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_srv6_lan_endx_sid_subtlv *lan; if (json) { struct json_object *arr_adj_json, *flags_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ arr_adj_json = json_object_new_array(); json_object_object_add(json, "srv6-lan-endx-sid", arr_adj_json); @@ -1031,7 +1432,53 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, json_object_array_add(arr_adj_json, flags_json); if (lan->subsubtlvs) isis_format_subsubtlvs(lan->subsubtlvs, - NULL, json, + NULL, + arr_adj_json, + indent + 4); + } + /* end old deprecated key format */ + + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "srv6LanEndxSID", + arr_adj_json); + for (lan = (struct isis_srv6_lan_endx_sid_subtlv *) + exts->srv6_lan_endx_sid.head; + lan; lan = lan->next) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", + &lan->sid); + flags_json = json_object_new_object(); + json_object_string_addf(flags_json, "sid", + "%pI6", &lan->sid); + json_object_int_add(flags_json, "weight", + lan->weight); + json_object_string_add(flags_json, "algorithm", + sr_algorithm_string( + lan->algorithm)); + json_object_int_add(flags_json, "weight", + lan->weight); + json_object_string_add(flags_json, "behavior", + seg6local_action2str( + lan->behavior)); + json_object_boolean_add( + flags_json, "flagB", + !!(lan->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); + json_object_boolean_add( + flags_json, "flagS", + !!(lan->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); + json_object_boolean_add( + flags_json, "flagP", + !!(lan->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); + json_object_string_addf(flags_json, + "neighbor-id", "%pSY", + lan->neighbor_id); + json_object_array_add(arr_adj_json, flags_json); + if (lan->subsubtlvs) + isis_format_subsubtlvs(lan->subsubtlvs, + NULL, + arr_adj_json, indent + 4); } } else @@ -1063,7 +1510,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } } for (ALL_LIST_ELEMENTS_RO(exts->aslas, node, asla)) - format_item_asla_subtlvs(asla, buf, indent); + format_item_asla_subtlvs(asla, json, buf, indent); } static void free_item_ext_subtlvs(struct isis_ext_subtlvs *exts) @@ -2127,15 +2574,26 @@ static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i, struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i; if (json) { - struct json_object *sr_json; + struct json_object *sr_json, *array_json; + sr_json = json_object_new_object(); - json_object_object_add(json, "sr", sr_json); + json_object_object_get_ex(json, "sr", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "sr", array_json); + } + json_object_array_add(array_json, sr_json); if (sid->flags & ISIS_PREFIX_SID_VALUE) { json_object_int_add(sr_json, "label", sid->value); } else { json_object_int_add(sr_json, "index", sid->value); } json_object_int_add(sr_json, "alg", sid->algorithm); + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated non boolean json") +#endif + /* old deprecated keys (no booleans) */ json_object_string_add( sr_json, "readvertised", ((sid->flags & ISIS_PREFIX_SID_READVERTISED) ? "yes" @@ -2157,6 +2615,27 @@ static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i, json_object_string_add( sr_json, "local", ((sid->flags & ISIS_PREFIX_SID_LOCAL) ? "yes" : "")); + /* end deprecated keys (no booleans) */ + + struct json_object *flags_json; + + flags_json = json_object_new_object(); + json_object_object_add(sr_json, "flags", flags_json); + + json_object_boolean_add(flags_json, "readvertised", + !!(sid->flags & + ISIS_PREFIX_SID_READVERTISED)); + json_object_boolean_add(flags_json, "node", + !!(sid->flags & ISIS_PREFIX_SID_NODE)); + json_object_boolean_add(flags_json, "noPHP", + !!(sid->flags & ISIS_PREFIX_SID_NO_PHP)); + json_object_boolean_add(flags_json, "explicitNull", + !!(sid->flags & + ISIS_PREFIX_SID_EXPLICIT_NULL)); + json_object_boolean_add(flags_json, "value", + !!(sid->flags & ISIS_PREFIX_SID_VALUE)); + json_object_boolean_add(flags_json, "local", + !!(sid->flags & ISIS_PREFIX_SID_LOCAL)); } else { sbuf_push(buf, indent, "SR Prefix-SID "); @@ -2286,7 +2765,11 @@ static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p, char prefixbuf[PREFIX2STR_BUFFER]; if (json) { prefix2str(p, prefixbuf, sizeof(prefixbuf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "ipv6-src-prefix", prefixbuf); + json_object_string_add(json, "ipv6SrcPrefix", prefixbuf); } else { sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n", prefix2str(p, prefixbuf, sizeof(prefixbuf))); @@ -2388,6 +2871,11 @@ static void format_subsubtlv_srv6_sid_structure( if (json) { struct json_object *sid_struct_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ sid_struct_json = json_object_new_object(); json_object_object_add(json, "srv6-sid-structure", sid_struct_json); @@ -2399,6 +2887,19 @@ static void format_subsubtlv_srv6_sid_structure( sid_struct->func_len); json_object_int_add(sid_struct_json, "arg-len", sid_struct->arg_len); + /* end old deprecated key format */ + + sid_struct_json = json_object_new_object(); + json_object_object_add(json, "srv6SidStructure", + sid_struct_json); + json_object_int_add(sid_struct_json, "locBlockLen", + sid_struct->loc_block_len); + json_object_int_add(sid_struct_json, "locNodeLen", + sid_struct->loc_node_len); + json_object_int_add(sid_struct_json, "funcLen", + sid_struct->func_len); + json_object_int_add(sid_struct_json, "argLen", + sid_struct->arg_len); } else { sbuf_push(buf, indent, "SRv6 SID Structure "); sbuf_push(buf, 0, "Locator Block length: %hhu, ", @@ -2680,6 +3181,11 @@ static void format_item_srv6_end_sid(uint16_t mtid, struct isis_item *i, if (json) { struct json_object *sid_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ sid_json = json_object_new_object(); json_object_object_add(json, "srv6-end-sid", sid_json); json_object_string_add(sid_json, "endpoint-behavior", @@ -2694,6 +3200,21 @@ static void format_item_srv6_end_sid(uint16_t mtid, struct isis_item *i, isis_format_subsubtlvs(sid->subsubtlvs, NULL, subtlvs_json, 0); } + /* end old deprecated key format */ + + sid_json = json_object_new_object(); + json_object_object_add(json, "srv6EndSid", sid_json); + json_object_string_add(sid_json, "endpointBehavior", + seg6local_action2str(sid->behavior)); + json_object_string_addf(sid_json, "sidValue", "%pI6", &sid->sid); + if (sid->subsubtlvs) { + struct json_object *subtlvs_json; + subtlvs_json = json_object_new_object(); + json_object_object_add(sid_json, "subsubtlvs", + subtlvs_json); + isis_format_subsubtlvs(sid->subsubtlvs, NULL, + subtlvs_json, 0); + } } else { sbuf_push(buf, indent, "SRv6 End SID "); sbuf_push(buf, 0, "Endpoint Behavior: %s, ", @@ -2841,9 +3362,13 @@ static void format_item_area_address(uint16_t mtid, struct isis_item *i, memcpy(iso_addr.area_addr, addr->addr, ISO_ADDR_SIZE); iso_addr.addr_len = addr->len; - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_addf(json, "area-addr", "%pIS", &iso_addr); - else + json_object_string_addf(json, "areaAddr", "%pIS", &iso_addr); + } else sbuf_push(buf, indent, "Area Address: %pIS\n", &iso_addr); } @@ -2929,11 +3454,34 @@ static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i, snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pPN", r->id); if (json) { - struct json_object *old_json; + struct json_object *old_json, *array_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ old_json = json_object_new_object(); - json_object_object_add(json, "old-reach-style", old_json); + json_object_object_get_ex(json, "old-reach-style", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "old-reach-style", + array_json); + } + json_object_array_add(array_json, old_json); json_object_string_add(old_json, "is-reach", sys_id); json_object_int_add(old_json, "metric", r->metric); + /* end old deprecated key format */ + + old_json = json_object_new_object(); + json_object_object_get_ex(json, "oldReachStyle", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "oldReachStyle", + array_json); + } + json_object_array_add(array_json, old_json); + json_object_string_add(old_json, "isReach", sys_id); + json_object_int_add(old_json, "metric", r->metric); } else sbuf_push(buf, indent, "IS Reachability: %s (Metric: %hhu)\n", sys_id, r->metric); @@ -3011,9 +3559,13 @@ static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i, char sys_id[ISO_SYSID_STRLEN]; snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pSY", n->mac); - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "lan-neighbor", sys_id); - else + json_object_string_add(json, "lanNeighbor", sys_id); + } else sbuf_push(buf, indent, "LAN Neighbor: %s\n", sys_id); } @@ -3086,6 +3638,9 @@ static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i, char buf[255]; struct json_object *lsp_json; lsp_json = json_object_new_object(); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_object_add(json, "lsp-entry", lsp_json); json_object_string_add(lsp_json, "id", sys_id); snprintfrr(buf,sizeof(buf),"0x%08x",e->seqno); @@ -3093,6 +3648,15 @@ static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i, snprintfrr(buf,sizeof(buf),"0x%04hx",e->checksum); json_object_string_add(lsp_json, "chksum", buf); json_object_int_add(lsp_json, "lifetime", e->checksum); + + lsp_json = json_object_new_object(); + json_object_object_add(json, "lspEntry", lsp_json); + json_object_string_add(lsp_json, "id", sys_id); + snprintfrr(buf, sizeof(buf), "0x%08x", e->seqno); + json_object_string_add(lsp_json, "seq", buf); + snprintfrr(buf, sizeof(buf), "0x%04hx", e->checksum); + json_object_string_add(lsp_json, "chksum", buf); + json_object_int_add(lsp_json, "lifetime", e->checksum); } else sbuf_push( buf, indent, @@ -3173,9 +3737,19 @@ static void format_item_extended_reach(uint16_t mtid, struct isis_item *i, snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pPN", r->id); if (json) { - struct json_object *reach_json; + struct json_object *reach_json, *array_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ reach_json = json_object_new_object(); - json_object_object_add(json, "ext-reach", reach_json); + json_object_object_get_ex(json, "ext-reach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "ext-reach", array_json); + } + json_object_array_add(array_json, reach_json); json_object_string_add( reach_json, "mt-id", (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT"); @@ -3186,7 +3760,29 @@ static void format_item_extended_reach(uint16_t mtid, struct isis_item *i, isis_mtid2str(mtid)); if (r->subtlvs) - format_item_ext_subtlvs(r->subtlvs, NULL, json, + format_item_ext_subtlvs(r->subtlvs, NULL, reach_json, + indent + 2, mtid); + /* end old deprecated key format */ + + reach_json = json_object_new_object(); + json_object_object_get_ex(json, "extReach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "extReach", array_json); + } + json_object_array_add(array_json, reach_json); + json_object_string_add(reach_json, "mtId", + (mtid == ISIS_MT_IPV4_UNICAST) + ? "Extended" + : "MT"); + json_object_string_add(reach_json, "id", sys_id); + json_object_int_add(reach_json, "metric", r->metric); + if (mtid != ISIS_MT_IPV4_UNICAST) + json_object_string_add(reach_json, "mtName", + isis_mtid2str(mtid)); + + if (r->subtlvs) + format_item_ext_subtlvs(r->subtlvs, NULL, reach_json, indent + 2, mtid); } else { sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)", @@ -3314,13 +3910,40 @@ static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i, char prefixbuf[PREFIX2STR_BUFFER]; if (json) { - struct json_object *old_json; + struct json_object *old_json, *array_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ old_json = json_object_new_object(); - json_object_object_add(json, "old-ip-reach-style", old_json); + json_object_object_get_ex(json, "old-ip-reach-style", + &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "old-ip-reach-style", + old_json); + } + json_object_array_add(array_json, old_json); json_object_string_add(old_json, "prefix", prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); json_object_int_add(old_json, "metric", r->metric); - } else + /* end old deprecated key format */ + + old_json = json_object_new_object(); + json_object_object_get_ex(json, "oldIpReachStyle", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "oldIpReachStyle", + old_json); + } + json_object_array_add(array_json, old_json); + json_object_string_add(old_json, "prefix", + prefix2str(&r->prefix, prefixbuf, + sizeof(prefixbuf))); + json_object_int_add(old_json, "metric", r->metric); + return; + } sbuf_push(buf, indent, "IP Reachability: %s (Metric: %hhu)\n", prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric); @@ -3412,6 +4035,10 @@ static void format_tlv_protocols_supported(struct isis_protocols_supported *p, struct json_object *protocol_json; char buf[255]; +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ protocol_json = json_object_new_object(); json_object_object_add(json, "protocols-supported", protocol_json); @@ -3420,6 +4047,16 @@ static void format_tlv_protocols_supported(struct isis_protocols_supported *p, json_object_string_add(protocol_json, buf, nlpid2str(p->protocols[i])); } + + protocol_json = json_object_new_object(); + json_object_object_add(json, "supportedProtocols", + protocol_json); + for (uint8_t i = 0; i < p->count; i++) { + snprintfrr(buf, sizeof(buf), "%d", i); + json_object_string_add(protocol_json, buf, + nlpid2str(p->protocols[i])); + } + /* end old deprecated key format */ } else { sbuf_push(buf, indent, "Protocols Supported: "); for (uint8_t i = 0; i < p->count; i++) { @@ -3635,9 +4272,13 @@ static void format_item_global_ipv6_address(uint16_t mtid, struct isis_item *i, char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf)); - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "global-ipv6", addrbuf); - else + json_object_string_add(json, "globalIpv6", addrbuf); + } else sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n", addrbuf); } @@ -3705,12 +4346,30 @@ static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i, struct isis_mt_router_info *info = (struct isis_mt_router_info *)i; if (json) { - struct json_object *mt_json; + struct json_object *mt_json, *array_json; mt_json = json_object_new_object(); - json_object_object_add(json, "mt", mt_json); + json_object_object_get_ex(json, "mt", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "mt", array_json); + } + json_object_array_add(array_json, mt_json); json_object_int_add(mt_json, "mtid", info->mtid); + json_object_string_add(mt_json, "mt-description", + isis_mtid2str_fake(info->mtid)); + json_object_string_add(mt_json, "mtDescription", + isis_mtid2str(mtid)); + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated non boolean format") +#endif json_object_string_add(mt_json, "overload", info->overload?"true":"false"); json_object_string_add(mt_json, "attached", info->attached?"true":"false"); + + json_object_boolean_add(mt_json, "overloadBit", + !!info->overload); + json_object_boolean_add(mt_json, "attachedbit", + !!info->attached); } else sbuf_push(buf, indent, "MT Router Info: %s%s%s\n", isis_mtid2str_fake(info->mtid), @@ -3793,9 +4452,13 @@ static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf, char addrbuf[INET_ADDRSTRLEN]; inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf)); - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "te-router-id", addrbuf); - else + json_object_string_add(json, "teRouterId", addrbuf); + } else sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf); } @@ -3866,27 +4529,64 @@ static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i, struct json_object *json, int indent) { struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i; + struct json_object *ext_json, *array_json; char prefixbuf[PREFIX2STR_BUFFER]; if (json) { - struct json_object *ext_json; +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ ext_json = json_object_new_object(); - json_object_object_add(json, "ext-ip-reach", ext_json); - json_object_string_add( - json, "mt-id", - (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT"); - json_object_string_add( - json, "ip-reach", - prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); - json_object_int_add(json, "ip-reach-metric", r->metric); - json_object_string_add(json, "down", r->down ? "yes" : ""); + json_object_object_get_ex(json, "ext-ip-reach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "ext-ip-reach", array_json); + } + json_object_array_add(array_json, ext_json); + json_object_string_add(ext_json, "mt-id", + (mtid == ISIS_MT_IPV4_UNICAST) + ? "Extended" + : "MT"); + json_object_string_add(ext_json, "ip-reach", + prefix2str(&r->prefix, prefixbuf, + sizeof(prefixbuf))); + json_object_int_add(ext_json, "ip-reach-metric", r->metric); + json_object_string_add(ext_json, "down", r->down ? "yes" : ""); if (mtid != ISIS_MT_IPV4_UNICAST) - json_object_string_add(json, "mt-name", + json_object_string_add(ext_json, "mt-name", isis_mtid2str(mtid)); if (r->subtlvs) { struct json_object *subtlv_json; subtlv_json = json_object_new_object(); - json_object_object_add(json, "subtlvs", subtlv_json); + json_object_object_add(ext_json, "subtlvs", subtlv_json); + format_subtlvs(r->subtlvs, NULL, subtlv_json, 0); + } + /* end old deprecated key format */ + + ext_json = json_object_new_object(); + json_object_object_get_ex(json, "extIpReach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "extIpReach", array_json); + } + json_object_array_add(array_json, ext_json); + json_object_string_add(ext_json, "mtId", + (mtid == ISIS_MT_IPV4_UNICAST) + ? "Extended" + : "MT"); + json_object_string_add(ext_json, "ipReach", + prefix2str(&r->prefix, prefixbuf, + sizeof(prefixbuf))); + json_object_int_add(ext_json, "ipReachMetric", r->metric); + json_object_boolean_add(ext_json, "down", !!r->down); + if (mtid != ISIS_MT_IPV4_UNICAST) + json_object_string_add(ext_json, "mtName", + isis_mtid2str(mtid)); + if (r->subtlvs) { + struct json_object *subtlv_json; + subtlv_json = json_object_new_object(); + json_object_object_add(ext_json, "subtlvs", subtlv_json); format_subtlvs(r->subtlvs, NULL, subtlv_json, 0); } } else { @@ -4146,9 +4846,13 @@ static void format_tlv_te_router_id_ipv6(const struct in6_addr *id, char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, id, addrbuf, sizeof(addrbuf)); - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "ipv6-te-router-id", addrbuf); - else + json_object_string_add(json, "ipv6TeRouterId", addrbuf); + } else sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf); } @@ -4225,6 +4929,11 @@ static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf, if (json) { struct json_object *spine_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated format */ spine_json = json_object_new_object(); json_object_object_add(json, "spine-leaf-extension", spine_json); @@ -4243,6 +4952,25 @@ static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf, spine_leaf->is_spine ? "yes" : ""); json_object_string_add(spine_json, "flag-backup", spine_leaf->is_backup ? "yes" : ""); + /* end old deprecated format */ + + spine_json = json_object_new_object(); + json_object_object_add(json, "spineLeafExtension", spine_json); + if (spine_leaf->has_tier) { + snprintfrr(aux_buf, sizeof(aux_buf), "%hhu", + spine_leaf->tier); + json_object_string_add(spine_json, "tier", + (spine_leaf->tier == + ISIS_TIER_UNDEFINED) + ? "undefined" + : aux_buf); + } + json_object_boolean_add(spine_json, "flagLeaf", + spine_leaf->is_leaf ? true : false); + json_object_boolean_add(spine_json, "flagSpine", + spine_leaf->is_spine ? true : false); + json_object_boolean_add(spine_json, "flagBackup", + spine_leaf->is_backup ? true : false); } else { sbuf_push(buf, indent, "Spine-Leaf-Extension:\n"); if (spine_leaf->has_tier) { @@ -4384,6 +5112,11 @@ format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj, snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pSY", threeway_adj->neighbor_id); if (json) { struct json_object *three_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ three_json = json_object_new_object(); json_object_object_add(json, "p2p-three-way-adj", three_json); json_object_string_add( @@ -4392,11 +5125,28 @@ format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj, json_object_int_add(three_json, "state", threeway_adj->state); json_object_int_add(three_json, "ext-local-circuit-id", threeway_adj->local_circuit_id); - if (!threeway_adj->neighbor_set) - return; - json_object_string_add(three_json, "neigh-system-id", sys_id); - json_object_int_add(three_json, "neigh-ext-circuit-id", - threeway_adj->neighbor_circuit_id); + if (threeway_adj->neighbor_set) { + json_object_string_add(three_json, "neigh-system-id", + sys_id); + json_object_int_add(three_json, "neigh-ext-circuit-id", + threeway_adj->neighbor_circuit_id); + } + /* end old deprecated key format */ + + three_json = json_object_new_object(); + json_object_object_add(json, "p2pThreeWayAdj", three_json); + json_object_string_add(three_json, "stateName", + isis_threeway_state_name( + threeway_adj->state)); + json_object_int_add(three_json, "state", threeway_adj->state); + json_object_int_add(three_json, "extLocalCircuitId", + threeway_adj->local_circuit_id); + if (threeway_adj->neighbor_set) { + json_object_string_add(three_json, "neighSystemId", + sys_id); + json_object_int_add(three_json, "neighExtCircuitId", + threeway_adj->neighbor_circuit_id); + } } else { sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n"); sbuf_push(buf, indent, " State: %s (%d)\n", @@ -4500,9 +5250,51 @@ static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i, char prefixbuf[PREFIX2STR_BUFFER]; if (json) { - struct json_object *reach_json; + struct json_object *reach_json, *array_json; + + reach_json = json_object_new_object(); + json_object_object_get_ex(json, "ipv6Reach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "ipv6Reach", array_json); + } + json_object_array_add(array_json, reach_json); + json_object_string_add(reach_json, "mtId", + (mtid == ISIS_MT_IPV4_UNICAST) ? "" + : "mt"); + json_object_string_add(reach_json, "prefix", + prefix2str(&r->prefix, prefixbuf, + sizeof(prefixbuf))); + json_object_int_add(reach_json, "metric", r->metric); + json_object_boolean_add(reach_json, "down", + r->down ? true : false); + json_object_boolean_add(reach_json, "external", + r->external ? true : false); + if (mtid != ISIS_MT_IPV4_UNICAST) { + json_object_string_add(reach_json, "mt-name", + isis_mtid2str(mtid)); + json_object_string_add(reach_json, "mtName", + isis_mtid2str(mtid)); + } + if (r->subtlvs) { + struct json_object *subtlvs_json; + subtlvs_json = json_object_new_object(); + json_object_object_add(reach_json, "subtlvs", + subtlvs_json); + format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0); + } + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated JSON key format */ reach_json = json_object_new_object(); - json_object_object_add(json, "ipv6-reach", reach_json); + json_object_object_get_ex(json, "ipv6-reach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "ipv6-reach", array_json); + } + json_object_array_add(array_json, reach_json); json_object_string_add(reach_json, "mt-id", (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "mt"); @@ -4520,9 +5312,11 @@ static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i, if (r->subtlvs) { struct json_object *subtlvs_json; subtlvs_json = json_object_new_object(); - json_object_object_add(json, "subtlvs", subtlvs_json); + json_object_object_add(reach_json, "subtlvs", + subtlvs_json); format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0); } + /* end deprecated key format */ } else { sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s", @@ -4734,6 +5528,11 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, /* Router ID and Flags */ struct json_object *cap_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* deprecated JSON key format */ cap_json = json_object_new_object(); json_object_object_add(json, "router-capability", cap_json); inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf)); @@ -4744,10 +5543,26 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, json_object_string_add( cap_json, "flag-s", router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? "1" : "0"); + /* end deprecated JSON key format */ + + cap_json = json_object_new_object(); + json_object_object_add(json, "routerCapability", cap_json); + inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf)); + json_object_string_add(cap_json, "id", addrbuf); + json_object_boolean_add(cap_json, "flagD", + !!(router_cap->flags & ISIS_ROUTER_CAP_FLAG_D)); + json_object_boolean_add(cap_json, "flagS", + !!(router_cap->flags & ISIS_ROUTER_CAP_FLAG_S)); + /* Segment Routing Global Block as per RFC8667 section #3.1 */ if (router_cap->srgb.range_size != 0) { struct json_object *gb_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* deprecated old key format */ gb_json = json_object_new_object(); json_object_object_add(json, "segment-routing-gb", gb_json); json_object_string_add(gb_json, "ipv4", @@ -4760,23 +5575,52 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, router_cap->srgb.lower_bound); json_object_int_add(gb_json, "global-block-range", router_cap->srgb.range_size); + + gb_json = json_object_new_object(); + json_object_object_add(json, "segmentRoutingGb", gb_json); + json_object_boolean_add(gb_json, "ipv4", + !!IS_SR_IPV4(&router_cap->srgb)); + json_object_boolean_add(gb_json, "ipv6", + !!IS_SR_IPV6(&router_cap->srgb)); + json_object_int_add(gb_json, "globalBlockBase", + router_cap->srgb.lower_bound); + json_object_int_add(gb_json, "globalBlockRange", + router_cap->srgb.range_size); } /* Segment Routing Local Block as per RFC8667 section #3.3 */ if (router_cap->srlb.range_size != 0) { struct json_object *lb_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ lb_json = json_object_new_object(); json_object_object_add(json, "segment-routing-lb", lb_json); json_object_int_add(lb_json, "global-block-base", router_cap->srlb.lower_bound); json_object_int_add(lb_json, "global-block-range", router_cap->srlb.range_size); + /* end old deprecated key format */ + + lb_json = json_object_new_object(); + json_object_object_add(json, "segmentRoutingLb", lb_json); + json_object_int_add(lb_json, "globalBlockBase", + router_cap->srlb.lower_bound); + json_object_int_add(lb_json, "globalBlockRange", + router_cap->srlb.range_size); } /* Segment Routing Algorithms as per RFC8667 section #3.2 */ if (router_cap->algo[0] != SR_ALGORITHM_UNSET) { char buf[255]; struct json_object *alg_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ alg_json = json_object_new_object(); json_object_object_add(json, "segment-routing-algorithm", alg_json); @@ -4788,6 +5632,20 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, ? "SPF" : "Strict SPF"); } + /* end old deprecated key format */ + + alg_json = json_object_new_object(); + json_object_object_add(json, "segmentRoutingAlgorithm", + alg_json); + for (int i = 0; i < SR_ALGORITHM_COUNT; i++) { + if (router_cap->algo[i] != SR_ALGORITHM_UNSET) { + snprintfrr(buf, sizeof(buf), "%d", i); + json_object_string_add(alg_json, buf, + router_cap->algo[i] == 0 + ? "SPF" + : "Strict SPF"); + } + } } /* Segment Routing Node MSD as per RFC8491 section #2 */ @@ -5631,16 +6489,24 @@ static void format_item_auth(uint16_t mtid, struct isis_item *i, struct isis_auth *auth = (struct isis_auth *)i; char obuf[768]; - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "test-auth", "ok"); - else + json_object_string_add(json, "testAuth", "ok"); + } else sbuf_push(buf, indent, "Authentication:\n"); switch (auth->type) { case ISIS_PASSWD_TYPE_CLEARTXT: zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length); - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "auth-pass", obuf); - else + json_object_string_add(json, "authPass", obuf); + } else sbuf_push(buf, indent, " Password: %s\n", obuf); break; case ISIS_PASSWD_TYPE_HMAC_MD5: @@ -5648,15 +6514,23 @@ static void format_item_auth(uint16_t mtid, struct isis_item *i, snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j, "%02hhx", auth->value[j]); } - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "auth-hmac-md5", obuf); - else + json_object_string_add(json, "authHmacMd5", obuf); + } else sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf); break; default: - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_int_add(json, "auth-unknown", auth->type); - else + json_object_int_add(json, "authUnknown", auth->type); + } else sbuf_push(buf, indent, " Unknown (%hhu)\n", auth->type); break; @@ -5771,12 +6645,25 @@ static void format_tlv_purge_originator(struct isis_purge_originator *poi, if (json) { struct json_object *purge_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ purge_json = json_object_new_object(); json_object_object_add(json, "purge_originator", purge_json); json_object_string_add(purge_json, "id", gen_id); if (poi->sender_set) json_object_string_add(purge_json, "rec-from", sen_id); + /* end old deprecated key format */ + + purge_json = json_object_new_object(); + json_object_object_add(json, "purgeOriginator", purge_json); + + json_object_string_add(purge_json, "id", gen_id); + if (poi->sender_set) + json_object_string_add(purge_json, "recFrom", sen_id); } else { sbuf_push(buf, indent, "Purge Originator Identification:\n"); sbuf_push(buf, indent, " Generator: %s\n", gen_id); @@ -6319,6 +7206,11 @@ static void format_item_srv6_locator(uint16_t mtid, struct isis_item *i, if (json) { struct json_object *loc_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old json key format */ loc_json = json_object_new_object(); json_object_object_add(json, "srv6-locator", loc_json); json_object_int_add(loc_json, "mt-id", mtid); @@ -6340,6 +7232,26 @@ static void format_item_srv6_locator(uint16_t mtid, struct isis_item *i, subtlvs_json); format_subtlvs(loc->subtlvs, NULL, subtlvs_json, 0); } + /* old deprecated key format */ + + loc_json = json_object_new_object(); + json_object_object_add(json, "srv6Locator", loc_json); + json_object_int_add(loc_json, "mtId", mtid); + json_object_string_addf(loc_json, "prefix", "%pFX", + &loc->prefix); + json_object_int_add(loc_json, "metric", loc->metric); + json_object_boolean_add(loc_json, "flagD", + !!CHECK_FLAG(loc->flags, + ISIS_TLV_SRV6_LOCATOR_FLAG_D)); + json_object_int_add(loc_json, "algorithm", loc->algorithm); + json_object_string_add(loc_json, "MTName", isis_mtid2str(mtid)); + if (loc->subtlvs) { + struct json_object *subtlvs_json; + subtlvs_json = json_object_new_object(); + json_object_object_add(loc_json, "subtlvs", + subtlvs_json); + format_subtlvs(loc->subtlvs, NULL, subtlvs_json, 0); + } } else { sbuf_push(buf, indent, "SRv6 Locator: %pFX (Metric: %u)%s", &loc->prefix, loc->metric, @@ -6623,9 +7535,13 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, struct json_ob &tlvs->area_addresses, buf, json, indent); if (tlvs->mt_router_info_empty) { - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "mt-router-info", "none"); - else + json_object_object_add(json, "mtRouterInfo", NULL); + } else sbuf_push(buf, indent, "MT Router Info: None\n"); } else { format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO, diff --git a/isisd/isisd.c b/isisd/isisd.c index 382a6aa3b..982df0839 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -2649,6 +2649,7 @@ void show_isis_database_lspdb_json(struct json_object *json, struct lspdb_head *lspdb, const char *sysid_str, int ui_level) { + struct json_object *array_json, *lsp_json; struct isis_lsp *lsp; int lsp_count; struct json_object *lsp_arr_json; @@ -2661,11 +2662,19 @@ void show_isis_database_lspdb_json(struct json_object *json, } if (lsp) { + json_object_object_get_ex(json, "lsps", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "lsps", array_json); + } + lsp_json = json_object_new_object(); + json_object_array_add(array_json, lsp_json); + if (ui_level == ISIS_UI_LEVEL_DETAIL) - lsp_print_detail(lsp, NULL, json, + lsp_print_detail(lsp, NULL, lsp_json, area->dynhostname, area->isis); else - lsp_print_json(lsp, json, area->dynhostname, + lsp_print_json(lsp, lsp_json, area->dynhostname, area->isis); } else if (sysid_str == NULL) { lsp_arr_json = json_object_new_array(); @@ -2739,6 +2748,8 @@ static void show_isis_database_json(struct json_object *json, const char *sysid_ json_object_object_add(area_json,"area",tag_area_json); json_object_object_add(area_json,"levels",arr_json); for (level = 0; level < ISIS_LEVELS; level++) { + if (lspdb_count(&area->lspdb[level]) == 0) + continue; lsp_json = json_object_new_object(); show_isis_database_lspdb_json(lsp_json, area, level, &area->lspdb[level], diff --git a/lib/ipaddr.h b/lib/ipaddr.h index c86e38c86..888955fba 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -40,8 +40,9 @@ struct ipaddr { #define IS_IPADDR_V4(p) ((p)->ipa_type == IPADDR_V4) #define IS_IPADDR_V6(p) ((p)->ipa_type == IPADDR_V6) -#define SET_IPADDR_V4(p) (p)->ipa_type = IPADDR_V4 -#define SET_IPADDR_V6(p) (p)->ipa_type = IPADDR_V6 +#define SET_IPADDR_NONE(p) ((p)->ipa_type = IPADDR_NONE) +#define SET_IPADDR_V4(p) ((p)->ipa_type = IPADDR_V4) +#define SET_IPADDR_V6(p) ((p)->ipa_type = IPADDR_V6) #define IPADDRSZ(p) \ (IS_IPADDR_V4((p)) ? sizeof(struct in_addr) : sizeof(struct in6_addr)) @@ -165,9 +166,17 @@ static inline bool ipaddr_is_zero(const struct ipaddr *ip) return true; } +static inline bool ipaddr_is_same(const struct ipaddr *ip1, + const struct ipaddr *ip2) +{ + return ipaddr_cmp(ip1, ip2) == 0; +} + +/* clang-format off */ #ifdef _FRR_ATTRIBUTE_PRINTFRR #pragma FRR printfrr_ext "%pIA" (struct ipaddr *) #endif +/* clang-format on */ #ifdef __cplusplus } diff --git a/lib/prefix.c b/lib/prefix.c index f342c4c1d..2485c3e61 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1124,6 +1124,15 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) return str; } +void prefix_mcast_ip_dump(const char *onfail, const struct ipaddr *addr, + char *buf, int buf_size) +{ + if (ipaddr_is_zero(addr)) + strlcpy(buf, "*", buf_size); + else + (void)snprintfrr(buf, buf_size, "%pIA", addr); +} + static ssize_t prefixhost2str(struct fbuf *fbuf, union prefixconstptr pu) { const struct prefix *p = pu.p; @@ -1166,7 +1175,7 @@ const char *prefix_sg2str(const struct prefix_sg *sg, char *sg_str) char src_str[INET_ADDRSTRLEN]; char grp_str[INET_ADDRSTRLEN]; - prefix_mcast_inet4_dump("<src?>", sg->src, src_str, sizeof(src_str)); + prefix_mcast_ip_dump("<src?>", &sg->src, src_str, sizeof(src_str)); prefix_mcast_inet4_dump("<grp?>", sg->grp, grp_str, sizeof(grp_str)); snprintf(sg_str, PREFIX_SG_STR_LEN, "(%s,%s)", src_str, grp_str); @@ -1637,10 +1646,10 @@ static ssize_t printfrr_psg(struct fbuf *buf, struct printfrr_eargs *ea, if (!sg) return bputs(buf, "(null)"); - if (sg->src.s_addr == INADDR_ANY) + if (ipaddr_is_zero(&sg->src)) ret += bputs(buf, "(*,"); else - ret += bprintfrr(buf, "(%pI4,", &sg->src); + ret += bprintfrr(buf, "(%pIA,", &sg->src); if (sg->grp.s_addr == INADDR_ANY) ret += bputs(buf, "*)"); diff --git a/lib/prefix.h b/lib/prefix.h index 14f269593..2d679d062 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -52,10 +52,10 @@ typedef enum { /* Maximum number of VTEPs per-ES - * XXX - temporary limit for allocating strings etc. */ -#define ES_VTEP_MAX_CNT 10 -#define ES_VTEP_LIST_STR_SZ (ES_VTEP_MAX_CNT * 16) +#define ES_VTEP_MAX_CNT 10 +#define ES_VTEP_LIST_STR_SZ (ES_VTEP_MAX_CNT * IPADDR_STRING_SIZE) -#define ETHER_ADDR_STRLEN (3*ETH_ALEN) +#define ETHER_ADDR_STRLEN (3 * ETH_ALEN) /* * there isn't a portable ethernet address type. We define our * own to simplify internal handling @@ -282,7 +282,7 @@ struct prefix_fs { struct prefix_sg { uint8_t family; uint16_t prefixlen; - struct in_addr src __attribute__((aligned(8))); + struct ipaddr src __attribute__((aligned(8))); struct in_addr grp; }; @@ -415,6 +415,8 @@ extern int str2prefix(const char *string, struct prefix *prefix); #define PREFIX2STR_BUFFER PREFIX_STRLEN +extern void prefix_mcast_ip_dump(const char *onfail, const struct ipaddr *addr, + char *buf, int buf_size); extern void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size); extern const char *prefix_sg2str(const struct prefix_sg *sg, char *str); diff --git a/lib/stream.c b/lib/stream.c index fa20ebdbe..bb90f3b94 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -921,7 +921,7 @@ int stream_put_in_addr(struct stream *s, const struct in_addr *addr) return sizeof(uint32_t); } -bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip) +bool stream_put_ipaddr(struct stream *s, const struct ipaddr *ip) { stream_putw(s, ip->ipa_type); diff --git a/lib/stream.h b/lib/stream.h index 61eaa46c9..e48cedc61 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -175,7 +175,7 @@ extern int stream_putq(struct stream *, uint64_t); extern int stream_putq_at(struct stream *, size_t, uint64_t); extern int stream_put_ipv4(struct stream *, uint32_t); extern int stream_put_in_addr(struct stream *s, const struct in_addr *addr); -extern bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip); +extern bool stream_put_ipaddr(struct stream *s, const struct ipaddr *ip); extern int stream_put_in_addr_at(struct stream *s, size_t putp, const struct in_addr *addr); extern int stream_put_in6_addr_at(struct stream *s, size_t putp, @@ -390,6 +390,21 @@ int vty_json_no_pretty(struct vty *vty, struct json_object *json) return vty_json_helper(vty, json, JSON_C_TO_STRING_NOSLASHESCAPE); } + +void vty_json_key(struct vty *vty, const char *key, bool *first_key) +{ + vty_out(vty, "%s\"%s\":", *first_key ? "{" : ",", key); + *first_key = false; +} + +void vty_json_close(struct vty *vty, bool first_key) +{ + if (first_key) + /* JSON was not opened */ + vty_out(vty, "{"); + vty_out(vty, "}\n"); +} + void vty_json_empty(struct vty *vty, struct json_object *json) { json_object *jsonobj = json; @@ -378,6 +378,8 @@ extern bool vty_set_include(struct vty *vty, const char *regexp); */ extern int vty_json(struct vty *vty, struct json_object *json); extern int vty_json_no_pretty(struct vty *vty, struct json_object *json); +void vty_json_key(struct vty *vty, const char *key, bool *first_key); +void vty_json_close(struct vty *vty, bool first_key); extern void vty_json_empty(struct vty *vty, struct json_object *json); /* post fd to be passed to the vtysh client * fd is owned by the VTY code after this and will be closed when done diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index 5d492249d..adb8be36d 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -83,13 +83,13 @@ static void nhrp_request_stop(void) debugf(NHRP_DEBUG_COMMON, "Exiting..."); frr_early_fini(); - vrf_terminate(); + nhrp_shortcut_terminate(); nhrp_nhs_terminate(); nhrp_zebra_terminate(); vici_terminate(); evmgr_terminate(); + vrf_terminate(); nhrp_vc_terminate(); - nhrp_shortcut_terminate(); debugf(NHRP_DEBUG_COMMON, "Done."); diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c index 04dad2aea..e83ce7f58 100644 --- a/nhrpd/nhrp_shortcut.c +++ b/nhrpd/nhrp_shortcut.c @@ -19,7 +19,8 @@ DEFINE_MTYPE_STATIC(NHRPD, NHRP_SHORTCUT, "NHRP shortcut"); static struct route_table *shortcut_rib[AFI_MAX]; static void nhrp_shortcut_do_purge(struct event *t); -static void nhrp_shortcut_delete(struct nhrp_shortcut *s); +static void nhrp_shortcut_delete(struct nhrp_shortcut *s, + void *arg __attribute__((__unused__))); static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s); static void nhrp_shortcut_check_use(struct nhrp_shortcut *s) @@ -72,7 +73,7 @@ static void nhrp_shortcut_cache_notify(struct notifier_block *n, s->route_installed = 0; } if (cmd == NOTIFY_CACHE_DELETE) - nhrp_shortcut_delete(s); + nhrp_shortcut_delete(s, NULL); break; } } @@ -132,7 +133,8 @@ static void nhrp_shortcut_update_binding(struct nhrp_shortcut *s, } } -static void nhrp_shortcut_delete(struct nhrp_shortcut *s) +static void nhrp_shortcut_delete(struct nhrp_shortcut *s, + void *arg __attribute__((__unused__))) { struct route_node *rn; afi_t afi = family2afi(PREFIX_FAMILY(s->p)); @@ -158,7 +160,7 @@ static void nhrp_shortcut_do_purge(struct event *t) { struct nhrp_shortcut *s = EVENT_ARG(t); s->t_timer = NULL; - nhrp_shortcut_delete(s); + nhrp_shortcut_delete(s, NULL); } static struct nhrp_shortcut *nhrp_shortcut_get(struct prefix *p) @@ -469,6 +471,8 @@ void nhrp_shortcut_init(void) void nhrp_shortcut_terminate(void) { + nhrp_shortcut_foreach(AFI_IP, nhrp_shortcut_delete, NULL); + nhrp_shortcut_foreach(AFI_IP6, nhrp_shortcut_delete, NULL); route_table_finish(shortcut_rib[AFI_IP]); route_table_finish(shortcut_rib[AFI_IP6]); } diff --git a/ospf6d/ospf6_auth_trailer.c b/ospf6d/ospf6_auth_trailer.c index 8d9eff409..860d27379 100644 --- a/ospf6d/ospf6_auth_trailer.c +++ b/ospf6d/ospf6_auth_trailer.c @@ -517,6 +517,15 @@ int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, } } else if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_MANUAL_KEY)) { + if (oi->at_data.key_id != ntohs(ospf6_auth->id)) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s]: Auth SA ID mismatch for %s, received %u vs configured %u", + oi->interface->name, + ospf6_message_type(oh->type), + ntohs(ospf6_auth->id), + oi->at_data.key_id); + return OSPF6_AUTH_VALIDATE_FAILURE; + } auth_str = oi->at_data.auth_key; hash_algo = oi->at_data.hash_algo; } diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index cebdda9e5..44a210403 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -23,6 +23,7 @@ #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_network.h" +#include "bgpd/bgp_label.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" @@ -1075,6 +1076,7 @@ int main(void) vrf_init(NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); bgp_attr_init(); + bgp_labels_init(); if (fileno(stdout) >= 0) tty = isatty(fileno(stdout)); diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index 12c2f1103..767c41cfe 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -18,6 +18,7 @@ #include "bgpd/bgp_vty.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_network.h" +#include "bgpd/bgp_label.h" #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -1374,6 +1375,7 @@ static void bgp_shutdown(void) bgp_route_finish(); bgp_route_map_terminate(); bgp_attr_finish(); + bgp_labels_finish(); bgp_pthreads_finish(); access_list_add_hook(NULL); access_list_delete_hook(NULL); diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c index cefa07ec7..a81ebcdbc 100644 --- a/tests/lib/test_printfrr.c +++ b/tests/lib/test_printfrr.c @@ -230,19 +230,25 @@ int main(int argc, char **argv) printchk("02:ca:fe:f0:0d:1e", "%pFXh", &pfx); struct prefix_sg sg; - sg.src.s_addr = INADDR_ANY; + SET_IPADDR_V4(&sg.src); + sg.src.ipaddr_v4.s_addr = INADDR_ANY; sg.grp.s_addr = INADDR_ANY; printchk("(*,*)", "%pPSG4", &sg); - inet_aton("192.168.1.2", &sg.src); + inet_aton("192.168.1.2", &sg.src.ipaddr_v4); printchk("(192.168.1.2,*)", "%pPSG4", &sg); inet_aton("224.1.2.3", &sg.grp); printchk("(192.168.1.2,224.1.2.3)", "%pPSG4", &sg); - sg.src.s_addr = INADDR_ANY; + SET_IPADDR_NONE(&sg.src); + sg.src.ipaddr_v4.s_addr = INADDR_ANY; printchk("(*,224.1.2.3)", "%pPSG4", &sg); + SET_IPADDR_V6(&sg.src); + inet_pton(AF_INET6, "1:2:3:4::5", &sg.src.ipaddr_v6); + printchk("(1:2:3:4::5,224.1.2.3)", "%pPSG4", &sg); + uint8_t randhex[] = { 0x12, 0x34, 0x00, 0xca, 0xfe, 0x00, 0xaa, 0x55 }; FMT_NSTD(printchk("12 34 00 ca fe 00 aa 55", "%.8pHX", randhex)); diff --git a/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_vpn_route_1723101.json b/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_vpn_route_1723101.json new file mode 100644 index 000000000..2ed76314b --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_vpn_route_1723101.json @@ -0,0 +1,50 @@ +{ + "444:1":{ + "prefix":"172.31.0.1/32", + "advertisedTo":{ + "192.168.0.1":{ + } + }, + "paths":[ + { + "aspath":{ + "string":"65500", + "segments":[ + { + "type":"as-sequence", + "list":[ + 65500 + ] + } + ], + "length":1 + }, + "origin":"incomplete", + "metric":0, + "valid":true, + "bestpath":{ + "overall":true, + "selectionReason":"First path received" + }, + "extendedCommunity":{ + "string":"RT:52:101" + }, + "remoteLabel":102, + "nexthops":[ + { + "ip":"192.168.0.1", + "afi":"ipv4", + "metric":0, + "accessible":true, + "used":true + } + ], + "peer":{ + "peerId":"192.168.0.1", + "routerId":"192.0.2.1", + "type":"external" + } + } + ] + } +} diff --git a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py index 8b2e674aa..189824311 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py +++ b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py @@ -228,7 +228,12 @@ def test_export_route_target_empty(): router = tgen.gears["r1"] logger.info("r1, Remove 'rt vpn export 52:100' command") router.vtysh_cmd( - "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nno rt vpn export 52:100\n" + """ +configure terminal +router bgp 65500 vrf vrf1 + address-family ipv4 unicast + no rt vpn export 52:100 +""" ) prefix = "172.31.0.1/32" @@ -254,10 +259,15 @@ def test_export_route_target_with_routemap_with_export_route_target(): router = tgen.gears["r1"] logger.info("r1, configuring route target with route-map with export route target") router.vtysh_cmd( - "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nroute-map vpn export rmap\n" - ) - router.vtysh_cmd( - "configure terminal\nroute-map rmap permit 1\nset extcommunity rt 52:100\n" + """ +configure terminal +router bgp 65500 vrf vrf1 + address-family ipv4 unicast + route-map vpn export RMAP +! +route-map RMAP permit 1 + set extcommunity rt 52:100 +""" ) prefix = "172.31.0.1/32" @@ -283,7 +293,11 @@ def test_export_route_target_with_routemap_without_export_route_target(): router = tgen.gears["r1"] logger.info("r1, removing 'set extcommunity rt 52:100.") router.vtysh_cmd( - "configure terminal\nroute-map rmap permit 1\nno set extcommunity rt\n" + """ +configure terminal +route-map RMAP permit 1 + no set extcommunity rt +""" ) prefix = "172.31.0.1/32" @@ -309,7 +323,12 @@ def test_export_route_target_with_default_command(): router = tgen.gears["r1"] logger.info("r1, detach route-map and re-add route target vpn export") router.vtysh_cmd( - "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nrt vpn export 52:100\n" + """ +configure terminal +router bgp 65500 vrf vrf1 + address-family ipv4 unicast + rt vpn export 52:100 +""" ) prefix = "172.31.0.1/32" logger.info("r1, check that exported prefix {} is added back".format(prefix)) @@ -334,9 +353,14 @@ def test_export_suppress_route_target_with_route_map_command(): router = tgen.gears["r1"] logger.info("r1, add an extended comm-list to delete 52:100") - router.vtysh_cmd("configure terminal\nbgp extcommunity-list 1 permit rt 52:100\n") router.vtysh_cmd( - "configure terminal\nroute-map rmap permit 1\nset extended-comm-list 1 delete\n" + """ +configure terminal +bgp extcommunity-list 1 permit rt 52:100 +! +route-map RMAP permit 1 + set extended-comm-list 1 delete +""" ) prefix = "172.31.0.1/32" logger.info("r1, check that exported prefix {} is removed".format(prefix)) @@ -361,7 +385,11 @@ def test_export_add_route_target_to_route_map_command(): router = tgen.gears["r1"] logger.info("r1, add an additional set extcommunity 52:101") router.vtysh_cmd( - "configure terminal\nroute-map rmap permit 1\nset extcommunity rt 52:101\n" + """ +configure terminal +route-map RMAP permit 1 + set extcommunity rt 52:101 +""" ) prefix = "172.31.0.1/32" logger.info("r1, check that exported prefix {} is added back".format(prefix)) @@ -376,6 +404,126 @@ def test_export_add_route_target_to_route_map_command(): assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) +def test_adj_rib_out_label_change(): + """ + Check that changing the VPN label on r1 + is propagated on r2 + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Changing VPN label value to export") + dump = tgen.gears["r1"].vtysh_cmd( + """ +configure terminal + router bgp 65500 vrf vrf1 + address-family ipv4 unicast + label vpn export 102 +""" + ) + # Check BGP IPv4 route entry for 172.31.0.1 on r1 + logger.info("Checking BGP IPv4 routes for convergence on r1") + router = tgen.gears["r2"] + json_file = "{}/{}/bgp_ipv4_vpn_route_1723101.json".format(CWD, router.name) + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, + router, + "show bgp ipv4 vpn 172.31.0.1/32 json", + expected, + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + +def test_adj_rib_in_label_change(): + """ + Check that syncinig with ADJ-RIB-in on r2 + permits restoring the initial label value + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Enable soft-reconfiguration inbound on r2") + + r2 = tgen.gears["r2"] + r2.vtysh_cmd( + """ +configure terminal +router bgp 65501 + address-family ipv4 vpn + neighbor 192.168.0.1 soft-reconfiguration inbound +""" + ) + + logger.info("Applying a deny-all route-map to input on r2") + r2.vtysh_cmd( + """ +configure terminal +route-map DENY-ALL deny 1 +! +router bgp 65501 + address-family ipv4 vpn + neighbor 192.168.0.1 route-map DENY-ALL in +""" + ) + + # check that 172.31.0.1 should not be present + logger.info("Check that received update 172.31.0.1 is not present") + + expected = {} + test_func = partial( + topotest.router_json_cmp, + r2, + "show bgp ipv4 vpn 172.31.0.1/32 json", + expected, + exact=True, + ) + success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert success, "r2, vpnv4 update 172.31.0.1 still present" + + +def test_adj_rib_in_label_change_remove_rmap(): + """ + Check that syncinig with ADJ-RIB-in on r2 + permits restoring the initial label value + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Removing the deny-all route-map from input on r2") + + r2 = tgen.gears["r2"] + r2.vtysh_cmd( + """ +configure terminal +router bgp 65501 + address-family ipv4 vpn + no neighbor 192.168.0.1 route-map DENY-ALL in +""" + ) + # Check BGP IPv4 route entry for 172.31.0.1 on r1 + logger.info( + "Checking that 172.31.0.1 BGP update is present and has valid label on r2" + ) + json_file = "{}/{}/bgp_ipv4_vpn_route_1723101.json".format(CWD, r2.name) + + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, + r2, + "show bgp ipv4 vpn 172.31.0.1/32 json", + expected, + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(r2.name) + assert result is None, assertmsg + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py index 3938a966e..6d4b436bc 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py +++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py @@ -338,6 +338,21 @@ interface EVA result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + """ + Check that "show ip route vrf DONNA json" and the JSON at key "DONNA" of + "show ip route vrf all json" gives the same result. + """ + + def check_vrf_table(router, vrf, expect): + output = router.vtysh_cmd("show ip route vrf all json", isjson=True) + vrf_table = output.get(vrf, {}) + + return topotest.json_cmp(vrf_table, expect) + + test_func = partial(check_vrf_table, r1, "DONNA", expect) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + def test_vrf_route_leak_donna_after_eva_up(): logger.info("Ensure that route states change after EVA interface goes up") diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index 532e70859..b388f52bd 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -685,7 +685,7 @@ def _check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected): ) database_json = json.loads(isis_database_output) - att_p_ol = database_json["areas"][0]["levels"][1]["att-p-ol"] + att_p_ol = database_json["areas"][0]["levels"][1]["lsps"][0]["attPOl"] if att_p_ol == att_p_ol_expected: return True return "{} peer with expected att_p_ol {} got {} ".format( diff --git a/tests/topotests/munet/__main__.py b/tests/topotests/munet/__main__.py index e50fea691..145eb265a 100644 --- a/tests/topotests/munet/__main__.py +++ b/tests/topotests/munet/__main__.py @@ -19,6 +19,7 @@ from . import parser from .args import add_launch_args from .base import get_event_loop from .cleanup import cleanup_previous +from .cleanup import is_running_in_rundir from .compat import PytestConfig @@ -139,10 +140,11 @@ def main(*args): eap = ap.add_argument_group(title="Uncommon", description="uncommonly used options") eap.add_argument("--log-config", help="logging config file (yaml, toml, json, ...)") eap.add_argument( - "--no-kill", + "--kill", action="store_true", - help="Do not kill previous running processes", + help="Kill previous running processes using same rundir and exit", ) + eap.add_argument("--no-kill", action="store_true", help=argparse.SUPPRESS) eap.add_argument( "--no-cli", action="store_true", help="Do not run the interactive CLI" ) @@ -157,7 +159,18 @@ def main(*args): sys.exit(0) rundir = args.rundir if args.rundir else "/tmp/munet" + rundir = os.path.abspath(rundir) args.rundir = rundir + + if args.kill: + logging.info("Killing any previous run using rundir: {rundir}") + cleanup_previous(args.rundir) + elif is_running_in_rundir(args.rundir): + logging.fatal( + "Munet processes using rundir: %s, use `--kill` to cleanup first", rundir + ) + return 1 + if args.cleanup: if os.path.exists(rundir): if not os.path.exists(f"{rundir}/config.json"): @@ -169,6 +182,10 @@ def main(*args): sys.exit(1) else: subprocess.run(["/usr/bin/rm", "-rf", rundir], check=True) + + if args.kill: + return 0 + subprocess.run(f"mkdir -p {rundir} && chmod 755 {rundir}", check=True, shell=True) os.environ["MUNET_RUNDIR"] = rundir @@ -183,9 +200,6 @@ def main(*args): logger.critical("No nodes defined in config file") return 1 - if not args.no_kill: - cleanup_previous() - loop = None status = 4 try: diff --git a/tests/topotests/munet/base.py b/tests/topotests/munet/base.py index a4811f179..e77eb15dc 100644 --- a/tests/topotests/munet/base.py +++ b/tests/topotests/munet/base.py @@ -469,6 +469,8 @@ class Commander: # pylint: disable=R0904 env = {**(kwargs["env"] if "env" in kwargs else os.environ)} if "MUNET_NODENAME" not in env: env["MUNET_NODENAME"] = self.name + if "MUNET_PID" not in env and "MUNET_PID" in os.environ: + env["MUNET_PID"] = os.environ["MUNET_PID"] kwargs["env"] = env defaults.update(kwargs) @@ -780,8 +782,14 @@ class Commander: # pylint: disable=R0904 ps1 = re.escape(ps1) ps2 = re.escape(ps2) - - extra = "PAGER=cat; export PAGER; TERM=dumb; unset HISTFILE; set +o emacs +o vi" + extra = [ + "TERM=dumb", + "set +o emacs", + "set +o vi", + "unset HISTFILE", + "PAGER=cat", + "export PAGER", + ] pchg = "PS1='{0}' PS2='{1}' PROMPT_COMMAND=''\n".format(ps1p, ps2p) p.send(pchg) return ShellWrapper(p, ps1, ps2, extra_init_cmd=extra, will_echo=will_echo) @@ -934,15 +942,25 @@ class Commander: # pylint: disable=R0904 def _cmd_status(self, cmds, raises=False, warn=True, stdin=None, **kwargs): """Execute a command.""" + timeout = None + if "timeout" in kwargs: + timeout = kwargs["timeout"] + del kwargs["timeout"] + pinput, stdin = Commander._cmd_status_input(stdin) p, actual_cmd = self._popen("cmd_status", cmds, stdin=stdin, **kwargs) - o, e = p.communicate(pinput) + o, e = p.communicate(pinput, timeout=timeout) return self._cmd_status_finish(p, cmds, actual_cmd, o, e, raises, warn) async def _async_cmd_status( self, cmds, raises=False, warn=True, stdin=None, text=None, **kwargs ): """Execute a command.""" + timeout = None + if "timeout" in kwargs: + timeout = kwargs["timeout"] + del kwargs["timeout"] + pinput, stdin = Commander._cmd_status_input(stdin) p, actual_cmd = await self._async_popen( "async_cmd_status", cmds, stdin=stdin, **kwargs @@ -955,7 +973,12 @@ class Commander: # pylint: disable=R0904 if encoding is not None and isinstance(pinput, str): pinput = pinput.encode(encoding) - o, e = await p.communicate(pinput) + try: + o, e = await asyncio.wait_for(p.communicate(), timeout=timeout) + except (TimeoutError, asyncio.TimeoutError) as error: + raise subprocess.TimeoutExpired( + cmd=actual_cmd, timeout=timeout, output=None, stderr=None + ) from error if encoding is not None: o = o.decode(encoding) if o is not None else o e = e.decode(encoding) if e is not None else e @@ -1220,7 +1243,13 @@ class Commander: # pylint: disable=R0904 if self.is_vm and self.use_ssh and not ns_only: # pylint: disable=E1101 if isinstance(cmd, str): cmd = shlex.split(cmd) - cmd = ["/usr/bin/env", f"MUNET_NODENAME={self.name}"] + cmd + cmd = [ + "/usr/bin/env", + f"MUNET_NODENAME={self.name}", + ] + if "MUNET_PID" in os.environ: + cmd.append(f"MUNET_PID={os.environ.get('MUNET_PID')}") + cmd += cmd # get the ssh cmd cmd = self._get_pre_cmd(False, True, ns_only=ns_only) + [shlex.join(cmd)] @@ -1240,6 +1269,8 @@ class Commander: # pylint: disable=R0904 envvars = f"MUNET_NODENAME={self.name} NODENAME={self.name}" if hasattr(self, "rundir"): envvars += f" RUNDIR={self.rundir}" + if "MUNET_PID" in os.environ: + envvars += f" MUNET_PID={os.environ.get('MUNET_PID')}" if hasattr(self.unet, "config_dirname") and self.unet.config_dirname: envvars += f" CONFIGDIR={self.unet.config_dirname}" elif "CONFIGDIR" in os.environ: @@ -2520,7 +2551,7 @@ class Bridge(SharedNamespace, InterfaceMixin): self.logger.debug("Bridge: Creating") - assert len(self.name) <= 16 # Make sure fits in IFNAMSIZE + # assert len(self.name) <= 16 # Make sure fits in IFNAMSIZE self.cmd_raises(f"ip link delete {name} || true") self.cmd_raises(f"ip link add {name} type bridge") if self.mtu: @@ -2644,10 +2675,6 @@ class BaseMunet(LinuxNamespace): self.cfgopt = munet_config.ConfigOptionsProxy(pytestconfig) - super().__init__( - name, mount=True, net=isolated, uts=isolated, pid=pid, unet=None, **kwargs - ) - # This allows us to cleanup any leftover running munet's if "MUNET_PID" in os.environ: if os.environ["MUNET_PID"] != str(our_pid): @@ -2658,6 +2685,10 @@ class BaseMunet(LinuxNamespace): ) os.environ["MUNET_PID"] = str(our_pid) + super().__init__( + name, mount=True, net=isolated, uts=isolated, pid=pid, unet=None, **kwargs + ) + # this is for testing purposes do not use if not BaseMunet.g_unet: BaseMunet.g_unet = self @@ -2765,7 +2796,7 @@ class BaseMunet(LinuxNamespace): self.logger.error('"%s" len %s > 16', nsif1, len(nsif1)) elif len(nsif2) > 16: self.logger.error('"%s" len %s > 16', nsif2, len(nsif2)) - assert len(nsif1) <= 16 and len(nsif2) <= 16 # Make sure fits in IFNAMSIZE + assert len(nsif1) < 16 and len(nsif2) < 16 # Make sure fits in IFNAMSIZE self.logger.debug("%s: Creating veth pair for link %s", self, lname) @@ -2993,8 +3024,11 @@ if True: # pylint: disable=using-constant-test self._expectf = self.child.expect if extra_init_cmd: - self.expect_prompt() - self.child.sendline(extra_init_cmd) + if isinstance(extra_init_cmd, str): + extra_init_cmd = [extra_init_cmd] + for ecmd in extra_init_cmd: + self.expect_prompt() + self.child.sendline(ecmd) self.expect_prompt() def expect_prompt(self, timeout=-1): diff --git a/tests/topotests/munet/cleanup.py b/tests/topotests/munet/cleanup.py index c641cda68..12ea6e284 100644 --- a/tests/topotests/munet/cleanup.py +++ b/tests/topotests/munet/cleanup.py @@ -59,25 +59,33 @@ def _get_our_pids(): return {} -def _get_other_pids(): - piddict = get_pids_with_env("MUNET_PID") - unet_pids = {d["MUNET_PID"] for d in piddict.values()} +def _get_other_pids(rundir): + if rundir: + # get only munet pids using the given rundir + piddict = get_pids_with_env("MUNET_RUNDIR", str(rundir)) + else: + # Get all munet pids + piddict = get_pids_with_env("MUNET_PID") + unet_pids = {d["MUNET_PID"] for d in piddict.values() if "MUNET_PID" in d} pids_by_upid = {p: set() for p in unet_pids} for pid, envdict in piddict.items(): + if "MUNET_PID" not in envdict: + continue unet_pid = envdict["MUNET_PID"] pids_by_upid[unet_pid].add(pid) # Filter out any child pid sets whos munet pid is still running return {x: y for x, y in pids_by_upid.items() if x not in y} -def _get_pids_by_upid(ours): +def _get_pids_by_upid(ours, rundir): if ours: + assert rundir is None return _get_our_pids() - return _get_other_pids() + return _get_other_pids(rundir) -def _cleanup_pids(ours): - pids_by_upid = _get_pids_by_upid(ours).items() +def _cleanup_pids(ours, rundir): + pids_by_upid = _get_pids_by_upid(ours, rundir).items() if not pids_by_upid: return @@ -94,7 +102,7 @@ def _cleanup_pids(ours): # return # time.sleep(1) - pids_by_upid = _get_pids_by_upid(ours).items() + pids_by_upid = _get_pids_by_upid(ours, rundir).items() _kill_piddict(pids_by_upid, signal.SIGKILL) @@ -103,12 +111,16 @@ def cleanup_current(): Currently this only scans for old processes. """ - _cleanup_pids(True) + _cleanup_pids(True, None) -def cleanup_previous(): +def cleanup_previous(rundir=None): """Attempt to cleanup preview runs. Currently this only scans for old processes. """ - _cleanup_pids(False) + _cleanup_pids(False, rundir) + + +def is_running_in_rundir(rundir): + return bool(get_pids_with_env("MUNET_RUNDIR", str(rundir))) diff --git a/tests/topotests/munet/cli.py b/tests/topotests/munet/cli.py index 133644e85..01a709151 100644 --- a/tests/topotests/munet/cli.py +++ b/tests/topotests/munet/cli.py @@ -106,9 +106,13 @@ def is_host_regex(restr): def get_host_regex(restr): - if len(restr) < 3 or restr[0] != "/" or restr[-1] != "/": + try: + if len(restr) < 3 or restr[0] != "/" or restr[-1] != "/": + return None + return re.compile(restr[1:-1]) + except re.error: + logging.error("Invalid regex") return None - return re.compile(restr[1:-1]) def host_in(restr, names): @@ -126,8 +130,8 @@ def expand_host(restr, names): hosts = [] regexp = get_host_regex(restr) if not regexp: - assert restr in names - hosts.append(restr) + if restr in names: + hosts.append(restr) else: for name in names: if regexp.fullmatch(name): diff --git a/tests/topotests/munet/logconf-mutest.yaml b/tests/topotests/munet/logconf-mutest.yaml index b450fb938..c0b636cd6 100644 --- a/tests/topotests/munet/logconf-mutest.yaml +++ b/tests/topotests/munet/logconf-mutest.yaml @@ -1,5 +1,8 @@ version: 1 formatters: + result_color: + class: munet.mulog.ResultColorFormatter + format: '%(levelname)5s: %(message)s' brief: format: '%(levelname)5s: %(message)s' operfmt: @@ -22,7 +25,7 @@ handlers: info_console: level: INFO class: logging.StreamHandler - formatter: brief + formatter: result_color stream: ext://sys.stderr oper_console: level: DEBUG diff --git a/tests/topotests/munet/mucmd.py b/tests/topotests/munet/mucmd.py index d6101e1a5..cd356f38a 100644 --- a/tests/topotests/munet/mucmd.py +++ b/tests/topotests/munet/mucmd.py @@ -89,14 +89,14 @@ def main(*args): ecmd = "/usr/bin/nsenter" eargs = [ecmd] - # start mucmd same way base process is started + #start mucmd same way base process is started eargs.append(f"--mount=/proc/{pid}/ns/mnt") eargs.append(f"--net=/proc/{pid}/ns/net") eargs.append(f"--pid=/proc/{pid}/ns/pid_for_children") eargs.append(f"--uts=/proc/{pid}/ns/uts") eargs.append(f"--wd={rundir}") eargs += args.shellcmd - # print("Using ", eargs) + #print("Using ", eargs) return os.execvpe(ecmd, eargs, {**env, **envcfg}) diff --git a/tests/topotests/munet/mulog.py b/tests/topotests/munet/mulog.py index f840eae2d..968acd9d1 100644 --- a/tests/topotests/munet/mulog.py +++ b/tests/topotests/munet/mulog.py @@ -12,6 +12,9 @@ import logging from pathlib import Path +do_color = True + + class MultiFileHandler(logging.FileHandler): """A logging handler that logs to new files based on the logger name. @@ -118,5 +121,28 @@ class ColorFormatter(logging.Formatter): super().__init__(fmt, datefmt, style, **kwargs) def format(self, record): + if not do_color: + return super().format(record) formatter = self.formatters.get(record.levelno) return formatter.format(record) + + +class ResultColorFormatter(logging.Formatter): + """A formatter that colorizes PASS/FAIL strings based on level.""" + + green = "\x1b[32m" + red = "\x1b[31m" + reset = "\x1b[0m" + + def format(self, record): + s = super().format(record) + if not do_color: + return s + idx = s.find("FAIL") + if idx >= 0 and record.levelno > logging.INFO: + s = s[:idx] + self.red + "FAIL" + self.reset + s[idx + 4 :] + elif record.levelno == logging.INFO: + idx = s.find("PASS") + if idx >= 0: + s = s[:idx] + self.green + "PASS" + self.reset + s[idx + 4 :] + return s diff --git a/tests/topotests/munet/munet-schema.json b/tests/topotests/munet/munet-schema.json index 7d577e63b..6ebc368dc 100644 --- a/tests/topotests/munet/munet-schema.json +++ b/tests/topotests/munet/munet-schema.json @@ -93,6 +93,9 @@ "image": { "type": "string" }, + "hostnet": { + "type": "boolean" + }, "server": { "type": "string" }, @@ -383,6 +386,9 @@ }, "ipv6": { "type": "string" + }, + "external": { + "type": "boolean" } } } @@ -422,6 +428,9 @@ "image": { "type": "string" }, + "hostnet": { + "type": "boolean" + }, "server": { "type": "string" }, diff --git a/tests/topotests/munet/mutest/__main__.py b/tests/topotests/munet/mutest/__main__.py index d94e702c5..a78c69e26 100644 --- a/tests/topotests/munet/mutest/__main__.py +++ b/tests/topotests/munet/mutest/__main__.py @@ -20,6 +20,7 @@ from copy import deepcopy from pathlib import Path from typing import Union +from munet import mulog from munet import parser from munet.args import add_testing_args from munet.base import Bridge @@ -380,8 +381,10 @@ async def run_tests(args): for result in results: test_name, passed, failed, e = result tnum += 1 - s = "FAIL" if failed or e else "PASS" - reslog.info(" %s %s:%s", s, tnum, test_name) + if failed or e: + reslog.warning(" FAIL %s:%s", tnum, test_name) + else: + reslog.info(" PASS %s:%s", tnum, test_name) reslog.info("-" * 70) reslog.info( @@ -447,8 +450,9 @@ def main(): sys.exit(0) rundir = args.rundir if args.rundir else "/tmp/mutest" - args.rundir = Path(rundir) - os.environ["MUNET_RUNDIR"] = rundir + rundir = Path(rundir).absolute() + args.rundir = rundir + os.environ["MUNET_RUNDIR"] = str(rundir) subprocess.run(f"mkdir -p {rundir} && chmod 755 {rundir}", check=True, shell=True) config = parser.setup_logging(args, config_base="logconf-mutest") @@ -459,6 +463,9 @@ def main(): fconfig.get("format"), fconfig.get("datefmt") ) + if not hasattr(sys.stderr, "isatty") or not sys.stderr.isatty(): + mulog.do_color = False + loop = None status = 4 try: diff --git a/tests/topotests/munet/mutest/userapi.py b/tests/topotests/munet/mutest/userapi.py index f42fbc189..abc63af36 100644 --- a/tests/topotests/munet/mutest/userapi.py +++ b/tests/topotests/munet/mutest/userapi.py @@ -544,7 +544,9 @@ class TestCase: """ js = self._command_json(target, cmd) if js is None: - return expect_fail, {} + # Always fail on bad json, even if user expected failure + # return expect_fail, {} + return False, {} try: # Convert to string to validate the input is valid JSON @@ -556,7 +558,9 @@ class TestCase: self.olog.warning( "JSON load failed. Check match value is in JSON format: %s", error ) - return expect_fail, {} + # Always fail on bad json, even if user expected failure + # return expect_fail, {} + return False, {} if exact_match: deep_diff = json_cmp(expect, js) diff --git a/tests/topotests/munet/native.py b/tests/topotests/munet/native.py index de0f0ffc6..5747d5e1d 100644 --- a/tests/topotests/munet/native.py +++ b/tests/topotests/munet/native.py @@ -28,8 +28,10 @@ from . import cli from .base import BaseMunet from .base import Bridge from .base import Commander +from .base import InterfaceMixin from .base import LinuxNamespace from .base import MunetError +from .base import SharedNamespace from .base import Timeout from .base import _async_get_exec_path from .base import _get_exec_path @@ -132,6 +134,22 @@ def convert_ranges_to_bitmask(ranges): return bitmask +class ExternalNetwork(SharedNamespace, InterfaceMixin): + """A network external to munet.""" + + def __init__(self, name=None, unet=None, logger=None, mtu=None, config=None): + """Create an external network.""" + del logger # avoid linter + del mtu # avoid linter + # Do we want to use os.getpid() rather than unet.pid? + super().__init__(name, pid=unet.pid, nsflags=unet.nsflags, unet=unet) + self.config = config if config else {} + + async def _async_delete(self): + self.logger.debug("%s: deleting", self) + await super()._async_delete() + + class L2Bridge(Bridge): """A linux bridge with no IP network address.""" @@ -555,17 +573,38 @@ class NodeMixin: await super()._async_delete() +class HostnetNode(NodeMixin, LinuxNamespace): + """A node for running commands in the host network namespace.""" + + def __init__(self, name, pid=True, **kwargs): + if "net" in kwargs: + del kwargs["net"] + super().__init__(name, pid=pid, net=False, **kwargs) + + self.logger.debug("%s: creating", self) + + self.mgmt_ip = None + self.mgmt_ip6 = None + self.set_ns_cwd(self.rundir) + + super().pytest_hook_open_shell() + self.logger.info("%s: created", self) + + def get_ifname(self, netname): # pylint: disable=useless-return + del netname + return None + + async def _async_delete(self): + self.logger.debug("%s: deleting", self) + await super()._async_delete() + + class SSHRemote(NodeMixin, Commander): """SSHRemote a node representing an ssh connection to something.""" def __init__( self, name, - server, - port=22, - user=None, - password=None, - idfile=None, **kwargs, ): super().__init__(name, **kwargs) @@ -580,32 +619,33 @@ class SSHRemote(NodeMixin, Commander): self.mgmt_ip = None self.mgmt_ip6 = None - self.port = port - - if user: - self.user = user - elif "SUDO_USER" in os.environ: - self.user = os.environ["SUDO_USER"] - else: + self.server = self.config["server"] + self.port = int(self.config.get("server-port", 22)) + self.sudo_user = os.environ.get("SUDO_USER") + self.user = self.config.get("ssh-user") + if not self.user: + self.user = self.sudo_user + if not self.user: self.user = getpass.getuser() - self.password = password - self.idfile = idfile - - self.server = f"{self.user}@{server}" + self.password = self.config.get("ssh-password") + self.idfile = self.config.get("ssh-identity-file") + self.use_host_network = None # Setup our base `pre-cmd` values # # We maybe should add environment variable transfer here in particular # MUNET_NODENAME. The problem is the user has to explicitly approve # of SendEnv variables. - self.__base_cmd = [ - get_exec_path_host("sudo"), - "-E", - f"-u{self.user}", - get_exec_path_host("ssh"), - ] - if port != 22: - self.__base_cmd.append(f"-p{port}") + self.__base_cmd = [] + if self.idfile and self.sudo_user: + self.__base_cmd += [ + get_exec_path_host("sudo"), + "-E", + f"-u{self.sudo_user}", + ] + self.__base_cmd.append(get_exec_path_host("ssh")) + if self.port != 22: + self.__base_cmd.append(f"-p{self.port}") self.__base_cmd.append("-q") self.__base_cmd.append("-oStrictHostKeyChecking=no") self.__base_cmd.append("-oUserKnownHostsFile=/dev/null") @@ -615,15 +655,34 @@ class SSHRemote(NodeMixin, Commander): # self.__base_cmd.append("-oSendVar='TEST'") self.__base_cmd_pty = list(self.__base_cmd) self.__base_cmd_pty.append("-t") - self.__base_cmd.append(self.server) - self.__base_cmd_pty.append(self.server) + server_str = f"{self.user}@{self.server}" + self.__base_cmd.append(server_str) + self.__base_cmd_pty.append(server_str) # self.set_pre_cmd(pre_cmd, pre_cmd_tty) self.logger.info("%s: created", self) def _get_pre_cmd(self, use_str, use_pty, ns_only=False, **kwargs): - pre_cmd = [] - if self.unet: + # None on first use, set after + if self.use_host_network is None: + # We have networks now so try and ping the server in the namespace + if not self.unet: + self.use_host_network = True + else: + rc, _, _ = self.unet.cmd_status(f"ping -w1 -c1 {self.server}") + if rc: + self.use_host_network = True + else: + self.use_host_network = False + + if self.use_host_network: + self.logger.debug("Using host namespace for ssh connection") + else: + self.logger.debug("Using munet namespace for ssh connection") + + if self.use_host_network: + pre_cmd = [] + else: pre_cmd = self.unet._get_pre_cmd(False, use_pty, ns_only=False, **kwargs) if ns_only: return pre_cmd @@ -979,17 +1038,16 @@ ff02::2\tip6-allrouters ) self.unet.rootcmd.cmd_status(f"ip link set {dname} name {hname}") - rc, o, _ = self.unet.rootcmd.cmd_status("ip -o link show") - m = re.search(rf"\d+:\s+{re.escape(hname)}:.*", o) - if m: - self.unet.rootcmd.cmd_nostatus(f"ip link set {hname} down ") - self.unet.rootcmd.cmd_raises(f"ip link set {hname} netns {self.pid}") + # Make sure the interface is there. + self.unet.rootcmd.cmd_raises(f"ip -o link show {hname}") + self.unet.rootcmd.cmd_nostatus(f"ip link set {hname} down ") + self.unet.rootcmd.cmd_raises(f"ip link set {hname} netns {self.pid}") + # Wait for interface to show up in namespace for retry in range(0, 10): rc, o, _ = self.cmd_status(f"ip -o link show {hname}") if not rc: - if re.search(rf"\d+: {re.escape(hname)}:.*", o): - break + break if retry > 0: await asyncio.sleep(1) self.cmd_raises(f"ip link set {hname} name {lname}") @@ -1001,12 +1059,11 @@ ff02::2\tip6-allrouters lname = self.host_intfs[hname] self.cmd_raises(f"ip link set {lname} down") self.cmd_raises(f"ip link set {lname} name {hname}") - self.cmd_status(f"ip link set netns 1 dev {hname}") - # The above is failing sometimes and not sure why - # logging.error( - # "XXX after setns %s", - # self.unet.rootcmd.cmd_nostatus(f"ip link show {hname}"), - # ) + # We need to NOT run this command in the new pid namespace so that pid 1 is the + # root init process and so the interface gets returned to the root namespace + self.unet.rootcmd.cmd_raises( + f"nsenter -t {self.pid} -n ip link set netns 1 dev {hname}" + ) del self.host_intfs[hname] async def add_phy_intf(self, devaddr, lname): @@ -1917,7 +1974,11 @@ class L3QemuVM(L3NodeMixin, LinuxNamespace): # InterfaceMixin override # We need a name unique in the shared namespace. def get_ns_ifname(self, ifname): - return self.name + ifname + ifname = self.name + ifname + ifname = re.sub("gigabitethernet", "GE", ifname, flags=re.I) + if len(ifname) >= 16: + ifname = ifname[0:7] + ifname[-8:] + return ifname async def add_host_intf(self, hname, lname, mtu=None): # L3QemuVM needs it's own add_host_intf for macvtap, We need to create the tap @@ -2093,16 +2154,22 @@ class L3QemuVM(L3NodeMixin, LinuxNamespace): ) con.cmd_raises(rf"rm -rf {tmpdir}") - self.logger.info("Saved coverage data in VM at %s", dest) + self.logger.debug("Saved coverage data in VM at %s", dest) ldest = os.path.join(self.rundir, "gcov-data.tgz") if self.use_ssh: self.cmd_raises(["/bin/cat", dest], stdout=open(ldest, "wb")) - self.logger.info("Saved coverage data on host at %s", ldest) + self.logger.debug("Saved coverage data on host at %s", ldest) else: output = con.cmd_raises(rf"base64 {dest}") with open(ldest, "wb") as f: f.write(base64.b64decode(output)) - self.logger.info("Saved coverage data on host at %s", ldest) + self.logger.debug("Saved coverage data on host at %s", ldest) + self.logger.info("Extracting coverage for %s into %s", self.name, ldest) + + # We need to place the gcda files where munet expects to find them + gcdadir = Path(os.environ["GCOV_PREFIX"]) / self.name + self.unet.cmd_raises_nsonly(f"mkdir -p {gcdadir}") + self.unet.cmd_raises_nsonly(f"tar -C {gcdadir} -xzf {ldest}") async def _opencons( self, @@ -2878,7 +2945,9 @@ ff02::2\tip6-allrouters else: node2.set_lan_addr(node1, c2) - if "physical" not in c1 and not node1.is_vm: + if isinstance(node1, ExternalNetwork): + pass + elif "physical" not in c1 and not node1.is_vm: node1.set_intf_constraints(if1, **c1) if "physical" not in c2 and not node2.is_vm: node2.set_intf_constraints(if2, **c2) @@ -2891,14 +2960,8 @@ ff02::2\tip6-allrouters cls = L3QemuVM elif config and config.get("server"): cls = SSHRemote - kwargs["server"] = config["server"] - kwargs["port"] = int(config.get("server-port", 22)) - if "ssh-identity-file" in config: - kwargs["idfile"] = config.get("ssh-identity-file") - if "ssh-user" in config: - kwargs["user"] = config.get("ssh-user") - if "ssh-password" in config: - kwargs["password"] = config.get("ssh-password") + elif config and config.get("hostnet"): + cls = HostnetNode else: cls = L3NamespaceNode return super().add_host(name, cls=cls, config=config, **kwargs) @@ -2908,7 +2971,12 @@ ff02::2\tip6-allrouters if config is None: config = {} - cls = L3Bridge if config.get("ip") else L2Bridge + if config.get("external"): + cls = ExternalNetwork + elif config.get("ip"): + cls = L3Bridge + else: + cls = L2Bridge mtu = kwargs.get("mtu", config.get("mtu")) return super().add_switch(name, cls=cls, config=config, mtu=mtu, **kwargs) @@ -2947,7 +3015,7 @@ ff02::2\tip6-allrouters bdir = Path(os.environ["GCOV_BUILD_DIR"]) gcdadir = Path(os.environ["GCOV_PREFIX"]) - # Create GCNO symlinks + # Create .gcno symlinks if they don't already exist, for kernel they will self.logger.info("Creating .gcno symlinks from '%s' to '%s'", gcdadir, bdir) commander.cmd_raises( f'cd "{gcdadir}"; bdir="{bdir}"' @@ -2955,9 +3023,11 @@ ff02::2\tip6-allrouters for f in $(find . -name '*.gcda'); do f=${f#./}; f=${f%.gcda}.gcno; - ln -fs $bdir/$f $f; - touch -h -r $bdir/$f $f; - echo $f; + if [ ! -h "$f" ]; then + ln -fs $bdir/$f $f; + touch -h -r $bdir/$f $f; + echo $f; + fi; done""" ) @@ -2977,10 +3047,30 @@ done""" # f"\nCOVERAGE-SUMMARY-START\n{output}\nCOVERAGE-SUMMARY-END\n" # ) - async def run(self): + async def load_images(self, images): tasks = [] + for image in images: + logging.debug("Checking for image %s", image) + rc, _, _ = self.rootcmd.cmd_status( + f"podman image inspect {image}", warn=False + ) + if not rc: + continue + logging.info("Pulling missing image %s", image) + aw = self.rootcmd.async_cmd_raises(f"podman pull {image}") + tasks.append(asyncio.create_task(aw)) + if not tasks: + return + _, pending = await asyncio.wait(tasks, timeout=600) + assert not pending, "Failed to pull container images" + async def run(self): + tasks = [] hosts = self.hosts.values() + + images = {x.container_image for x in hosts if hasattr(x, "container_image")} + await self.load_images(images) + launch_nodes = [x for x in hosts if hasattr(x, "launch")] launch_nodes = [x for x in launch_nodes if x.config.get("qemu")] run_nodes = [x for x in hosts if x.has_run_cmd()] @@ -3049,10 +3139,10 @@ done""" await asyncio.sleep(0.25) logging.debug("%s is ready!", x) + tasks = [asyncio.create_task(wait_until_ready(x)) for x in ready_nodes] + logging.debug("Waiting for ready on nodes: %s", ready_nodes) - _, pending = await asyncio.wait( - [wait_until_ready(x) for x in ready_nodes], timeout=30 - ) + _, pending = await asyncio.wait(tasks, timeout=30) if pending: logging.warning("Timeout waiting for ready: %s", pending) for nr in pending: diff --git a/tests/topotests/munet/testing/fixtures.py b/tests/topotests/munet/testing/fixtures.py index 4150d28b5..3c6ddf9ae 100644 --- a/tests/topotests/munet/testing/fixtures.py +++ b/tests/topotests/munet/testing/fixtures.py @@ -25,7 +25,6 @@ from ..base import BaseMunet from ..base import Bridge from ..base import get_event_loop from ..cleanup import cleanup_current -from ..cleanup import cleanup_previous from ..native import L3NodeMixin from ..parser import async_build_topology from ..parser import get_config @@ -130,9 +129,12 @@ def session_autouse(): else: is_worker = True - if not is_worker: - # This is unfriendly to multi-instance - cleanup_previous() + # We dont want to kill all munet and we don't have the rundir here yet + # This was more useful back when we used to leave processes around a lot + # more. + # if not is_worker: + # # This is unfriendly to multi-instance + # cleanup_previous() # We never pop as we want to keep logging _push_log_handler("session", "/tmp/unet-test/pytest-session.log") @@ -150,8 +152,9 @@ def session_autouse(): @pytest.fixture(autouse=True, scope="module") def module_autouse(request): + root_path = os.environ.get("MUNET_RUNDIR", "/tmp/unet-test") logpath = get_test_logdir(request.node.nodeid, True) - logpath = os.path.join("/tmp/unet-test", logpath, "pytest-exec.log") + logpath = os.path.join(root_path, logpath, "pytest-exec.log") with log_handler("module", logpath): sdir = os.path.dirname(os.path.realpath(request.fspath)) with chdir(sdir, "module autouse fixture"): @@ -174,7 +177,8 @@ def event_loop(): @pytest.fixture(scope="module") def rundir_module(): - d = os.path.join("/tmp/unet-test", get_test_logdir(module=True)) + root_path = os.environ.get("MUNET_RUNDIR", "/tmp/unet-test") + d = os.path.join(root_path, get_test_logdir(module=True)) logging.debug("conftest: test module rundir %s", d) return d @@ -375,7 +379,8 @@ async def astepf(pytestconfig): @pytest.fixture(scope="function") def rundir(): - d = os.path.join("/tmp/unet-test", get_test_logdir(module=False)) + root_path = os.environ.get("MUNET_RUNDIR", "/tmp/unet-test") + d = os.path.join(root_path, get_test_logdir(module=False)) logging.debug("conftest: test function rundir %s", d) return d @@ -383,9 +388,8 @@ def rundir(): # Configure logging @pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_setup(item): - d = os.path.join( - "/tmp/unet-test", get_test_logdir(nodeid=item.nodeid, module=False) - ) + root_path = os.environ.get("MUNET_RUNDIR", "/tmp/unet-test") + d = os.path.join(root_path, get_test_logdir(nodeid=item.nodeid, module=False)) config = item.config logging_plugin = config.pluginmanager.get_plugin("logging-plugin") filename = Path(d, "pytest-exec.log") diff --git a/tests/topotests/munet/watchlog.py b/tests/topotests/munet/watchlog.py index f764f9dac..27bc3251a 100644 --- a/tests/topotests/munet/watchlog.py +++ b/tests/topotests/munet/watchlog.py @@ -15,7 +15,6 @@ from pathlib import Path class MatchFoundError(Exception): """An error raised when a match is not found.""" - def __init__(self, watchlog, match): self.watchlog = watchlog self.match = match diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py index 58608e249..00c98ac97 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py @@ -175,7 +175,7 @@ def test_ospf6_auth_trailer_tc1_md5(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -208,7 +208,7 @@ def test_ospf6_auth_trailer_tc1_md5(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -266,7 +266,7 @@ def test_ospf6_auth_trailer_tc1_md5(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 using" + "Verify that the neighbor is FULL between R1 and R2 using" " show ip ospf6 neighbor cmd." ) @@ -283,7 +283,7 @@ def test_ospf6_auth_trailer_tc1_md5(request): dut = "r2" step( - "Verify that the neighbour is not FULL between R1 and R2 using " + "Verify that the neighbor is not FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) @@ -295,7 +295,7 @@ def test_ospf6_auth_trailer_tc1_md5(request): shutdown_bringup_interface(tgen, dut, intf, True) step( - "Verify that the neighbour is FULL between R1 and R2 using " + "Verify that the neighbor is FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) @@ -341,7 +341,7 @@ def test_ospf6_auth_trailer_tc2_sha256(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -374,7 +374,7 @@ def test_ospf6_auth_trailer_tc2_sha256(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -432,7 +432,7 @@ def test_ospf6_auth_trailer_tc2_sha256(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 using" + "Verify that the neighbor is FULL between R1 and R2 using" " show ip ospf6 neighbor cmd." ) @@ -449,7 +449,7 @@ def test_ospf6_auth_trailer_tc2_sha256(request): dut = "r2" step( - "Verify that the neighbour is not FULL between R1 and R2 using " + "Verify that the neighbor is not FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) @@ -461,7 +461,66 @@ def test_ospf6_auth_trailer_tc2_sha256(request): shutdown_bringup_interface(tgen, dut, intf, True) step( - "Verify that the neighbour is FULL between R1 and R2 using " + "Verify that the neighbor is FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, ospf6_covergence + ) + + step("Change the key ID on R2 to not match R1") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "30", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify on R1 that R2 nbr is deleted due to key-id mismatch " + "after dead interval expiry" + ) + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=5 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error: {}".format( + tc_name, ospf6_covergence + ) + + step("Correct the key ID on R2 so that it matches R1") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbor is FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) @@ -524,7 +583,7 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -555,7 +614,7 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -600,7 +659,7 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 using" + "Verify that the neighbor is FULL between R1 and R2 using" " show ip ospf6 neighbor cmd." ) @@ -617,7 +676,7 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request): dut = "r2" step( - "Verify that the neighbour is not FULL between R1 and R2 using " + "Verify that the neighbor is not FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) @@ -629,7 +688,7 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request): shutdown_bringup_interface(tgen, dut, intf, True) step( - "Verify that the neighbour is FULL between R1 and R2 using " + "Verify that the neighbor is FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) @@ -692,7 +751,7 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -723,7 +782,7 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -768,7 +827,7 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 using" + "Verify that the neighbor is FULL between R1 and R2 using" " show ip ospf6 neighbor cmd." ) @@ -785,7 +844,7 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request): dut = "r2" step( - "Verify that the neighbour is not FULL between R1 and R2 using " + "Verify that the neighbor is not FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) @@ -797,7 +856,7 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request): shutdown_bringup_interface(tgen, dut, intf, True) step( - "Verify that the neighbour is FULL between R1 and R2 using " + "Verify that the neighbor is FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) @@ -843,7 +902,7 @@ def test_ospf6_auth_trailer_tc5_md5_keymissmatch(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -876,11 +935,11 @@ def test_ospf6_auth_trailer_tc5_md5_keymissmatch(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is not FULL between R1 and R2 " + "Verify that the neighbor is not FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) - step("Verify that the neighbour is FULL between R1 and R2.") + step("Verify that the neighbor is FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r2" @@ -913,7 +972,7 @@ def test_ospf6_auth_trailer_tc5_md5_keymissmatch(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -959,7 +1018,7 @@ def test_ospf6_auth_trailer_tc6_sha256_mismatch(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -991,7 +1050,7 @@ def test_ospf6_auth_trailer_tc6_sha256_mismatch(request): result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r2" @@ -1024,7 +1083,7 @@ def test_ospf6_auth_trailer_tc6_sha256_mismatch(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -1095,7 +1154,7 @@ def test_ospf6_auth_trailer_tc7_keychain_md5_missmatch(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -1125,7 +1184,7 @@ def test_ospf6_auth_trailer_tc7_keychain_md5_missmatch(request): result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r2" @@ -1156,7 +1215,7 @@ def test_ospf6_auth_trailer_tc7_keychain_md5_missmatch(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -1227,7 +1286,7 @@ def test_ospf6_auth_trailer_tc8_keychain_sha256_missmatch(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -1257,7 +1316,7 @@ def test_ospf6_auth_trailer_tc8_keychain_sha256_missmatch(request): result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r2" @@ -1288,7 +1347,7 @@ def test_ospf6_auth_trailer_tc8_keychain_sha256_missmatch(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -1335,7 +1394,7 @@ def test_ospf6_auth_trailer_tc9_keychain_not_configured(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -1365,7 +1424,7 @@ def test_ospf6_auth_trailer_tc9_keychain_not_configured(request): result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r2" @@ -1396,7 +1455,7 @@ def test_ospf6_auth_trailer_tc10_no_auth_trailer(request): router2 = tgen.gears["r2"] step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 245b799a9..9ad92d626 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -654,14 +654,6 @@ static void fpm_read(struct event *t) hdr_available_bytes = fpm.msg_len - FPM_MSG_HDR_LEN; available_bytes -= hdr_available_bytes; - /* Sanity check: must be at least header size. */ - if (hdr->nlmsg_len < sizeof(*hdr)) { - zlog_warn( - "%s: [seq=%u] invalid message length %u (< %zu)", - __func__, hdr->nlmsg_seq, hdr->nlmsg_len, - sizeof(*hdr)); - continue; - } if (hdr->nlmsg_len > fpm.msg_len) { zlog_warn( "%s: Received a inner header length of %u that is greater than the fpm total length of %u", @@ -691,6 +683,14 @@ static void fpm_read(struct event *t) switch (hdr->nlmsg_type) { case RTM_NEWROUTE: + /* Sanity check: need at least route msg header size. */ + if (hdr->nlmsg_len < sizeof(struct rtmsg)) { + zlog_warn("%s: [seq=%u] invalid message length %u (< %zu)", + __func__, hdr->nlmsg_seq, + hdr->nlmsg_len, sizeof(struct rtmsg)); + break; + } + ctx = dplane_ctx_alloc(); dplane_ctx_route_init(ctx, DPLANE_OP_ROUTE_NOTIFY, NULL, NULL); diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index 5c19d226b..75e7e2017 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -3026,7 +3026,7 @@ void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up) } static char *zebra_evpn_es_vtep_str(char *vtep_str, struct zebra_evpn_es *es, - uint8_t vtep_str_size) + size_t vtep_str_size) { struct zebra_evpn_es_vtep *zvtep; struct listnode *node; diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index 617a2225f..fb326b0dd 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -15,6 +15,7 @@ #include <sched.h> #endif #include <dirent.h> +#include <libgen.h> #include <sys/inotify.h> #include <sys/stat.h> @@ -234,6 +235,7 @@ static void zebra_ns_ready_read(struct event *t) { struct zebra_netns_info *zns_info = EVENT_ARG(t); const char *netnspath; + const char *netnspath_basename; int err, stop_retry = 0; if (!zns_info) @@ -261,23 +263,24 @@ static void zebra_ns_ready_read(struct event *t) zebra_ns_continue_read(zns_info, stop_retry); return; } + netnspath_basename = basename(strdupa(netnspath)); /* check default name is not already set */ - if (strmatch(VRF_DEFAULT_NAME, basename(netnspath))) { - zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath)); + if (strmatch(VRF_DEFAULT_NAME, netnspath_basename)) { + zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", netnspath_basename); zebra_ns_continue_read(zns_info, 1); return; } - if (zebra_ns_notify_is_default_netns(basename(netnspath))) { + if (zebra_ns_notify_is_default_netns(netnspath_basename)) { zlog_warn( "NS notify : NS %s is default VRF. Ignore VRF creation", - basename(netnspath)); + netnspath_basename); zebra_ns_continue_read(zns_info, 1); return; } /* success : close fd and create zns context */ - zebra_ns_notify_create_context_from_entry_name(basename(netnspath)); + zebra_ns_notify_create_context_from_entry_name(netnspath_basename); zebra_ns_continue_read(zns_info, 1); } @@ -396,7 +399,7 @@ void zebra_ns_notify_parse(void) continue; } /* check default name is not already set */ - if (strmatch(VRF_DEFAULT_NAME, basename(dent->d_name))) { + if (strmatch(VRF_DEFAULT_NAME, basename(strdupa(dent->d_name)))) { zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent->d_name); continue; } diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index c5b850599..d5cd30e64 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -475,16 +475,24 @@ static int zebra_sr_config(struct vty *vty) struct listnode *node; struct srv6_locator *locator; char str[256]; + bool display_source_srv6 = false; + + if (srv6 && !IPV6_ADDR_SAME(&srv6->encap_src_addr, &in6addr_any)) + display_source_srv6 = true; vty_out(vty, "!\n"); - if (zebra_srv6_is_enable()) { + if (display_source_srv6 || zebra_srv6_is_enable()) { vty_out(vty, "segment-routing\n"); vty_out(vty, " srv6\n"); + } + if (display_source_srv6) { if (!IPV6_ADDR_SAME(&srv6->encap_src_addr, &in6addr_any)) { vty_out(vty, " encapsulation\n"); vty_out(vty, " source-address %pI6\n", &srv6->encap_src_addr); } + } + if (zebra_srv6_is_enable()) { vty_out(vty, " locators\n"); for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { inet_ntop(AF_INET6, &locator->prefix.prefix, @@ -514,6 +522,8 @@ static int zebra_sr_config(struct vty *vty) vty_out(vty, " !\n"); vty_out(vty, " exit\n"); vty_out(vty, " !\n"); + } + if (display_source_srv6 || zebra_srv6_is_enable()) { vty_out(vty, "exit\n"); vty_out(vty, "!\n"); } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 44720754b..c31218a7c 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -60,8 +60,8 @@ struct route_show_ctx { }; static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, - safi_t safi, bool use_fib, json_object *vrf_json, - bool use_json, route_tag_t tag, + safi_t safi, bool use_fib, bool use_json, + route_tag_t tag, const struct prefix *longer_prefix_p, bool supernets_only, int type, unsigned short ospf_instance_id, uint32_t tableid, @@ -153,8 +153,8 @@ DEFPY (show_ip_rpf, }; return do_show_ip_route(vty, VRF_DEFAULT_NAME, ip ? AFI_IP : AFI_IP6, - SAFI_MULTICAST, false, NULL, uj, 0, NULL, false, - 0, 0, 0, false, &ctx); + SAFI_MULTICAST, false, uj, 0, NULL, false, 0, 0, + 0, false, &ctx); } DEFPY (show_ip_rpf_addr, @@ -858,19 +858,20 @@ static void vty_show_ip_route_detail_json(struct vty *vty, vty_json(vty, json); } -static void -do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, - struct route_table *table, afi_t afi, bool use_fib, - json_object *vrf_json, route_tag_t tag, - const struct prefix *longer_prefix_p, bool supernets_only, - int type, unsigned short ospf_instance_id, bool use_json, - uint32_t tableid, bool show_ng, struct route_show_ctx *ctx) +static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, + struct route_table *table, afi_t afi, + bool use_fib, route_tag_t tag, + const struct prefix *longer_prefix_p, + bool supernets_only, int type, + unsigned short ospf_instance_id, bool use_json, + uint32_t tableid, bool show_ng, + struct route_show_ctx *ctx) { struct route_node *rn; struct route_entry *re; + bool first_json = true; int first = 1; rib_dest_t *dest; - json_object *json = NULL; json_object *json_prefix = NULL; uint32_t addr; char buf[BUFSIZ]; @@ -886,9 +887,6 @@ do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, * => display the VRF and table if specific */ - if (use_json && !vrf_json) - json = json_object_new_object(); - /* Show all routes. */ for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) { dest = rib_dest_from_rnode(rn); @@ -961,28 +959,20 @@ do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, if (json_prefix) { prefix2str(&rn->p, buf, sizeof(buf)); - if (!vrf_json) - json_object_object_add(json, buf, json_prefix); - else - json_object_object_add(vrf_json, buf, - json_prefix); + vty_json_key(vty, buf, &first_json); + vty_json_no_pretty(vty, json_prefix); + json_prefix = NULL; } } - /* - * This is an extremely expensive operation at scale - * and non-pretty reduces memory footprint significantly. - */ - if (use_json && !vrf_json) { - vty_json_no_pretty(vty, json); - json = NULL; - } + if (use_json) + vty_json_close(vty, first_json); } static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, - afi_t afi, bool use_fib, json_object *vrf_json, - bool use_json, route_tag_t tag, + afi_t afi, bool use_fib, bool use_json, + route_tag_t tag, const struct prefix *longer_prefix_p, bool supernets_only, int type, unsigned short ospf_instance_id, bool show_ng, @@ -1002,15 +992,15 @@ static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, continue; do_show_ip_route(vty, zvrf_name(zvrf), afi, SAFI_UNICAST, - use_fib, vrf_json, use_json, tag, - longer_prefix_p, supernets_only, type, - ospf_instance_id, zrt->tableid, show_ng, ctx); + use_fib, use_json, tag, longer_prefix_p, + supernets_only, type, ospf_instance_id, + zrt->tableid, show_ng, ctx); } } static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, - safi_t safi, bool use_fib, json_object *vrf_json, - bool use_json, route_tag_t tag, + safi_t safi, bool use_fib, bool use_json, + route_tag_t tag, const struct prefix *longer_prefix_p, bool supernets_only, int type, unsigned short ospf_instance_id, uint32_t tableid, @@ -1045,7 +1035,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, return CMD_SUCCESS; } - do_show_route_helper(vty, zvrf, table, afi, use_fib, vrf_json, tag, + do_show_route_helper(vty, zvrf, table, afi, use_fib, tag, longer_prefix_p, supernets_only, type, ospf_instance_id, use_json, tableid, show_ng, ctx); @@ -1744,13 +1734,13 @@ DEFPY (show_route, "Nexthop Group Information\n") { afi_t afi = ipv4 ? AFI_IP : AFI_IP6; + bool first_vrf_json = true; struct vrf *vrf; int type = 0; struct zebra_vrf *zvrf; struct route_show_ctx ctx = { .multi = vrf_all || table_all, }; - json_object *root_json = NULL; if (!vrf_is_backend_netns()) { if ((vrf_all || vrf_name) && (table || table_all)) { @@ -1772,43 +1762,30 @@ DEFPY (show_route, } if (vrf_all) { - if (!!json) - root_json = json_object_new_object(); RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - json_object *vrf_json = NULL; - if ((zvrf = vrf->info) == NULL || (zvrf->table[afi][SAFI_UNICAST] == NULL)) continue; - - if (!!json) - vrf_json = json_object_new_object(); - + if (json) + vty_json_key(vty, zvrf_name(zvrf), + &first_vrf_json); if (table_all) do_show_ip_route_all(vty, zvrf, afi, !!fib, - vrf_json, !!json, tag, + !!json, tag, prefix_str ? prefix : NULL, !!supernets_only, type, ospf_instance_id, !!ng, &ctx); else do_show_ip_route(vty, zvrf_name(zvrf), afi, - SAFI_UNICAST, !!fib, vrf_json, - !!json, tag, - prefix_str ? prefix : NULL, + SAFI_UNICAST, !!fib, !!json, + tag, prefix_str ? prefix : NULL, !!supernets_only, type, ospf_instance_id, table, !!ng, &ctx); - - if (!!json) - json_object_object_add(root_json, - zvrf_name(zvrf), - vrf_json); - } - if (!!json) { - vty_json_no_pretty(vty, root_json); - root_json = NULL; } + if (json) + vty_json_close(vty, first_vrf_json); } else { vrf_id_t vrf_id = VRF_DEFAULT; @@ -1823,13 +1800,13 @@ DEFPY (show_route, return CMD_SUCCESS; if (table_all) - do_show_ip_route_all(vty, zvrf, afi, !!fib, NULL, !!json, - tag, prefix_str ? prefix : NULL, + do_show_ip_route_all(vty, zvrf, afi, !!fib, !!json, tag, + prefix_str ? prefix : NULL, !!supernets_only, type, ospf_instance_id, !!ng, &ctx); else do_show_ip_route(vty, vrf->name, afi, SAFI_UNICAST, - !!fib, NULL, !!json, tag, + !!fib, !!json, tag, prefix_str ? prefix : NULL, !!supernets_only, type, ospf_instance_id, table, !!ng, &ctx); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 65dc6638b..b8c11e186 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -108,10 +108,11 @@ static void zevpn_build_hash_table(void); static unsigned int zebra_vxlan_sg_hash_key_make(const void *p); static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2); static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf, - struct in_addr sip, struct in_addr mcast_grp); -static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(struct zebra_vrf *vrf, - struct in_addr sip, - struct in_addr mcast_grp); + const struct ipaddr *sip, + const struct in_addr mcast_grp); +static struct zebra_vxlan_sg * +zebra_vxlan_sg_do_ref(struct zebra_vrf *vrf, const struct ipaddr *sip, + const struct in_addr mcast_grp); static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf); bool zebra_evpn_do_dup_addr_detect(struct zebra_vrf *zvrf) @@ -5891,7 +5892,10 @@ static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf, zclient_create_header(s, cmd, VRF_DEFAULT); stream_putl(s, IPV4_MAX_BYTELEN); - stream_put(s, &sg->src.s_addr, IPV4_MAX_BYTELEN); + /* + * There is currently no support for IPv6 VTEPs with PIM. + */ + stream_put(s, &sg->src.ipaddr_v4, IPV4_MAX_BYTELEN); stream_put(s, &sg->grp.s_addr, IPV4_MAX_BYTELEN); /* Write packet size. */ @@ -5914,9 +5918,17 @@ static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf, static unsigned int zebra_vxlan_sg_hash_key_make(const void *p) { const struct zebra_vxlan_sg *vxlan_sg = p; + uint32_t hash1; - return (jhash_2words(vxlan_sg->sg.src.s_addr, - vxlan_sg->sg.grp.s_addr, 0)); + if (IS_IPADDR_V4(&vxlan_sg->sg.src)) { + return (jhash_2words(vxlan_sg->sg.src.ipaddr_v4.s_addr, + vxlan_sg->sg.grp.s_addr, 0)); + } else { + hash1 = jhash_1word(vxlan_sg->sg.grp.s_addr, 0); + return jhash2(vxlan_sg->sg.src.ipaddr_v6.s6_addr32, + array_size(vxlan_sg->sg.src.ipaddr_v6.s6_addr32), + hash1); + } } static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2) @@ -5924,8 +5936,8 @@ static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2) const struct zebra_vxlan_sg *sg1 = p1; const struct zebra_vxlan_sg *sg2 = p2; - return ((sg1->sg.src.s_addr == sg2->sg.src.s_addr) - && (sg1->sg.grp.s_addr == sg2->sg.grp.s_addr)); + return (ipaddr_is_same(&sg1->sg.src, &sg2->sg.src) && + (sg1->sg.grp.s_addr == sg2->sg.grp.s_addr)); } static struct zebra_vxlan_sg *zebra_vxlan_sg_new(struct zebra_vrf *zvrf, @@ -5961,7 +5973,7 @@ static struct zebra_vxlan_sg *zebra_vxlan_sg_add(struct zebra_vrf *zvrf, { struct zebra_vxlan_sg *vxlan_sg; struct zebra_vxlan_sg *parent = NULL; - struct in_addr sip; + struct ipaddr sip; vxlan_sg = zebra_vxlan_sg_find(zvrf, sg); if (vxlan_sg) @@ -5972,9 +5984,9 @@ static struct zebra_vxlan_sg *zebra_vxlan_sg_add(struct zebra_vrf *zvrf, * 2. the XG entry is used by pimd to setup the * vxlan-termination-mroute */ - if (sg->src.s_addr != INADDR_ANY) { + if (!ipaddr_is_zero(&sg->src)) { memset(&sip, 0, sizeof(sip)); - parent = zebra_vxlan_sg_do_ref(zvrf, sip, sg->grp); + parent = zebra_vxlan_sg_do_ref(zvrf, &sip, sg->grp); if (!parent) return NULL; } @@ -5989,7 +6001,7 @@ static struct zebra_vxlan_sg *zebra_vxlan_sg_add(struct zebra_vrf *zvrf, static void zebra_vxlan_sg_del(struct zebra_vxlan_sg *vxlan_sg) { - struct in_addr sip; + struct ipaddr sip; struct zebra_vrf *zvrf; zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -5997,13 +6009,13 @@ static void zebra_vxlan_sg_del(struct zebra_vxlan_sg *vxlan_sg) /* On SG entry deletion remove the reference to its parent XG * entry */ - if (vxlan_sg->sg.src.s_addr != INADDR_ANY) { + if (!ipaddr_is_zero(&vxlan_sg->sg.src)) { memset(&sip, 0, sizeof(sip)); - zebra_vxlan_sg_do_deref(zvrf, sip, vxlan_sg->sg.grp); + zebra_vxlan_sg_do_deref(zvrf, &sip, vxlan_sg->sg.grp); } - zebra_vxlan_sg_send(zvrf, &vxlan_sg->sg, - vxlan_sg->sg_str, ZEBRA_VXLAN_SG_DEL); + zebra_vxlan_sg_send(zvrf, &vxlan_sg->sg, vxlan_sg->sg_str, + ZEBRA_VXLAN_SG_DEL); hash_release(vxlan_sg->zvrf->vxlan_sg_table, vxlan_sg); @@ -6014,14 +6026,15 @@ static void zebra_vxlan_sg_del(struct zebra_vxlan_sg *vxlan_sg) } static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf, - struct in_addr sip, struct in_addr mcast_grp) + const struct ipaddr *sip, + const struct in_addr mcast_grp) { struct zebra_vxlan_sg *vxlan_sg; struct prefix_sg sg; sg.family = AF_INET; sg.prefixlen = IPV4_MAX_BYTELEN; - sg.src = sip; + sg.src = *sip; sg.grp = mcast_grp; vxlan_sg = zebra_vxlan_sg_find(zvrf, &sg); if (!vxlan_sg) @@ -6034,16 +6047,16 @@ static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf, zebra_vxlan_sg_del(vxlan_sg); } -static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf, - struct in_addr sip, - struct in_addr mcast_grp) +static struct zebra_vxlan_sg * +zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf, const struct ipaddr *sip, + const struct in_addr mcast_grp) { struct zebra_vxlan_sg *vxlan_sg; struct prefix_sg sg; sg.family = AF_INET; sg.prefixlen = IPV4_MAX_BYTELEN; - sg.src = sip; + sg.src = *sip; sg.grp = mcast_grp; vxlan_sg = zebra_vxlan_sg_add(zvrf, &sg); if (vxlan_sg) @@ -6052,10 +6065,10 @@ static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf, return vxlan_sg; } -void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, - struct in_addr mcast_grp) +void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, struct in_addr mcast_grp) { struct zebra_vrf *zvrf; + struct ipaddr local_vtep_ipaddr; if (local_vtep_ip.s_addr == INADDR_ANY || mcast_grp.s_addr == INADDR_ANY) @@ -6063,20 +6076,26 @@ void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_sg_do_deref(zvrf, local_vtep_ip, mcast_grp); + SET_IPADDR_V4(&local_vtep_ipaddr); + local_vtep_ipaddr.ipaddr_v4 = local_vtep_ip; + + zebra_vxlan_sg_do_deref(zvrf, &local_vtep_ipaddr, mcast_grp); } void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip, struct in_addr mcast_grp) { struct zebra_vrf *zvrf; + struct ipaddr local_vtep_ipaddr; - if (local_vtep_ip.s_addr == INADDR_ANY - || mcast_grp.s_addr == INADDR_ANY) + if (local_vtep_ip.s_addr == INADDR_ANY || mcast_grp.s_addr == INADDR_ANY) return; zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_sg_do_ref(zvrf, local_vtep_ip, mcast_grp); + SET_IPADDR_V4(&local_vtep_ipaddr); + local_vtep_ipaddr.ipaddr_v4 = local_vtep_ip; + + zebra_vxlan_sg_do_ref(zvrf, &local_vtep_ipaddr, mcast_grp); } static void zebra_vxlan_xg_pre_cleanup(struct hash_bucket *bucket, void *arg) @@ -6086,7 +6105,7 @@ static void zebra_vxlan_xg_pre_cleanup(struct hash_bucket *bucket, void *arg) /* increment the ref count against (*,G) to prevent them from being * deleted */ - if (vxlan_sg->sg.src.s_addr == INADDR_ANY) + if (ipaddr_is_zero(&vxlan_sg->sg.src)) ++vxlan_sg->ref_cnt; } @@ -6095,7 +6114,7 @@ static void zebra_vxlan_xg_post_cleanup(struct hash_bucket *bucket, void *arg) struct zebra_vxlan_sg *vxlan_sg = (struct zebra_vxlan_sg *)bucket->data; /* decrement the dummy ref count against (*,G) to delete them */ - if (vxlan_sg->sg.src.s_addr == INADDR_ANY) { + if (ipaddr_is_zero(&vxlan_sg->sg.src)) { if (vxlan_sg->ref_cnt) --vxlan_sg->ref_cnt; if (!vxlan_sg->ref_cnt) |