diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 490bc30d74f4..9e7ed114ee24 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -756,20 +756,6 @@ static int bfd_ifp_destroy(struct interface *ifp) return 0; } -static int bfdd_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t nvrfid; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, &nvrfid); - if (ifp == NULL) - return 0; - - if_update_to_new_vrf(ifp, nvrfid); - - return 0; -} - static void bfdd_sessions_enable_address(struct connected *ifc) { struct bfd_session_observer *bso; @@ -833,9 +819,6 @@ static zclient_handler *const bfd_handlers[] = { */ [ZEBRA_BFD_DEST_REPLAY] = bfdd_replay, - /* Learn about interface VRF. */ - [ZEBRA_INTERFACE_VRF_UPDATE] = bfdd_interface_vrf_update, - /* Learn about new addresses being registered. */ [ZEBRA_INTERFACE_ADDRESS_ADD] = bfdd_interface_address_update, [ZEBRA_INTERFACE_ADDRESS_DELETE] = bfdd_interface_address_update, diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index da7b496d65f2..17d6592c0f78 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -83,10 +83,25 @@ void bgp_advertise_free(struct bgp_advertise *adv) void bgp_advertise_add(struct bgp_advertise_attr *baa, struct bgp_advertise *adv) { - adv->next = baa->adv; - if (baa->adv) - baa->adv->prev = adv; - baa->adv = adv; + struct bgp_advertise *spot, *prev = NULL; + + spot = baa->adv; + + while (spot) { + prev = spot; + spot = spot->next; + } + + if (prev) { + prev->next = adv; + adv->prev = prev; + } else + adv->prev = NULL; + + adv->next = NULL; + + if (!baa->adv) + baa->adv = adv; } void bgp_advertise_delete(struct bgp_advertise_attr *baa, @@ -188,22 +203,22 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr, bgp_dest_lock_node(dest); } -void bgp_adj_in_remove(struct bgp_dest *dest, struct bgp_adj_in *bai) +void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai) { bgp_attr_unintern(&bai->attr); - BGP_ADJ_IN_DEL(dest, bai); - bgp_dest_unlock_node(dest); + BGP_ADJ_IN_DEL(*dest, bai); + *dest = bgp_dest_unlock_node(*dest); peer_unlock(bai->peer); /* adj_in peer reference */ XFREE(MTYPE_BGP_ADJ_IN, bai); } -bool bgp_adj_in_unset(struct bgp_dest *dest, struct peer *peer, +bool bgp_adj_in_unset(struct bgp_dest **dest, struct peer *peer, uint32_t addpath_id) { struct bgp_adj_in *adj; struct bgp_adj_in *adj_next; - adj = dest->adj_in; + adj = (*dest)->adj_in; if (!adj) return false; @@ -215,6 +230,8 @@ bool bgp_adj_in_unset(struct bgp_dest *dest, struct peer *peer, bgp_adj_in_remove(dest, adj); adj = adj_next; + + assert(*dest); } return true; diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index a063208b6d10..94168e2fd7cc 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -130,9 +130,9 @@ 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); -extern bool bgp_adj_in_unset(struct bgp_dest *dest, struct peer *peer, +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); +extern void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai); extern unsigned int bgp_advertise_attr_hash_key(const void *p); extern bool bgp_advertise_attr_hash_cmp(const void *p1, const void *p2); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 2e2248cd72c0..fc13085437f8 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1703,7 +1703,7 @@ struct aspath *aspath_filter_exclude_acl(struct aspath *source, if (cur_seg == source->segments) /* first segment */ source->segments = cur_seg->next; - else + else if (prev_seg) prev_seg->next = cur_seg->next; assegment_free(cur_seg); } @@ -1725,8 +1725,9 @@ struct aspath *aspath_filter_exclude_acl(struct aspath *source, else if (prev_seg) prev_seg->next = new_seg; assegment_free(cur_seg); - } - prev_seg = cur_seg; + prev_seg = new_seg; + } else + prev_seg = cur_seg; cur_seg = next_seg; } diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 8c53191d680f..808b98e41998 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -40,8 +40,12 @@ #endif #include "bgp_evpn.h" #include "bgp_flowspec_private.h" +#include "bgp_linkstate_tlv.h" #include "bgp_mac.h" +DEFINE_MTYPE_STATIC(BGPD, BGP_ATTR_LS, "BGP Attribute Link-State"); +DEFINE_MTYPE_STATIC(BGPD, BGP_ATTR_LS_DATA, "BGP Attribute Link-State Data"); + /* Attribute strings for logging. */ static const struct message attr_str[] = { {BGP_ATTR_ORIGIN, "ORIGIN"}, @@ -65,6 +69,7 @@ static const struct message attr_str[] = { #ifdef ENABLE_BGP_VNC_ATTR {BGP_ATTR_VNC, "VNC"}, #endif + {BGP_ATTR_LINK_STATE, "LINK_STATE"}, {BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY"}, {BGP_ATTR_PREFIX_SID, "PREFIX_SID"}, {BGP_ATTR_IPV6_EXT_COMMUNITIES, "IPV6_EXT_COMMUNITIES"}, @@ -199,6 +204,8 @@ static struct hash *vnc_hash = NULL; static struct hash *srv6_l3vpn_hash; static struct hash *srv6_vpn_hash; +static struct hash *link_state_hash; + struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig) { struct bgp_attr_encap_subtlv *new; @@ -716,6 +723,99 @@ static void srv6_finish(void) hash_clean_and_free(&srv6_vpn_hash, (void (*)(void *))srv6_vpn_free); } +static void *link_state_hash_alloc(void *p) +{ + return p; +} + +static void link_state_free(struct bgp_attr_ls *link_state) +{ + XFREE(MTYPE_BGP_ATTR_LS_DATA, link_state->data); + XFREE(MTYPE_BGP_ATTR_LS, link_state); +} + +static struct bgp_attr_ls *link_state_intern(struct bgp_attr_ls *link_state) +{ + struct bgp_attr_ls *find; + + find = hash_get(link_state_hash, link_state, link_state_hash_alloc); + if (find != link_state) + link_state_free(link_state); + find->refcnt++; + return find; +} + +static void link_state_unintern(struct bgp_attr_ls **link_statep) +{ + struct bgp_attr_ls *link_state = *link_statep; + + if (!*link_statep) + return; + + if (link_state->refcnt) + link_state->refcnt--; + + if (link_state->refcnt == 0) { + hash_release(link_state_hash, link_state); + link_state_free(link_state); + *link_statep = NULL; + } +} + +static uint32_t link_state_hash_key_make(const void *p) +{ + const struct bgp_attr_ls *link_state = p; + uint32_t key = 0; + + key = jhash_1word(link_state->length, key); + key = jhash(link_state->data, link_state->length, key); + + return key; +} + +static bool link_state_hash_cmp(const void *p1, const void *p2) +{ + const struct bgp_attr_ls *link_state1 = p1; + const struct bgp_attr_ls *link_state2 = p2; + + if (!link_state1 && link_state2) + return false; + if (link_state1 && !link_state2) + return false; + if (!link_state1 && !link_state2) + return true; + + if (link_state1->length != link_state2->length) + return false; + + return !memcmp(link_state1->data, link_state2->data, + link_state1->length); +} + +static bool link_state_same(const struct bgp_attr_ls *h1, + const struct bgp_attr_ls *h2) +{ + if (h1 == h2) + return true; + else if (h1 == NULL || h2 == NULL) + return false; + else + return link_state_hash_cmp((const void *)h1, (const void *)h2); +} + +static void link_state_init(void) +{ + link_state_hash = + hash_create(link_state_hash_key_make, link_state_hash_cmp, + "BGP Link-State Attributes TLVs"); +} + +static void link_state_finish(void) +{ + hash_clean_and_free(&link_state_hash, + (void (*)(void *))link_state_free); +} + static unsigned int transit_hash_key_make(const void *p) { const struct transit *transit = p; @@ -805,6 +905,8 @@ unsigned int attrhash_key_make(const void *p) MIX(attr->bh_type); MIX(attr->otc); MIX(bgp_attr_get_aigp_metric(attr)); + if (attr->link_state) + MIX(link_state_hash_key_make(attr->link_state)); return key; } @@ -870,7 +972,8 @@ bool attrhash_cmp(const void *p1, const void *p2) attr1->srte_color == attr2->srte_color && attr1->nh_type == attr2->nh_type && attr1->bh_type == attr2->bh_type && - attr1->otc == attr2->otc) + attr1->otc == attr2->otc && + link_state_same(attr1->link_state, attr2->link_state)) return true; } @@ -1030,6 +1133,12 @@ struct attr *bgp_attr_intern(struct attr *attr) else attr->srv6_vpn->refcnt++; } + if (attr->link_state) { + if (!attr->link_state->refcnt) + attr->link_state = link_state_intern(attr->link_state); + else + attr->link_state->refcnt++; + } #ifdef ENABLE_BGP_VNC struct bgp_attr_encap_subtlv *vnc_subtlvs = bgp_attr_get_vnc_subtlvs(attr); @@ -1248,6 +1357,8 @@ void bgp_attr_unintern_sub(struct attr *attr) srv6_l3vpn_unintern(&attr->srv6_l3vpn); srv6_vpn_unintern(&attr->srv6_vpn); + + link_state_unintern(&attr->link_state); } /* Free bgp attribute and aspath. */ @@ -1368,7 +1479,8 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, /* Only relax error handling for eBGP peers */ if (peer->sort != BGP_PEER_EBGP) { - bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, subcode, + bgp_notify_send_with_data(peer->connection, + BGP_NOTIFY_UPDATE_ERR, subcode, notify_datap, length); return BGP_ATTR_PARSE_ERROR; } @@ -1396,6 +1508,7 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, */ case BGP_ATTR_ORIGIN: case BGP_ATTR_AS_PATH: + case BGP_ATTR_AS4_PATH: case BGP_ATTR_NEXT_HOP: case BGP_ATTR_MULTI_EXIT_DISC: case BGP_ATTR_LOCAL_PREF: @@ -1405,12 +1518,15 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, case BGP_ATTR_LARGE_COMMUNITIES: case BGP_ATTR_ORIGINATOR_ID: case BGP_ATTR_CLUSTER_LIST: + case BGP_ATTR_PMSI_TUNNEL: case BGP_ATTR_ENCAP: case BGP_ATTR_OTC: return BGP_ATTR_PARSE_WITHDRAW; + case BGP_ATTR_LINK_STATE: case BGP_ATTR_MP_REACH_NLRI: case BGP_ATTR_MP_UNREACH_NLRI: - bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, subcode, + bgp_notify_send_with_data(peer->connection, + BGP_NOTIFY_UPDATE_ERR, subcode, notify_datap, length); return BGP_ATTR_PARSE_ERROR; } @@ -1493,6 +1609,7 @@ const uint8_t attr_flags_values[] = { [BGP_ATTR_IPV6_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AIGP] = BGP_ATTR_FLAG_OPTIONAL, + [BGP_ATTR_LINK_STATE] = BGP_ATTR_FLAG_OPTIONAL, }; static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1; @@ -1766,7 +1883,8 @@ enum bgp_attr_parse_ret bgp_attr_nexthop_valid(struct peer *peer, data[1] = BGP_ATTR_NEXT_HOP; data[2] = BGP_ATTR_NHLEN_IPV4; memcpy(&data[3], &attr->nexthop.s_addr, BGP_ATTR_NHLEN_IPV4); - bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send_with_data(peer->connection, + BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, data, 7); return BGP_ATTR_PARSE_ERROR; @@ -3285,6 +3403,32 @@ static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args) return bgp_attr_ignore(peer, args->type); } +/* Link-State (rfc7752) */ +static enum bgp_attr_parse_ret +bgp_attr_linkstate(struct bgp_attr_parser_args *args) +{ + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; + struct stream *s = peer->curr; + struct bgp_attr_ls *bgp_attr_ls; + void *bgp_attr_ls_data; + + if (STREAM_READABLE(s) == 0) + return BGP_ATTR_PARSE_PROCEED; + + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LINK_STATE); + + bgp_attr_ls = XCALLOC(MTYPE_BGP_ATTR_LS, sizeof(struct bgp_attr_ls)); + bgp_attr_ls->length = length; + bgp_attr_ls_data = XCALLOC(MTYPE_BGP_ATTR_LS_DATA, length); + bgp_attr_ls->data = bgp_attr_ls_data; + stream_get(bgp_attr_ls_data, s, length); + attr->link_state = link_state_intern(bgp_attr_ls); + + return BGP_ATTR_PARSE_PROCEED; +} + /* OTC attribute. */ static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args) { @@ -3485,7 +3629,8 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, - stream_pnt(BGP_INPUT(peer)))); if (peer->sort != BGP_PEER_EBGP) { - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send(peer->connection, + BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); ret = BGP_ATTR_PARSE_ERROR; } else { @@ -3514,7 +3659,8 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, - stream_pnt(BGP_INPUT(peer)))); if (peer->sort != BGP_PEER_EBGP) { - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send(peer->connection, + BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); ret = BGP_ATTR_PARSE_ERROR; } else { @@ -3579,10 +3725,10 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, stream_get(&ndata[lfl + 1], BGP_INPUT(peer), ndl); - bgp_notify_send_with_data( - peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, ndata, - ndl + lfl + 1); + bgp_notify_send_with_data(peer->connection, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + ndata, ndl + lfl + 1); ret = BGP_ATTR_PARSE_ERROR; goto done; @@ -3617,7 +3763,8 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, "%s: error BGP attribute type %d appears twice in a message", peer->host, type); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send(peer->connection, + BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); ret = BGP_ATTR_PARSE_ERROR; goto done; @@ -3739,13 +3886,16 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, case BGP_ATTR_AIGP: ret = bgp_attr_aigp(&attr_args); break; + case BGP_ATTR_LINK_STATE: + ret = bgp_attr_linkstate(&attr_args); + break; default: ret = bgp_attr_unknown(&attr_args); break; } if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS) { - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); ret = BGP_ATTR_PARSE_ERROR; goto done; @@ -3775,7 +3925,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, flog_warn(EC_BGP_ATTRIBUTE_FETCH_ERROR, "%s: BGP attribute %s, fetch error", peer->host, lookup_msg(attr_str, type, NULL)); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); ret = BGP_ATTR_PARSE_ERROR; goto done; @@ -3798,7 +3948,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, flog_warn(EC_BGP_ATTRIBUTES_MISMATCH, "%s: BGP attribute %s, length mismatch", peer->host, lookup_msg(attr_str, type, NULL)); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); ret = BGP_ATTR_PARSE_ERROR; @@ -3850,7 +4000,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)) && bgp_attr_munge_as4_attrs(peer, attr, as4_path, as4_aggregator, &as4_aggregator_addr)) { - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); ret = BGP_ATTR_PARSE_ERROR; goto done; @@ -3995,6 +4145,8 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, switch (nh_afi) { case AFI_IP: switch (safi) { + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_LABELED_UNICAST: @@ -4028,6 +4180,8 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, break; case AFI_IP6: switch (safi) { + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_LABELED_UNICAST: @@ -4078,8 +4232,9 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, break; } break; + case AFI_LINKSTATE: case AFI_L2VPN: - if (safi != SAFI_FLOWSPEC) + if (nh_afi == AFI_L2VPN && safi != SAFI_FLOWSPEC) flog_err( EC_BGP_ATTR_NH_SEND_LEN, "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d", @@ -4130,6 +4285,12 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, stream_put_labeled_prefix(s, p, label, addpath_capable, addpath_tx_id); break; + case SAFI_LINKSTATE: + bgp_nlri_encode_linkstate(s, p); + break; + case SAFI_LINKSTATE_VPN: + /* not yet supported */ + break; case SAFI_FLOWSPEC: stream_putc(s, p->u.prefix_flowspec.prefixlen); stream_put(s, (const void *)p->u.prefix_flowspec.ptr, @@ -4156,6 +4317,8 @@ size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, case SAFI_MAX: assert(!"Attempting to figure size for a SAFI_UNSPEC/SAFI_MAX this is a DEV ESCAPE"); break; + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_UNICAST: case SAFI_MULTICAST: break; @@ -4818,6 +4981,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, #endif } + /* BGP Link-State */ + if (attr->link_state) { + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); + stream_putc(s, BGP_ATTR_LINK_STATE); + stream_putc(s, attr->link_state->length); + stream_put(s, attr->link_state->data, attr->link_state->length); + } + /* PMSI Tunnel */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); @@ -4922,6 +5093,7 @@ void bgp_attr_init(void) transit_init(); encap_init(); srv6_init(); + link_state_init(); } void bgp_attr_finish(void) @@ -4935,6 +5107,7 @@ void bgp_attr_finish(void) transit_finish(); encap_finish(); srv6_finish(); + link_state_finish(); } /* Make attribute packet. */ @@ -5143,7 +5316,7 @@ void bgp_path_attribute_discard_vty(struct vty *vty, struct peer *peer, * then flush all. */ if (!discard_attrs) { - for (i = 0; i < BGP_ATTR_MAX; i++) + for (i = 1; i <= BGP_ATTR_MAX; i++) peer->discard_attrs[i] = false; goto discard_soft_clear; } @@ -5152,7 +5325,7 @@ void bgp_path_attribute_discard_vty(struct vty *vty, struct peer *peer, frrstr_split(discard_attrs, " ", &attributes, &num_attributes); if (set) - for (i = 0; i < BGP_ATTR_MAX; i++) + for (i = 1; i <= BGP_ATTR_MAX; i++) peer->discard_attrs[i] = false; for (i = 0; i < num_attributes; i++) { @@ -5212,7 +5385,7 @@ void bgp_path_attribute_withdraw_vty(struct vty *vty, struct peer *peer, * then flush all. */ if (!withdraw_attrs) { - for (i = 0; i < BGP_ATTR_MAX; i++) + for (i = 1; i <= BGP_ATTR_MAX; i++) peer->withdraw_attrs[i] = false; goto withdraw_soft_clear; } @@ -5221,7 +5394,7 @@ void bgp_path_attribute_withdraw_vty(struct vty *vty, struct peer *peer, frrstr_split(withdraw_attrs, " ", &attributes, &num_attributes); if (set) - for (i = 0; i < BGP_ATTR_MAX; i++) + for (i = 1; i <= BGP_ATTR_MAX; i++) peer->withdraw_attrs[i] = false; for (i = 0; i < num_attributes; i++) { diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 961e5f122470..e637b0efbfd3 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -136,6 +136,13 @@ struct bgp_attr_srv6_l3vpn { uint8_t transposition_offset; }; +struct bgp_attr_ls { + unsigned long refcnt; + + uint8_t length; + void *data; +}; + /* BGP core attribute structure. */ struct attr { /* AS Path structure */ @@ -159,6 +166,8 @@ struct attr { /* Path origin attribute */ uint8_t origin; + struct bgp_attr_ls *link_state; /* BGP Link State attribute */ + /* PMSI tunnel type (RFC 6514). */ enum pta_type pmsi_tnl_type; diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 7f83e97107fc..21864cf1a695 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -57,17 +57,17 @@ static void bfd_session_status_update(struct bfd_session_params *bsp, /* rfc9384 */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_BFD_DOWN); - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Stop); } - if (bss->state == BSS_UP && bss->previous_state != BSS_UP - && !peer_established(peer)) { + if (bss->state == BSS_UP && bss->previous_state != BSS_UP && + !peer_established(peer->connection)) { if (!BGP_PEER_START_SUPPRESSED(peer)) { - bgp_fsm_nht_update(peer, true); - BGP_EVENT_ADD(peer, BGP_Start); + bgp_fsm_nht_update(peer->connection, peer, true); + BGP_EVENT_ADD(peer->connection, BGP_Start); } } } @@ -163,36 +163,35 @@ void bgp_peer_bfd_update_source(struct peer *p) /* Update peer's source/destination addresses. */ bfd_sess_addresses(session, &family, &src.v6, &dst.v6); if (family == AF_INET) { - if ((source && source->sin.sin_addr.s_addr != src.v4.s_addr) - || p->su.sin.sin_addr.s_addr != dst.v4.s_addr) { + if ((source && source->sin.sin_addr.s_addr != src.v4.s_addr) || + p->connection->su.sin.sin_addr.s_addr != dst.v4.s_addr) { if (BGP_DEBUG(bfd, BFD_LIB)) - zlog_debug( - "%s: address [%pI4->%pI4] to [%pI4->%pI4]", - __func__, &src.v4, &dst.v4, - source ? &source->sin.sin_addr - : &src.v4, - &p->su.sin.sin_addr); - - bfd_sess_set_ipv4_addrs( - session, source ? &source->sin.sin_addr : NULL, - &p->su.sin.sin_addr); + zlog_debug("%s: address [%pI4->%pI4] to [%pI4->%pI4]", + __func__, &src.v4, &dst.v4, + source ? &source->sin.sin_addr + : &src.v4, + &p->connection->su.sin.sin_addr); + + bfd_sess_set_ipv4_addrs(session, + source ? &source->sin.sin_addr + : NULL, + &p->connection->su.sin.sin_addr); changed = true; } } else { - if ((source && memcmp(&source->sin6, &src.v6, sizeof(src.v6))) - || memcmp(&p->su.sin6, &dst.v6, sizeof(dst.v6))) { + if ((source && memcmp(&source->sin6, &src.v6, sizeof(src.v6))) || + memcmp(&p->connection->su.sin6, &dst.v6, sizeof(dst.v6))) { if (BGP_DEBUG(bfd, BFD_LIB)) - zlog_debug( - "%s: address [%pI6->%pI6] to [%pI6->%pI6]", - __func__, &src.v6, &dst.v6, - source ? &source->sin6.sin6_addr - : &src.v6, - &p->su.sin6.sin6_addr); + zlog_debug("%s: address [%pI6->%pI6] to [%pI6->%pI6]", + __func__, &src.v6, &dst.v6, + source ? &source->sin6.sin6_addr + : &src.v6, + &p->connection->su.sin6.sin6_addr); bfd_sess_set_ipv6_addrs(session, source ? &source->sin6.sin6_addr : NULL, - &p->su.sin6.sin6_addr); + &p->connection->su.sin6.sin6_addr); changed = true; } } @@ -284,16 +283,17 @@ void bgp_peer_configure_bfd(struct peer *p, bool manual) bgp_peer_bfd_reset(p); /* Configure session with basic BGP peer data. */ - if (p->su.sa.sa_family == AF_INET) + if (p->connection->su.sa.sa_family == AF_INET) bfd_sess_set_ipv4_addrs(p->bfd_config->session, p->su_local ? &p->su_local->sin.sin_addr : NULL, - &p->su.sin.sin_addr); + &p->connection->su.sin.sin_addr); else - bfd_sess_set_ipv6_addrs( - p->bfd_config->session, - p->su_local ? &p->su_local->sin6.sin6_addr : NULL, - &p->su.sin6.sin6_addr); + bfd_sess_set_ipv6_addrs(p->bfd_config->session, + p->su_local + ? &p->su_local->sin6.sin6_addr + : NULL, + &p->connection->su.sin6.sin6_addr); bfd_sess_set_vrf(p->bfd_config->session, p->bgp->vrf_id); bfd_sess_set_hop_count(p->bfd_config->session, diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 9821dcf7bb32..7270802915e6 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -264,7 +264,7 @@ static void bmp_per_peer_hdr(struct stream *s, struct peer *peer, stream_putc(s, BMP_PEER_TYPE_GLOBAL_INSTANCE); /* Peer Flags */ - if (peer->su.sa.sa_family == AF_INET6) + if (peer->connection->su.sa.sa_family == AF_INET6) SET_FLAG(flags, BMP_PEER_FLAG_V); else UNSET_FLAG(flags, BMP_PEER_FLAG_V); @@ -275,13 +275,13 @@ static void bmp_per_peer_hdr(struct stream *s, struct peer *peer, stream_put(s, &peer_distinguisher[0], 8); /* Peer Address */ - if (peer->su.sa.sa_family == AF_INET6) - stream_put(s, &peer->su.sin6.sin6_addr, 16); - else if (peer->su.sa.sa_family == AF_INET) { + if (peer->connection->su.sa.sa_family == AF_INET6) + stream_put(s, &peer->connection->su.sin6.sin6_addr, 16); + else if (peer->connection->su.sa.sa_family == AF_INET) { stream_putl(s, 0); stream_putl(s, 0); stream_putl(s, 0); - stream_put_in_addr(s, &peer->su.sin.sin_addr); + stream_put_in_addr(s, &peer->connection->su.sin.sin_addr); } else { stream_putl(s, 0); stream_putl(s, 0); @@ -370,7 +370,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) #define BGP_BMP_MAX_PACKET_SIZE 1024 s = stream_new(BGP_MAX_PACKET_SIZE); - if (peer_established(peer) && !down) { + if (peer_established(peer->connection) && !down) { struct bmp_bgp_peer *bbpeer; bmp_common_hdr(s, BMP_VERSION_3, @@ -716,7 +716,7 @@ static int bmp_peer_status_changed(struct peer *peer) /* Check if this peer just went to Established */ if ((peer->connection->ostatus != OpenConfirm) || - !(peer_established(peer))) + !(peer_established(peer->connection))) return 0; if (peer->doppelganger && @@ -1170,7 +1170,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) zlog_info("bmp: skipping queued item for deleted peer"); goto out; } - if (!peer_established(peer)) + if (!peer_established(peer->connection)) goto out; bool is_vpn = (bqe->afi == AFI_L2VPN && bqe->safi == SAFI_EVPN) || @@ -1355,7 +1355,7 @@ static void bmp_stats(struct event *thread) for (ALL_LIST_ELEMENTS_RO(bt->bgp->peer, node, peer)) { size_t count = 0, count_pos, len; - if (!peer_established(peer)) + if (!peer_established(peer->connection)) continue; s = stream_new(BGP_MAX_PACKET_SIZE); diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c index fc3363b098e7..c4e866c42ebc 100644 --- a/bgpd/bgp_btoa.c +++ b/bgpd/bgp_btoa.c @@ -120,6 +120,7 @@ int main(int argc, char **argv) struct in_addr dip; uint16_t viewno, seq_num; struct prefix_ipv4 p; + char tbuf[32]; s = stream_new(10000); @@ -155,7 +156,7 @@ int main(int argc, char **argv) subtype = stream_getw(s); len = stream_getl(s); - printf("TIME: %s", ctime(&now)); + printf("TIME: %s", ctime_r(&now, tbuf)); /* printf ("TYPE: %d/%d\n", type, subtype); */ @@ -176,6 +177,9 @@ int main(int argc, char **argv) case AFI_IP6: printf("/AFI_IP6\n"); break; + case AFI_LINKSTATE: + printf("/AFI_LINKSTATE\n"); + break; default: printf("/UNKNOWN %d", subtype); break; @@ -239,7 +243,8 @@ int main(int argc, char **argv) source_as = stream_getw(s); printf("FROM: %pI4 AS%d\n", &peer, source_as); - printf("ORIGINATED: %s", ctime(&originated)); + printf("ORIGINATED: %s", ctime_r(&originated, + tbuf)); attrlen = stream_getw(s); printf("ATTRLEN: %d\n", attrlen); diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 3fd246397fd8..e52230713420 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -735,6 +735,27 @@ bool community_list_exact_match(struct community *com, return false; } +bool community_list_any_match(struct community *com, struct community_list *list) +{ + struct community_entry *entry; + uint32_t val; + int i; + + for (i = 0; i < com->size; i++) { + val = community_val_get(com, i); + + for (entry = list->head; entry; entry = entry->next) { + if (entry->style == COMMUNITY_LIST_STANDARD && + community_include(entry->u.com, val)) + return entry->direct == COMMUNITY_PERMIT; + if ((entry->style == COMMUNITY_LIST_EXPANDED) && + community_regexp_include(entry->reg, com, i)) + return entry->direct == COMMUNITY_PERMIT; + } + } + return false; +} + /* Delete all permitted communities in the list from com. */ struct community *community_list_match_delete(struct community *com, struct community_list *list) @@ -922,6 +943,28 @@ int community_list_unset(struct community_list_handler *ch, const char *name, return 0; } +bool lcommunity_list_any_match(struct lcommunity *lcom, + struct community_list *list) +{ + struct community_entry *entry; + uint8_t *ptr; + int i; + + for (i = 0; i < lcom->size; i++) { + ptr = lcom->val + (i * LCOMMUNITY_SIZE); + + for (entry = list->head; entry; entry = entry->next) { + if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) && + lcommunity_include(entry->u.lcom, ptr)) + return entry->direct == COMMUNITY_PERMIT; + if ((entry->style == LARGE_COMMUNITY_LIST_EXPANDED) && + lcommunity_regexp_include(entry->reg, lcom, i)) + return entry->direct == COMMUNITY_PERMIT; + } + } + return false; +} + /* Delete all permitted large communities in the list from com. */ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom, struct community_list *list) diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h index 251169876da6..a435b92ce183 100644 --- a/bgpd/bgp_clist.h +++ b/bgpd/bgp_clist.h @@ -158,8 +158,12 @@ extern bool community_list_exact_match(struct community *com, struct community_list *list); extern bool lcommunity_list_exact_match(struct lcommunity *lcom, struct community_list *list); +extern bool community_list_any_match(struct community *com, + struct community_list *list); extern struct community * community_list_match_delete(struct community *com, struct community_list *list); +extern bool lcommunity_list_any_match(struct lcommunity *lcom, + struct community_list *list); extern struct lcommunity * lcommunity_list_match_delete(struct lcommunity *lcom, struct community_list *list); diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index 53652f7dced0..b30052d95a73 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -194,7 +194,7 @@ static void bgp_conditional_adv_timer(struct event *t) if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) continue; - if (!peer_established(peer)) + if (!peer_established(peer->connection)) continue; FOREACH_AFI_SAFI (afi, safi) { diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index a6d0e74dc0df..80425ebe7adb 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -558,7 +558,7 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi, { struct bgp_damp_info *bdi; time_t t_now, t_diff; - char timebuf[BGP_UPTIME_LEN]; + char timebuf[BGP_UPTIME_LEN] = {}; int penalty; struct bgp_damp_config *bdc = &damp[afi][safi]; @@ -570,7 +570,9 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi, /* If dampening is not enabled or there is no dampening information, return immediately. */ - if (!bdc || !bdi) + if (!CHECK_FLAG(path->peer->bgp->af_flags[afi][safi], + BGP_CONFIG_DAMPENING) || + !bdi) return; /* Calculate new penalty. */ @@ -624,7 +626,9 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, /* If dampening is not enabled or there is no dampening information, return immediately. */ - if (!bdc || !bdi) + if (!CHECK_FLAG(path->peer->bgp->af_flags[afi][safi], + BGP_CONFIG_DAMPENING) || + !bdi) return NULL; /* Calculate new penalty. */ diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 782245e51214..35f83062de27 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -51,6 +51,7 @@ unsigned long conf_bgp_debug_nht; unsigned long conf_bgp_debug_update_groups; unsigned long conf_bgp_debug_vpn; unsigned long conf_bgp_debug_flowspec; +unsigned long conf_bgp_debug_linkstate; unsigned long conf_bgp_debug_labelpool; unsigned long conf_bgp_debug_pbr; unsigned long conf_bgp_debug_graceful_restart; @@ -72,6 +73,7 @@ unsigned long term_bgp_debug_nht; unsigned long term_bgp_debug_update_groups; unsigned long term_bgp_debug_vpn; unsigned long term_bgp_debug_flowspec; +unsigned long term_bgp_debug_linkstate; unsigned long term_bgp_debug_labelpool; unsigned long term_bgp_debug_pbr; unsigned long term_bgp_debug_graceful_restart; @@ -498,12 +500,13 @@ const char *bgp_notify_subcode_str(char code, char subcode) const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data, size_t datalen) { + memset(buf, 0, bufsz); if (!data || datalen < 1) - return NULL; + return buf; uint8_t len = data[0]; if (!len || len > datalen - 1) - return NULL; + return buf; return zlog_sanitize(buf, bufsz, data + 1, len); } diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 118325e0a34e..38beebf872f3 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -60,6 +60,7 @@ extern unsigned long conf_bgp_debug_nht; extern unsigned long conf_bgp_debug_update_groups; extern unsigned long conf_bgp_debug_vpn; extern unsigned long conf_bgp_debug_flowspec; +extern unsigned long conf_bgp_debug_linkstate; extern unsigned long conf_bgp_debug_labelpool; extern unsigned long conf_bgp_debug_pbr; extern unsigned long conf_bgp_debug_graceful_restart; @@ -79,6 +80,7 @@ extern unsigned long term_bgp_debug_nht; extern unsigned long term_bgp_debug_update_groups; extern unsigned long term_bgp_debug_vpn; extern unsigned long term_bgp_debug_flowspec; +extern unsigned long term_bgp_debug_linkstate; extern unsigned long term_bgp_debug_labelpool; extern unsigned long term_bgp_debug_pbr; extern unsigned long term_bgp_debug_graceful_restart; @@ -118,6 +120,7 @@ struct bgp_debug_filter { #define BGP_DEBUG_VPN_LEAK_RMAP_EVENT 0x04 #define BGP_DEBUG_VPN_LEAK_LABEL 0x08 #define BGP_DEBUG_FLOWSPEC 0x01 +#define BGP_DEBUG_LINKSTATE 0x01 #define BGP_DEBUG_LABELPOOL 0x01 #define BGP_DEBUG_PBR 0x01 #define BGP_DEBUG_PBR_ERROR 0x02 diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 3b5fbf368bcd..529713ee3275 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -246,14 +246,15 @@ static void bgp_dump_routes_index_table(struct bgp *bgp) /* Walk down all peers */ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + int family = sockunion_family(&peer->connection->su); /* Peer's type */ - if (sockunion_family(&peer->su) == AF_INET) { + if (family == AF_INET) { stream_putc( obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP); - } else if (sockunion_family(&peer->su) == AF_INET6) { + } else if (family == AF_INET6) { stream_putc( obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4 @@ -264,10 +265,13 @@ static void bgp_dump_routes_index_table(struct bgp *bgp) stream_put_in_addr(obuf, &peer->remote_id); /* Peer's IP address */ - if (sockunion_family(&peer->su) == AF_INET) { - stream_put_in_addr(obuf, &peer->su.sin.sin_addr); - } else if (sockunion_family(&peer->su) == AF_INET6) { - stream_write(obuf, (uint8_t *)&peer->su.sin6.sin6_addr, + if (family == AF_INET) { + stream_put_in_addr(obuf, + &peer->connection->su.sin.sin_addr); + } else if (family == AF_INET6) { + stream_write(obuf, + (uint8_t *)&peer->connection->su.sin6 + .sin6_addr, IPV6_MAX_BYTELEN); } @@ -468,24 +472,26 @@ static void bgp_dump_common(struct stream *obuf, struct peer *peer, stream_putw(obuf, peer->local_as); } - if (peer->su.sa.sa_family == AF_INET) { + if (peer->connection->su.sa.sa_family == AF_INET) { stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0); stream_putw(obuf, AFI_IP); - stream_put(obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN); + stream_put(obuf, &peer->connection->su.sin.sin_addr, + IPV4_MAX_BYTELEN); if (peer->su_local) stream_put(obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN); else stream_put(obuf, empty, IPV4_MAX_BYTELEN); - } else if (peer->su.sa.sa_family == AF_INET6) { + } else if (peer->connection->su.sa.sa_family == AF_INET6) { /* Interface Index and Address family. */ stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0); stream_putw(obuf, AFI_IP6); /* Source IP Address and Destination IP Address. */ - stream_put(obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN); + stream_put(obuf, &peer->connection->su.sin6.sin6_addr, + IPV6_MAX_BYTELEN); if (peer->su_local) stream_put(obuf, &peer->su_local->sin6.sin6_addr, @@ -532,10 +538,10 @@ static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer, /* If dump file pointer is disabled return immediately. */ if (bgp_dump->fp == NULL) return; - if (peer->su.sa.sa_family == AF_INET) { + if (peer->connection->su.sa.sa_family == AF_INET) { addpath_capable = bgp_addpath_encode_rx(peer, AFI_IP, SAFI_UNICAST); - } else if (peer->su.sa.sa_family == AF_INET6) { + } else if (peer->connection->su.sa.sa_family == AF_INET6) { addpath_capable = bgp_addpath_encode_rx(peer, AFI_IP6, SAFI_UNICAST); } diff --git a/bgpd/bgp_errors.c b/bgpd/bgp_errors.c index cfcefed996a5..2f9f16f8007f 100644 --- a/bgpd/bgp_errors.c +++ b/bgpd/bgp_errors.c @@ -449,6 +449,12 @@ static struct log_ref ferr_bgp_err[] = { .description = "The BGP flowspec subsystem has detected that there was a failure for installation/removal/modification of Flowspec from the dataplane", .suggestion = "Gather log files from the router and open an issue, Restart FRR" }, + { + .code = EC_BGP_LINKSTATE_PACKET, + .title = "BGP Link-State packet processing error", + .description = "The BGP Link-State subsystem has detected a error in the send or receive of a packet", + .suggestion = "Gather log files from both sides of the peering relationship and open an issue" + }, { .code = EC_BGP_DOPPELGANGER_CONFIG, .title = "BGP has detected a configuration overwrite during peer collision resolution", diff --git a/bgpd/bgp_errors.h b/bgpd/bgp_errors.h index 4567f8783548..bc6b5a4a3daa 100644 --- a/bgpd/bgp_errors.h +++ b/bgpd/bgp_errors.h @@ -59,6 +59,7 @@ enum bgp_log_refs { EC_BGP_EVPN_INSTANCE_MISMATCH, EC_BGP_FLOWSPEC_PACKET, EC_BGP_FLOWSPEC_INSTALLATION, + EC_BGP_LINKSTATE_PACKET, EC_BGP_ASPATH_FEWER_HOPS, EC_BGP_DEFUNCT_SNPA_LEN, EC_BGP_MISSING_ATTRIBUTE, diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index e5d33e6d5980..ad101f171a7f 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1722,8 +1722,8 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi, continue; } - if (bgp_evpn_path_info_cmp(bgp, tmp_pi, - second_best_path, &paths_eq)) + if (bgp_evpn_path_info_cmp(bgp, tmp_pi, second_best_path, + &paths_eq, false)) second_best_path = tmp_pi; } @@ -2035,10 +2035,10 @@ static void evpn_zebra_reinstall_best_route(struct bgp *bgp, * additional handling to prevent bgp from injecting and holding on to a * non-best local path. */ -static void evpn_cleanup_local_non_best_route(struct bgp *bgp, - struct bgpevpn *vpn, - struct bgp_dest *dest, - struct bgp_path_info *local_pi) +static struct bgp_dest * +evpn_cleanup_local_non_best_route(struct bgp *bgp, struct bgpevpn *vpn, + struct bgp_dest *dest, + struct bgp_path_info *local_pi) { /* local path was not picked as the winner; kick it out */ if (bgp_debug_zebra(NULL)) @@ -2046,10 +2046,11 @@ static void evpn_cleanup_local_non_best_route(struct bgp *bgp, dest); evpn_delete_old_local_route(bgp, vpn, dest, local_pi, NULL); - bgp_path_info_reap(dest, local_pi); /* tell zebra to re-add the best remote path */ evpn_zebra_reinstall_best_route(bgp, vpn, dest); + + return bgp_path_info_reap(dest, local_pi); } static inline bool bgp_evpn_route_add_l3_ecomm_ok(struct bgpevpn *vpn, @@ -2186,7 +2187,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, } else { if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) { route_change = 0; - evpn_cleanup_local_non_best_route(bgp, vpn, dest, pi); + dest = evpn_cleanup_local_non_best_route(bgp, vpn, dest, + pi); } else { bool new_is_sync; @@ -2203,7 +2205,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, } bgp_path_info_unlock(pi); - bgp_dest_unlock_node(dest); + if (dest) + bgp_dest_unlock_node(dest); /* If this is a new route or some attribute has changed, export the * route to the global table. The route will be advertised to peers @@ -2327,9 +2330,13 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, */ delete_evpn_route_entry(bgp, afi, safi, dest, &pi); if (pi) { - bgp_path_info_reap(dest, pi); + dest = bgp_path_info_reap(dest, pi); + assert(dest); evpn_route_select_install(bgp, vpn, dest); } + + /* dest should still exist due to locking make coverity happy */ + assert(dest); bgp_dest_unlock_node(dest); return 0; @@ -2571,7 +2578,8 @@ static void delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) } } -static void delete_vni_type2_route(struct bgp *bgp, struct bgp_dest *dest) +static struct bgp_dest *delete_vni_type2_route(struct bgp *bgp, + struct bgp_dest *dest) { struct bgp_path_info *pi; afi_t afi = AFI_L2VPN; @@ -2581,13 +2589,15 @@ static void delete_vni_type2_route(struct bgp *bgp, struct bgp_dest *dest) (const struct prefix_evpn *)bgp_dest_get_prefix(dest); if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) - return; + return dest; delete_evpn_route_entry(bgp, afi, safi, dest, &pi); /* Route entry in local table gets deleted immediately. */ if (pi) - bgp_path_info_reap(dest, pi); + dest = bgp_path_info_reap(dest, pi); + + return dest; } static void delete_vni_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) @@ -2598,12 +2608,16 @@ static void delete_vni_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) * routes. */ for (dest = bgp_table_top(vpn->mac_table); dest; - dest = bgp_route_next(dest)) - delete_vni_type2_route(bgp, dest); + dest = bgp_route_next(dest)) { + dest = delete_vni_type2_route(bgp, dest); + assert(dest); + } for (dest = bgp_table_top(vpn->ip_table); dest; - dest = bgp_route_next(dest)) - delete_vni_type2_route(bgp, dest); + dest = bgp_route_next(dest)) { + dest = delete_vni_type2_route(bgp, dest); + assert(dest); + } } /* @@ -2635,7 +2649,9 @@ static void delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) { bgp_evpn_remote_ip_hash_del(vpn, pi); bgp_path_info_delete(dest, pi); - bgp_path_info_reap(dest, pi); + dest = bgp_path_info_reap(dest, pi); + + assert(dest); } } @@ -2644,7 +2660,9 @@ static void delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) { bgp_path_info_delete(dest, pi); - bgp_path_info_reap(dest, pi); + dest = bgp_path_info_reap(dest, pi); + + assert(dest); } } } @@ -3011,14 +3029,14 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Process for route leaking. */ vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi); - bgp_dest_unlock_node(dest); - if (bgp_debug_zebra(NULL)) zlog_debug("... %s pi dest %p (l %d) pi %p (l %d, f 0x%x)", new_pi ? "new" : "update", dest, bgp_dest_get_lock_count(dest), pi, pi->lock, pi->flags); + bgp_dest_unlock_node(dest); + return ret; } diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 91db9a061a9c..ffb1b17ec7f7 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -323,7 +323,9 @@ static void bgp_evpn_es_route_del_all(struct bgp *bgp, struct bgp_evpn_es *es) for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) { bgp_path_info_delete(dest, pi); - bgp_path_info_reap(dest, pi); + dest = bgp_path_info_reap(dest, pi); + + assert(dest); } } } @@ -513,8 +515,11 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es, */ delete_evpn_route_entry(bgp, afi, safi, dest, &pi); if (pi) - bgp_path_info_reap(dest, pi); + dest = bgp_path_info_reap(dest, pi); + + assert(dest); bgp_dest_unlock_node(dest); + return 0; } diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index e4c7fdb124f0..eb9f34ef02ad 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2687,16 +2687,16 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, */ if (is_evpn_prefix_ipaddr_none(evp)) { /* VNI MAC -> Global */ - evpn_type2_prefix_global_copy( - (struct prefix_evpn *)&tmp_p, evp, - NULL /* mac */, - evpn_type2_path_info_get_ip(pi)); + evpn_type2_prefix_global_copy(&tmp_p, evp, + NULL /* mac */, + evpn_type2_path_info_get_ip( + pi)); } else { /* VNI IP -> Global */ - evpn_type2_prefix_global_copy( - (struct prefix_evpn *)&tmp_p, evp, - evpn_type2_path_info_get_mac(pi), - NULL /* ip */); + evpn_type2_prefix_global_copy(&tmp_p, evp, + evpn_type2_path_info_get_mac( + pi), + NULL /* ip */); } route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p, diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 786e953843c6..eef3b644080a 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -93,9 +93,11 @@ int bgp_peer_reg_with_nht(struct peer *peer) && !CHECK_FLAG(peer->bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) connected = 1; - return bgp_find_or_add_nexthop( - peer->bgp, peer->bgp, family2afi(peer->su.sa.sa_family), - SAFI_UNICAST, NULL, peer, connected, NULL); + return bgp_find_or_add_nexthop(peer->bgp, peer->bgp, + family2afi( + peer->connection->su.sa.sa_family), + SAFI_UNICAST, NULL, peer, connected, + NULL); } static void peer_xfer_stats(struct peer *peer_dst, struct peer *peer_src) @@ -116,17 +118,29 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) struct peer *peer; afi_t afi; safi_t safi; - int fd; - enum bgp_fsm_status status, pstatus; enum bgp_fsm_events last_evt, last_maj_evt; + struct peer_connection *keeper, *going_away; assert(from_peer != NULL); + /* + * Keeper is the connection that is staying around + */ + keeper = from_peer->connection; peer = from_peer->doppelganger; if (!peer || !CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) return from_peer; + /* + * from_peer is pointing at the non config node and + * at this point peer is pointing at the CONFIG node + * peer ( non incoming connection ). The going_away pointer + * is the connection that is being placed on to + * the non Config node for deletion. + */ + going_away = peer->connection; + /* * Let's check that we are not going to loose known configuration * state based upon doppelganger rules. @@ -146,10 +160,10 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) from_peer->host, from_peer, from_peer->connection->fd, peer, peer->connection->fd); - bgp_writes_off(peer->connection); - bgp_reads_off(peer->connection); - bgp_writes_off(from_peer->connection); - bgp_reads_off(from_peer->connection); + bgp_writes_off(going_away); + bgp_reads_off(going_away); + bgp_writes_off(keeper); + bgp_reads_off(keeper); /* * Before exchanging FD remove doppelganger from @@ -157,70 +171,29 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) * fd is set to -1. If blocked on lock then keepalive * thread can access peer pointer with fd -1. */ - bgp_keepalives_off(from_peer); - - EVENT_OFF(peer->t_routeadv); - EVENT_OFF(peer->t_connect); - EVENT_OFF(peer->t_delayopen); - EVENT_OFF(peer->t_connect_check_r); - EVENT_OFF(peer->t_connect_check_w); - EVENT_OFF(from_peer->t_routeadv); - EVENT_OFF(from_peer->t_connect); - EVENT_OFF(from_peer->t_delayopen); - EVENT_OFF(from_peer->t_connect_check_r); - EVENT_OFF(from_peer->t_connect_check_w); - EVENT_OFF(from_peer->connection->t_process_packet); + bgp_keepalives_off(keeper); + + EVENT_OFF(going_away->t_routeadv); + EVENT_OFF(going_away->t_connect); + EVENT_OFF(going_away->t_delayopen); + EVENT_OFF(going_away->t_connect_check_r); + EVENT_OFF(going_away->t_connect_check_w); + EVENT_OFF(keeper->t_routeadv); + EVENT_OFF(keeper->t_connect); + EVENT_OFF(keeper->t_delayopen); + EVENT_OFF(keeper->t_connect_check_r); + EVENT_OFF(keeper->t_connect_check_w); + EVENT_OFF(keeper->t_process_packet); /* * At this point in time, it is possible that there are packets pending * on various buffers. Those need to be transferred or dropped, * otherwise we'll get spurious failures during session establishment. */ - frr_with_mutex (&peer->connection->io_mtx, - &from_peer->connection->io_mtx) { - fd = peer->connection->fd; - peer->connection->fd = from_peer->connection->fd; - from_peer->connection->fd = fd; - - stream_fifo_clean(peer->connection->ibuf); - stream_fifo_clean(peer->connection->obuf); - - /* - * this should never happen, since bgp_process_packet() is the - * only task that sets and unsets the current packet and it - * runs in our pthread. - */ - if (peer->curr) { - flog_err( - EC_BGP_PKT_PROCESS, - "[%s] Dropping pending packet on connection transfer:", - peer->host); - /* there used to be a bgp_packet_dump call here, but - * that's extremely confusing since there's no way to - * identify the packet in MRT dumps or BMP as dropped - * due to connection transfer. - */ - stream_free(peer->curr); - peer->curr = NULL; - } - - // copy each packet from old peer's output queue to new peer - while (from_peer->connection->obuf->head) - stream_fifo_push(peer->connection->obuf, - stream_fifo_pop( - from_peer->connection->obuf)); - - // copy each packet from old peer's input queue to new peer - while (from_peer->connection->ibuf->head) - stream_fifo_push(peer->connection->ibuf, - stream_fifo_pop( - from_peer->connection->ibuf)); - - ringbuf_wipe(peer->connection->ibuf_work); - ringbuf_copy(peer->connection->ibuf_work, - from_peer->connection->ibuf_work, - ringbuf_remain(from_peer->connection->ibuf_work)); - } + peer->connection = keeper; + keeper->peer = peer; + from_peer->connection = going_away; + going_away->peer = from_peer; peer->as = from_peer->as; peer->v_holdtime = from_peer->v_holdtime; @@ -230,16 +203,10 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) peer->v_gr_restart = from_peer->v_gr_restart; peer->cap = from_peer->cap; peer->remote_role = from_peer->remote_role; - status = peer->connection->status; - pstatus = peer->connection->ostatus; last_evt = peer->last_event; last_maj_evt = peer->last_major_event; - peer->connection->status = from_peer->connection->status; - peer->connection->ostatus = from_peer->connection->ostatus; peer->last_event = from_peer->last_event; peer->last_major_event = from_peer->last_major_event; - from_peer->connection->status = status; - from_peer->connection->ostatus = pstatus; from_peer->last_event = last_evt; from_peer->last_major_event = last_maj_evt; peer->remote_id = from_peer->remote_id; @@ -301,13 +268,12 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER) ? "accept" : ""), - peer->host, peer->connection->fd, - from_peer->connection->fd); - BGP_EVENT_ADD(peer, BGP_Stop); - BGP_EVENT_ADD(from_peer, BGP_Stop); + peer->host, going_away->fd, keeper->fd); + BGP_EVENT_ADD(going_away, BGP_Stop); + BGP_EVENT_ADD(keeper, BGP_Stop); return NULL; } - if (from_peer->connection->status > Active) { + if (going_away->status > Active) { if (bgp_getsockname(from_peer) < 0) { flog_err(EC_LIB_SOCKET, "%%bgp_getsockname() failed for %s from_peer %s fd %d (peer fd %d)", @@ -316,9 +282,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) PEER_STATUS_ACCEPT_PEER) ? "accept" : ""), - from_peer->host, from_peer->connection->fd, - peer->connection->fd); - bgp_stop(from_peer->connection); + from_peer->host, going_away->fd, keeper->fd); + bgp_stop(going_away); from_peer = NULL; } } @@ -335,10 +300,10 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) if (from_peer) bgp_replace_nexthop_by_peer(from_peer, peer); - bgp_reads_on(peer->connection); - bgp_writes_on(peer->connection); - event_add_event(bm->master, bgp_process_packet, peer->connection, 0, - &peer->connection->t_process_packet); + bgp_reads_on(keeper); + bgp_writes_on(keeper); + event_add_event(bm->master, bgp_process_packet, keeper, 0, + &keeper->t_process_packet); return (peer); } @@ -346,88 +311,90 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) /* Hook function called after bgp event is occered. And vty's neighbor command invoke this function after making neighbor structure. */ -void bgp_timer_set(struct peer *peer) +void bgp_timer_set(struct peer_connection *connection) { afi_t afi; safi_t safi; + struct peer *peer = connection->peer; - switch (peer->connection->status) { + switch (connection->status) { case Idle: /* First entry point of peer's finite state machine. In Idle status start timer is on unless peer is shutdown or peer is inactive. All other timer must be turned off */ if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer) || peer->bgp->vrf_id == VRF_UNKNOWN) { - EVENT_OFF(peer->t_start); + EVENT_OFF(connection->t_start); } else { - BGP_TIMER_ON(peer->t_start, bgp_start_timer, + BGP_TIMER_ON(connection->t_start, bgp_start_timer, peer->v_start); } - EVENT_OFF(peer->t_connect); - EVENT_OFF(peer->t_holdtime); - bgp_keepalives_off(peer); - EVENT_OFF(peer->t_routeadv); - EVENT_OFF(peer->t_delayopen); + EVENT_OFF(connection->t_connect); + EVENT_OFF(connection->t_holdtime); + bgp_keepalives_off(connection); + EVENT_OFF(connection->t_routeadv); + EVENT_OFF(connection->t_delayopen); break; case Connect: /* After start timer is expired, the peer moves to Connect status. Make sure start timer is off and connect timer is on. */ - EVENT_OFF(peer->t_start); + EVENT_OFF(connection->t_start); if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN)) - BGP_TIMER_ON(peer->t_connect, bgp_connect_timer, + BGP_TIMER_ON(connection->t_connect, bgp_connect_timer, (peer->v_delayopen + peer->v_connect)); else - BGP_TIMER_ON(peer->t_connect, bgp_connect_timer, + BGP_TIMER_ON(connection->t_connect, bgp_connect_timer, peer->v_connect); - EVENT_OFF(peer->t_holdtime); - bgp_keepalives_off(peer); - EVENT_OFF(peer->t_routeadv); + EVENT_OFF(connection->t_holdtime); + bgp_keepalives_off(connection); + EVENT_OFF(connection->t_routeadv); break; case Active: /* Active is waiting connection from remote peer. And if connect timer is expired, change status to Connect. */ - EVENT_OFF(peer->t_start); + EVENT_OFF(connection->t_start); /* If peer is passive mode, do not set connect timer. */ if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE) || CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { - EVENT_OFF(peer->t_connect); + EVENT_OFF(connection->t_connect); } else { if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN)) - BGP_TIMER_ON( - peer->t_connect, bgp_connect_timer, - (peer->v_delayopen + peer->v_connect)); + BGP_TIMER_ON(connection->t_connect, + bgp_connect_timer, + (peer->v_delayopen + + peer->v_connect)); else - BGP_TIMER_ON(peer->t_connect, bgp_connect_timer, - peer->v_connect); + BGP_TIMER_ON(connection->t_connect, + bgp_connect_timer, peer->v_connect); } - EVENT_OFF(peer->t_holdtime); - bgp_keepalives_off(peer); - EVENT_OFF(peer->t_routeadv); + EVENT_OFF(connection->t_holdtime); + bgp_keepalives_off(connection); + EVENT_OFF(connection->t_routeadv); break; case OpenSent: /* OpenSent status. */ - EVENT_OFF(peer->t_start); - EVENT_OFF(peer->t_connect); + EVENT_OFF(connection->t_start); + EVENT_OFF(connection->t_connect); if (peer->v_holdtime != 0) { - BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer, + BGP_TIMER_ON(connection->t_holdtime, bgp_holdtime_timer, peer->v_holdtime); } else { - EVENT_OFF(peer->t_holdtime); + EVENT_OFF(connection->t_holdtime); } - bgp_keepalives_off(peer); - EVENT_OFF(peer->t_routeadv); - EVENT_OFF(peer->t_delayopen); + bgp_keepalives_off(connection); + EVENT_OFF(connection->t_routeadv); + EVENT_OFF(connection->t_delayopen); break; case OpenConfirm: /* OpenConfirm status. */ - EVENT_OFF(peer->t_start); - EVENT_OFF(peer->t_connect); + EVENT_OFF(connection->t_start); + EVENT_OFF(connection->t_connect); /* * If the negotiated Hold Time value is zero, then the Hold Time @@ -435,24 +402,24 @@ void bgp_timer_set(struct peer *peer) * Additionally if a different hold timer has been negotiated * than we must stop then start the timer again */ - EVENT_OFF(peer->t_holdtime); + EVENT_OFF(connection->t_holdtime); if (peer->v_holdtime == 0) - bgp_keepalives_off(peer); + bgp_keepalives_off(connection); else { - BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer, + BGP_TIMER_ON(connection->t_holdtime, bgp_holdtime_timer, peer->v_holdtime); - bgp_keepalives_on(peer); + bgp_keepalives_on(connection); } - EVENT_OFF(peer->t_routeadv); - EVENT_OFF(peer->t_delayopen); + EVENT_OFF(connection->t_routeadv); + EVENT_OFF(connection->t_delayopen); break; case Established: /* In Established status start and connect timer is turned off. */ - EVENT_OFF(peer->t_start); - EVENT_OFF(peer->t_connect); - EVENT_OFF(peer->t_delayopen); + EVENT_OFF(connection->t_start); + EVENT_OFF(connection->t_connect); + EVENT_OFF(connection->t_delayopen); /* * Same as OpenConfirm, if holdtime is zero then both holdtime @@ -460,32 +427,32 @@ void bgp_timer_set(struct peer *peer) * Additionally if a different hold timer has been negotiated * then we must stop then start the timer again */ - EVENT_OFF(peer->t_holdtime); + EVENT_OFF(connection->t_holdtime); if (peer->v_holdtime == 0) - bgp_keepalives_off(peer); + bgp_keepalives_off(connection); else { - BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer, + BGP_TIMER_ON(connection->t_holdtime, bgp_holdtime_timer, peer->v_holdtime); - bgp_keepalives_on(peer); + bgp_keepalives_on(connection); } break; case Deleted: - EVENT_OFF(peer->t_gr_restart); - EVENT_OFF(peer->t_gr_stale); + EVENT_OFF(peer->connection->t_gr_restart); + EVENT_OFF(peer->connection->t_gr_stale); FOREACH_AFI_SAFI (afi, safi) EVENT_OFF(peer->t_llgr_stale[afi][safi]); - EVENT_OFF(peer->t_pmax_restart); + EVENT_OFF(peer->connection->t_pmax_restart); EVENT_OFF(peer->t_refresh_stalepath); /* fallthru */ case Clearing: - EVENT_OFF(peer->t_start); - EVENT_OFF(peer->t_connect); - EVENT_OFF(peer->t_holdtime); - bgp_keepalives_off(peer); - EVENT_OFF(peer->t_routeadv); - EVENT_OFF(peer->t_delayopen); + EVENT_OFF(connection->t_start); + EVENT_OFF(connection->t_connect); + EVENT_OFF(connection->t_holdtime); + bgp_keepalives_off(connection); + EVENT_OFF(connection->t_routeadv); + EVENT_OFF(connection->t_delayopen); break; case BGP_STATUS_MAX: flog_err(EC_LIB_DEVELOPMENT, @@ -498,9 +465,8 @@ void bgp_timer_set(struct peer *peer) and process event. */ static void bgp_start_timer(struct event *thread) { - struct peer *peer; - - peer = EVENT_ARG(thread); + struct peer_connection *connection = EVENT_ARG(thread); + struct peer *peer = connection->peer; if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [FSM] Timer (start timer expire).", peer->host); @@ -512,21 +478,20 @@ static void bgp_start_timer(struct event *thread) /* BGP connect retry timer. */ static void bgp_connect_timer(struct event *thread) { - struct peer *peer; - - peer = EVENT_ARG(thread); + struct peer_connection *connection = EVENT_ARG(thread); + struct peer *peer = connection->peer; /* stop the DelayOpenTimer if it is running */ - EVENT_OFF(peer->t_delayopen); + EVENT_OFF(connection->t_delayopen); - assert(!peer->connection->t_write); - assert(!peer->connection->t_read); + assert(!connection->t_write); + assert(!connection->t_read); if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [FSM] Timer (connect timer expire)", peer->host); if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) - bgp_stop(peer->connection); + bgp_stop(connection); else { EVENT_VAL(thread) = ConnectRetry_timer_expired; bgp_event(thread); /* bgp_event unlocks peer */ @@ -537,9 +502,8 @@ static void bgp_connect_timer(struct event *thread) static void bgp_holdtime_timer(struct event *thread) { atomic_size_t inq_count; - struct peer *peer; - - peer = EVENT_ARG(thread); + struct peer_connection *connection = EVENT_ARG(thread); + struct peer *peer = connection->peer; if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [FSM] Timer (holdtime timer expire)", @@ -555,10 +519,10 @@ static void bgp_holdtime_timer(struct event *thread) * for systems where we are heavily loaded for one * reason or another. */ - inq_count = atomic_load_explicit(&peer->connection->ibuf->count, + inq_count = atomic_load_explicit(&connection->ibuf->count, memory_order_relaxed); if (inq_count) - BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer, + BGP_TIMER_ON(connection->t_holdtime, bgp_holdtime_timer, peer->v_holdtime); EVENT_VAL(thread) = Hold_Timer_expired; @@ -567,18 +531,16 @@ static void bgp_holdtime_timer(struct event *thread) void bgp_routeadv_timer(struct event *thread) { - struct peer *peer; - - peer = EVENT_ARG(thread); + struct peer_connection *connection = EVENT_ARG(thread); + struct peer *peer = connection->peer; if (bgp_debug_neighbor_events(peer)) - zlog_debug("%s [FSM] Timer (routeadv timer expire)", - peer->host); + zlog_debug("%s [FSM] Timer (routeadv timer expire)", peer->host); peer->synctime = monotime(NULL); - event_add_timer_msec(bm->master, bgp_generate_updgrp_packets, peer, 0, - &peer->t_generate_updgrp_packets); + event_add_timer_msec(bm->master, bgp_generate_updgrp_packets, connection, + 0, &connection->t_generate_updgrp_packets); /* MRAI timer will be started again when FIFO is built, no need to * do it here. @@ -588,9 +550,8 @@ void bgp_routeadv_timer(struct event *thread) /* RFC 4271 DelayOpenTimer */ void bgp_delayopen_timer(struct event *thread) { - struct peer *peer; - - peer = EVENT_ARG(thread); + struct peer_connection *connection = EVENT_ARG(thread); + struct peer *peer = connection->peer; if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [FSM] Timer (DelayOpentimer expire)", @@ -638,7 +599,8 @@ const char *const peer_down_str[] = {"", "Socket Error", "Admin. shutdown (RTT)"}; -static void bgp_graceful_restart_timer_off(struct peer *peer) +static void bgp_graceful_restart_timer_off(struct peer_connection *connection, + struct peer *peer) { afi_t afi; safi_t safi; @@ -649,7 +611,7 @@ static void bgp_graceful_restart_timer_off(struct peer *peer) return; UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); - EVENT_OFF(peer->t_gr_stale); + EVENT_OFF(connection->t_gr_stale); if (peer_dynamic_neighbor(peer) && !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { @@ -659,7 +621,7 @@ static void bgp_graceful_restart_timer_off(struct peer *peer) peer_delete(peer); } - bgp_timer_set(peer); + bgp_timer_set(connection); } static void bgp_llgr_stale_timer_expire(struct event *thread) @@ -687,7 +649,7 @@ static void bgp_llgr_stale_timer_expire(struct event *thread) bgp_clear_stale_route(peer, afi, safi); - bgp_graceful_restart_timer_off(peer); + bgp_graceful_restart_timer_off(peer->connection, peer); } static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) @@ -766,14 +728,14 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) static void bgp_graceful_restart_timer_expire(struct event *thread) { - struct peer *peer, *tmp_peer; + struct peer_connection *connection = EVENT_ARG(thread); + struct peer *peer = connection->peer; + struct peer *tmp_peer; struct listnode *node, *nnode; struct peer_af *paf; afi_t afi; safi_t safi; - peer = EVENT_ARG(thread); - if (bgp_debug_neighbor_events(peer)) { zlog_debug("%pBP graceful restart timer expired", peer); zlog_debug("%pBP graceful restart stalepath timer stopped", @@ -826,17 +788,16 @@ static void bgp_graceful_restart_timer_expire(struct event *thread) } } - bgp_graceful_restart_timer_off(peer); + bgp_graceful_restart_timer_off(connection, peer); } static void bgp_graceful_stale_timer_expire(struct event *thread) { - struct peer *peer; + struct peer_connection *connection = EVENT_ARG(thread); + struct peer *peer = connection->peer; afi_t afi; safi_t safi; - peer = EVENT_ARG(thread); - if (bgp_debug_neighbor_events(peer)) zlog_debug("%pBP graceful restart stalepath timer expired", peer); @@ -964,10 +925,13 @@ void bgp_start_routeadv(struct bgp *bgp) sizeof(bgp->update_delay_peers_resume_time)); for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (!peer_established(peer)) + struct peer_connection *connection = peer->connection; + + if (!peer_established(connection)) continue; - EVENT_OFF(peer->t_routeadv); - BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0); + + EVENT_OFF(connection->t_routeadv); + BGP_TIMER_ON(connection->t_routeadv, bgp_routeadv_timer, 0); } } @@ -979,6 +943,7 @@ void bgp_adjust_routeadv(struct peer *peer) time_t nowtime = monotime(NULL); double diff; unsigned long remain; + struct peer_connection *connection = peer->connection; /* Bypass checks for special case of MRAI being 0 */ if (peer->v_routeadv == 0) { @@ -986,7 +951,7 @@ void bgp_adjust_routeadv(struct peer *peer) * different * duration and schedule write thread immediately. */ - EVENT_OFF(peer->t_routeadv); + EVENT_OFF(connection->t_routeadv); peer->synctime = monotime(NULL); /* If suppress fib pending is enabled, route is advertised to @@ -994,7 +959,7 @@ void bgp_adjust_routeadv(struct peer *peer) * is added to update group packet generate which will allow * more routes to be sent in the update message */ - BGP_UPDATE_GROUP_TIMER_ON(&peer->t_generate_updgrp_packets, + BGP_UPDATE_GROUP_TIMER_ON(&connection->t_generate_updgrp_packets, bgp_generate_updgrp_packets); return; } @@ -1018,8 +983,8 @@ void bgp_adjust_routeadv(struct peer *peer) */ diff = difftime(nowtime, peer->last_update); if (diff > (double)peer->v_routeadv) { - EVENT_OFF(peer->t_routeadv); - BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0); + EVENT_OFF(connection->t_routeadv); + BGP_TIMER_ON(connection->t_routeadv, bgp_routeadv_timer, 0); return; } @@ -1039,14 +1004,14 @@ void bgp_adjust_routeadv(struct peer *peer) * * (MRAI - m) < r */ - if (peer->t_routeadv) - remain = event_timer_remain_second(peer->t_routeadv); + if (connection->t_routeadv) + remain = event_timer_remain_second(connection->t_routeadv); else remain = peer->v_routeadv; diff = peer->v_routeadv - diff; if (diff <= (double)remain) { - EVENT_OFF(peer->t_routeadv); - BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, diff); + EVENT_OFF(connection->t_routeadv); + BGP_TIMER_ON(connection->t_routeadv, bgp_routeadv_timer, diff); } } @@ -1154,7 +1119,7 @@ static void bgp_maxmed_onstartup_begin(struct bgp *bgp) static void bgp_maxmed_onstartup_process_status_change(struct peer *peer) { - if (peer_established(peer) && !peer->bgp->established) { + if (peer_established(peer->connection) && !peer->bgp->established) { bgp_maxmed_onstartup_begin(peer->bgp); } } @@ -1212,7 +1177,7 @@ static void bgp_update_delay_begin(struct bgp *bgp) static void bgp_update_delay_process_status_change(struct peer *peer) { - if (peer_established(peer)) { + if (peer_established(peer->connection)) { if (!peer->bgp->established++) { bgp_update_delay_begin(peer->bgp); zlog_info( @@ -1238,17 +1203,18 @@ static void bgp_update_delay_process_status_change(struct peer *peer) /* Called after event occurred, this function change status and reset read/write and timer thread. */ -void bgp_fsm_change_status(struct peer *peer, enum bgp_fsm_status status) +void bgp_fsm_change_status(struct peer_connection *connection, + enum bgp_fsm_status status) { - struct bgp *bgp; + struct peer *peer = connection->peer; + struct bgp *bgp = peer->bgp; uint32_t peer_count; - bgp = peer->bgp; peer_count = bgp->established_peers; if (status == Established) bgp->established_peers++; - else if ((peer_established(peer)) && (status != Established)) + else if ((peer_established(connection)) && (status != Established)) bgp->established_peers--; if (bgp_debug_neighbor_events(peer)) { @@ -1295,19 +1261,19 @@ void bgp_fsm_change_status(struct peer *peer, enum bgp_fsm_status status) */ if (!work_queue_is_scheduled(peer->clear_node_queue) && status != Deleted) - BGP_EVENT_ADD(peer, Clearing_Completed); + BGP_EVENT_ADD(connection, Clearing_Completed); } /* Preserve old status and change into new status. */ - peer->connection->ostatus = peer->connection->status; - peer->connection->status = status; + connection->ostatus = connection->status; + connection->status = status; /* Reset received keepalives counter on every FSM change */ peer->rtt_keepalive_rcv = 0; /* Fire backward transition hook if that's the case */ - if (peer->connection->ostatus == Established && - peer->connection->status != Established) + if (connection->ostatus == Established && + connection->status != Established) hook_call(peer_backward_transition, peer); /* Save event that caused status change. */ @@ -1335,23 +1301,19 @@ void bgp_fsm_change_status(struct peer *peer, enum bgp_fsm_status status) if (bgp_debug_neighbor_events(peer)) zlog_debug("%s fd %d went from %s to %s", peer->host, - peer->connection->fd, - lookup_msg(bgp_status_msg, peer->connection->ostatus, - NULL), - lookup_msg(bgp_status_msg, peer->connection->status, - NULL)); + connection->fd, + lookup_msg(bgp_status_msg, connection->ostatus, NULL), + lookup_msg(bgp_status_msg, connection->status, NULL)); } /* Flush the event queue and ensure the peer is shut down */ static enum bgp_fsm_state_progress bgp_clearing_completed(struct peer_connection *connection) { - struct peer *peer = connection->peer; - enum bgp_fsm_state_progress rc = bgp_stop(connection); if (rc >= BGP_FSM_SUCCESS) - BGP_EVENT_FLUSH(peer); + event_cancel_event_ready(bm->master, connection); return rc; } @@ -1387,11 +1349,11 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) /* Can't do this in Clearing; events are used for state transitions */ if (connection->status != Clearing) { /* Delete all existing events of the peer */ - BGP_EVENT_FLUSH(peer); + event_cancel_event_ready(bm->master, connection); } /* Increment Dropped count. */ - if (peer_established(peer)) { + if (peer_established(connection)) { peer->dropped++; /* Notify BGP conditional advertisement process */ @@ -1413,8 +1375,8 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) } /* graceful restart */ - if (peer->t_gr_stale) { - EVENT_OFF(peer->t_gr_stale); + if (connection->t_gr_stale) { + EVENT_OFF(connection->t_gr_stale); if (bgp_debug_neighbor_events(peer)) zlog_debug( "%pBP graceful restart stalepath timer stopped", @@ -1429,10 +1391,10 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) "%pBP graceful restart stalepath timer started for %d sec", peer, peer->bgp->stalepath_time); } - BGP_TIMER_ON(peer->t_gr_restart, + BGP_TIMER_ON(connection->t_gr_restart, bgp_graceful_restart_timer_expire, peer->v_gr_restart); - BGP_TIMER_ON(peer->t_gr_stale, + BGP_TIMER_ON(connection->t_gr_stale, bgp_graceful_stale_timer_expire, peer->bgp->stalepath_time); } else { @@ -1501,21 +1463,21 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) } /* stop keepalives */ - bgp_keepalives_off(peer); + bgp_keepalives_off(connection); /* Stop read and write threads. */ bgp_writes_off(connection); bgp_reads_off(connection); - EVENT_OFF(peer->t_connect_check_r); - EVENT_OFF(peer->t_connect_check_w); + EVENT_OFF(connection->t_connect_check_r); + EVENT_OFF(connection->t_connect_check_w); /* Stop all timers. */ - EVENT_OFF(peer->t_start); - EVENT_OFF(peer->t_connect); - EVENT_OFF(peer->t_holdtime); - EVENT_OFF(peer->t_routeadv); - EVENT_OFF(peer->t_delayopen); + EVENT_OFF(connection->t_start); + EVENT_OFF(connection->t_connect); + EVENT_OFF(connection->t_holdtime); + EVENT_OFF(connection->t_routeadv); + EVENT_OFF(peer->connection->t_delayopen); /* Clear input and output buffer. */ frr_with_mutex (&connection->io_mtx) { @@ -1561,7 +1523,7 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) peer->orf_plist[afi][safi] = NULL; if ((connection->status == OpenConfirm) || - peer_established(peer)) { + peer_established(connection)) { /* ORF received prefix-filter pnt */ snprintf(orf_name, sizeof(orf_name), "%s.%d.%d", peer->host, afi, safi); @@ -1591,7 +1553,7 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) peer_delete(peer); ret = BGP_FSM_FAILURE_AND_DELETE; } else { - bgp_peer_conf_if_to_su_update(peer); + bgp_peer_conf_if_to_su_update(connection); } return ret; } @@ -1623,10 +1585,13 @@ bgp_stop_with_error(struct peer_connection *connection) /* something went wrong, send notify and tear down */ static enum bgp_fsm_state_progress -bgp_stop_with_notify(struct peer *peer, uint8_t code, uint8_t sub_code) +bgp_stop_with_notify(struct peer_connection *connection, uint8_t code, + uint8_t sub_code) { + struct peer *peer = connection->peer; + /* Send notify to remote peer */ - bgp_notify_send(peer, code, sub_code); + bgp_notify_send(connection, code, sub_code); if (peer_dynamic_neighbor_no_nsf(peer)) { if (bgp_debug_neighbor_events(peer)) @@ -1639,7 +1604,7 @@ bgp_stop_with_notify(struct peer *peer, uint8_t code, uint8_t sub_code) /* Clear start timer value to default. */ peer->v_start = BGP_INIT_START_TIMER; - return bgp_stop(peer->connection); + return bgp_stop(connection); } /** @@ -1662,44 +1627,43 @@ static void bgp_connect_check(struct event *thread) int status; socklen_t slen; int ret; - struct peer *peer; + struct peer_connection *connection = EVENT_ARG(thread); + struct peer *peer = connection->peer; - peer = EVENT_ARG(thread); - assert(!CHECK_FLAG(peer->connection->thread_flags, - PEER_THREAD_READS_ON)); - assert(!CHECK_FLAG(peer->connection->thread_flags, - PEER_THREAD_WRITES_ON)); - assert(!peer->connection->t_read); - assert(!peer->connection->t_write); + assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_READS_ON)); + assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_WRITES_ON)); + assert(!connection->t_read); + assert(!connection->t_write); - EVENT_OFF(peer->t_connect_check_r); - EVENT_OFF(peer->t_connect_check_w); + EVENT_OFF(connection->t_connect_check_r); + EVENT_OFF(connection->t_connect_check_w); /* Check file descriptor. */ slen = sizeof(status); - ret = getsockopt(peer->connection->fd, SOL_SOCKET, SO_ERROR, - (void *)&status, &slen); + ret = getsockopt(connection->fd, SOL_SOCKET, SO_ERROR, (void *)&status, + &slen); /* If getsockopt is fail, this is fatal error. */ if (ret < 0) { zlog_err("can't get sockopt for nonblocking connect: %d(%s)", errno, safe_strerror(errno)); - BGP_EVENT_ADD(peer, TCP_fatal_error); + BGP_EVENT_ADD(connection, TCP_fatal_error); return; } /* When status is 0 then TCP connection is established. */ if (status == 0) { if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN)) - BGP_EVENT_ADD(peer, TCP_connection_open_w_delay); + BGP_EVENT_ADD(connection, + TCP_connection_open_w_delay); else - BGP_EVENT_ADD(peer, TCP_connection_open); + BGP_EVENT_ADD(connection, TCP_connection_open); return; } else { if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [Event] Connect failed %d(%s)", peer->host, status, safe_strerror(status)); - BGP_EVENT_ADD(peer, TCP_connection_open_failed); + BGP_EVENT_ADD(connection, TCP_connection_open_failed); return; } } @@ -1721,7 +1685,7 @@ bgp_connect_success(struct peer_connection *connection) flog_err_sys(EC_LIB_SOCKET, "%s: bgp_getsockname(): failed for peer %s, fd %d", __func__, peer->host, connection->fd); - bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_FSM_ERR, bgp_fsm_error_subcode(connection->status)); bgp_writes_on(connection); return BGP_FSM_FAILURE; @@ -1744,7 +1708,7 @@ bgp_connect_success(struct peer_connection *connection) } /* Send an open message */ - bgp_open_send(peer); + bgp_open_send(connection); return BGP_FSM_SUCCESS; } @@ -1767,7 +1731,7 @@ bgp_connect_success_w_delayopen(struct peer_connection *connection) flog_err_sys(EC_LIB_SOCKET, "%s: bgp_getsockname(): failed for peer %s, fd %d", __func__, peer->host, connection->fd); - bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_FSM_ERR, bgp_fsm_error_subcode(connection->status)); bgp_writes_on(connection); return BGP_FSM_FAILURE; @@ -1793,8 +1757,8 @@ bgp_connect_success_w_delayopen(struct peer_connection *connection) peer->v_delayopen = peer->delayopen; /* Start the DelayOpenTimer if it is not already running */ - if (!peer->t_delayopen) - BGP_TIMER_ON(peer->t_delayopen, bgp_delayopen_timer, + if (!peer->connection->t_delayopen) + BGP_TIMER_ON(peer->connection->t_delayopen, bgp_delayopen_timer, peer->v_delayopen); if (bgp_debug_neighbor_events(peer)) @@ -1835,9 +1799,9 @@ static enum bgp_fsm_state_progress bgp_start(struct peer_connection *connection) struct peer *peer = connection->peer; int status; - bgp_peer_conf_if_to_su_update(peer); + bgp_peer_conf_if_to_su_update(connection); - if (peer->su.sa.sa_family == AF_UNSPEC) { + if (connection->su.sa.sa_family == AF_UNSPEC) { if (bgp_debug_neighbor_events(peer)) zlog_debug( "%s [FSM] Unable to get neighbor's IP address, waiting...", @@ -1862,32 +1826,12 @@ static enum bgp_fsm_state_progress bgp_start(struct peer_connection *connection) return BGP_FSM_FAILURE; } - /* Scrub some information that might be left over from a previous, - * session - */ - /* Connection information. */ - if (peer->su_local) { - sockunion_free(peer->su_local); - peer->su_local = NULL; - } - - if (peer->su_remote) { - sockunion_free(peer->su_remote); - peer->su_remote = NULL; - } - /* Clear remote router-id. */ peer->remote_id.s_addr = INADDR_ANY; /* Clear peer capability flag. */ peer->cap = 0; - /* If the peer is passive mode, force to move to Active mode. */ - if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) { - BGP_EVENT_ADD(peer, TCP_connection_open_failed); - return BGP_FSM_SUCCESS; - } - if (peer->bgp->vrf_id == VRF_UNKNOWN) { if (bgp_debug_neighbor_events(peer)) flog_err( @@ -1908,7 +1852,7 @@ static enum bgp_fsm_state_progress bgp_start(struct peer_connection *connection) "%s [FSM] Waiting for NHT, no path to neighbor present", peer->host); peer->last_reset = PEER_DOWN_WAITING_NHT; - BGP_EVENT_ADD(peer, TCP_connection_open_failed); + BGP_EVENT_ADD(connection, TCP_connection_open_failed); return BGP_FSM_SUCCESS; } } @@ -1917,20 +1861,20 @@ static enum bgp_fsm_state_progress bgp_start(struct peer_connection *connection) assert(!connection->t_read); assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_WRITES_ON)); assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_READS_ON)); - status = bgp_connect(peer); + status = bgp_connect(connection); switch (status) { case connect_error: if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [FSM] Connect error", peer->host); - BGP_EVENT_ADD(peer, TCP_connection_open_failed); + BGP_EVENT_ADD(connection, TCP_connection_open_failed); break; case connect_success: if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [FSM] Connect immediately success, fd %d", peer->host, connection->fd); - BGP_EVENT_ADD(peer, TCP_connection_open); + BGP_EVENT_ADD(connection, TCP_connection_open); break; case connect_in_progress: /* To check nonblocking connect, we wait until socket is @@ -1952,10 +1896,10 @@ static enum bgp_fsm_state_progress bgp_start(struct peer_connection *connection) * bgp_connect_check() as the handler for each and cancel the * unused event in that function. */ - event_add_read(bm->master, bgp_connect_check, peer, - peer->connection->fd, &peer->t_connect_check_r); - event_add_write(bm->master, bgp_connect_check, peer, - peer->connection->fd, &peer->t_connect_check_w); + event_add_read(bm->master, bgp_connect_check, connection, + connection->fd, &connection->t_connect_check_r); + event_add_write(bm->master, bgp_connect_check, connection, + connection->fd, &connection->t_connect_check_w); break; } return BGP_FSM_SUCCESS; @@ -1986,7 +1930,7 @@ bgp_fsm_open(struct peer_connection *connection) /* If DelayOpen is active, we may still need to send an open message */ if ((connection->status == Connect) || (connection->status == Active)) - bgp_open_send(peer); + bgp_open_send(connection); /* Send keepalive and make keepalive timer */ bgp_keepalive_send(peer); @@ -2005,7 +1949,7 @@ bgp_fsm_event_error(struct peer_connection *connection) peer->host, lookup_msg(bgp_status_msg, connection->status, NULL)); - return bgp_stop_with_notify(peer, BGP_NOTIFY_FSM_ERR, + return bgp_stop_with_notify(connection, BGP_NOTIFY_FSM_ERR, bgp_fsm_error_subcode(connection->status)); } @@ -2023,28 +1967,26 @@ bgp_fsm_holdtime_expire(struct peer_connection *connection) * the Graceful Restart procedures to be performed when the BGP * speaker receives a BGP NOTIFICATION message or the Hold Time expires. */ - if (peer_established(peer) && + if (peer_established(connection) && bgp_has_graceful_restart_notification(peer)) if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); - return bgp_stop_with_notify(peer, BGP_NOTIFY_HOLD_ERR, 0); + return bgp_stop_with_notify(connection, BGP_NOTIFY_HOLD_ERR, 0); } /* RFC 4271 DelayOpenTimer_Expires event */ static enum bgp_fsm_state_progress bgp_fsm_delayopen_timer_expire(struct peer_connection *connection) { - struct peer *peer = connection->peer; - /* Stop the DelayOpenTimer */ - EVENT_OFF(peer->t_delayopen); + EVENT_OFF(connection->t_delayopen); /* Send open message to peer */ - bgp_open_send(peer); + bgp_open_send(connection); /* Set the HoldTimer to a large value (4 minutes) */ - peer->v_holdtime = 245; + connection->peer->v_holdtime = 245; return BGP_FSM_SUCCESS; } @@ -2160,6 +2102,11 @@ bgp_establish(struct peer_connection *connection) hash_alloc_intern); return BGP_FSM_FAILURE; } + /* + * At this point the connections have been possibly swapped + * let's reset it. + */ + connection = peer->connection; if (other == peer) ret = BGP_FSM_SUCCESS_STATE_TRANSFER; @@ -2173,7 +2120,7 @@ bgp_establish(struct peer_connection *connection) /* Increment established count. */ peer->established++; - bgp_fsm_change_status(peer, Established); + bgp_fsm_change_status(connection, Established); /* bgp log-neighbor-changes of neighbor Up */ if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) { @@ -2264,8 +2211,8 @@ bgp_establish(struct peer_connection *connection) SET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); else { UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); - if (peer->t_gr_stale) { - EVENT_OFF(peer->t_gr_stale); + if (connection->t_gr_stale) { + EVENT_OFF(connection->t_gr_stale); if (bgp_debug_neighbor_events(peer)) zlog_debug( "%pBP graceful restart stalepath timer stopped", @@ -2273,15 +2220,15 @@ bgp_establish(struct peer_connection *connection) } } - if (peer->t_gr_restart) { - EVENT_OFF(peer->t_gr_restart); + if (connection->t_gr_restart) { + EVENT_OFF(connection->t_gr_restart); if (bgp_debug_neighbor_events(peer)) zlog_debug("%pBP graceful restart timer stopped", peer); } /* Reset uptime, turn on keepalives, send current table. */ if (!peer->v_holdtime) - bgp_keepalives_on(peer); + bgp_keepalives_on(connection); peer->uptime = monotime(NULL); @@ -2327,8 +2274,9 @@ bgp_establish(struct peer_connection *connection) * of read-only mode. */ if (!bgp_update_delay_active(peer->bgp)) { - EVENT_OFF(peer->t_routeadv); - BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0); + EVENT_OFF(peer->connection->t_routeadv); + BGP_TIMER_ON(peer->connection->t_routeadv, bgp_routeadv_timer, + 0); } if (peer->doppelganger && @@ -2339,7 +2287,8 @@ bgp_establish(struct peer_connection *connection) peer->host); if (peer->doppelganger->connection->status > Active) - bgp_notify_send(peer->doppelganger, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->doppelganger->connection, + BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); else peer_delete(peer->doppelganger); @@ -2364,7 +2313,7 @@ bgp_establish(struct peer_connection *connection) static enum bgp_fsm_state_progress bgp_fsm_keepalive(struct peer_connection *connection) { - EVENT_OFF(connection->peer->t_holdtime); + EVENT_OFF(connection->t_holdtime); return BGP_FSM_SUCCESS; } @@ -2372,7 +2321,7 @@ bgp_fsm_keepalive(struct peer_connection *connection) static enum bgp_fsm_state_progress bgp_fsm_update(struct peer_connection *connection) { - EVENT_OFF(connection->peer->t_holdtime); + EVENT_OFF(connection->t_holdtime); return BGP_FSM_SUCCESS; } @@ -2405,26 +2354,27 @@ bgp_fsm_exception(struct peer_connection *connection) return bgp_stop(connection); } -void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops) +void bgp_fsm_nht_update(struct peer_connection *connection, struct peer *peer, + bool has_valid_nexthops) { if (!peer) return; - switch (peer->connection->status) { + switch (connection->status) { case Idle: if (has_valid_nexthops) - BGP_EVENT_ADD(peer, BGP_Start); + BGP_EVENT_ADD(connection, BGP_Start); break; case Connect: if (!has_valid_nexthops) { - EVENT_OFF(peer->t_connect); - BGP_EVENT_ADD(peer, TCP_fatal_error); + EVENT_OFF(connection->t_connect); + BGP_EVENT_ADD(connection, TCP_fatal_error); } break; case Active: if (has_valid_nexthops) { - EVENT_OFF(peer->t_connect); - BGP_EVENT_ADD(peer, ConnectRetry_timer_expired); + EVENT_OFF(connection->t_connect); + BGP_EVENT_ADD(connection, ConnectRetry_timer_expired); } break; case OpenSent: @@ -2433,7 +2383,7 @@ void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops) if (!has_valid_nexthops && (peer->gtsm_hops == BGP_GTSM_HOPS_CONNECTED || peer->bgp->fast_convergence)) - BGP_EVENT_ADD(peer, TCP_fatal_error); + BGP_EVENT_ADD(connection, TCP_fatal_error); case Clearing: case Deleted: case BGP_STATUS_MAX: @@ -2611,50 +2561,48 @@ static const struct { /* Execute event process. */ void bgp_event(struct event *thread) { + struct peer_connection *connection = EVENT_ARG(thread); enum bgp_fsm_events event; - struct peer *peer; + struct peer *peer = connection->peer; - peer = EVENT_ARG(thread); event = EVENT_VAL(thread); peer_lock(peer); - bgp_event_update(peer, event); + bgp_event_update(connection, event); peer_unlock(peer); } -int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) +int bgp_event_update(struct peer_connection *connection, + enum bgp_fsm_events event) { enum bgp_fsm_status next; enum bgp_fsm_state_progress ret = 0; int fsm_result = FSM_PEER_NOOP; - struct peer *other; int passive_conn = 0; int dyn_nbr; - struct peer_connection *connection = peer->connection; + struct peer *peer = connection->peer; - other = peer->doppelganger; passive_conn = (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) ? 1 : 0; dyn_nbr = peer_dynamic_neighbor(peer); /* Logging this event. */ - next = FSM[peer->connection->status - 1][event - 1].next_state; + next = FSM[connection->status - 1][event - 1].next_state; - if (bgp_debug_neighbor_events(peer) && peer->connection->status != next) + if (bgp_debug_neighbor_events(peer) && connection->status != next) zlog_debug("%s [FSM] %s (%s->%s), fd %d", peer->host, bgp_event_str[event], - lookup_msg(bgp_status_msg, peer->connection->status, - NULL), + lookup_msg(bgp_status_msg, connection->status, NULL), lookup_msg(bgp_status_msg, next, NULL), - peer->connection->fd); + connection->fd); peer->last_event = peer->cur_event; peer->cur_event = event; /* Call function. */ - if (FSM[peer->connection->status - 1][event - 1].func) - ret = (*(FSM[peer->connection->status - 1][event - 1].func))( - peer->connection); + if (FSM[connection->status - 1][event - 1].func) + ret = (*(FSM[connection->status - 1][event - 1].func))( + connection); switch (ret) { case BGP_FSM_SUCCESS: @@ -2665,12 +2613,11 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) bgp_establish. Update the peer pointer accordingly */ fsm_result = FSM_PEER_TRANSFERRED; - peer = other; } /* If status is changed. */ - if (next != peer->connection->status) { - bgp_fsm_change_status(peer, next); + if (next != connection->status) { + bgp_fsm_change_status(connection, next); /* * If we're going to ESTABLISHED then we executed a @@ -2684,7 +2631,7 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) } /* Make sure timer is set. */ - bgp_timer_set(peer); + bgp_timer_set(connection); break; case BGP_FSM_FAILURE: /* @@ -2706,8 +2653,8 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) connection->fd, peer_down_str[peer->last_reset]); bgp_stop(connection); - bgp_fsm_change_status(peer, Idle); - bgp_timer_set(peer); + bgp_fsm_change_status(connection, Idle); + bgp_timer_set(connection); } fsm_result = FSM_PEER_STOPPED; break; diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index 1f53ac6118b4..fd46b7994e3a 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -17,33 +17,28 @@ enum bgp_fsm_state_progress { /* Macro for BGP read, write and timer thread. */ #define BGP_TIMER_ON(T, F, V) \ do { \ - if ((peer->connection->status != Deleted)) \ - event_add_timer(bm->master, (F), peer, (V), &(T)); \ + if ((connection->status != Deleted)) \ + event_add_timer(bm->master, (F), connection, (V), \ + &(T)); \ } while (0) -#define BGP_EVENT_ADD(P, E) \ +#define BGP_EVENT_ADD(C, E) \ do { \ - if ((P)->connection->status != Deleted) \ - event_add_event(bm->master, bgp_event, (P), (E), NULL); \ + if ((C)->status != Deleted) \ + event_add_event(bm->master, bgp_event, (C), (E), NULL); \ } while (0) -#define BGP_EVENT_FLUSH(P) \ - do { \ - assert(peer); \ - event_cancel_event_ready(bm->master, (P)); \ - } while (0) - -#define BGP_UPDATE_GROUP_TIMER_ON(T, F) \ - do { \ - if (BGP_SUPPRESS_FIB_ENABLED(peer->bgp) && \ - PEER_ROUTE_ADV_DELAY(peer)) \ - event_add_timer_msec( \ - bm->master, (F), peer, \ - (BGP_DEFAULT_UPDATE_ADVERTISEMENT_TIME * \ - 1000), \ - (T)); \ - else \ - event_add_timer_msec(bm->master, (F), peer, 0, (T)); \ +#define BGP_UPDATE_GROUP_TIMER_ON(T, F) \ + do { \ + if (BGP_SUPPRESS_FIB_ENABLED(peer->bgp) && \ + PEER_ROUTE_ADV_DELAY(peer)) \ + event_add_timer_msec(bm->master, (F), connection, \ + (BGP_DEFAULT_UPDATE_ADVERTISEMENT_TIME * \ + 1000), \ + (T)); \ + else \ + event_add_timer_msec(bm->master, (F), connection, 0, \ + (T)); \ } while (0) #define BGP_MSEC_JITTER 10 @@ -111,13 +106,15 @@ enum bgp_fsm_state_progress { /* * Update FSM for peer based on whether we have valid nexthops or not. */ -extern void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops); +extern void bgp_fsm_nht_update(struct peer_connection *connection, + struct peer *peer, bool has_valid_nexthops); extern void bgp_event(struct event *event); -extern int bgp_event_update(struct peer *, enum bgp_fsm_events event); +extern int bgp_event_update(struct peer_connection *connection, + enum bgp_fsm_events event); extern enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection); -extern void bgp_timer_set(struct peer *); +extern void bgp_timer_set(struct peer_connection *connection); extern void bgp_routeadv_timer(struct event *event); -extern void bgp_fsm_change_status(struct peer *peer, +extern void bgp_fsm_change_status(struct peer_connection *connection, enum bgp_fsm_status status); extern const char *const peer_down_str[]; extern void bgp_update_delay_end(struct bgp *); diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index 84e428cbc4c0..b07e69ac31bb 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -45,7 +45,6 @@ static bool validate_header(struct peer_connection *connection); void bgp_writes_on(struct peer_connection *connection) { struct frr_pthread *fpt = bgp_pth_io; - struct peer *peer = connection->peer; assert(fpt->running); @@ -53,8 +52,8 @@ void bgp_writes_on(struct peer_connection *connection) assert(connection->obuf); assert(connection->ibuf); assert(connection->ibuf_work); - assert(!peer->t_connect_check_r); - assert(!peer->t_connect_check_w); + assert(!connection->t_connect_check_r); + assert(!connection->t_connect_check_w); assert(connection->fd); event_add_write(fpt->master, bgp_process_writes, connection, @@ -69,14 +68,13 @@ void bgp_writes_off(struct peer_connection *connection) assert(fpt->running); event_cancel_async(fpt->master, &connection->t_write, NULL); - EVENT_OFF(peer->t_generate_updgrp_packets); + EVENT_OFF(connection->t_generate_updgrp_packets); UNSET_FLAG(peer->connection->thread_flags, PEER_THREAD_WRITES_ON); } void bgp_reads_on(struct peer_connection *connection) { - struct peer *peer = connection->peer; struct frr_pthread *fpt = bgp_pth_io; assert(fpt->running); @@ -85,8 +83,8 @@ void bgp_reads_on(struct peer_connection *connection) assert(connection->fd); assert(connection->ibuf_work); assert(connection->obuf); - assert(!peer->t_connect_check_r); - assert(!peer->t_connect_check_w); + assert(!connection->t_connect_check_r); + assert(!connection->t_connect_check_w); assert(connection->fd); event_add_read(fpt->master, bgp_process_reads, connection, @@ -151,7 +149,7 @@ static void bgp_process_writes(struct event *thread) event_add_write(fpt->master, bgp_process_writes, connection, connection->fd, &connection->t_write); } else if (!fatal) { - BGP_UPDATE_GROUP_TIMER_ON(&peer->t_generate_updgrp_packets, + BGP_UPDATE_GROUP_TIMER_ON(&connection->t_generate_updgrp_packets, bgp_generate_updgrp_packets); } } @@ -362,7 +360,7 @@ static uint16_t bgp_write(struct peer_connection *connection) if (num < 0) { if (!ERRNO_IO_RETRY(errno)) { - BGP_EVENT_ADD(peer, TCP_fatal_error); + BGP_EVENT_ADD(connection, TCP_fatal_error); SET_FLAG(status, BGP_IO_FATAL_ERR); } else { SET_FLAG(status, BGP_IO_TRANS_ERR); @@ -439,7 +437,7 @@ static uint16_t bgp_write(struct peer_connection *connection) * Handle Graceful Restart case where the state changes * to Connect instead of Idle. */ - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(connection, BGP_Stop); goto done; case BGP_MSG_KEEPALIVE: diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c index 48bde1220d6c..92123c2cd9bf 100644 --- a/bgpd/bgp_keepalives.c +++ b/bgpd/bgp_keepalives.c @@ -229,8 +229,10 @@ void *bgp_keepalives_start(void *arg) /* --- thread external functions ------------------------------------------- */ -void bgp_keepalives_on(struct peer *peer) +void bgp_keepalives_on(struct peer_connection *connection) { + struct peer *peer = connection->peer; + if (CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON)) return; @@ -258,8 +260,10 @@ void bgp_keepalives_on(struct peer *peer) } } -void bgp_keepalives_off(struct peer *peer) +void bgp_keepalives_off(struct peer_connection *connection) { + struct peer *peer = connection->peer; + if (!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON)) return; diff --git a/bgpd/bgp_keepalives.h b/bgpd/bgp_keepalives.h index 2b4389cac381..33e574da133b 100644 --- a/bgpd/bgp_keepalives.h +++ b/bgpd/bgp_keepalives.h @@ -27,7 +27,7 @@ * If the peer is already registered for keepalives via this function, nothing * happens. */ -extern void bgp_keepalives_on(struct peer *); +extern void bgp_keepalives_on(struct peer_connection *connection); /** * Turns off keepalives for a peer. @@ -36,7 +36,7 @@ extern void bgp_keepalives_on(struct peer *); * * If the peer is already unregistered for keepalives, nothing happens. */ -extern void bgp_keepalives_off(struct peer *); +extern void bgp_keepalives_off(struct peer_connection *connection); /** * Pre-run initialization function for keepalives pthread. diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 30090e0590b7..b8ce1ae467fd 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -195,7 +195,8 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, return -1; } - bgp_dest_unlock_node(dest); + dest = bgp_dest_unlock_node(dest); + assert(dest); if (BGP_DEBUG(labelpool, LABELPOOL)) zlog_debug("%s: FEC %pRN label=%u, allocated=%d", __func__, diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c index dc032660ceeb..883338610c64 100644 --- a/bgpd/bgp_labelpool.c +++ b/bgpd/bgp_labelpool.c @@ -1131,7 +1131,7 @@ static void show_bgp_nexthop_label_afi(struct vty *vty, afi_t afi, ifindex2ifname(iter->nh->ifindex, iter->nh->vrf_id)); tbuf = time(NULL) - (monotime(NULL) - iter->last_update); - vty_out(vty, " Last update: %s", ctime(&tbuf)); + vty_out(vty, " Last update: %s", ctime_r(&tbuf, buf)); if (!detail) continue; vty_out(vty, " Paths:\n"); diff --git a/bgpd/bgp_linkstate.c b/bgpd/bgp_linkstate.c new file mode 100644 index 000000000000..f76c68ca5d37 --- /dev/null +++ b/bgpd/bgp_linkstate.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP Link-State + * Copyright 2023 6WIND S.A. + */ + +#include + +#include "prefix.h" +#include "lib_errors.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_errors.h" +#include "bgpd/bgp_linkstate.h" +#include "bgpd/bgp_linkstate_tlv.h" + +void bgp_linkstate_init(void) +{ + prefix_set_linkstate_display_hook(bgp_linkstate_nlri_prefix_display); +} diff --git a/bgpd/bgp_linkstate.h b/bgpd/bgp_linkstate.h new file mode 100644 index 000000000000..c8d4d23f16ca --- /dev/null +++ b/bgpd/bgp_linkstate.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP Link-State header + * Copyright 2023 6WIND S.A. + */ + +#ifndef _FRR_BGP_LINKSTATE_H +#define _FRR_BGP_LINKSTATE_H + +void bgp_linkstate_init(void); +#endif /* _FRR_BGP_LINKSTATE_H */ diff --git a/bgpd/bgp_linkstate_tlv.c b/bgpd/bgp_linkstate_tlv.c new file mode 100644 index 000000000000..fbec96a907f1 --- /dev/null +++ b/bgpd/bgp_linkstate_tlv.c @@ -0,0 +1,1749 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP Link-State TLV Serializer/Deserializer + * Copyright 2023 6WIND S.A. + */ + +#include + +#include "iso.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_errors.h" +#include "bgpd/bgp_linkstate_tlv.h" + + +static bool bgp_linkstate_nlri_value_display(char *buf, size_t size, + uint8_t *pnt, uint16_t nlri_type, + uint16_t type, uint16_t length, + bool first, json_object *json); + +struct bgp_linkstate_tlv_info { + const char *descr; + uint8_t min_size; + uint16_t max_size; + uint8_t multiple; +}; + +#define UNDEF_MIN_SZ 0xFF +#define MAX_SZ 0xFFFF +#define UNDEF_MULTPL 1 + +/* clang-format off */ +struct bgp_linkstate_tlv_info bgp_linkstate_tlv_infos[BGP_LS_TLV_MAX + 1] = { + /* NLRI TLV */ + [BGP_LS_TLV_LOCAL_NODE_DESCRIPTORS] = {"Local Node Descriptors", 1, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_REMOTE_NODE_DESCRIPTORS] = {"Remote Node Descriptors", 1, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_LINK_LOCAL_REMOTE_IDENTIFIERS] = {"Link Local/Remote Identifiers", 2, 2, UNDEF_MULTPL}, + [BGP_LS_TLV_IPV4_INTERFACE_ADDRESS] = {"IPv4 interface address", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_IPV4_NEIGHBOR_ADDRESS] = {"IPv4 neighbor address", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_IPV6_INTERFACE_ADDRESS] = {"IPv6 interface address", 16, 16, UNDEF_MULTPL}, + [BGP_LS_TLV_IPV6_NEIGHBOR_ADDRESS] = {"IPv6 neighbor address", 16, 16, UNDEF_MULTPL}, + [BGP_LS_TLV_OSPF_ROUTE_TYPE] = {"OSPF Route Type", 1, 1, UNDEF_MULTPL}, + [BGP_LS_TLV_IP_REACHABILITY_INFORMATION] = {"IP Reachability Information", 2, 17, UNDEF_MULTPL}, + [BGP_LS_TLV_AUTONOMOUS_SYSTEM] = {"Autonomous System", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_BGP_LS_IDENTIFIER] = {"BGP-LS Identifier", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_OSPF_AREA_ID] = {"OSPF Area-ID", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_IGP_ROUTER_ID] = {"IGP Router-ID", 4, 8, UNDEF_MULTPL}, + /* NRLI & BGP-LS Attributes */ + [BGP_LS_TLV_MULTI_TOPOLOGY_ID] = {"Multi-Topology ID", 2, MAX_SZ, 2}, + /* BGP-LS Attributes */ + [BGP_LS_TLV_NODE_MSD] = {"Node MSD", 2, MAX_SZ, 2}, + [BGP_LS_TLV_LINK_MSD] = {"Link MSD", 2, MAX_SZ, 2}, + [BGP_LS_TLV_BGP_ROUTER_ID] = {"BGP Router-ID", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_BGP_CONFEDERATION_MEMBER] = {"BGP Confederation Member", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_NODE_FLAG_BITS] = {"Node Flag Bits", 1, 1, UNDEF_MULTPL}, + [BGP_LS_TLV_OPAQUE_NODE_ATTRIBUTE] = {"Opaque Node Attribute", 1, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_NODE_NAME] = {"Node Name", 1, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_IS_IS_AREA_IDENTIFIER] = {"IS-IS Area Identifier", 1, 13, UNDEF_MULTPL}, + [BGP_LS_TLV_IPV4_ROUTER_ID_OF_LOCAL_NODE] = {"IPv4 Router-ID of Local Node", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_IPV6_ROUTER_ID_OF_LOCAL_NODE] = {"IPv6 Router-ID of Local Node", 16, 16, UNDEF_MULTPL}, + [BGP_LS_TLV_IPV4_ROUTER_ID_OF_REMOTE_NODE] = {"IPv4 Router-ID of Remote Node", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_IPV6_ROUTER_ID_OF_REMOTE_NODE] = {"IPv6 Router-ID of Remote Node", 16, 16, UNDEF_MULTPL}, + [BGP_LS_TLV_S_BFD_DISCRIMINATORS] = {"S-BFD Discriminators", 4, MAX_SZ, 4}, + [BGP_LS_TLV_SR_CAPABILITIES] = {"SR Capabilities", 12, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_ALGORITHM] = {"SR Algorithm", 1, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_LOCAL_BLOCK] = {"SR Local Block", 12, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SRMS_PREFERENCE] = {"SRMS Preference", 1, 1, UNDEF_MULTPL}, + [BGP_LS_TLV_FLEXIBLE_ALGORITHM_DEFINITION] = {"Flexible Algorithm Definition", 4, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_FLEXIBLE_ALGORITHM_EXCLUDE_ANY_AFFINITY] = {"Flexible Algorithm Exclude Any Affinity", 4, MAX_SZ, 4}, + [BGP_LS_TLV_FLEXIBLE_ALGORITHM_INCLUDE_ANY_AFFINITY] = {"Flexible Algorithm Include Any Affinity", 4, MAX_SZ, 4}, + [BGP_LS_TLV_FLEXIBLE_ALGORITHM_INCLUDE_ALL_AFFINITY] = {"Flexible Algorithm Include All Affinity", 4, MAX_SZ, 4}, + [BGP_LS_TLV_FLEXIBLE_ALGORITHM_DEFINITION_FLAGS] = {"Flexible Algorithm Definition Flags", 4, MAX_SZ, 4}, + [BGP_LS_TLV_FLEXIBLE_ALGORITHM_PREFIX_METRIC] = {"Flexible Algorithm Prefix Metric", 8, 8, UNDEF_MULTPL}, + [BGP_LS_TLV_FLEXIBLE_ALGORITHM_EXCLUDE_SRLG] = {"Flexible Algorithm Exclude SRLG", 4, MAX_SZ, 4}, + [BGP_LS_TLV_ADMINISTRATIVE_GROUP] = {"Administrative group", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_MAXIMUM_LINK_BANDWIDTH] = {"Maximum link bandwidth", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_MAX_RESERVABLE_LINK_BANDWIDTH] = {"Max. reservable link bandwidth", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_UNRESERVED_BANDWIDTH] = {"Unreserved bandwidth", 32, 32, UNDEF_MULTPL}, + [BGP_LS_TLV_TE_DEFAULT_METRIC] = {"TE Default Metric", 3, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_LINK_PROTECTION_TYPE] = {"Link Protection Type", 2, 2, UNDEF_MULTPL}, + [BGP_LS_TLV_MPLS_PROTOCOL_MASK] = {"MPLS Protocol Mask", 1, 1, UNDEF_MULTPL}, + [BGP_LS_TLV_IGP_METRIC] = {"IGP Metric", 1, 3, UNDEF_MULTPL}, + [BGP_LS_TLV_SHARED_RISK_LINK_GROUP] = {"Shared Risk Link Group", 4, MAX_SZ, 4}, + [BGP_LS_TLV_OPAQUE_LINK_ATTRIBUTE] = {"Opaque Link Attribute", 1, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_LINK_NAME] = {"Link Name", 1, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_ADJACENCY_SID] = {"Adjacency SID", 7, 8, UNDEF_MULTPL}, + [BGP_LS_TLV_LAN_ADJACENCY_SID] = {"LAN Adjacency SID", 11, 14, UNDEF_MULTPL}, + [BGP_LS_TLV_PEERNODE_SID] = {"PeerNode SID", 7, 8, UNDEF_MULTPL}, + [BGP_LS_TLV_PEERADJ_SID] = {"PeerAdj SID", 7, 8, UNDEF_MULTPL}, + [BGP_LS_TLV_PEERSET_SID] = {"PeerSet SID", 7, 8, UNDEF_MULTPL}, + [BGP_LS_TLV_RTM_CAPABILITY] = {"RTM Capability", 1, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_UNIDIRECTIONAL_LINK_DELAY] = {"Unidirectional Link Delay", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_MIN_MAX_UNIDIRECTIONAL_LINK_DELAY] = {"Min/Max Unidirectional Link Delay", 8, 8, UNDEF_MULTPL}, + [BGP_LS_TLV_UNIDIRECTIONAL_DELAY_VARIATION] = {"Unidirectional Delay Variation", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_UNIDIRECTIONAL_LINK_LOSS] = {"Unidirectional Link Loss", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_UNIDIRECTIONAL_RESIDUAL_BANDWIDTH] = {"Unidirectional Residual Bandwidth", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_UNIDIRECTIONAL_AVAILABLE_BANDWIDTH] = {"Unidirectional Available Bandwidth", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_UNIDIRECTIONAL_UTILIZED_BANDWIDTH] = {"Unidirectional Utilized Bandwidth", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_GRACEFUL_LINK_SHUTDOWN_TLV] = {"Graceful-Link-Shutdown TLV", 0, 0, UNDEF_MULTPL}, + [BGP_LS_TLV_APPLICATION_SPECIFIC_LINK_ATTRIBUTES] = {"Application-Specific Link Attributes", 11, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_IGP_FLAGS] = {"IGP Flags", 1, 1, UNDEF_MULTPL}, + [BGP_LS_TLV_IGP_ROUTE_TAG] = {"IGP Route Tag", 4, MAX_SZ, 4}, + [BGP_LS_TLV_IGP_EXTENDED_ROUTE_TAG] = {"IGP Extended Route Tag", 8, MAX_SZ, 8}, + [BGP_LS_TLV_PREFIX_METRIC] = {"Prefix Metric", 3, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_OSPF_FORWARDING_ADDRESS] = {"OSPF Forwarding Address", 4, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_OPAQUE_PREFIX_ATTRIBUTE] = {"Opaque Prefix Attribute", 1, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_PREFIX_SID] = {"Prefix-SID", 7, 8, UNDEF_MULTPL}, + [BGP_LS_TLV_RANGE] = {"Range", 11, 12, UNDEF_MULTPL}, + [BGP_LS_TLV_SID_LABEL] = {"SID/Label", 3, 4, UNDEF_MULTPL}, + [BGP_LS_TLV_PREFIX_ATTRIBUTES_FLAGS] = {"Prefix Attributes Flags", 1, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SOURCE_ROUTER_IDENTIFIER] = {"Source Router Identifier", 4, 16, UNDEF_MULTPL}, + [BGP_LS_TLV_L2_BUNDLE_MEMBER_ATTRIBUTES] = {"L2 Bundle Member Attributes", 4, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_EXTENDED_ADMINISTRATIVE_GROUP] = {"Extended Administrative Group", 4, MAX_SZ, 4}, + [BGP_LS_TLV_SOURCE_OSPF_ROUTER_ID] = {"Source OSPF Router-ID", 4, 4, UNDEF_MULTPL}, + /* display not yet supported */ + [BGP_LS_TLV_SRV6_SID_INFORMATION_TLV] = {"SRv6 SID Information TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_TUNNEL_ID_TLV] = {"Tunnel ID TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_LSP_ID_TLV] = {"LSP ID TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_IPV4_6_TUNNEL_HEAD_END_ADDRESS_TLV] = {"IPv4/6 Tunnel Head-end address TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_IPV4_6_TUNNEL_TAIL_END_ADDRESS_TLV] = {"IPv4/6 Tunnel Tail-end address TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_POLICY_CP_DESCRIPTOR_TLV] = {"SR Policy CP Descriptor TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_MPLS_LOCAL_CROSS_CONNECT_TLV] = {"MPLS Local Cross Connect TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_MPLS_CROSS_CONNECT_INTERFACE_TLV] = {"MPLS Cross Connect Interface TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_MPLS_CROSS_CONNECT_FEC_TLV] = {"MPLS Cross Connect FEC TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SRV6_CAPABILITIES_TLV] = {"SRv6 Capabilities TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_FLEXIBLE_ALGORITHM_UNSUPPORTED] = {"Flexible Algorithm Unsupported", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SRV6_END_X_SID_TLV] = {"SRv6 End.X SID TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_IS_IS_SRV6_LAN_END_X_SID_TLV] = {"IS-IS SRv6 LAN End.X SID TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_OSPFV3_SRV6_LAN_END_X_SID_TLV] = {"OSPFv3 SRv6 LAN End.X SID TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_IS_IS_FLOOD_REFLECTION] = {"IS-IS Flood Reflection", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SRV6_LOCATOR_TLV] = {"SRv6 Locator TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_MPLS_TE_POLICY_STATE_TLV] = {"MPLS-TE Policy State TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_BSID_TLV] = {"SR BSID TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_CP_STATE_TLV] = {"SR CP State TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_CP_NAME_TLV] = {"SR CP Name TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_CP_CONSTRAINTS_TLV] = {"SR CP Constraints TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_SEGMENT_LIST_TLV] = {"SR Segment List TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_SEGMENT_SUB_TLV] = {"SR Segment sub-TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_SEGMENT_LIST_METRIC_SUB_TLV] = {"SR Segment List Metric sub-TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_AFFINITY_CONSTRAINT_SUB_TLV] = {"SR Affinity Constraint sub-TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_SRLG_CONSTRAINT_SUB_TLV] = {"SR SRLG Constraint sub-TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_BANDWIDTH_CONSTRAINT_SUB_TLV] = {"SR Bandwidth Constraint sub-TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_DISJOINT_GROUP_CONSTRAINT_SUB_TLV] = {"SR Disjoint Group Constraint sub-TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SRV6_BSID_TLV] = {"SRv6 BSID TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SR_POLICY_NAME_TLV] = {"SR Policy Name TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SRV6_ENDPOINT_FUNCTION_TLV] = {"SRv6 Endpoint Function TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SRV6_BGP_PEER_NODE_SID_TLV] = {"SRv6 BGP Peer Node SID TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, + [BGP_LS_TLV_SRV6_SID_STRUCTURE_TLV] = {"SRv6 SID Structure TLV", UNDEF_MIN_SZ, MAX_SZ, UNDEF_MULTPL}, +}; +/* clang-format on */ + +/* Return the TLV length is valid for the TLV type */ +static bool bgp_ls_tlv_check_size(enum bgp_linkstate_tlv type, size_t length) +{ + if (type > BGP_LS_TLV_MAX || + bgp_linkstate_tlv_infos[type].descr == NULL) + /* TLV type is not defined. Cannot check size */ + return false; + + if (bgp_linkstate_tlv_infos[type].min_size > length) + return false; + if (bgp_linkstate_tlv_infos[type].max_size < length) + return false; + if (length % bgp_linkstate_tlv_infos[type].multiple != 0) + return false; + + return true; +} + +static uint8_t pnt_decode8(uint8_t **pnt) +{ + uint8_t data; + + data = **pnt; + *pnt += 1; + return data; +} + +static uint16_t pnt_decode16(uint8_t **pnt) +{ + uint16_t data; + + *pnt = ptr_get_be16(*pnt, &data); + + return data; +} + +static uint32_t pnt_decode24(uint8_t **pnt) +{ + uint8_t tmp1; + uint16_t tmp2; + + memcpy(&tmp1, *pnt, sizeof(uint8_t)); + memcpy(&tmp2, *pnt + sizeof(uint8_t), sizeof(uint16_t)); + + *pnt += 3; + + return (tmp1 << 16) | ntohs(tmp2); +} + +static uint32_t pnt_decode32(uint8_t **pnt) +{ + uint32_t data; + + *pnt = (uint8_t *)ptr_get_be32(*pnt, &data); + + return data; +} + +static uint64_t pnt_decode64(uint8_t **pnt) +{ + uint64_t data; + + *pnt = (uint8_t *)ptr_get_be64(*pnt, &data); + + return data; +} + +static const char *bgp_ls_print_nlri_proto(enum bgp_ls_nlri_proto proto) +{ + switch (proto) { + case BGP_LS_NLRI_PROTO_ID_IS_IS_LEVEL_1: + return "ISIS-L1"; + case BGP_LS_NLRI_PROTO_ID_IS_IS_LEVEL_2: + return "ISIS-L2"; + case BGP_LS_NLRI_PROTO_ID_OSPF: + return "OSPFv2"; + case BGP_LS_NLRI_PROTO_ID_DIRECT: + return "Direct"; + case BGP_LS_NLRI_PROTO_ID_STATIC: + return "Static"; + case BGP_LS_NLRI_PROTO_ID_OSPFv3: + return "OSPFv3"; + case BGP_LS_NLRI_PROTO_ID_UNKNOWN: + return "Unknown"; + } + return "Unknown"; +} + +int bgp_nlri_parse_linkstate(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, int withdraw) +{ + uint8_t *pnt; + uint8_t *lim; + afi_t afi; + safi_t safi; + uint16_t length = 0; + struct prefix p; + + /* Start processing the NLRI - there may be multiple in the MP_REACH */ + pnt = packet->nlri; + lim = pnt + packet->length; + afi = packet->afi; + safi = packet->safi; + + for (; pnt < lim; pnt += length) { + /* Clear prefix structure. */ + memset(&p, 0, sizeof(p)); + + /* All linkstate NLRI begin with NRLI type and length. */ + if (pnt + 4 > lim) + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; + + p.u.prefix_linkstate.nlri_type = pnt_decode16(&pnt); + length = pnt_decode16(&pnt); + /* When packet overflow occur return immediately. */ + if (pnt + length > lim) { + flog_err( + EC_BGP_LINKSTATE_PACKET, + "Link-State NLRI length inconsistent (size %u seen)", + length); + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; + } + p.family = AF_LINKSTATE; + + p.u.prefix_linkstate.ptr = (uintptr_t)pnt; + p.prefixlen = length; + + if (BGP_DEBUG(linkstate, LINKSTATE)) { + zlog_debug("LS Rx %s %s %pFX", + withdraw ? "Withdraw" : "Update", + afi2str(afi), &p); + } + + /* Process the route. */ + if (withdraw) + bgp_withdraw(peer, &p, 0, afi, safi, ZEBRA_ROUTE_BGP, + BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL); + else + bgp_update(peer, &p, 0, attr, afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, + NULL, 0, 0, NULL); + } + return BGP_NLRI_PARSE_OK; +} + +/* + * Encode Link-State prefix in Update (MP_REACH) + */ +void bgp_nlri_encode_linkstate(struct stream *s, const struct prefix *p) +{ + /* NLRI type */ + stream_putw(s, p->u.prefix_linkstate.nlri_type); + + /* Size */ + stream_putw(s, p->prefixlen); + + stream_put(s, (const void *)p->u.prefix_linkstate.ptr, p->prefixlen); +} + +static size_t bgp_linkstate_nlri_hexa_display(char *buf, size_t size, + uint8_t *pnt, uint16_t type, + uint16_t length, bool first, + json_object *json) +{ + json_object *json_array = NULL; + uint8_t *lim = pnt + length; + char json_buf[19]; + int i; + + if (json) { + snprintf(json_buf, sizeof(json_buf), "%u", type); + json_array = json_object_new_array(); + json_object_object_add(json, json_buf, json_array); + for (i = 0; pnt < lim; pnt++, i++) { + if (i % 8 == 0) { + if (i != 0) + json_object_array_add( + json_array, + json_object_new_string( + json_buf)); + snprintf(json_buf, sizeof(buf), "0x"); + } + snprintf(json_buf + strlen(json_buf), + sizeof(json_buf) - strlen(json_buf), "%02x", + *pnt); + } + if (strlen(json_buf) > 2) /* do not only contain 0x */ + json_object_array_add(json_array, + json_object_new_string(json_buf)); + + return size; + } + + snprintf(buf, size, "%s%u:", first ? "" : " ", type); + size -= strlen(buf); + buf += strlen(buf); + + snprintf(buf, size, "0x"); + size -= strlen(buf); + buf += strlen(buf); + + for (i = 0; pnt < lim; pnt++, i++) { + snprintf(buf, size, "%02x", *pnt); + size -= strlen(buf); + buf += strlen(buf); + } + + return size; +} + +static void bgp_linkstate_nlri_mtid_display(char *buf, size_t size, + uint8_t *pnt, uint16_t type, + uint16_t length, bool first, + json_object *json) +{ + json_object *json_array = NULL; + + if (json) { + json_array = json_object_new_array(); + json_object_object_add(json, "mtID", json_array); + for (int i = 0; i < (length / 2); i++) { + json_object_array_add( + json_array, + json_object_new_int(pnt_decode16(&pnt))); + } + return; + } + + for (int i = 0; i < (length / 2); i++) { + if (i == 0) + snprintf(buf, size, "%sMT:%hu", first ? "" : " ", + pnt_decode16(&pnt)); + else + snprintf(buf, size, ",%hu", pnt_decode16(&pnt)); + size -= strlen(buf); + buf += strlen(buf); + } +} + +static bool bgp_linkstate_nlri_node_descriptor_display( + char *buf, size_t size, uint8_t *pnt, uint16_t nlri_type, uint16_t type, + uint16_t length, bool first, json_object *json) +{ + json_object *json_node = NULL; + bool sub_first = true; + uint8_t *lim = pnt + length; + uint16_t sub_type, sub_length; + + if (json) { + json_node = json_object_new_object(); + if (type == BGP_LS_TLV_LOCAL_NODE_DESCRIPTORS) + json_object_object_add(json, "localNode", json_node); + else + json_object_object_add(json, "remoteNode", json_node); + } else { + if (type == BGP_LS_TLV_LOCAL_NODE_DESCRIPTORS) + snprintf(buf, size, "%sLocal {", first ? "" : " "); + else + snprintf(buf, size, "%sRemote {", first ? "" : " "); + size -= strlen(buf); + buf += strlen(buf); + } + + for (; pnt < lim; pnt += sub_length) { + sub_type = pnt_decode16(&pnt); + sub_length = pnt_decode16(&pnt); + + if (pnt + sub_length > lim) + /* bad length */ + return false; + + bgp_linkstate_nlri_value_display(buf, size, pnt, nlri_type, + sub_type, sub_length, + sub_first, json_node); + + if (!json) { + size -= strlen(buf); + buf += strlen(buf); + sub_first = false; + } + } + + if (!json) + snprintf(buf, size, "}"); + + return true; +} + +static bool bgp_linkstate_nlri_value_display(char *buf, size_t size, + uint8_t *pnt, uint16_t nlri_type, + uint16_t type, uint16_t length, + bool first, json_object *json) +{ + struct in_addr ipv4 = {0}; + struct in6_addr ipv6 = {0}; + uint8_t mask_length; + + if (!bgp_ls_tlv_check_size(type, length) && !json) { + bgp_linkstate_nlri_hexa_display(buf, size, pnt, type, length, + first, json); + return true; + } + + switch (type) { + case BGP_LS_TLV_LOCAL_NODE_DESCRIPTORS: + case BGP_LS_TLV_REMOTE_NODE_DESCRIPTORS: + return bgp_linkstate_nlri_node_descriptor_display( + buf, size, pnt, nlri_type, type, length, first, json); + case BGP_LS_TLV_AUTONOMOUS_SYSTEM: + if (json) + json_object_int_add(json, "as", pnt_decode32(&pnt)); + else + snprintf(buf, size, "%sAS:%u", first ? "" : " ", + pnt_decode32(&pnt)); + break; + case BGP_LS_TLV_BGP_LS_IDENTIFIER: + if (json) + json_object_int_add(json, "identifier", + pnt_decode32(&pnt)); + else + snprintf(buf, size, "%sID:%u", first ? "" : " ", + pnt_decode32(&pnt)); + break; + case BGP_LS_TLV_OSPF_AREA_ID: + if (json) + json_object_int_add(json, "area", pnt_decode32(&pnt)); + else + snprintf(buf, size, "%sArea:%u", first ? "" : " ", + pnt_decode32(&pnt)); + break; + case BGP_LS_TLV_IGP_ROUTER_ID: + switch (length) { + case BGP_LS_TLV_IGP_ROUTER_ID_ISIS_NON_PSEUDOWIRE_SIZE: + if (json) + json_object_string_addf(json, "routerID", + "%pSY", pnt); + else + snprintfrr(buf, size, "%sRtr:%pSY", + first ? "" : " ", pnt); + break; + case BGP_LS_TLV_IGP_ROUTER_ID_ISIS_PSEUDOWIRE_SIZE: + if (json) + json_object_string_addf(json, "routerID", + "%pPN", pnt); + else + snprintfrr(buf, size, "%sRtr:%pPN", + first ? "" : " ", pnt); + break; + case BGP_LS_TLV_IGP_ROUTER_ID_OSPF_NON_PSEUDOWIRE_SIZE: + if (json) + json_object_string_addf(json, "routerID", + "%pI4", + (in_addr_t *)pnt); + else + snprintfrr(buf, size, "%sRtr:%pI4", + first ? "" : " ", (in_addr_t *)pnt); + break; + case BGP_LS_TLV_IGP_ROUTER_ID_OSPF_PSEUDOWIRE_SIZE: + if (json) + json_object_string_addf(json, "routerID", + "%pI4:%pI4", + (in_addr_t *)pnt, + ((in_addr_t *)pnt + 1)); + else + snprintfrr(buf, size, "%sRtr:%pI4:%pI4", + first ? "" : " ", (in_addr_t *)pnt, + ((in_addr_t *)pnt + 1)); + break; + default: + bgp_linkstate_nlri_hexa_display(buf, size, pnt, type, + length, first, json); + } + break; + case BGP_LS_TLV_LINK_LOCAL_REMOTE_IDENTIFIERS: + if (json) + json_object_int_add(json, "localRemoteID", + pnt_decode16(&pnt)); + else + snprintf(buf, size, "%sLocal/remote:%hu", + first ? "" : " ", pnt_decode16(&pnt)); + break; + case BGP_LS_TLV_IPV4_INTERFACE_ADDRESS: + if (json) + json_object_string_addf(json, "interfaceIPv4", "%pI4", + (in_addr_t *)pnt); + else + snprintfrr(buf, size, "%sIPv4:%pI4", first ? "" : " ", + (in_addr_t *)pnt); + break; + case BGP_LS_TLV_IPV4_NEIGHBOR_ADDRESS: + if (json) + json_object_string_addf(json, "neighborIPv4", "%pI4", + (in_addr_t *)pnt); + else + snprintfrr(buf, size, "%sNeigh-IPv4:%pI4", + first ? "" : " ", (in_addr_t *)pnt); + break; + case BGP_LS_TLV_IPV6_INTERFACE_ADDRESS: + if (json) + json_object_string_addf(json, "interfaceIPv6", "%pI6", + (struct in6_addr *)pnt); + else + snprintfrr(buf, size, "%sIPv6:%pI6", first ? "" : " ", + (struct in6_addr *)pnt); + break; + case BGP_LS_TLV_IPV6_NEIGHBOR_ADDRESS: + if (json) + json_object_string_addf(json, "neighborIPv6", "%pI6", + (struct in6_addr *)pnt); + else + snprintfrr(buf, size, "%sNeigh-IPv6:%pI6", + first ? "" : " ", (struct in6_addr *)pnt); + break; + case BGP_LS_TLV_MULTI_TOPOLOGY_ID: + bgp_linkstate_nlri_mtid_display(buf, size, pnt, type, length, + first, json); + break; + case BGP_LS_TLV_OSPF_ROUTE_TYPE: + if (json) + json_object_int_add(json, "ospfRouteType", + pnt_decode8(&pnt)); + else + snprintf(buf, size, "%sOSPF-Route-Type:%u", + first ? "" : " ", pnt_decode8(&pnt)); + break; + case BGP_LS_TLV_IP_REACHABILITY_INFORMATION: + mask_length = pnt_decode8(&pnt); + if (nlri_type == BGP_LINKSTATE_PREFIX4 && + ((length - sizeof(mask_length)) <= sizeof(ipv4.s_addr))) { + memcpy(&ipv4.s_addr, pnt, length - sizeof(mask_length)); + if (json) + json_object_string_addf(json, "ipReachability", + "%pI4/%u", &ipv4, + mask_length); + else + snprintfrr(buf, size, "%sIPv4:%pI4/%u", + first ? "" : " ", &ipv4, + mask_length); + } else if (nlri_type == BGP_LINKSTATE_PREFIX6 && + ((length - sizeof(mask_length)) <= sizeof(ipv6))) { + memcpy(&ipv6, pnt, length - sizeof(mask_length)); + if (json) + json_object_string_addf(json, "ipReachability", + "%pI6/%u", &ipv6, + mask_length); + else + snprintfrr(buf, size, "%sIPv6:%pI6/%u", + first ? "" : " ", &ipv6, + mask_length); + } else + bgp_linkstate_nlri_hexa_display(buf, size, pnt, type, + length, first, json); + + break; + default: + bgp_linkstate_nlri_hexa_display(buf, size, pnt, type, length, + first, json); + } + + return true; +} + +char *bgp_linkstate_nlri_prefix_display(char *buf, size_t size, + uint16_t nlri_type, uintptr_t ptr, + uint16_t len) +{ + uint8_t *pnt = (uint8_t *)ptr; + uint8_t *lim = pnt + len; + uint16_t type, length; + char *cbuf = buf, *cbuf2; + uint8_t proto; + bool ret; + bool first = true; + + proto = pnt_decode8(&pnt); + + snprintfrr(buf, size, "%s %s ID:0x%" PRIx64 " {", + bgp_linkstate_nlri_type_2str(nlri_type), + bgp_ls_print_nlri_proto(proto), pnt_decode64(&pnt)); + size -= strlen(buf); + buf += strlen(buf); + + cbuf2 = buf; + + for (; pnt < lim; pnt += length) { + type = pnt_decode16(&pnt); + length = pnt_decode16(&pnt); + + if (pnt + length > lim) { + /* bad length */ + snprintf(cbuf2, size, "Bad format}"); + return cbuf; + } + + ret = bgp_linkstate_nlri_value_display( + buf, size, pnt, nlri_type, type, length, first, NULL); + + if (!ret) { + /* bad length */ + snprintf(cbuf2, size, "Bad format}"); + return cbuf; + } + + size -= strlen(buf); + buf += strlen(buf); + first = false; + } + + snprintf(buf, size, "}"); + + return cbuf; +} + +void bgp_linkstate_nlri_prefix_json(json_object *json, uint16_t nlri_type, + uintptr_t ptr, uint16_t len) +{ + json_object *json_nlri = json_object_new_object(); + uint8_t *pnt = (uint8_t *)ptr; + uint8_t *lim = pnt + len; + uint16_t type, length; + uint8_t proto; + bool ret; + + proto = pnt_decode8(&pnt); + + json_object_object_add(json, "linkStateNLRI", json_nlri); + json_object_string_add(json_nlri, "nlriType", + bgp_linkstate_nlri_type_2str(nlri_type)); + json_object_string_add(json_nlri, "protocol", + bgp_ls_print_nlri_proto(proto)); + json_object_string_addf(json_nlri, "identifier", "0x%" PRIx64, + pnt_decode64(&pnt)); + + for (; pnt < lim; pnt += length) { + type = pnt_decode16(&pnt); + length = pnt_decode16(&pnt); + + if (pnt + length > lim) + /* bad length */ + return; + + ret = bgp_linkstate_nlri_value_display(NULL, 0, pnt, nlri_type, + type, length, false, + json_nlri); + + if (!ret) + /* bad length */ + return; + } +} + + +static uint8_t *bgp_linkstate_tlv_binary_string(char *buf, size_t buf_sz, + uint8_t *pnt, uint16_t length) +{ + uint8_t tmp; + int i, j; + + for (i = 0; i < length; i++) { + if (i == 0) + snprintf(buf, buf_sz, "0b"); + else + snprintf(buf + strlen(buf), buf_sz - strlen(buf), " "); + tmp = pnt_decode8(&pnt); + for (j = 7; j >= 0; j--) + snprintf(buf + strlen(buf), buf_sz - strlen(buf), "%d", + (tmp >> j) & 1); + } + + return pnt; +} + +/* dump bits. Their meaning is not decoded */ +static uint8_t *bgp_linkstate_tlv_binary_display(struct vty *vty, uint8_t *pnt, + uint16_t length, + json_object *json) +{ + char buf[290]; + uint8_t tmp; + int i, j; + + if (json) { + pnt = bgp_linkstate_tlv_binary_string(buf, sizeof(buf), pnt, + length); + json_object_string_add(json, "data", buf); + return pnt; + } + + for (i = 0; i < length; i++) { + if (i == 0) + vty_out(vty, "0b"); + else + vty_out(vty, " "); + tmp = pnt_decode8(&pnt); + for (j = 7; j >= 0; j--) + vty_out(vty, "%d", (tmp >> j) & 1); + } + vty_out(vty, "\n"); + + return pnt; +} + +static void bgp_linkstate_tlv_hexa_display(struct vty *vty, uint8_t *pnt, + uint16_t length, json_object *json) +{ + uint8_t *lim = pnt + length; + char buf[290]; + int i; + + if (json) { + snprintf(buf, sizeof(buf), "0x"); + for (; pnt < lim; pnt++) + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + "%02x", *pnt); + json_object_string_add(json, "data", buf); + + return; + } + + vty_out(vty, "0x"); + for (i = 0; pnt < lim; pnt++, i++) { + if (i != 0 && i % 8 == 0) + vty_out(vty, " "); + vty_out(vty, "%02x", *pnt); + } + vty_out(vty, "\n"); +} + +static void bgp_linkstate_tlv_integer_list_display(struct vty *vty, + uint8_t *pnt, + uint16_t length, + uint8_t integer_sz, + json_object *json) +{ + json_object *json_array = NULL; + int i; + + if (json) { + json_array = json_object_new_array(); + json_object_object_add(json, "data", json_array); + } + + for (i = 0; i < (length / integer_sz); i++) { + switch (integer_sz) { + case 1: + if (json) { + json_object_array_add( + json_array, + json_object_new_int(pnt_decode8(&pnt))); + break; + } + vty_out(vty, "%s%u", i == 0 ? "" : ", ", + pnt_decode8(&pnt)); + break; + case 2: + if (json) { + json_object_array_add( + json_array, + json_object_new_int( + pnt_decode16(&pnt))); + break; + } + vty_out(vty, "%s%u", i == 0 ? "" : ", ", + pnt_decode16(&pnt)); + break; + case 4: + if (json) { + json_object_array_add( + json_array, + json_object_new_int( + pnt_decode32(&pnt))); + break; + } + vty_out(vty, "%s%u", i == 0 ? "" : ", ", + pnt_decode32(&pnt)); + break; + case 8: + if (json) { + json_object_array_add( + json_array, + json_object_new_int64( + pnt_decode64(&pnt))); + break; + } + vty_out(vty, "%s%" PRIu64, i == 0 ? "" : ", ", + pnt_decode64(&pnt)); + break; + } + } + vty_out(vty, "\n"); +} + +static void bgp_linkstate_tlv_integer_display(struct vty *vty, uint8_t *pnt, + uint16_t length, + json_object *json) +{ + switch (length) { + case 1: + if (json) { + json_object_int_add(json, "data", pnt_decode8(&pnt)); + break; + } + vty_out(vty, "%u\n", pnt_decode8(&pnt)); + break; + case 2: + if (json) { + json_object_int_add(json, "data", pnt_decode16(&pnt)); + break; + } + vty_out(vty, "%u\n", pnt_decode16(&pnt)); + break; + case 3: + if (json) { + json_object_int_add(json, "data", pnt_decode24(&pnt)); + break; + } + vty_out(vty, "%u\n", pnt_decode24(&pnt)); + break; + case 4: + if (json) { + json_object_int_add(json, "data", pnt_decode32(&pnt)); + break; + } + vty_out(vty, "%u\n", pnt_decode32(&pnt)); + break; + case 8: + if (json) { + json_object_int_add(json, "data", pnt_decode64(&pnt)); + break; + } + vty_out(vty, "%" PRIu64 "\n", pnt_decode64(&pnt)); + break; + } +} + +static void bgp_linkstate_tlv_ipv4_6_address_display(struct vty *vty, + uint8_t *pnt, + uint16_t length, + json_object *json) +{ + if (length == IPV4_MAX_BYTELEN) { + if (json) { + json_object_string_addf(json, "data", "%pI4", + (in_addr_t *)pnt); + return; + } + vty_out(vty, "%pI4\n", (in_addr_t *)pnt); + } else if (length == IPV6_MAX_BYTELEN) { + if (json) { + json_object_string_addf(json, "data", "%pI6", + (struct in6_addr *)pnt); + return; + } + vty_out(vty, "%pI6\n", (struct in6_addr *)pnt); + } else + bgp_linkstate_tlv_hexa_display(vty, pnt, length, json); +} + +static void bgp_linkstate_tlv_name_display(struct vty *vty, uint8_t *pnt, + uint16_t length, json_object *json) +{ + char buf[length + 1]; + int i; + + buf[0] = '\0'; + for (i = 0; i < length; i++) + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c", + pnt_decode8(&pnt)); + + if (json) + json_object_string_add(json, "data", buf); + else + vty_out(vty, "%s\n", buf); +} + +static void bgp_linkstate_tlv_msd_display(struct vty *vty, uint8_t *pnt, + uint16_t length, int indent, + json_object *json) +{ + json_object *json_array = NULL; + json_object *json_data = NULL; + int i; + + if (json) { + json_array = json_object_new_array(); + json_object_object_add(json, "data", json_array); + } + + for (i = 0; i < (length / 2); i++) { + if (json) { + json_data = json_object_new_object(); + json_object_array_add(json_array, json_data); + json_object_int_add(json_data, "type", + pnt_decode8(&pnt)); + json_object_int_add(json_data, "value", + pnt_decode8(&pnt)); + continue; + } + vty_out(vty, "\n%*sType: %u Value: %u", indent, "", + pnt_decode8(&pnt), pnt_decode8(&pnt)); + } + + if (!json) + vty_out(vty, "\n"); +} + +static void bgp_linkstate_tlv_bandwidth_display(struct vty *vty, uint8_t *pnt, + uint16_t length, + json_object *json) +{ + union { + float r; + uint32_t d; + } float_uint32; + + float_uint32.d = pnt_decode32(&pnt); + + if (json) { + json_object_double_add(json, "data", float_uint32.r); + json_object_string_add(json, "dataUnit", "bps"); + return; + } + vty_out(vty, "%g Mbps\n", float_uint32.r / 1000 / 1000 * 8); +} + +static void bgp_linkstate_tlv_unreserved_bandwidth_display(struct vty *vty, + uint8_t *pnt, + uint16_t length, + int indent, + json_object *json) +{ + json_object *json_data = NULL; + union { + float r; + uint32_t d; + } float_uint32; + char buf[3]; + int i; + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + for (i = 0; i < MAX_CLASS_TYPE; i++) { + float_uint32.d = pnt_decode32(&pnt); + snprintf(buf, sizeof(buf), "%d", i); + json_object_double_add(json_data, buf, float_uint32.r); + } + json_object_string_add(json, "dataUnit", "bps"); + return; + } + + for (i = 0; i < MAX_CLASS_TYPE; i += 2) { + float_uint32.d = pnt_decode32(&pnt); + vty_out(vty, "\n%*s[%d]: %g Mbps ", indent, "", i, + float_uint32.r / 1000 / 1000 * 8); + float_uint32.d = pnt_decode32(&pnt); + vty_out(vty, "[%d]: %g Mbps", i + 1, + float_uint32.r / 1000 / 1000 * 8); + } + vty_out(vty, "\n"); +} + +static void bgp_linkstate_tlv_sid_display(struct vty *vty, uint8_t *pnt, + uint16_t length, uint16_t type, + int indent, json_object *json) +{ + json_object *json_data = NULL; + char buf[11]; + uint32_t sid; + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + } + + if (json) { + pnt = bgp_linkstate_tlv_binary_string(buf, sizeof(buf), pnt, 1); + json_object_string_add(json_data, "flags", buf); + } else { + vty_out(vty, "\n%*sFlags: ", indent, ""); + pnt = bgp_linkstate_tlv_binary_display(vty, pnt, 1, json); + } + + if (type == BGP_LS_TLV_PREFIX_SID) { + if (json) + json_object_int_add(json_data, "algorithm", + pnt_decode8(&pnt)); + else + vty_out(vty, "%*sAlgorithm: %u\n", indent, "", + pnt_decode8(&pnt)); + } else { + if (json) + json_object_int_add(json_data, "weight", + pnt_decode8(&pnt)); + else + vty_out(vty, "%*sWeight: %u\n", indent, "", + pnt_decode8(&pnt)); + } + + pnt += 2; /* ignore reserved 2 bytes */ + + if (type == BGP_LS_TLV_LAN_ADJACENCY_SID) { + vty_out(vty, "%*sNeighbor ID:", indent, ""); + if (length == 11 || length == 12) { + /* OSPF Router-ID */ + if (json) + json_object_string_addf(json_data, "neighborId", + "%pI4\n", + (in_addr_t *)pnt); + else + vty_out(vty, "%pI4\n", (in_addr_t *)pnt); + pnt += 4; + } else { + /* IS-IS System-ID */ + if (json) + json_object_string_addf(json_data, "neighborId", + "%pSY\n", pnt); + else + vty_out(vty, "%pSY\n", pnt); + pnt += 6; + } + } + + if (length == 7 || length == 11 || length == 13) + sid = pnt_decode24(&pnt); + else + sid = pnt_decode32(&pnt); + + if (json) + json_object_int_add(json_data, "sid", sid); + else + vty_out(vty, "%*sSID: %u\n", indent, "", sid); +} + +static void bgp_linkstate_tlv_range_display(struct vty *vty, uint8_t *pnt, + uint16_t length, int indent, + json_object *json) +{ + json_object *json_data = NULL; + char buf[11]; + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + pnt = bgp_linkstate_tlv_binary_string(buf, sizeof(buf), pnt, 1); + json_object_string_add(json_data, "flags", buf); + } else { + vty_out(vty, "\n%*sFlags: ", indent, ""); + pnt = bgp_linkstate_tlv_binary_display(vty, pnt, 1, json); + } + pnt++; /* ignore reserved byte */ + if (json) + json_object_int_add(json_data, "rangeSize", pnt_decode16(&pnt)); + else + vty_out(vty, "%*sRange Size: %u\n", indent, "", + pnt_decode16(&pnt)); + + /* RFC9085 2.3.5 is unclear. Just display a hexa dump */ + bgp_linkstate_tlv_hexa_display(vty, pnt, length - 4, json_data); +} + +static void bgp_linkstate_tlv_delay_display(struct vty *vty, uint8_t *pnt, + uint16_t length, uint16_t type, + json_object *json) +{ + json_object *json_data = NULL; + uint32_t tmp32; + bool anomalous; + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + } + + tmp32 = pnt_decode32(&pnt); + anomalous = !!(tmp32 & TE_EXT_ANORMAL); + + if (json) + json_object_boolean_add(json_data, "anomalous", anomalous); + else if (anomalous) + vty_out(vty, "Anomalous "); + + if (json) + json_object_string_add(json, "dataUnit", "microseconds"); + + if (type == BGP_LS_TLV_UNIDIRECTIONAL_LINK_DELAY || + type == BGP_LS_TLV_UNIDIRECTIONAL_DELAY_VARIATION) { + if (json) + json_object_int_add(json_data, "delay", + tmp32 & TE_EXT_MASK); + else + vty_out(vty, "%u microseconds\n", tmp32 & TE_EXT_MASK); + } else if (type == BGP_LS_TLV_MIN_MAX_UNIDIRECTIONAL_LINK_DELAY) { + if (json) { + json_object_int_add(json_data, "minDelay", + tmp32 & TE_EXT_MASK); + json_object_int_add(json_data, "maxDelay", + pnt_decode32(&pnt) & TE_EXT_MASK); + } else { + vty_out(vty, "%u", tmp32 & TE_EXT_MASK); + vty_out(vty, "/%u microseconds\n", + pnt_decode32(&pnt) & TE_EXT_MASK); + } + } +} + +static void bgp_linkstate_tlv_unidirectional_link_loss_display( + struct vty *vty, uint8_t *pnt, uint16_t length, json_object *json) +{ + json_object *json_data = NULL; + uint32_t tmp32; + float value; + bool anomalous; + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + } + + tmp32 = pnt_decode32(&pnt); + + anomalous = !!(tmp32 & TE_EXT_ANORMAL); + value = ((float)(tmp32 & TE_EXT_MASK)) * LOSS_PRECISION; + + if (json) { + json_object_boolean_add(json_data, "anomalous", anomalous); + json_object_double_add(json_data, "lossPercent", value); + return; + } + + if (anomalous) + vty_out(vty, "Anomalous "); + vty_out(vty, "%g%%\n", value); +} + +static void bgp_linkstate_tlv_asla_display(struct vty *vty, uint8_t *pnt, + uint16_t length, int indent, + json_object *json) +{ + json_object *json_data = NULL; + char buf[290]; + uint8_t sabm_len, udabm_len; + struct bgp_attr_ls attr_ls; + uint8_t *orig_pnt = pnt; + + sabm_len = pnt_decode8(&pnt); + udabm_len = pnt_decode8(&pnt); + pnt += 2; /* ignore reserved 2 bytes */ + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + pnt = bgp_linkstate_tlv_binary_string(buf, sizeof(buf), pnt, + sabm_len); + json_object_string_add(json_data, "sabmFlags", buf); + pnt = bgp_linkstate_tlv_binary_string(buf, sizeof(buf), pnt, + udabm_len); + json_object_string_add(json_data, "udabmFlags", buf); + } else { + vty_out(vty, "\n%*sSABM Flags : ", indent, ""); + pnt = bgp_linkstate_tlv_binary_display(vty, pnt, sabm_len, + json); + vty_out(vty, "%*sUDABM Flags: ", indent, ""); + pnt = bgp_linkstate_tlv_binary_display(vty, pnt, udabm_len, + json); + } + + attr_ls.length = length - (pnt - orig_pnt); + attr_ls.data = pnt; + + bgp_linkstate_tlv_attribute_display(vty, &attr_ls, indent, json_data); +} + +static void bgp_linkstate_tlv_sr_range_display(struct vty *vty, uint8_t *pnt, + uint16_t length, int indent, + json_object *json) +{ + json_object *json_data = NULL; + struct bgp_attr_ls attr_ls; + uint8_t *orig_pnt = pnt; + char buf[11]; + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + pnt = bgp_linkstate_tlv_binary_string(buf, sizeof(buf), pnt, 1); + json_object_string_add(json_data, "flags", buf); + } else { + vty_out(vty, "\n%*sFlags: ", indent, ""); + pnt = bgp_linkstate_tlv_binary_display(vty, pnt, 1, json); + } + pnt++; /* ignore reserved byte */ + if (json) + json_object_int_add(json_data, "range", pnt_decode24(&pnt)); + else + vty_out(vty, "%*sRange: %u\n", indent, "", pnt_decode24(&pnt)); + + attr_ls.length = length - (pnt - orig_pnt); + attr_ls.data = pnt; + + bgp_linkstate_tlv_attribute_display(vty, &attr_ls, indent, json_data); +} + +static void bgp_linkstate_tlv_sid_label_display(struct vty *vty, uint8_t *pnt, + uint16_t length, + json_object *json) +{ + json_object *json_data = NULL; + + /* RFC9085 + * If the length is set to 3, then the 20 rightmost bits + * represent a label (the total TLV size is 7), and the 4 + * leftmost bits are set to 0. If the length is set to 4, then + * the value represents a 32-bit SID (the total TLV size is 8). + */ + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + } + + if (length == 3) { + if (json) + json_object_int_add(json_data, "fromLabel", + pnt_decode24(&pnt) & 0x0FFFFF); + else + vty_out(vty, "From Label: %u\n", + pnt_decode24(&pnt) & 0x0FFFFF); + } else { + if (json) + json_object_int_add(json_data, "fromIndex", + pnt_decode32(&pnt)); + else + vty_out(vty, "From Index: %u\n", pnt_decode32(&pnt)); + } +} + +static void bgp_linkstate_tlv_flexible_algorithm_definition_display( + struct vty *vty, uint8_t *pnt, uint16_t length, int indent, + json_object *json) +{ + json_object *json_data = NULL; + struct bgp_attr_ls attr_ls; + uint8_t *orig_pnt = pnt; + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + json_object_int_add(json_data, "flexAlgo", pnt_decode8(&pnt)); + json_object_int_add(json_data, "metricType", pnt_decode8(&pnt)); + json_object_int_add(json_data, "calcType", pnt_decode8(&pnt)); + json_object_int_add(json_data, "priority", pnt_decode8(&pnt)); + } else { + vty_out(vty, "\n%*sFlex-Algo: %u\n", indent, "", + pnt_decode8(&pnt)); + vty_out(vty, "%*sMetric-Type: %u\n", indent, "", + pnt_decode8(&pnt)); + vty_out(vty, "%*sCalc-Type: %u\n", indent, "", + pnt_decode8(&pnt)); + vty_out(vty, "%*sPriority: %u\n", indent, "", + pnt_decode8(&pnt)); + } + + attr_ls.length = length - (pnt - orig_pnt); + attr_ls.data = pnt; + + bgp_linkstate_tlv_attribute_display(vty, &attr_ls, indent, json_data); +} + +static void bgp_linkstate_tlv_flexible_algorithm_prefix_metric_display( + struct vty *vty, uint8_t *pnt, uint16_t length, int indent, + json_object *json) +{ + json_object *json_data = NULL; + char buf[11]; + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + json_object_int_add(json_data, "flexAlgo", pnt_decode8(&pnt)); + pnt = bgp_linkstate_tlv_binary_string(buf, sizeof(buf), pnt, 1); + json_object_string_add(json_data, "flags", buf); + pnt += 2; /* ignore reserved 2 bytes */ + json_object_int_add(json_data, "metric", pnt_decode32(&pnt)); + return; + } + + vty_out(vty, "\n%*sFlex-Algo: %u\n", indent, "", pnt_decode8(&pnt)); + vty_out(vty, "%*sFlags: ", indent, ""); + pnt = bgp_linkstate_tlv_binary_display(vty, pnt, 1, json); + pnt += 2; /* ignore reserved 2 bytes */ + vty_out(vty, "%*sMetric: %u\n", indent, "", pnt_decode32(&pnt)); +} + +static void bgp_linkstate_tlv_opaque_display(struct vty *vty, uint8_t *pnt, + uint16_t length, int indent, + json_object *json) +{ + uint16_t sub_type = 0, sub_length = 0; + json_object *json_data = NULL; + json_object *json_tlv = NULL; + uint8_t *lim = pnt + length; + bool ospf_tlv_header; + char tlv_type[6]; + + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + } + + /* Opaque TLV carries original IGP TLVs + * IS-IS TLV header is 1 byte each for the TLV type and length. + * OSPF TLV header is 2 bytes each for the TLV type and length + * but the TLV type values are far from exceeding 255. + * Assume TLV header format is the OSPF one if first value is 0x00. + */ + ospf_tlv_header = (*pnt == 0); + + for (; pnt < lim; pnt += sub_length) { + if (ospf_tlv_header) { + sub_type = pnt_decode16(&pnt); + sub_length = pnt_decode16(&pnt); + } else { + sub_type = pnt_decode8(&pnt); + sub_length = pnt_decode8(&pnt); + } + + if (json) { + snprintf(tlv_type, sizeof(tlv_type), "%u", sub_type); + json_tlv = json_object_new_object(); + json_object_object_add(json_data, tlv_type, json_tlv); + + json_object_int_add(json_tlv, "type", sub_type); + json_object_int_add(json_tlv, "length", sub_length); + + if (pnt + sub_length > lim) { + json_object_string_addf( + json_tlv, "error", + "too high length received: %u", + sub_length); + break; + } + + bgp_linkstate_tlv_hexa_display(vty, pnt, sub_length, + json_tlv); + continue; + } + + vty_out(vty, "\n%*sTLV type %u: ", indent, "", sub_type); + + if (pnt + sub_length > lim) { + vty_out(vty, "Bad length received: %u\n", sub_length); + break; + } + + bgp_linkstate_tlv_hexa_display(vty, pnt, sub_length, NULL); + } +} + +static void bgp_linkstate_tlv_rtm_capability_display(struct vty *vty, + uint8_t *pnt, + uint16_t length, + json_object *json) +{ + json_object *json_data = NULL; + json_object *json_array = NULL; + uint8_t *lim = pnt + length; + uint8_t tmp8; + char buf[11]; + int i; + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + + tmp8 = pnt_decode8(&pnt); + snprintf(buf, sizeof(buf), "0b"); + for (i = 7; i >= 5; i--) + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + "%d", (tmp8 >> i) & 1); + json_object_string_add(json_data, "flags", buf); + + if (length > 8) { + json_array = json_object_new_array(); + json_object_object_add(json, "values", json_array); + for (i = 0; pnt < lim; pnt++, i++) { + if (i % 8 == 0) { + if (i != 0) + json_object_array_add( + json_array, + json_object_new_string( + buf)); + snprintf(buf, sizeof(buf), "0x"); + } + if (i == 0) + snprintf(buf + strlen(buf), + sizeof(buf) - strlen(buf), + "%02x", tmp8 & 0x1F); + else + snprintf(buf + strlen(buf), + sizeof(buf) - strlen(buf), + "%02x", *pnt); + } + if (strlen(buf) > 2) /* do not only contain 0x */ + json_object_array_add( + json_array, + json_object_new_string(buf)); + } else { + snprintf(buf, sizeof(buf), "0x"); + for (i = 0; pnt < lim; pnt++, i++) { + if (i == 0) + snprintf(buf + strlen(buf), + sizeof(buf) - strlen(buf), + "%02x", tmp8 & 0x1F); + else + snprintf(buf + strlen(buf), + sizeof(buf) - strlen(buf), + "%02x", *pnt); + } + json_object_string_add(json_data, "values", buf); + } + return; + } + + tmp8 = pnt_decode8(&pnt); + + vty_out(vty, "Flags: 0b"); + for (i = 7; i >= 5; i--) + vty_out(vty, "%d", (tmp8 >> i) & 1); + vty_out(vty, " Values: 0x%02x", tmp8 & 0x1F); + for (; pnt < lim; pnt++) + vty_out(vty, "%02x", *pnt); + vty_out(vty, "\n"); +} + +static void bgp_linkstate_tlv_l2_member_attributes_display(struct vty *vty, + uint8_t *pnt, + uint16_t length, + int indent, + json_object *json) +{ + json_object *json_data = NULL; + struct bgp_attr_ls attr_ls; + uint8_t *orig_pnt = pnt; + + if (json) { + json_data = json_object_new_object(); + json_object_object_add(json, "data", json_data); + json_object_string_addf(json_data, "descriptor", "0x%02x", + pnt_decode32(&pnt)); + } else + vty_out(vty, "Descriptor: 0x%02x\n", pnt_decode32(&pnt)); + + attr_ls.length = length - (pnt - orig_pnt); + attr_ls.data = pnt; + + if (attr_ls.length == 0) + /* No Sub-TLV */ + return; + + bgp_linkstate_tlv_attribute_display(vty, &attr_ls, indent, json_data); +} + +static void bgp_linkstate_tlv_isis_area_indentifier_display(struct vty *vty, + uint8_t *pnt, + uint16_t length, + json_object *json) +{ + struct iso_address addr; + + if (length > sizeof(addr.area_addr)) { + bgp_linkstate_tlv_hexa_display(vty, pnt, length, json); + return; + } + + addr.addr_len = length; + memcpy(addr.area_addr, pnt, length); + + if (json) + json_object_string_addf(json, "data", "%pIS", &addr); + else + vty_out(vty, "%pIS\n", &addr); +} + +static void +bgp_linkstate_tlv_attribute_value_display(struct vty *vty, uint8_t *pnt, + uint16_t type, uint16_t length, + int indent, json_object *json) +{ + if (!bgp_ls_tlv_check_size(type, length)) { + bgp_linkstate_tlv_hexa_display(vty, pnt, length, json); + return; + } + + switch (type) { + case BGP_LS_TLV_SRMS_PREFERENCE: + case BGP_LS_TLV_IGP_METRIC: + case BGP_LS_TLV_PREFIX_METRIC: + case BGP_LS_TLV_TE_DEFAULT_METRIC: + bgp_linkstate_tlv_integer_display(vty, pnt, length, json); + break; + case BGP_LS_TLV_SR_ALGORITHM: + bgp_linkstate_tlv_integer_list_display(vty, pnt, length, 1, + json); + break; + case BGP_LS_TLV_MULTI_TOPOLOGY_ID: + bgp_linkstate_tlv_integer_list_display(vty, pnt, length, 2, + json); + break; + case BGP_LS_TLV_IGP_ROUTE_TAG: + case BGP_LS_TLV_SHARED_RISK_LINK_GROUP: + case BGP_LS_TLV_S_BFD_DISCRIMINATORS: + case BGP_LS_TLV_FLEXIBLE_ALGORITHM_EXCLUDE_SRLG: + bgp_linkstate_tlv_integer_list_display(vty, pnt, length, 4, + json); + break; + case BGP_LS_TLV_IGP_EXTENDED_ROUTE_TAG: + bgp_linkstate_tlv_integer_list_display(vty, pnt, length, 8, + json); + break; + case BGP_LS_TLV_IPV4_ROUTER_ID_OF_LOCAL_NODE: + case BGP_LS_TLV_IPV6_ROUTER_ID_OF_LOCAL_NODE: + case BGP_LS_TLV_IPV4_ROUTER_ID_OF_REMOTE_NODE: + case BGP_LS_TLV_IPV6_ROUTER_ID_OF_REMOTE_NODE: + case BGP_LS_TLV_OSPF_FORWARDING_ADDRESS: + case BGP_LS_TLV_SOURCE_OSPF_ROUTER_ID: + case BGP_LS_TLV_SOURCE_ROUTER_IDENTIFIER: + bgp_linkstate_tlv_ipv4_6_address_display(vty, pnt, length, + json); + break; + case BGP_LS_TLV_NODE_NAME: + case BGP_LS_TLV_LINK_NAME: + bgp_linkstate_tlv_name_display(vty, pnt, length, json); + break; + case BGP_LS_TLV_NODE_FLAG_BITS: + case BGP_LS_TLV_IGP_FLAGS: + case BGP_LS_TLV_PREFIX_ATTRIBUTES_FLAGS: + case BGP_LS_TLV_MPLS_PROTOCOL_MASK: + case BGP_LS_TLV_LINK_PROTECTION_TYPE: + case BGP_LS_TLV_FLEXIBLE_ALGORITHM_DEFINITION_FLAGS: + bgp_linkstate_tlv_binary_display(vty, pnt, length, json); + break; + case BGP_LS_TLV_ADMINISTRATIVE_GROUP: + case BGP_LS_TLV_EXTENDED_ADMINISTRATIVE_GROUP: + case BGP_LS_TLV_FLEXIBLE_ALGORITHM_EXCLUDE_ANY_AFFINITY: + case BGP_LS_TLV_FLEXIBLE_ALGORITHM_INCLUDE_ANY_AFFINITY: + case BGP_LS_TLV_FLEXIBLE_ALGORITHM_INCLUDE_ALL_AFFINITY: + bgp_linkstate_tlv_hexa_display(vty, pnt, length, json); + break; + case BGP_LS_TLV_OPAQUE_NODE_ATTRIBUTE: + case BGP_LS_TLV_OPAQUE_LINK_ATTRIBUTE: + case BGP_LS_TLV_OPAQUE_PREFIX_ATTRIBUTE: + bgp_linkstate_tlv_opaque_display(vty, pnt, length, indent + 2, + json); + break; + case BGP_LS_TLV_NODE_MSD: + case BGP_LS_TLV_LINK_MSD: + bgp_linkstate_tlv_msd_display(vty, pnt, length, indent + 2, + json); + break; + case BGP_LS_TLV_MAXIMUM_LINK_BANDWIDTH: + case BGP_LS_TLV_MAX_RESERVABLE_LINK_BANDWIDTH: + case BGP_LS_TLV_UNIDIRECTIONAL_RESIDUAL_BANDWIDTH: + case BGP_LS_TLV_UNIDIRECTIONAL_AVAILABLE_BANDWIDTH: + case BGP_LS_TLV_UNIDIRECTIONAL_UTILIZED_BANDWIDTH: + bgp_linkstate_tlv_bandwidth_display(vty, pnt, length, json); + break; + case BGP_LS_TLV_UNRESERVED_BANDWIDTH: + bgp_linkstate_tlv_unreserved_bandwidth_display( + vty, pnt, length, indent + 2, json); + break; + case BGP_LS_TLV_IS_IS_AREA_IDENTIFIER: + bgp_linkstate_tlv_isis_area_indentifier_display(vty, pnt, + length, json); + break; + case BGP_LS_TLV_PREFIX_SID: + case BGP_LS_TLV_ADJACENCY_SID: + case BGP_LS_TLV_LAN_ADJACENCY_SID: + case BGP_LS_TLV_PEERNODE_SID: + case BGP_LS_TLV_PEERADJ_SID: + case BGP_LS_TLV_PEERSET_SID: + bgp_linkstate_tlv_sid_display(vty, pnt, length, type, + indent + 2, json); + break; + case BGP_LS_TLV_RANGE: + bgp_linkstate_tlv_range_display(vty, pnt, length, indent + 2, + json); + break; + case BGP_LS_TLV_UNIDIRECTIONAL_LINK_DELAY: + case BGP_LS_TLV_MIN_MAX_UNIDIRECTIONAL_LINK_DELAY: + case BGP_LS_TLV_UNIDIRECTIONAL_DELAY_VARIATION: + bgp_linkstate_tlv_delay_display(vty, pnt, length, type, json); + break; + case BGP_LS_TLV_UNIDIRECTIONAL_LINK_LOSS: + bgp_linkstate_tlv_unidirectional_link_loss_display( + vty, pnt, length, json); + break; + case BGP_LS_TLV_APPLICATION_SPECIFIC_LINK_ATTRIBUTES: + bgp_linkstate_tlv_asla_display(vty, pnt, length, indent + 2, + json); + break; + case BGP_LS_TLV_SR_CAPABILITIES: + case BGP_LS_TLV_SR_LOCAL_BLOCK: + bgp_linkstate_tlv_sr_range_display(vty, pnt, length, indent + 2, + json); + break; + case BGP_LS_TLV_SID_LABEL: + bgp_linkstate_tlv_sid_label_display(vty, pnt, length, json); + break; + case BGP_LS_TLV_FLEXIBLE_ALGORITHM_DEFINITION: + bgp_linkstate_tlv_flexible_algorithm_definition_display( + vty, pnt, length, indent + 2, json); + break; + case BGP_LS_TLV_FLEXIBLE_ALGORITHM_PREFIX_METRIC: + bgp_linkstate_tlv_flexible_algorithm_prefix_metric_display( + vty, pnt, length, indent + 2, json); + break; + case BGP_LS_TLV_GRACEFUL_LINK_SHUTDOWN_TLV: + if (!json) + vty_out(vty, "Enabled\n"); /* TLV must have no data */ + break; + case BGP_LS_TLV_L2_BUNDLE_MEMBER_ATTRIBUTES: + bgp_linkstate_tlv_l2_member_attributes_display( + vty, pnt, length, indent + 2, json); + break; + case BGP_LS_TLV_RTM_CAPABILITY: + bgp_linkstate_tlv_rtm_capability_display(vty, pnt, length, + json); + break; + default: + bgp_linkstate_tlv_hexa_display(vty, pnt, length, json); + } +} + +void bgp_linkstate_tlv_attribute_display(struct vty *vty, + struct bgp_attr_ls *attr_ls, + int indent, json_object *json) +{ + uint8_t *pnt = attr_ls->data; + uint8_t *lim = pnt + attr_ls->length; + uint16_t length = 0; + uint16_t type = 0; + char tlv_type[6]; + json_object *json_tlv = NULL; + + for (; pnt < lim; pnt += length) { + type = pnt_decode16(&pnt); + length = pnt_decode16(&pnt); + + if (json) { + snprintf(tlv_type, sizeof(tlv_type), "%u", type); + + json_tlv = json_object_new_object(); + json_object_object_add(json, tlv_type, json_tlv); + + if (type <= BGP_LS_TLV_MAX && + bgp_linkstate_tlv_infos[type].descr != NULL) + json_object_string_add( + json_tlv, "description", + bgp_linkstate_tlv_infos[type].descr); + + json_object_int_add(json_tlv, "type", type); + json_object_int_add(json_tlv, "length", length); + + if (pnt + length > lim) { + json_object_string_addf( + json_tlv, "error", + "too high length received: %u", length); + break; + } + if (type <= BGP_LS_TLV_MAX && + bgp_linkstate_tlv_infos[type].descr != NULL && + !bgp_ls_tlv_check_size(type, length)) + json_object_string_addf( + json_tlv, "error", + "unexpected length received: %u", + length); + } else { + if (type <= BGP_LS_TLV_MAX && + bgp_linkstate_tlv_infos[type].descr != NULL) + vty_out(vty, "%*s%s: ", indent, "", + bgp_linkstate_tlv_infos[type].descr); + else + vty_out(vty, "%*sTLV type %u: ", indent, "", + type); + + if (pnt + length > lim) { + vty_out(vty, "Bad length received: %u\n", + length); + break; + } + } + + bgp_linkstate_tlv_attribute_value_display( + vty, pnt, type, length, indent, json_tlv); + } +} diff --git a/bgpd/bgp_linkstate_tlv.h b/bgpd/bgp_linkstate_tlv.h new file mode 100644 index 000000000000..cc543735b77f --- /dev/null +++ b/bgpd/bgp_linkstate_tlv.h @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP Link-State TLV Serializer/Deserializer header + * Copyright 2023 6WIND S.A. + */ + +#ifndef BGP_LINKSTATE_TLV_H +#define BGP_LINKSTATE_TLV_H + +/* RFC7752 Link-State NLRI Protocol-ID values + * +-------------+----------------------------------+ + * | Protocol-ID | NLRI information source protocol | + * +-------------+----------------------------------+ + * | 1 | IS-IS Level 1 | + * | 2 | IS-IS Level 2 | + * | 3 | OSPFv2 | + * | 4 | Direct | + * | 5 | Static configuration | + * | 6 | OSPFv3 | + * +-------------+----------------------------------+ + */ + +enum bgp_ls_nlri_proto { + BGP_LS_NLRI_PROTO_ID_UNKNOWN = 0, + BGP_LS_NLRI_PROTO_ID_IS_IS_LEVEL_1 = 1, + BGP_LS_NLRI_PROTO_ID_IS_IS_LEVEL_2 = 2, + BGP_LS_NLRI_PROTO_ID_OSPF = 3, + BGP_LS_NLRI_PROTO_ID_DIRECT = 4, + BGP_LS_NLRI_PROTO_ID_STATIC = 5, + BGP_LS_NLRI_PROTO_ID_OSPFv3 = 6, +}; + +/* + * List of BGP Link-State TLVs extracted from + * https://www.iana.org/assignments/bgp-ls-parameters/bgp-ls-parameters.xhtml#node-descriptor-link-descriptor-prefix-descriptor-attribute-tlv + * + * Retrieved on 2023-01-03 + * + * The following bash command was used to convert the list: + * sed -e 's| (.\+)||g' tmp \ + * | awk -F'\t' '($1 ~ /^[0-9]+$/) {gsub(/(\/|-| |\.)/,"_",$2); printf + * "\tBGP_LS_TLV_"toupper($2)" = "$1", \/\* "$4" \*\/\n"}' \ + * | grep -v UNASSIGNED \ + * | sed -e 's/\[//g;s/\]//g' + * + */ + +enum bgp_linkstate_tlv { + BGP_LS_TLV_LOCAL_NODE_DESCRIPTORS = 256, /* RFC7752, Section 3.2.1.2 */ + BGP_LS_TLV_REMOTE_NODE_DESCRIPTORS = 257, /* RFC7752, Section 3.2.1.3 */ + BGP_LS_TLV_LINK_LOCAL_REMOTE_IDENTIFIERS = + 258, /* RFC5307, Section 1.1 */ + BGP_LS_TLV_IPV4_INTERFACE_ADDRESS = 259, /* RFC5305, Section 3.2 */ + BGP_LS_TLV_IPV4_NEIGHBOR_ADDRESS = 260, /* RFC5305, Section 3.3 */ + BGP_LS_TLV_IPV6_INTERFACE_ADDRESS = 261, /* RFC6119, Section 4.2 */ + BGP_LS_TLV_IPV6_NEIGHBOR_ADDRESS = 262, /* RFC6119, Section 4.3 */ + BGP_LS_TLV_MULTI_TOPOLOGY_ID = 263, /* RFC7752, Section 3.2.1.5 */ + BGP_LS_TLV_OSPF_ROUTE_TYPE = 264, /* RFC7752, Section 3.2.3 */ + BGP_LS_TLV_IP_REACHABILITY_INFORMATION = + 265, /* RFC7752, Section 3.2.3 */ + BGP_LS_TLV_NODE_MSD = 266, /* RFC8814 */ + BGP_LS_TLV_LINK_MSD = 267, /* RFC8814 */ + BGP_LS_TLV_AUTONOMOUS_SYSTEM = 512, /* RFC7752, Section 3.2.1.4 */ + BGP_LS_TLV_BGP_LS_IDENTIFIER = 513, /* RFC7752, Section 3.2.1.4 */ + BGP_LS_TLV_OSPF_AREA_ID = 514, /* RFC7752, Section 3.2.1.4 */ + BGP_LS_TLV_IGP_ROUTER_ID = 515, /* RFC7752, Section 3.2.1.4 */ + BGP_LS_TLV_BGP_ROUTER_ID = 516, /* RFC9086 */ + BGP_LS_TLV_BGP_CONFEDERATION_MEMBER = 517, /* RFC9086 */ + BGP_LS_TLV_SRV6_SID_INFORMATION_TLV = + 518, /* draft-ietf-idr-bgpls-srv6-ext-08 */ + BGP_LS_TLV_TUNNEL_ID_TLV = + 550, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_LSP_ID_TLV = 551, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_IPV4_6_TUNNEL_HEAD_END_ADDRESS_TLV = + 552, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_IPV4_6_TUNNEL_TAIL_END_ADDRESS_TLV = + 553, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_POLICY_CP_DESCRIPTOR_TLV = + 554, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_MPLS_LOCAL_CROSS_CONNECT_TLV = + 555, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_MPLS_CROSS_CONNECT_INTERFACE_TLV = + 556, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_MPLS_CROSS_CONNECT_FEC_TLV = + 557, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_NODE_FLAG_BITS = 1024, /* RFC7752, Section 3.3.1.1 */ + BGP_LS_TLV_OPAQUE_NODE_ATTRIBUTE = 1025, /* RFC7752, Section 3.3.1.5 */ + BGP_LS_TLV_NODE_NAME = 1026, /* RFC7752, Section 3.3.1.3 */ + BGP_LS_TLV_IS_IS_AREA_IDENTIFIER = 1027, /* RFC7752, Section 3.3.1.2 */ + BGP_LS_TLV_IPV4_ROUTER_ID_OF_LOCAL_NODE = + 1028, /* RFC5305, Section 4.3 */ + BGP_LS_TLV_IPV6_ROUTER_ID_OF_LOCAL_NODE = + 1029, /* RFC6119, Section 4.1 */ + BGP_LS_TLV_IPV4_ROUTER_ID_OF_REMOTE_NODE = + 1030, /* RFC5305, Section 4.3 */ + BGP_LS_TLV_IPV6_ROUTER_ID_OF_REMOTE_NODE = + 1031, /* RFC6119, Section 4.1 */ + BGP_LS_TLV_S_BFD_DISCRIMINATORS = 1032, /* RFC9247 */ + BGP_LS_TLV_UNASSIGNED = 1033, /* */ + BGP_LS_TLV_SR_CAPABILITIES = 1034, /* RFC9085, Section 2.1.2 */ + BGP_LS_TLV_SR_ALGORITHM = 1035, /* RFC9085, Section 2.1.3 */ + BGP_LS_TLV_SR_LOCAL_BLOCK = 1036, /* RFC9085, Section 2.1.4 */ + BGP_LS_TLV_SRMS_PREFERENCE = 1037, /* RFC9085, Section 2.1.5 */ + BGP_LS_TLV_SRV6_CAPABILITIES_TLV = + 1038, /* draft-ietf-idr-bgpls-srv6-ext-08 */ + BGP_LS_TLV_FLEXIBLE_ALGORITHM_DEFINITION = 1039, /* RFC9351 */ + BGP_LS_TLV_FLEXIBLE_ALGORITHM_EXCLUDE_ANY_AFFINITY = 1040, /* RFC9351 */ + BGP_LS_TLV_FLEXIBLE_ALGORITHM_INCLUDE_ANY_AFFINITY = 1041, /* RFC9351 */ + BGP_LS_TLV_FLEXIBLE_ALGORITHM_INCLUDE_ALL_AFFINITY = 1042, /* RFC9351 */ + BGP_LS_TLV_FLEXIBLE_ALGORITHM_DEFINITION_FLAGS = 1043, /* RFC9351 */ + BGP_LS_TLV_FLEXIBLE_ALGORITHM_PREFIX_METRIC = 1044, /* RFC9351 */ + BGP_LS_TLV_FLEXIBLE_ALGORITHM_EXCLUDE_SRLG = 1045, /* RFC9351 */ + BGP_LS_TLV_FLEXIBLE_ALGORITHM_UNSUPPORTED = 1046, /* RFC9351 */ + BGP_LS_TLV_ADMINISTRATIVE_GROUP = 1088, /* RFC5305, Section 3.1 */ + BGP_LS_TLV_MAXIMUM_LINK_BANDWIDTH = 1089, /* RFC5305, Section 3.4 */ + BGP_LS_TLV_MAX_RESERVABLE_LINK_BANDWIDTH = + 1090, /* RFC5305, Section 3.5 */ + BGP_LS_TLV_UNRESERVED_BANDWIDTH = 1091, /* RFC5305, Section 3.6 */ + BGP_LS_TLV_TE_DEFAULT_METRIC = 1092, /* RFC7752, Section 3.3.2.3 */ + BGP_LS_TLV_LINK_PROTECTION_TYPE = 1093, /* RFC5307, Section 1.2 */ + BGP_LS_TLV_MPLS_PROTOCOL_MASK = 1094, /* RFC7752, Section 3.3.2.2 */ + BGP_LS_TLV_IGP_METRIC = 1095, /* RFC7752, Section 3.3.2.4 */ + BGP_LS_TLV_SHARED_RISK_LINK_GROUP = 1096, /* RFC7752, Section 3.3.2.5 */ + BGP_LS_TLV_OPAQUE_LINK_ATTRIBUTE = 1097, /* RFC7752, Section 3.3.2.6 */ + BGP_LS_TLV_LINK_NAME = 1098, /* RFC7752, Section 3.3.2.7 */ + BGP_LS_TLV_ADJACENCY_SID = 1099, /* RFC9085, Section 2.2.1 */ + BGP_LS_TLV_LAN_ADJACENCY_SID = 1100, /* RFC9085, Section 2.2.2 */ + BGP_LS_TLV_PEERNODE_SID = 1101, /* RFC9086 */ + BGP_LS_TLV_PEERADJ_SID = 1102, /* RFC9086 */ + BGP_LS_TLV_PEERSET_SID = 1103, /* RFC9086 */ + BGP_LS_TLV_RTM_CAPABILITY = 1105, /* RFC8169 */ + BGP_LS_TLV_SRV6_END_X_SID_TLV = + 1106, /* draft-ietf-idr-bgpls-srv6-ext-08 */ + BGP_LS_TLV_IS_IS_SRV6_LAN_END_X_SID_TLV = + 1107, /* draft-ietf-idr-bgpls-srv6-ext-08 */ + BGP_LS_TLV_OSPFV3_SRV6_LAN_END_X_SID_TLV = + 1108, /* draft-ietf-idr-bgpls-srv6-ext-08 */ + BGP_LS_TLV_UNIDIRECTIONAL_LINK_DELAY = 1114, /* RFC8571 */ + BGP_LS_TLV_MIN_MAX_UNIDIRECTIONAL_LINK_DELAY = 1115, /* RFC8571 */ + BGP_LS_TLV_UNIDIRECTIONAL_DELAY_VARIATION = 1116, /* RFC8571 */ + BGP_LS_TLV_UNIDIRECTIONAL_LINK_LOSS = 1117, /* RFC8571 */ + BGP_LS_TLV_UNIDIRECTIONAL_RESIDUAL_BANDWIDTH = 1118, /* RFC8571 */ + BGP_LS_TLV_UNIDIRECTIONAL_AVAILABLE_BANDWIDTH = 1119, /* RFC8571 */ + BGP_LS_TLV_UNIDIRECTIONAL_UTILIZED_BANDWIDTH = 1120, /* RFC8571 */ + BGP_LS_TLV_GRACEFUL_LINK_SHUTDOWN_TLV = 1121, /* RFC8379 */ + BGP_LS_TLV_APPLICATION_SPECIFIC_LINK_ATTRIBUTES = 1122, /* RFC9294 */ + BGP_LS_TLV_IGP_FLAGS = 1152, /* RFC7752, Section 3.3.3.1 */ + BGP_LS_TLV_IGP_ROUTE_TAG = 1153, /* RFC5130 */ + BGP_LS_TLV_IGP_EXTENDED_ROUTE_TAG = 1154, /* RFC5130 */ + BGP_LS_TLV_PREFIX_METRIC = 1155, /* RFC5305 */ + BGP_LS_TLV_OSPF_FORWARDING_ADDRESS = 1156, /* RFC2328 */ + BGP_LS_TLV_OPAQUE_PREFIX_ATTRIBUTE = + 1157, /* RFC7752, Section 3.3.3.6 */ + BGP_LS_TLV_PREFIX_SID = 1158, /* RFC9085, Section 2.3.1 */ + BGP_LS_TLV_RANGE = 1159, /* RFC9085, Section 2.3.5 */ + BGP_LS_TLV_IS_IS_FLOOD_REFLECTION = + 1160, /* draft-ietf-idr-bgp-ls-isis-flood-reflection-02 */ + BGP_LS_TLV_SID_LABEL = 1161, /* RFC9085, Section 2.1.1 */ + BGP_LS_TLV_SRV6_LOCATOR_TLV = + 1162, /* draft-ietf-idr-bgpls-srv6-ext-08 */ + BGP_LS_TLV_PREFIX_ATTRIBUTES_FLAGS = 1170, /* RFC9085, Section 2.3.2 */ + BGP_LS_TLV_SOURCE_ROUTER_IDENTIFIER = 1171, /* RFC9085, Section 2.3.3 */ + BGP_LS_TLV_L2_BUNDLE_MEMBER_ATTRIBUTES = + 1172, /* RFC9085, Section 2.2.3 */ + BGP_LS_TLV_EXTENDED_ADMINISTRATIVE_GROUP = 1173, /* RFC9104 */ + BGP_LS_TLV_SOURCE_OSPF_ROUTER_ID = 1174, /* RFC9085, Section 2.3.4 */ + BGP_LS_TLV_MPLS_TE_POLICY_STATE_TLV = + 1200, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_BSID_TLV = + 1201, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_CP_STATE_TLV = + 1202, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_CP_NAME_TLV = + 1203, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_CP_CONSTRAINTS_TLV = + 1204, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_SEGMENT_LIST_TLV = + 1205, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_SEGMENT_SUB_TLV = + 1206, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_SEGMENT_LIST_METRIC_SUB_TLV = + 1207, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_AFFINITY_CONSTRAINT_SUB_TLV = + 1208, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_SRLG_CONSTRAINT_SUB_TLV = + 1209, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_BANDWIDTH_CONSTRAINT_SUB_TLV = + 1210, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_DISJOINT_GROUP_CONSTRAINT_SUB_TLV = + 1211, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SRV6_BSID_TLV = + 1212, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SR_POLICY_NAME_TLV = + 1213, /* draft-ietf-idr-te-lsp-distribution-17 */ + BGP_LS_TLV_SRV6_ENDPOINT_FUNCTION_TLV = + 1250, /* draft-ietf-idr-bgpls-srv6-ext-08 */ + BGP_LS_TLV_SRV6_BGP_PEER_NODE_SID_TLV = + 1251, /* draft-ietf-idr-bgpls-srv6-ext-08 */ + BGP_LS_TLV_SRV6_SID_STRUCTURE_TLV = + 1252, /* draft-ietf-idr-bgpls-srv6-ext-08 */ + BGP_LS_TLV_MAX = 1252, /* max TLV value for table size*/ +}; + +/* RFC7752 #3.2.1.4 IGP router-ID */ +enum bgp_ls_nlri_node_descr_ig_router_id_size { + BGP_LS_TLV_IGP_ROUTER_ID_ISIS_NON_PSEUDOWIRE_SIZE = 6, + BGP_LS_TLV_IGP_ROUTER_ID_ISIS_PSEUDOWIRE_SIZE = 7, + BGP_LS_TLV_IGP_ROUTER_ID_OSPF_NON_PSEUDOWIRE_SIZE = 4, + BGP_LS_TLV_IGP_ROUTER_ID_OSPF_PSEUDOWIRE_SIZE = 8, +}; + +extern int bgp_nlri_parse_linkstate(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, int withdraw); + +extern void bgp_nlri_encode_linkstate(struct stream *s, const struct prefix *p); + +extern char *bgp_linkstate_nlri_prefix_display(char *buf, size_t size, + uint16_t nlri_type, + uintptr_t prefix, uint16_t len); +extern void bgp_linkstate_nlri_prefix_json(json_object *json, + uint16_t nlri_type, uintptr_t prefix, + uint16_t len); +extern void bgp_linkstate_tlv_attribute_display(struct vty *vty, + struct bgp_attr_ls *attr_ls, + int indent, json_object *json); + +#endif /* BGP_LINKSTATE_TLV_H */ diff --git a/bgpd/bgp_linkstate_vty.c b/bgpd/bgp_linkstate_vty.c new file mode 100644 index 000000000000..3962da9c698d --- /dev/null +++ b/bgpd/bgp_linkstate_vty.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP Link-State VTY + * Copyright 2023 6WIND S.A. + */ + +#include +#include "command.h" +#include "prefix.h" +#include "lib/json.h" +#include "lib/printfrr.h" +#include "stream.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_linkstate_vty.h" +#include "bgpd/bgp_linkstate.h" +#include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_vty.h" +#include "bgpd/bgp_debug.h" + +#include "bgpd/bgp_linkstate_vty_clippy.c" + + +DEFPY (debug_bgp_linkstate, + debug_bgp_linkstate_cmd, + "[no] debug bgp linkstate", + NO_STR + DEBUG_STR + BGP_STR + "BGP allow linkstate debugging entries\n") +{ + if (vty->node == CONFIG_NODE) { + if (no) + DEBUG_OFF(linkstate, LINKSTATE); + else + DEBUG_ON(linkstate, LINKSTATE); + } else { + if (no) + TERM_DEBUG_OFF(linkstate, LINKSTATE); + else + TERM_DEBUG_ON(linkstate, LINKSTATE); + vty_out(vty, "BGP linkstate debugging is %s\n", + no ? "off" : "on"); + } + + return CMD_SUCCESS; +} + + +void bgp_linkstate_vty_init(void) +{ + install_element(ENABLE_NODE, &debug_bgp_linkstate_cmd); + install_element(CONFIG_NODE, &debug_bgp_linkstate_cmd); +} diff --git a/bgpd/bgp_linkstate_vty.h b/bgpd/bgp_linkstate_vty.h new file mode 100644 index 000000000000..5ba96b58b467 --- /dev/null +++ b/bgpd/bgp_linkstate_vty.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP Link-State VTY header + * Copyright 2023 6WIND S.A. + */ + +#ifndef _FRR_BGP_LINKSTATE_VTY_H +#define _FRR_BGP_LINKSTATE_VTY_H + +void bgp_linkstate_vty_init(void); + +#endif /* _FRR_BGP_LINKSTATE_VTY_H */ diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c index 0398e4e8c17c..e629732c78ee 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -219,7 +219,7 @@ static void bgp_mac_rescan_evpn_table(struct bgp *bgp, struct ethaddr *macaddr) if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) continue; - if (!peer_established(peer)) + if (!peer_established(peer->connection)) continue; if (bgp_debug_update(peer, NULL, NULL, 1)) diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index edaaef6021c0..5c3067f96de4 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -17,6 +17,7 @@ DEFINE_MGROUP(BGPD, "bgpd"); DEFINE_MTYPE(BGPD, BGP, "BGP instance"); DEFINE_MTYPE(BGPD, BGP_LISTENER, "BGP listen socket details"); DEFINE_MTYPE(BGPD, BGP_PEER, "BGP peer"); +DEFINE_MTYPE(BGPD, BGP_PEER_CONNECTION, "BGP peer connection"); DEFINE_MTYPE(BGPD, BGP_PEER_HOST, "BGP peer hostname"); DEFINE_MTYPE(BGPD, BGP_PEER_IFNAME, "BGP peer ifname"); DEFINE_MTYPE(BGPD, PEER_GROUP, "Peer group"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 1256eafd0093..7acb41eeb51c 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -13,6 +13,7 @@ DECLARE_MGROUP(BGPD); DECLARE_MTYPE(BGP); DECLARE_MTYPE(BGP_LISTENER); DECLARE_MTYPE(BGP_PEER); +DECLARE_MTYPE(BGP_PEER_CONNECTION); DECLARE_MTYPE(BGP_PEER_HOST); DECLARE_MTYPE(BGP_PEER_IFNAME); DECLARE_MTYPE(PEER_GROUP); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 3ecb72b4ef5d..138b182718e2 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1179,12 +1179,13 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, /* Process change. */ bgp_aggregate_increment(to_bgp, p, bpi, afi, safi); bgp_process(to_bgp, bn, afi, safi); - bgp_dest_unlock_node(bn); if (debug) zlog_debug("%s: ->%s: %pBD Found route, changed attr", __func__, to_bgp->name_pretty, bn); + bgp_dest_unlock_node(bn); + return bpi; } @@ -1238,13 +1239,14 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, bgp_aggregate_increment(to_bgp, p, new, afi, safi); bgp_path_info_add(bn, new); - bgp_dest_unlock_node(bn); bgp_process(to_bgp, bn, afi, safi); if (debug) zlog_debug("%s: ->%s: %pBD: Added new route", __func__, to_bgp->name_pretty, bn); + bgp_dest_unlock_node(bn); + return new; } @@ -3140,7 +3142,7 @@ int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd, return CMD_WARNING; } table = bgp->rib[afi][SAFI_MPLS_VPN]; - return bgp_show_table_rd(vty, bgp, SAFI_MPLS_VPN, table, prd, type, + return bgp_show_table_rd(vty, bgp, afi, SAFI_MPLS_VPN, table, prd, type, output_arg, show_flags); } @@ -4203,6 +4205,7 @@ static void show_bgp_mplsvpn_nh_label_bind_internal(struct vty *vty, struct bgp *bgp_path; struct bgp_table *table; time_t tbuf; + char buf[32]; vty_out(vty, "Current BGP mpls-vpn nexthop label bind cache, %s\n", bgp->name_pretty); @@ -4220,7 +4223,7 @@ static void show_bgp_mplsvpn_nh_label_bind_internal(struct vty *vty, ifindex2ifname(iter->nh->ifindex, iter->nh->vrf_id)); tbuf = time(NULL) - (monotime(NULL) - iter->last_update); - vty_out(vty, " Last update: %s", ctime(&tbuf)); + vty_out(vty, " Last update: %s", ctime_r(&tbuf, buf)); if (!detail) continue; vty_out(vty, " Paths:\n"); diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 62748a9e5631..19b6f4eb777e 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -245,8 +245,7 @@ static inline void vpn_leak_postchange(enum vpn_policy_direction direction, if (!CHECK_FLAG(bgp_vpn->af_flags[afi][SAFI_MPLS_VPN], BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL)) bgp_clear_soft_in(bgp_vpn, afi, SAFI_MPLS_VPN); - else - vpn_leak_to_vrf_update_all(bgp_vrf, bgp_vpn, afi); + vpn_leak_to_vrf_update_all(bgp_vrf, bgp_vpn, afi); } if (direction == BGP_VPN_POLICY_DIR_TOVPN) { diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index c5e7f7be63cd..d831c6a781ae 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -35,7 +35,7 @@ extern struct zebra_privs_t bgpd_privs; -static char *bgp_get_bound_name(struct peer *peer); +static char *bgp_get_bound_name(struct peer_connection *connection); void bgp_dump_listener_info(struct vty *vty) { @@ -117,11 +117,13 @@ static int bgp_md5_set_connect(int socket, union sockunion *su, return ret; } -static int bgp_md5_set_password(struct peer *peer, const char *password) +static int bgp_md5_set_password(struct peer_connection *connection, + const char *password) { struct listnode *node; int ret = 0; struct bgp_listener *listener; + struct peer *peer = connection->peer; /* * Set or unset the password on the listen socket(s). Outbound @@ -130,9 +132,9 @@ static int bgp_md5_set_password(struct peer *peer, const char *password) frr_with_privs(&bgpd_privs) { for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener)) if (listener->su.sa.sa_family == - peer->su.sa.sa_family) { + connection->su.sa.sa_family) { uint16_t prefixlen = - peer->su.sa.sa_family == AF_INET + connection->su.sa.sa_family == AF_INET ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN; @@ -149,8 +151,8 @@ static int bgp_md5_set_password(struct peer *peer, const char *password) continue; ret = bgp_md5_set_socket(listener->fd, - &peer->su, prefixlen, - password); + &connection->su, + prefixlen, password); break; } } @@ -186,10 +188,10 @@ int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p) return bgp_md5_set_prefix(bgp, p, NULL); } -int bgp_md5_set(struct peer *peer) +int bgp_md5_set(struct peer_connection *connection) { /* Set the password from listen socket. */ - return bgp_md5_set_password(peer, peer->password); + return bgp_md5_set_password(connection, connection->peer->password); } static void bgp_update_setsockopt_tcp_keepalive(struct bgp *bgp, int fd) @@ -211,18 +213,20 @@ static void bgp_update_setsockopt_tcp_keepalive(struct bgp *bgp, int fd) } } -int bgp_md5_unset(struct peer *peer) +int bgp_md5_unset(struct peer_connection *connection) { /* Unset the password from listen socket. */ - return bgp_md5_set_password(peer, NULL); + return bgp_md5_set_password(connection, NULL); } -int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) +int bgp_set_socket_ttl(struct peer_connection *connection) { int ret = 0; + struct peer *peer = connection->peer; if (!peer->gtsm_hops) { - ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, peer->ttl); + ret = sockopt_ttl(connection->su.sa.sa_family, connection->fd, + peer->ttl); if (ret) { flog_err( EC_LIB_SOCKET, @@ -235,7 +239,8 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) with the outgoing ttl. Therefore setting both. */ - ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, MAXTTL); + ret = sockopt_ttl(connection->su.sa.sa_family, connection->fd, + MAXTTL); if (ret) { flog_err( EC_LIB_SOCKET, @@ -243,7 +248,7 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) __func__, &peer->remote_id, errno); return ret; } - ret = sockopt_minttl(peer->su.sa.sa_family, bgp_sock, + ret = sockopt_minttl(connection->su.sa.sa_family, connection->fd, MAXTTL + 1 - peer->gtsm_hops); if (ret) { flog_err( @@ -329,6 +334,53 @@ static int bgp_get_instance_for_inc_conn(int sock, struct bgp **bgp_inst) #endif } +int bgp_tcp_mss_set(struct peer *peer) +{ + struct listnode *node; + int ret = 0; + struct bgp_listener *listener; + uint32_t min_mss = 0; + struct peer *p; + + for (ALL_LIST_ELEMENTS_RO(peer->bgp->peer, node, p)) { + if (!CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) + continue; + + if (!p->tcp_mss) + continue; + + if (!min_mss) + min_mss = p->tcp_mss; + + min_mss = MIN(min_mss, p->tcp_mss); + } + + frr_with_privs(&bgpd_privs) { + for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener)) { + if (listener->su.sa.sa_family != + peer->connection->su.sa.sa_family) + continue; + + if (!listener->bgp) { + if (peer->bgp->vrf_id != VRF_DEFAULT) + continue; + } else if (listener->bgp != peer->bgp) + continue; + + /* Set TCP MSS per listener only if there is at least + * one peer that is in passive mode. Otherwise, TCP MSS + * is set per socket via bgp_connect(). + */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) + sockopt_tcp_mss_set(listener->fd, min_mss); + + break; + } + } + + return ret; +} + static void bgp_socket_set_buffer_size(const int fd) { if (getsockopt_so_sendbuf(fd) < (int)bm->socket_buffer) @@ -344,8 +396,8 @@ static void bgp_accept(struct event *thread) int accept_sock; union sockunion su; struct bgp_listener *listener = EVENT_ARG(thread); - struct peer *peer; - struct peer *peer1; + struct peer *peer, *peer1; + struct peer_connection *connection, *connection1; char buf[SU_ADDRSTRLEN]; struct bgp *bgp = NULL; @@ -428,25 +480,24 @@ static void bgp_accept(struct event *thread) if (!peer1) { peer1 = peer_lookup_dynamic_neighbor(bgp, &su); if (peer1) { + connection1 = peer1->connection; /* Dynamic neighbor has been created, let it proceed */ - peer1->connection->fd = bgp_sock; + connection1->fd = bgp_sock; /* Set the user configured MSS to TCP socket */ if (CHECK_FLAG(peer1->flags, PEER_FLAG_TCP_MSS)) sockopt_tcp_mss_set(bgp_sock, peer1->tcp_mss); - bgp_fsm_change_status(peer1, Active); - EVENT_OFF( - peer1->t_start); /* created in peer_create() */ + bgp_fsm_change_status(connection1, Active); + EVENT_OFF(connection1->t_start); if (peer_active(peer1)) { if (CHECK_FLAG(peer1->flags, PEER_FLAG_TIMER_DELAYOPEN)) - BGP_EVENT_ADD( - peer1, - TCP_connection_open_w_delay); + BGP_EVENT_ADD(connection1, + TCP_connection_open_w_delay); else - BGP_EVENT_ADD(peer1, + BGP_EVENT_ADD(connection1, TCP_connection_open); } @@ -465,6 +516,7 @@ static void bgp_accept(struct event *thread) return; } + connection1 = peer1->connection; if (CHECK_FLAG(peer1->flags, PEER_FLAG_SHUTDOWN) || CHECK_FLAG(peer1->bgp->flags, BGP_FLAG_SHUTDOWN)) { if (bgp_debug_neighbor_events(peer1)) @@ -482,8 +534,7 @@ static void bgp_accept(struct event *thread) * Established and then the Clearing_Completed event is generated. Also, * block incoming connection in Deleted state. */ - if (peer1->connection->status == Clearing || - peer1->connection->status == Deleted) { + if (connection1->status == Clearing || connection1->status == Deleted) { if (bgp_debug_neighbor_events(peer1)) zlog_debug("[Event] Closing incoming conn for %s (%p) state %d", peer1->host, peer1, @@ -523,8 +574,8 @@ static void bgp_accept(struct event *thread) if (bgp_debug_neighbor_events(peer1)) zlog_debug("[Event] connection from %s fd %d, active peer status %d fd %d", - inet_sutop(&su, buf), bgp_sock, - peer1->connection->status, peer1->connection->fd); + inet_sutop(&su, buf), bgp_sock, connection1->status, + connection1->fd); if (peer1->doppelganger) { /* We have an existing connection. Kill the existing one and run @@ -537,15 +588,11 @@ static void bgp_accept(struct event *thread) peer_delete(peer1->doppelganger); } - if (bgp_set_socket_ttl(peer1, bgp_sock) < 0) - if (bgp_debug_neighbor_events(peer1)) - zlog_debug( - "[Event] Unable to set min/max TTL on peer %s, Continuing", - peer1->host); - peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as, peer1->as, peer1->as_type, NULL, false, NULL); + connection = peer->connection; + peer_xfer_config(peer, peer1); bgp_peer_gr_flags_update(peer); @@ -563,18 +610,25 @@ static void bgp_accept(struct event *thread) peer->doppelganger = peer1; peer1->doppelganger = peer; - peer->connection->fd = bgp_sock; + connection->fd = bgp_sock; + + if (bgp_set_socket_ttl(connection) < 0) + if (bgp_debug_neighbor_events(peer)) + zlog_debug("[Event] Unable to set min/max TTL on peer %s, Continuing", + peer->host); + frr_with_privs(&bgpd_privs) { - vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer)); + vrf_bind(peer->bgp->vrf_id, bgp_sock, + bgp_get_bound_name(peer->connection)); } bgp_peer_reg_with_nht(peer); - bgp_fsm_change_status(peer, Active); - EVENT_OFF(peer->t_start); /* created in peer_create() */ + bgp_fsm_change_status(connection, Active); + EVENT_OFF(connection->t_start); /* created in peer_create() */ SET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER); /* Make dummy peer until read Open packet. */ - if (peer_established(peer1) - && CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) { + if (peer_established(connection1) && + CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) { /* If we have an existing established connection with graceful * restart * capability announced with one or more address families, then @@ -588,14 +642,14 @@ static void bgp_accept(struct event *thread) PEER_FLAG_GRACEFUL_RESTART_HELPER)) SET_FLAG(peer1->sflags, PEER_STATUS_NSF_WAIT); - bgp_event_update(peer1, TCP_connection_closed); + bgp_event_update(connection1, TCP_connection_closed); } if (peer_active(peer)) { if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN)) - BGP_EVENT_ADD(peer, TCP_connection_open_w_delay); + BGP_EVENT_ADD(connection, TCP_connection_open_w_delay); else - BGP_EVENT_ADD(peer, TCP_connection_open); + BGP_EVENT_ADD(connection, TCP_connection_open); } /* @@ -606,24 +660,23 @@ static void bgp_accept(struct event *thread) } /* BGP socket bind. */ -static char *bgp_get_bound_name(struct peer *peer) +static char *bgp_get_bound_name(struct peer_connection *connection) { - if (!peer) - return NULL; + struct peer *peer = connection->peer; if ((peer->bgp->vrf_id == VRF_DEFAULT) && !peer->ifname && !peer->conf_if) return NULL; - if (peer->su.sa.sa_family != AF_INET - && peer->su.sa.sa_family != AF_INET6) + if (connection->su.sa.sa_family != AF_INET && + connection->su.sa.sa_family != AF_INET6) return NULL; // unexpected /* For IPv6 peering, interface (unnumbered or link-local with interface) * takes precedence over VRF. For IPv4 peering, explicit interface or * VRF are the situations to bind. */ - if (peer->su.sa.sa_family == AF_INET6 && peer->conf_if) + if (connection->su.sa.sa_family == AF_INET6 && peer->conf_if) return peer->conf_if; if (peer->ifname) @@ -667,11 +720,12 @@ int bgp_update_address(struct interface *ifp, const union sockunion *dst, } /* Update source selection. */ -static int bgp_update_source(struct peer *peer) +static int bgp_update_source(struct peer_connection *connection) { struct interface *ifp; union sockunion addr; int ret = 0; + struct peer *peer = connection->peer; sockunion_init(&addr); @@ -681,41 +735,41 @@ static int bgp_update_source(struct peer *peer) if (!ifp) return -1; - if (bgp_update_address(ifp, &peer->su, &addr)) + if (bgp_update_address(ifp, &connection->su, &addr)) return -1; - ret = sockunion_bind(peer->connection->fd, &addr, 0, &addr); + ret = sockunion_bind(connection->fd, &addr, 0, &addr); } /* Source is specified with IP address. */ if (peer->update_source) - ret = sockunion_bind(peer->connection->fd, peer->update_source, - 0, peer->update_source); + ret = sockunion_bind(connection->fd, peer->update_source, 0, + peer->update_source); return ret; } /* BGP try to connect to the peer. */ -int bgp_connect(struct peer *peer) +int bgp_connect(struct peer_connection *connection) { - assert(!CHECK_FLAG(peer->connection->thread_flags, - PEER_THREAD_WRITES_ON)); - assert(!CHECK_FLAG(peer->connection->thread_flags, - PEER_THREAD_READS_ON)); + struct peer *peer = connection->peer; + + assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_WRITES_ON)); + assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_READS_ON)); ifindex_t ifindex = 0; - if (peer->conf_if && BGP_PEER_SU_UNSPEC(peer)) { + if (peer->conf_if && BGP_CONNECTION_SU_UNSPEC(connection)) { if (bgp_debug_neighbor_events(peer)) zlog_debug("Peer address not learnt: Returning from connect"); return 0; } frr_with_privs(&bgpd_privs) { /* Make socket for the peer. */ - peer->connection->fd = - vrf_sockunion_socket(&peer->su, peer->bgp->vrf_id, - bgp_get_bound_name(peer)); + connection->fd = + vrf_sockunion_socket(&connection->su, peer->bgp->vrf_id, + bgp_get_bound_name(connection)); } - if (peer->connection->fd < 0) { + if (connection->fd < 0) { peer->last_reset = PEER_DOWN_SOCKET_ERROR; if (bgp_debug_neighbor_events(peer)) zlog_debug("%s: Failure to create socket for connection to %s, error received: %s(%d)", @@ -724,18 +778,18 @@ int bgp_connect(struct peer *peer) return -1; } - set_nonblocking(peer->connection->fd); + set_nonblocking(connection->fd); /* Set the user configured MSS to TCP socket */ if (CHECK_FLAG(peer->flags, PEER_FLAG_TCP_MSS)) - sockopt_tcp_mss_set(peer->connection->fd, peer->tcp_mss); + sockopt_tcp_mss_set(connection->fd, peer->tcp_mss); - bgp_socket_set_buffer_size(peer->connection->fd); + bgp_socket_set_buffer_size(connection->fd); /* Set TCP keepalive when TCP keepalive is enabled */ - bgp_update_setsockopt_tcp_keepalive(peer->bgp, peer->connection->fd); + bgp_update_setsockopt_tcp_keepalive(peer->bgp, connection->fd); - if (bgp_set_socket_ttl(peer, peer->connection->fd) < 0) { + if (bgp_set_socket_ttl(peer->connection) < 0) { peer->last_reset = PEER_DOWN_SOCKET_ERROR; if (bgp_debug_neighbor_events(peer)) zlog_debug("%s: Failure to set socket ttl for connection to %s, error received: %s(%d)", @@ -745,37 +799,42 @@ int bgp_connect(struct peer *peer) return -1; } - sockopt_reuseaddr(peer->connection->fd); - sockopt_reuseport(peer->connection->fd); + sockopt_reuseaddr(connection->fd); + sockopt_reuseport(connection->fd); #ifdef IPTOS_PREC_INTERNETCONTROL frr_with_privs(&bgpd_privs) { - if (sockunion_family(&peer->su) == AF_INET) - setsockopt_ipv4_tos(peer->connection->fd, bm->tcp_dscp); - else if (sockunion_family(&peer->su) == AF_INET6) - setsockopt_ipv6_tclass(peer->connection->fd, - bm->tcp_dscp); + if (sockunion_family(&connection->su) == AF_INET) + setsockopt_ipv4_tos(connection->fd, bm->tcp_dscp); + else if (sockunion_family(&connection->su) == AF_INET6) + setsockopt_ipv6_tclass(connection->fd, bm->tcp_dscp); } #endif if (peer->password) { - uint16_t prefixlen = peer->su.sa.sa_family == AF_INET + uint16_t prefixlen = peer->connection->su.sa.sa_family == AF_INET ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN; - if (!BGP_PEER_SU_UNSPEC(peer)) - bgp_md5_set(peer); + if (!BGP_CONNECTION_SU_UNSPEC(connection)) + bgp_md5_set(connection); - bgp_md5_set_connect(peer->connection->fd, &peer->su, prefixlen, + bgp_md5_set_connect(connection->fd, &connection->su, prefixlen, peer->password); } /* Update source bind. */ - if (bgp_update_source(peer) < 0) { + if (bgp_update_source(connection) < 0) { peer->last_reset = PEER_DOWN_SOCKET_ERROR; return connect_error; } + /* If the peer is passive mode, force to move to Active mode. */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) { + BGP_EVENT_ADD(connection, TCP_connection_open_failed); + return BGP_FSM_SUCCESS; + } + if (peer->conf_if || peer->ifname) ifindex = ifname2ifindex(peer->conf_if ? peer->conf_if : peer->ifname, @@ -783,10 +842,10 @@ int bgp_connect(struct peer *peer) if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [Event] Connect start to %s fd %d", peer->host, - peer->host, peer->connection->fd); + peer->host, connection->fd); /* Connect to the remote peer. */ - return sockunion_connect(peer->connection->fd, &peer->su, + return sockunion_connect(connection->fd, &connection->su, htons(peer->port), ifindex); } diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h index cf0b4362c533..7a0b3cc67d7e 100644 --- a/bgpd/bgp_network.h +++ b/bgpd/bgp_network.h @@ -21,15 +21,16 @@ extern int bgp_socket(struct bgp *bgp, unsigned short port, const char *address); extern void bgp_close_vrf_socket(struct bgp *bgp); extern void bgp_close(void); -extern int bgp_connect(struct peer *); -extern int bgp_getsockname(struct peer *); +extern int bgp_connect(struct peer_connection *connection); +extern int bgp_getsockname(struct peer *peer); extern int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p, const char *password); extern int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p); -extern int bgp_md5_set(struct peer *); -extern int bgp_md5_unset(struct peer *); -extern int bgp_set_socket_ttl(struct peer *, int fd); +extern int bgp_md5_set(struct peer_connection *connection); +extern int bgp_md5_unset(struct peer_connection *connection); +extern int bgp_set_socket_ttl(struct peer_connection *connection); +extern int bgp_tcp_mss_set(struct peer *peer); extern int bgp_update_address(struct interface *ifp, const union sockunion *dst, union sockunion *addr); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 6cb6d65c64b5..d12dc2233013 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -385,6 +385,7 @@ void bgp_connected_add(struct bgp *bgp, struct connected *ifc) struct bgp_connected_ref *bc; struct listnode *node, *nnode; struct peer *peer; + struct peer_connection *connection; addr = ifc->address; @@ -409,14 +410,14 @@ void bgp_connected_add(struct bgp *bgp, struct connected *ifc) } for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (peer->conf_if - && (strcmp(peer->conf_if, ifc->ifp->name) == 0) - && !peer_established(peer) - && !CHECK_FLAG(peer->flags, - PEER_FLAG_IFPEER_V6ONLY)) { + if (peer->conf_if && + (strcmp(peer->conf_if, ifc->ifp->name) == 0) && + !peer_established(peer->connection) && + !CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) { + connection = peer->connection; if (peer_active(peer)) - BGP_EVENT_ADD(peer, BGP_Stop); - BGP_EVENT_ADD(peer, BGP_Start); + BGP_EVENT_ADD(connection, BGP_Stop); + BGP_EVENT_ADD(connection, BGP_Start); } } } else if (addr->family == AF_INET6) { @@ -483,7 +484,9 @@ void bgp_connected_delete(struct bgp *bgp, struct connected *ifc) XFREE(MTYPE_BGP_CONN, bc); bgp_dest_set_bgp_connected_ref_info(dest, NULL); } - bgp_dest_unlock_node(dest); + + dest = bgp_dest_unlock_node(dest); + assert(dest); bgp_dest_unlock_node(dest); } @@ -594,7 +597,7 @@ bool bgp_multiaccess_check_v4(struct in_addr nexthop, struct peer *peer) p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; - p.u.prefix4 = peer->su.sin.sin_addr; + p.u.prefix4 = peer->connection->su.sin.sin_addr; dest2 = bgp_node_match(peer->bgp->connected_table[AFI_IP], &p); if (!dest2) { @@ -627,7 +630,7 @@ bool bgp_multiaccess_check_v6(struct in6_addr nexthop, struct peer *peer) p.family = AF_INET6; p.prefixlen = IPV6_MAX_BITLEN; - p.u.prefix6 = peer->su.sin6.sin6_addr; + p.u.prefix6 = peer->connection->su.sin6.sin6_addr; dest2 = bgp_node_match(peer->bgp->connected_table[AFI_IP6], &p); if (!dest2) { @@ -669,7 +672,7 @@ bool bgp_subgrp_multiaccess_check_v6(struct in6_addr nexthop, if (paf->peer == exclude) continue; - p.u.prefix6 = paf->peer->su.sin6.sin6_addr; + p.u.prefix6 = paf->peer->connection->su.sin6.sin6_addr; dest2 = bgp_node_match(bgp->connected_table[AFI_IP6], &p); if (dest1 == dest2) { bgp_dest_unlock_node(dest1); @@ -711,7 +714,7 @@ bool bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop, if (paf->peer == exclude) continue; - p.u.prefix4 = paf->peer->su.sin.sin_addr; + p.u.prefix4 = paf->peer->connection->su.sin.sin_addr; dest2 = bgp_node_match(bgp->connected_table[AFI_IP], &p); if (dest1 == dest2) { @@ -969,6 +972,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, { char buf[PREFIX2STR_BUFFER]; time_t tbuf; + char timebuf[32]; struct peer *peer; json_object *json_last_update = NULL; json_object *json_nexthop = NULL; @@ -1067,14 +1071,14 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, json_last_update = json_object_new_object(); json_object_int_add(json_last_update, "epoch", tbuf); json_object_string_add(json_last_update, "string", - ctime(&tbuf)); + ctime_r(&tbuf, timebuf)); json_object_object_add(json_nexthop, "lastUpdate", json_last_update); } else { json_object_int_add(json_nexthop, "lastUpdate", tbuf); } } else { - vty_out(vty, " Last update: %s", ctime(&tbuf)); + vty_out(vty, " Last update: %s", ctime_r(&tbuf, timebuf)); } /* show paths dependent on nexthop, if needed. */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 733dcc72a2d5..60d6f74e1478 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -173,20 +173,21 @@ void bgp_replace_nexthop_by_peer(struct peer *from, struct peer *to) afi_t afi; ifindex_t ifindex = 0; - if (!sockunion2hostprefix(&from->su, &pp)) + if (!sockunion2hostprefix(&from->connection->su, &pp)) return; /* * Gather the ifindex for if up/down events to be * tagged into this fun */ - if (from->conf_if && IN6_IS_ADDR_LINKLOCAL(&from->su.sin6.sin6_addr)) - ifindex = from->su.sin6.sin6_scope_id; + if (from->conf_if && + IN6_IS_ADDR_LINKLOCAL(&from->connection->su.sin6.sin6_addr)) + ifindex = from->connection->su.sin6.sin6_scope_id; afi = family2afi(pp.family); bncp = bnc_find(&from->bgp->nexthop_cache_table[afi], &pp, 0, ifindex); - if (!sockunion2hostprefix(&to->su, &pt)) + if (!sockunion2hostprefix(&to->connection->su, &pt)) return; /* @@ -194,8 +195,9 @@ void bgp_replace_nexthop_by_peer(struct peer *from, struct peer *to) * tagged into this fun */ ifindex = 0; - if (to->conf_if && IN6_IS_ADDR_LINKLOCAL(&to->su.sin6.sin6_addr)) - ifindex = to->su.sin6.sin6_scope_id; + if (to->conf_if && + IN6_IS_ADDR_LINKLOCAL(&to->connection->su.sin6.sin6_addr)) + ifindex = to->connection->su.sin6.sin6_scope_id; bnct = bnc_find(&to->bgp->nexthop_cache_table[afi], &pt, 0, ifindex); if (bnct != bncp) @@ -240,10 +242,10 @@ void bgp_unlink_nexthop_by_peer(struct peer *peer) { struct prefix p; struct bgp_nexthop_cache *bnc; - afi_t afi = family2afi(peer->su.sa.sa_family); + afi_t afi = family2afi(peer->connection->su.sa.sa_family); ifindex_t ifindex = 0; - if (!sockunion2hostprefix(&peer->su, &p)) { + if (!sockunion2hostprefix(&peer->connection->su, &p)) { /* * In scenarios where unnumbered BGP session is brought * down by shutting down the interface before unconfiguring @@ -261,8 +263,8 @@ void bgp_unlink_nexthop_by_peer(struct peer *peer) * tagged into this fun */ if (afi == AFI_IP6 && - IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) - ifindex = peer->su.sin6.sin6_scope_id; + IN6_IS_ADDR_LINKLOCAL(&peer->connection->su.sin6.sin6_addr)) + ifindex = peer->connection->su.sin6.sin6_scope_id; bnc = bnc_find(&peer->bgp->nexthop_cache_table[afi], &p, 0, ifindex); } @@ -317,12 +319,21 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, return 1; /* - * If path is learnt from an interface based peer, + * If it's a V6 nexthop, path is learnt from a v6 LL peer, + * and if the NH prefix matches peer's LL address then * set the ifindex to peer's interface index so that * correct nexthop can be found in nexthop tree. + * + * NH could be set to different v6 LL address (compared to + * peer's LL) using route-map. In such a scenario, do not set + * the ifindex. */ - if (pi->peer->conf_if) - ifindex = pi->peer->su.sin6.sin6_scope_id; + if (afi == AFI_IP6 && + IN6_IS_ADDR_LINKLOCAL( + &pi->peer->connection->su.sin6.sin6_addr) && + IPV6_ADDR_SAME(&pi->peer->connection->su.sin6.sin6_addr, + &p.u.prefix6)) + ifindex = pi->peer->connection->su.sin6.sin6_scope_id; if (!is_bgp_static_route && orig_prefix && prefix_same(&p, orig_prefix)) { @@ -344,8 +355,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, * tagged into this fun */ if (afi == AFI_IP6 && peer->conf_if && - IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) { - ifindex = peer->su.sin6.sin6_scope_id; + IN6_IS_ADDR_LINKLOCAL(&peer->connection->su.sin6.sin6_addr)) { + ifindex = peer->connection->su.sin6.sin6_scope_id; if (ifindex == 0) { if (BGP_DEBUG(nht, NHT)) { zlog_debug( @@ -356,7 +367,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, } } - if (!sockunion2hostprefix(&peer->su, &p)) { + if (!sockunion2hostprefix(&peer->connection->su, &p)) { if (BGP_DEBUG(nht, NHT)) { zlog_debug( "%s: Attempting to register with unknown AFI %d (not %d or %d)", @@ -512,14 +523,15 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer) * nodes of V6 nexthop cache to find the bnc, it is * currently not being called here. */ - if (!sockunion2hostprefix(&peer->su, &p)) + if (!sockunion2hostprefix(&peer->connection->su, &p)) return; /* * Gather the ifindex for if up/down events to be * tagged into this fun */ - if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) - ifindex = peer->su.sin6.sin6_scope_id; + if (afi == AFI_IP6 && + IN6_IS_ADDR_LINKLOCAL(&peer->connection->su.sin6.sin6_addr)) + ifindex = peer->connection->su.sin6.sin6_scope_id; bnc = bnc_find(&peer->bgp->nexthop_cache_table[family2afi(p.family)], &p, 0, ifindex); if (!bnc) { @@ -862,17 +874,18 @@ void bgp_nht_interface_events(struct peer *peer) struct prefix p; ifindex_t ifindex = 0; - if (!IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) + if (!IN6_IS_ADDR_LINKLOCAL(&peer->connection->su.sin6.sin6_addr)) return; - if (!sockunion2hostprefix(&peer->su, &p)) + if (!sockunion2hostprefix(&peer->connection->su, &p)) return; /* * Gather the ifindex for if up/down events to be * tagged into this fun */ - if (peer->conf_if && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) - ifindex = peer->su.sin6.sin6_scope_id; + if (peer->conf_if && + IN6_IS_ADDR_LINKLOCAL(&peer->connection->su.sin6.sin6_addr)) + ifindex = peer->connection->su.sin6.sin6_scope_id; table = &bgp->nexthop_cache_table[AFI_IP6]; bnc = bnc_find(table, &p, 0, ifindex); @@ -1400,7 +1413,8 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc) __func__, peer->host, peer->bgp->name_pretty, !!valid_nexthops); - bgp_fsm_nht_update(peer, !!valid_nexthops); + bgp_fsm_nht_update(peer->connection, peer, + !!valid_nexthops); SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); } } @@ -1461,7 +1475,7 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer) return; bgp = peer->bgp; - if (!sockunion2hostprefix(&peer->su, &p)) { + if (!sockunion2hostprefix(&peer->connection->su, &p)) { zlog_warn("%s: Unable to convert sockunion to prefix for %s", __func__, peer->host); return; @@ -1473,8 +1487,9 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer) * Gather the ifindex for if up/down events to be * tagged into this fun */ - if (peer->conf_if && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) - ifindex = peer->su.sin6.sin6_scope_id; + if (peer->conf_if && + IN6_IS_ADDR_LINKLOCAL(&peer->connection->su.sin6.sin6_addr)) + ifindex = peer->connection->su.sin6.sin6_scope_id; bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0, ifindex); if (!bnc) @@ -1510,7 +1525,7 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer) bgp = peer->bgp; - if (!sockunion2hostprefix(&peer->su, &p)) { + if (!sockunion2hostprefix(&peer->connection->su, &p)) { zlog_warn("%s: Unable to convert sockunion to prefix for %s", __func__, peer->host); return; @@ -1522,8 +1537,9 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer) * Gather the ifindex for if up/down events to be * tagged into this fun */ - if (peer->conf_if && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) - ifindex = peer->su.sin6.sin6_scope_id; + if (peer->conf_if && + IN6_IS_ADDR_LINKLOCAL(&peer->connection->su.sin6.sin6_addr)) + ifindex = peer->connection->su.sin6.sin6_scope_id; bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0, ifindex); if (!bnc) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index c7c91da74d2f..8a202b480ae3 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -147,6 +147,12 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, "capabilityErrorMultiProtocolAfi", "L2VPN"); break; + case AFI_LINKSTATE: + json_object_string_add( + json_cap, + "capabilityErrorMultiProtocolAfi", + "Link State"); + break; case AFI_UNSPEC: case AFI_MAX: json_object_int_add( @@ -198,6 +204,18 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, "capabilityErrorMultiProtocolSafi", "flowspec"); break; + case SAFI_LINKSTATE: + json_object_string_add( + json_cap, + "capabilityErrorMultiProtocolSafi", + "Link State"); + break; + case SAFI_LINKSTATE_VPN: + json_object_string_add( + json_cap, + "capabilityErrorMultiProtocolSafi", + "Link State VPN"); + break; case SAFI_UNSPEC: case SAFI_MAX: json_object_int_add( @@ -219,6 +237,9 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, case AFI_L2VPN: vty_out(vty, "AFI L2VPN, "); break; + case AFI_LINKSTATE: + vty_out(vty, "AFI Link State, "); + break; case AFI_UNSPEC: case AFI_MAX: vty_out(vty, "AFI Unknown %d, ", @@ -247,6 +268,12 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, case SAFI_EVPN: vty_out(vty, "SAFI EVPN"); break; + case SAFI_LINKSTATE: + vty_out(vty, "SAFI LINK STATE"); + break; + case SAFI_LINKSTATE_VPN: + vty_out(vty, "SAFI LINK STATE VPN"); + break; case SAFI_UNSPEC: case SAFI_MAX: vty_out(vty, "SAFI Unknown %d ", @@ -392,7 +419,7 @@ static int bgp_capability_orf_entry(struct peer *peer, zlog_info( "%s ORF Capability entry length error, Cap length %u, num %u", peer->host, hdr->length, num); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } @@ -576,18 +603,6 @@ static int bgp_capability_restart(struct peer *peer, static int bgp_capability_llgr(struct peer *peer, struct capability_header *caphdr) { -/* - * +--------------------------------------------------+ - * | Address Family Identifier (16 bits) | - * +--------------------------------------------------+ - * | Subsequent Address Family Identifier (8 bits) | - * +--------------------------------------------------+ - * | Flags for Address Family (8 bits) | - * +--------------------------------------------------+ - * | Long-lived Stale Time (24 bits) | - * +--------------------------------------------------+ - */ -#define BGP_CAP_LLGR_MIN_PACKET_LEN 7 struct stream *s = BGP_INPUT(peer); size_t end = stream_get_getp(s) + caphdr->length; @@ -965,7 +980,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length, if (stream_get_getp(s) + 2 > end) { zlog_info("%s Capability length error (< header)", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } @@ -978,7 +993,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length, if (start + caphdr.length > end) { zlog_info("%s Capability length error (< length)", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } @@ -1013,7 +1028,8 @@ static int bgp_capability_parse(struct peer *peer, size_t length, NULL), caphdr.length, (unsigned)cap_minsizes[caphdr.code]); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } @@ -1026,7 +1042,8 @@ static int bgp_capability_parse(struct peer *peer, size_t length, NULL), caphdr.length, (unsigned)cap_modsizes[caphdr.code]); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } @@ -1122,7 +1139,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length, } if (ret < 0) { - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } @@ -1170,7 +1187,7 @@ static bool bgp_role_violation(struct peer *peer) (local_role == ROLE_RS_SERVER && remote_role == ROLE_RS_CLIENT) || (local_role == ROLE_RS_CLIENT && remote_role == ROLE_RS_SERVER))) { - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_ROLE_MISMATCH); return true; } @@ -1178,7 +1195,7 @@ static bool bgp_role_violation(struct peer *peer) CHECK_FLAG(peer->flags, PEER_FLAG_ROLE_STRICT_MODE)) { const char *err_msg = "Strict mode. Please set the role on your side."; - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_ROLE_MISMATCH, (uint8_t *)err_msg, strlen(err_msg)); return true; @@ -1306,7 +1323,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, */ if (STREAM_READABLE(s) < 1) { zlog_info("%s Option length error", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } @@ -1319,7 +1336,8 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)) { if (STREAM_READABLE(s) < 2) { zlog_info("%s Option length error", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } @@ -1328,7 +1346,8 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, } else { if (STREAM_READABLE(s) < 1) { zlog_info("%s Option length error", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } @@ -1340,7 +1359,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, if (STREAM_READABLE(s) < opt_length) { zlog_info("%s Option length error (%d)", peer->host, opt_length); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } @@ -1359,7 +1378,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, mp_capability, &error); break; default: - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_PARAM); ret = -1; break; @@ -1378,7 +1397,8 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, if (CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) { /* If Unsupported Capability exists. */ if (error != error_data) { - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(peer->connection, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL, error_data, error - error_data); @@ -1388,7 +1408,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, /* Check local capability does not negotiated with remote peer. */ if (!strict_capability_same(peer)) { - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL); return -1; } @@ -1421,18 +1441,21 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, && !peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] && !peer->afc_nego[AFI_IP6][SAFI_ENCAP] && !peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] - && !peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) { + && !peer->afc_nego[AFI_L2VPN][SAFI_EVPN] + && !peer->afc_nego[AFI_LINKSTATE][SAFI_LINKSTATE]) { flog_err(EC_BGP_PKT_OPEN, "%s [Error] Configured AFI/SAFIs do not overlap with received MP capabilities", peer->host); if (error != error_data) - bgp_notify_send_with_data( - peer, BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_CAPBL, error_data, - error - error_data); + bgp_notify_send_with_data(peer->connection, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSUP_CAPBL, + error_data, + error - error_data); else - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(peer->connection, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL); return -1; } @@ -1705,11 +1728,11 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, * supporting RFC-5549 for * Link-Local peering only */ - if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE) - && peer->su.sa.sa_family == AF_INET6 - && afi == AFI_IP - && (safi == SAFI_UNICAST || safi == SAFI_MPLS_VPN - || safi == SAFI_LABELED_UNICAST)) { + if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE) && + peer->connection->su.sa.sa_family == AF_INET6 && + afi == AFI_IP && + (safi == SAFI_UNICAST || safi == SAFI_MPLS_VPN || + safi == SAFI_LABELED_UNICAST)) { /* RFC 5549 Extended Next Hop Encoding */ SET_FLAG(peer->cap, PEER_CAP_ENHE_ADV); diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 20f5fdb22bdf..a92c56d1b508 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -20,11 +20,24 @@ struct capability_mp_data { }; struct graceful_restart_af { - afi_t afi; - safi_t safi; + uint16_t afi; + uint8_t safi; uint8_t flag; }; +/* + * +--------------------------------------------------+ + * | Address Family Identifier (16 bits) | + * +--------------------------------------------------+ + * | Subsequent Address Family Identifier (8 bits) | + * +--------------------------------------------------+ + * | Flags for Address Family (8 bits) | + * +--------------------------------------------------+ + * | Long-lived Stale Time (24 bits) | + * +--------------------------------------------------+ + */ +#define BGP_CAP_LLGR_MIN_PACKET_LEN 7 + /* Capability Code */ #define CAPABILITY_CODE_MP 1 /* Multiprotocol Extensions */ #define CAPABILITY_CODE_REFRESH 2 /* Route Refresh Capability */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 74291383dadc..5d7441ed6dde 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -48,6 +48,7 @@ #include "bgpd/bgp_io.h" #include "bgpd/bgp_keepalives.h" #include "bgpd/bgp_flowspec.h" +#include "bgpd/bgp_linkstate_tlv.h" #include "bgpd/bgp_trace.h" DEFINE_HOOK(bgp_packet_dump, @@ -105,21 +106,22 @@ void bgp_packet_set_size(struct stream *s) * Push a packet onto the beginning of the peer's output queue. * This function acquires the peer's write mutex before proceeding. */ -static void bgp_packet_add(struct peer *peer, struct stream *s) +static void bgp_packet_add(struct peer_connection *connection, + struct peer *peer, struct stream *s) { intmax_t delta; uint32_t holdtime; intmax_t sendholdtime; - frr_with_mutex (&peer->connection->io_mtx) { + frr_with_mutex (&connection->io_mtx) { /* if the queue is empty, reset the "last OK" timestamp to * now, otherwise if we write another packet immediately * after it'll get confused */ - if (!stream_fifo_count_safe(peer->connection->obuf)) + if (!stream_fifo_count_safe(connection->obuf)) peer->last_sendq_ok = monotime(NULL); - stream_fifo_push(peer->connection->obuf, s); + stream_fifo_push(connection->obuf, s); delta = monotime(NULL) - peer->last_sendq_ok; @@ -146,7 +148,7 @@ static void bgp_packet_add(struct peer *peer, struct stream *s) EC_BGP_SENDQ_STUCK_PROPER, "%pBP has not made any SendQ progress for 2 holdtimes (%jds), terminating session", peer, sendholdtime); - BGP_EVENT_ADD(peer, TCP_fatal_error); + BGP_EVENT_ADD(connection, TCP_fatal_error); } else if (delta > (intmax_t)holdtime && monotime(NULL) - peer->last_sendq_warn > 5) { flog_warn( @@ -260,7 +262,7 @@ void bgp_update_restarted_peers(struct peer *peer) if (bgp_debug_neighbor_events(peer)) zlog_debug("Peer %s: Checking restarted", peer->host); - if (peer_established(peer)) { + if (peer_established(peer->connection)) { peer->update_delay_over = 1; peer->bgp->restarted_peers++; bgp_check_update_delay(peer->bgp); @@ -283,7 +285,7 @@ void bgp_update_implicit_eors(struct peer *peer) if (bgp_debug_neighbor_events(peer)) zlog_debug("Peer %s: Checking implicit EORs", peer->host); - if (peer_established(peer)) { + if (peer_established(peer->connection)) { peer->update_delay_over = 1; peer->bgp->implicit_eors++; bgp_check_update_delay(peer->bgp); @@ -348,7 +350,11 @@ int bgp_nlri_parse(struct peer *peer, struct attr *attr, return bgp_nlri_parse_evpn(peer, attr, packet, mp_withdraw); case SAFI_FLOWSPEC: return bgp_nlri_parse_flowspec(peer, attr, packet, mp_withdraw); + case SAFI_LINKSTATE: + return bgp_nlri_parse_linkstate(peer, attr, packet, + mp_withdraw); } + return BGP_NLRI_PARSE_ERROR; } @@ -391,6 +397,7 @@ static void bgp_write_proceed_actions(struct peer *peer) struct bpacket *next_pkt; struct update_subgroup *subgrp; enum bgp_af_index index; + struct peer_connection *connection = peer->connection; for (index = BGP_AF_START; index < BGP_AF_MAX; index++) { paf = peer->peer_af_array[index]; @@ -403,7 +410,7 @@ static void bgp_write_proceed_actions(struct peer *peer) next_pkt = paf->next_pkt_to_send; if (next_pkt && next_pkt->buffer) { - BGP_TIMER_ON(peer->t_generate_updgrp_packets, + BGP_TIMER_ON(connection->t_generate_updgrp_packets, bgp_generate_updgrp_packets, 0); return; } @@ -414,7 +421,7 @@ static void bgp_write_proceed_actions(struct peer *peer) if (bpacket_queue_is_full(SUBGRP_INST(subgrp), SUBGRP_PKTQ(subgrp)) || subgroup_packets_to_build(subgrp)) { - BGP_TIMER_ON(peer->t_generate_updgrp_packets, + BGP_TIMER_ON(connection->t_generate_updgrp_packets, bgp_generate_updgrp_packets, 0); return; } @@ -429,7 +436,7 @@ static void bgp_write_proceed_actions(struct peer *peer) && !CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND) && safi != SAFI_MPLS_VPN) { - BGP_TIMER_ON(peer->t_generate_updgrp_packets, + BGP_TIMER_ON(connection->t_generate_updgrp_packets, bgp_generate_updgrp_packets, 0); return; } @@ -444,8 +451,8 @@ static void bgp_write_proceed_actions(struct peer *peer) */ void bgp_generate_updgrp_packets(struct event *thread) { - struct peer *peer = EVENT_ARG(thread); - + struct peer_connection *connection = EVENT_ARG(thread); + struct peer *peer = connection->peer; struct stream *s; struct peer_af *paf; struct bpacket *next_pkt; @@ -462,14 +469,14 @@ void bgp_generate_updgrp_packets(struct event *thread) * if peer is Established and updates are not on hold (as part of * update-delay processing). */ - if (!peer_established(peer)) + if (!peer_established(peer->connection)) return; if ((peer->bgp->main_peers_update_hold) || bgp_update_delay_active(peer->bgp)) return; - if (peer->t_routeadv) + if (peer->connection->t_routeadv) return; /* @@ -477,7 +484,7 @@ void bgp_generate_updgrp_packets(struct event *thread) * let's stop adding to the outq if we are * already at the limit. */ - if (peer->connection->obuf->count >= bm->outq_limit) { + if (connection->obuf->count >= bm->outq_limit) { bgp_write_proceed_actions(peer); return; } @@ -601,14 +608,14 @@ void bgp_generate_updgrp_packets(struct event *thread) * packet with appropriate attributes from peer * and advance peer */ s = bpacket_reformat_for_peer(next_pkt, paf); - bgp_packet_add(peer, s); + bgp_packet_add(connection, peer, s); bpacket_queue_advance_peer(paf); } } while (s && (++generated < wpq) && - (peer->connection->obuf->count <= bm->outq_limit)); + (connection->obuf->count <= bm->outq_limit)); if (generated) - bgp_writes_on(peer->connection); + bgp_writes_on(connection); bgp_write_proceed_actions(peer); } @@ -635,7 +642,7 @@ void bgp_keepalive_send(struct peer *peer) zlog_debug("%s sending KEEPALIVE", peer->host); /* Add packet to the peer. */ - bgp_packet_add(peer, s); + bgp_packet_add(peer->connection, peer, s); bgp_writes_on(peer->connection); } @@ -644,11 +651,12 @@ void bgp_keepalive_send(struct peer *peer) * Creates a BGP Open packet and appends it to the peer's output queue. * Sets capabilities as necessary. */ -void bgp_open_send(struct peer *peer) +void bgp_open_send(struct peer_connection *connection) { struct stream *s; uint16_t send_holdtime; as_t local_as; + struct peer *peer = connection->peer; if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) send_holdtime = peer->holdtime; @@ -704,9 +712,9 @@ void bgp_open_send(struct peer *peer) hook_call(bgp_packet_send, peer, BGP_MSG_OPEN, stream_get_endp(s), s); /* Add packet to the peer. */ - bgp_packet_add(peer, s); + bgp_packet_add(connection, peer, s); - bgp_writes_on(peer->connection); + bgp_writes_on(connection); } /* @@ -721,14 +729,15 @@ void bgp_open_send(struct peer *peer) * @param peer * @return 0 */ -static void bgp_write_notify(struct peer *peer) +static void bgp_write_notify(struct peer_connection *connection, + struct peer *peer) { int ret, val; uint8_t type; struct stream *s; /* There should be at least one packet. */ - s = stream_fifo_pop(peer->connection->obuf); + s = stream_fifo_pop(connection->obuf); if (!s) return; @@ -739,7 +748,7 @@ static void bgp_write_notify(struct peer *peer) * socket is in nonblocking mode, if we can't deliver the NOTIFY, well, * we only care about getting a clean shutdown at this point. */ - ret = write(peer->connection->fd, STREAM_DATA(s), stream_get_endp(s)); + ret = write(connection->fd, STREAM_DATA(s), stream_get_endp(s)); /* * only connection reset/close gets counted as TCP_fatal_error, failure @@ -747,14 +756,14 @@ static void bgp_write_notify(struct peer *peer) */ if (ret <= 0) { stream_free(s); - BGP_EVENT_ADD(peer, TCP_fatal_error); + BGP_EVENT_ADD(connection, TCP_fatal_error); return; } /* Disable Nagle, make NOTIFY packet go out right away */ val = 1; - (void)setsockopt(peer->connection->fd, IPPROTO_TCP, TCP_NODELAY, - (char *)&val, sizeof(val)); + (void)setsockopt(connection->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, + sizeof(val)); /* Retrieve BGP packet type. */ stream_set_getp(s, BGP_MARKER_SIZE + 2); @@ -776,7 +785,7 @@ static void bgp_write_notify(struct peer *peer) * Handle Graceful Restart case where the state changes to * Connect instead of Idle */ - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(connection, BGP_Stop); stream_free(s); } @@ -902,15 +911,17 @@ bool bgp_notify_received_hard_reset(struct peer *peer, uint8_t code, * @param data Data portion * @param datalen length of data portion */ -static void bgp_notify_send_internal(struct peer *peer, uint8_t code, - uint8_t sub_code, uint8_t *data, - size_t datalen, bool use_curr) +static void bgp_notify_send_internal(struct peer_connection *connection, + uint8_t code, uint8_t sub_code, + uint8_t *data, size_t datalen, + bool use_curr) { struct stream *s; + struct peer *peer = connection->peer; bool hard_reset = bgp_notify_send_hard_reset(peer, code, sub_code); /* Lock I/O mutex to prevent other threads from pushing packets */ - frr_mutex_lock_autounlock(&peer->connection->io_mtx); + frr_mutex_lock_autounlock(&connection->io_mtx); /* ============================================== */ /* Allocate new stream. */ @@ -943,7 +954,7 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code, bgp_packet_set_size(s); /* wipe output buffer */ - stream_fifo_clean(peer->connection->obuf); + stream_fifo_clean(connection->obuf); /* * If possible, store last packet for debugging purposes. This check is @@ -1028,13 +1039,13 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code, peer->last_reset = PEER_DOWN_NOTIFY_SEND; /* Add packet to peer's output queue */ - stream_fifo_push(peer->connection->obuf, s); + stream_fifo_push(connection->obuf, s); bgp_peer_gr_flags_update(peer); BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp, peer->bgp->peer); - bgp_write_notify(peer); + bgp_write_notify(connection, peer); } /* @@ -1047,18 +1058,20 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code, * @param code BGP error code * @param sub_code BGP error subcode */ -void bgp_notify_send(struct peer *peer, uint8_t code, uint8_t sub_code) +void bgp_notify_send(struct peer_connection *connection, uint8_t code, + uint8_t sub_code) { - bgp_notify_send_internal(peer, code, sub_code, NULL, 0, true); + bgp_notify_send_internal(connection, code, sub_code, NULL, 0, true); } /* * Enqueue notification; called from the main pthread, peer object access is ok. */ -void bgp_notify_send_with_data(struct peer *peer, uint8_t code, +void bgp_notify_send_with_data(struct peer_connection *connection, uint8_t code, uint8_t sub_code, uint8_t *data, size_t datalen) { - bgp_notify_send_internal(peer, code, sub_code, data, datalen, true); + bgp_notify_send_internal(connection, code, sub_code, data, datalen, + true); } /* @@ -1069,7 +1082,8 @@ void bgp_notify_io_invalid(struct peer *peer, uint8_t code, uint8_t sub_code, uint8_t *data, size_t datalen) { /* Avoid touching the peer object */ - bgp_notify_send_internal(peer, code, sub_code, data, datalen, false); + bgp_notify_send_internal(peer->connection, code, sub_code, data, + datalen, false); } /* @@ -1179,7 +1193,7 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi, } /* Add packet to the peer. */ - bgp_packet_add(peer, s); + bgp_packet_add(peer->connection, peer, s); bgp_writes_on(peer->connection); } @@ -1201,8 +1215,11 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, iana_safi_t pkt_safi = IANA_SAFI_UNICAST; unsigned long cap_len; uint16_t len; + uint32_t gr_restart_time; + const char *capability = lookup_msg(capcode_str, capability_code, + "Unknown"); - if (!peer_established(peer)) + if (!peer_established(peer->connection)) return; if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) && @@ -1244,12 +1261,12 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, stream_putc_at(s, cap_len, len); if (bgp_debug_neighbor_events(peer)) - zlog_debug("%pBP sending CAPABILITY has %s Software Version for afi/safi: %s/%s", + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s", peer, action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing", - iana_afi2str(pkt_afi), + capability, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); break; case CAPABILITY_CODE_MP: @@ -1261,21 +1278,113 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, stream_putc(s, pkt_safi); if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%pBP sending CAPABILITY has %s MP_EXT CAP for afi/safi: %s/%s", - peer, - action == CAPABILITY_ACTION_SET ? "Advertising" - : "Removing", - iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + break; + case CAPABILITY_CODE_RESTART: + if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) + return; + + SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV); + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_RESTART); + cap_len = stream_get_endp(s); + stream_putc(s, 0); + gr_restart_time = peer->bgp->restart_time; + + if (peer->bgp->t_startup) { + SET_FLAG(gr_restart_time, GRACEFUL_RESTART_R_BIT); + SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); + } + + if (CHECK_FLAG(peer->bgp->flags, + BGP_FLAG_GRACEFUL_NOTIFICATION)) { + SET_FLAG(gr_restart_time, GRACEFUL_RESTART_N_BIT); + SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV); + } + + stream_putw(s, gr_restart_time); + + if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) { + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, + &pkt_safi); + stream_putw(s, pkt_afi); + stream_putc(s, pkt_safi); + if (CHECK_FLAG(peer->bgp->flags, + BGP_FLAG_GR_PRESERVE_FWD)) + stream_putc(s, GRACEFUL_RESTART_F_BIT); + else + stream_putc(s, 0); + } + } + + len = stream_get_endp(s) - cap_len - 1; + stream_putc_at(s, cap_len, len); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + + break; + case CAPABILITY_CODE_LLGR: + if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)) + return; + + SET_FLAG(peer->cap, PEER_CAP_LLGR_ADV); + + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_LLGR); + cap_len = stream_get_endp(s); + stream_putc(s, 0); + + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, + &pkt_safi); + + stream_putw(s, pkt_afi); + stream_putc(s, pkt_safi); + stream_putc(s, LLGR_F_BIT); + stream_put3(s, peer->bgp->llgr_stale_time); + + SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_LLGR_AF_ADV); + } + + len = stream_get_endp(s) - cap_len - 1; + stream_putc_at(s, cap_len, len); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); break; case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_ORF: - case CAPABILITY_CODE_RESTART: case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_DYNAMIC: case CAPABILITY_CODE_ADDPATH: case CAPABILITY_CODE_ENHANCED_RR: - case CAPABILITY_CODE_LLGR: case CAPABILITY_CODE_FQDN: case CAPABILITY_CODE_ENHE: case CAPABILITY_CODE_EXT_MESSAGE: @@ -1297,15 +1406,17 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, bgp_packet_set_size(s); /* Add packet to the peer. */ - bgp_packet_add(peer, s); + bgp_packet_add(peer->connection, peer, s); bgp_writes_on(peer->connection); } /* RFC1771 6.8 Connection collision detection. */ -static int bgp_collision_detect(struct peer *new, struct in_addr remote_id) +static int bgp_collision_detect(struct peer_connection *connection, + struct peer *new, struct in_addr remote_id) { struct peer *peer; + struct peer_connection *other; /* * Upon receipt of an OPEN message, the local system must examine @@ -1321,19 +1432,22 @@ static int bgp_collision_detect(struct peer *new, struct in_addr remote_id) if (peer == NULL) return 0; + other = peer->connection; + /* * Do not accept the new connection in Established or Clearing * states. Note that a peer GR is handled by closing the existing * connection upon receipt of new one. */ - if (peer_established(peer) || peer->connection->status == Clearing) { - bgp_notify_send(new, BGP_NOTIFY_CEASE, + if (peer_established(other) || + other->status == Clearing) { + bgp_notify_send(connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return -1; } - if ((peer->connection->status != OpenConfirm) && - (peer->connection->status != OpenSent)) + if ((other->status != OpenConfirm) && + (other->status != OpenSent)) return 0; /* @@ -1360,11 +1474,11 @@ static int bgp_collision_detect(struct peer *new, struct in_addr remote_id) * and accepts BGP connection initiated by * the remote system. */ - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(other, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return 1; } else { - bgp_notify_send(new, BGP_NOTIFY_CEASE, + bgp_notify_send(connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return -1; } @@ -1383,11 +1497,11 @@ static int bgp_collision_detect(struct peer *new, struct in_addr remote_id) * OpenConfirm state). */ if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) { - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(other, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return 1; } else { - bgp_notify_send(new, BGP_NOTIFY_CEASE, + bgp_notify_send(connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return -1; } @@ -1430,7 +1544,8 @@ static int bgp_collision_detect(struct peer *new, struct in_addr remote_id) * @param size size of the packet * @return as in summary */ -static int bgp_open_receive(struct peer *peer, bgp_size_t size) +static int bgp_open_receive(struct peer_connection *connection, + struct peer *peer, bgp_size_t size) { int ret; uint8_t version; @@ -1469,7 +1584,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) EC_BGP_PKT_OPEN, "%s: stream does not have enough bytes for extended optional parameters", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return BGP_Stop; } @@ -1481,7 +1596,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) EC_BGP_PKT_OPEN, "%s: stream does not have enough bytes to read the extended optional parameters optlen", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return BGP_Stop; } @@ -1508,7 +1623,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) flog_err(EC_BGP_PKT_OPEN, "%s: stream has not enough bytes (%u)", peer->host, optlen); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return BGP_Stop; } @@ -1530,7 +1645,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) flog_err(EC_BGP_PKT_OPEN, "%s bad OPEN, got AS4 capability, but AS4 set to 0", peer->host); - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as4, 4); return BGP_Stop; @@ -1540,7 +1655,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) if (remote_as == BGP_AS_ZERO) { flog_err(EC_BGP_PKT_OPEN, "%s bad OPEN, got AS set to 0", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send(connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS); return BGP_Stop; } @@ -1555,7 +1670,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) EC_BGP_PKT_OPEN, "%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed", peer->host); - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(connection, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as4, 4); return BGP_Stop; @@ -1583,7 +1699,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) EC_BGP_PKT_OPEN, "%s bad OPEN, got AS4 capability, but remote_as %u mismatch with 16bit 'myasn' %u in open", peer->host, as4, remote_as); - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(connection, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as4, 4); return BGP_Stop; @@ -1603,7 +1720,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) if (bgp_debug_neighbor_events(peer)) zlog_debug("%s bad OPEN, wrong router identifier %pI4", peer->host, &remote_id); - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_BGP_IDENT, notify_data_remote_id, 4); return BGP_Stop; @@ -1618,7 +1735,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) "%s bad protocol version, remote requested %d, local request %d", peer->host, version, BGP_VERSION_4); /* Data must be in network byte order here */ - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_VERSION, (uint8_t *)&maxver, 2); return BGP_Stop; @@ -1630,7 +1747,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) zlog_debug( "%s bad OPEN, remote AS is unspecified currently", peer->host); - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return BGP_Stop; @@ -1640,7 +1757,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) zlog_debug( "%s bad OPEN, remote AS is %u, internal specified", peer->host, remote_as); - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(connection, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return BGP_Stop; @@ -1652,7 +1770,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) zlog_debug( "%s bad OPEN, remote AS is %u, external specified", peer->host, remote_as); - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(connection, + BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return BGP_Stop; @@ -1662,7 +1781,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) if (bgp_debug_neighbor_events(peer)) zlog_debug("%s bad OPEN, remote AS is %u, expected %u", peer->host, remote_as, peer->as); - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return BGP_Stop; @@ -1672,7 +1791,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) * When collision is detected and this peer is closed. * Return immediately. */ - ret = bgp_collision_detect(peer, remote_id); + ret = bgp_collision_detect(connection, peer, remote_id); if (ret < 0) return BGP_Stop; @@ -1695,7 +1814,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) */ if (holdtime < 3 && holdtime != 0) { - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, (uint8_t *)holdtime_ptr, 2); return BGP_Stop; @@ -1705,7 +1824,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) * is smaller than configured minimum Hold Time. */ if (holdtime < peer->bgp->default_min_holdtime && peer->bgp->default_min_holdtime != 0) { - bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + bgp_notify_send_with_data(connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, (uint8_t *)holdtime_ptr, 2); return BGP_Stop; @@ -1782,6 +1901,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) peer->afc[AFI_L2VPN][SAFI_EVPN]; peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] = peer->afc[AFI_IP6][SAFI_FLOWSPEC]; + peer->afc_nego[AFI_LINKSTATE][SAFI_LINKSTATE] = + peer->afc[AFI_LINKSTATE][SAFI_LINKSTATE]; } /* Verify valid local address present based on negotiated @@ -1808,12 +1929,12 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) flog_err(EC_BGP_SND_FAIL, "%s: No local IPv6 address, and zebra does not support V6 routing with v4 nexthops, BGP routing for V6 will not work", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } } - peer->rtt = sockopt_tcp_rtt(peer->connection->fd); + peer->rtt = sockopt_tcp_rtt(connection->fd); return Receive_OPEN_message; } @@ -1825,14 +1946,15 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) * @param size size of the packet * @return as in summary */ -static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size) +static int bgp_keepalive_receive(struct peer_connection *connection, + struct peer *peer, bgp_size_t size) { if (bgp_debug_keepalive(peer)) zlog_debug("%s KEEPALIVE rcvd", peer->host); bgp_update_implicit_eors(peer); - peer->rtt = sockopt_tcp_rtt(peer->connection->fd); + peer->rtt = sockopt_tcp_rtt(connection->fd); /* If the peer's RTT is higher than expected, shutdown * the peer automatically. @@ -1885,7 +2007,7 @@ static void bgp_refresh_stalepath_timer_expire(struct event *thread) "%pBP route-refresh (BoRR) timer expired for afi/safi: %d/%d", peer, afi, safi); - bgp_timer_set(peer); + bgp_timer_set(peer->connection); } /** @@ -1897,7 +2019,8 @@ static void bgp_refresh_stalepath_timer_expire(struct event *thread) * @param size size of the packet * @return as in summary */ -static int bgp_update_receive(struct peer *peer, bgp_size_t size) +static int bgp_update_receive(struct peer_connection *connection, + struct peer *peer, bgp_size_t size) { int ret, nlri_ret; uint8_t *end; @@ -1918,13 +2041,13 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) struct bgp_nlri nlris[NLRI_TYPE_MAX]; /* Status must be Established. */ - if (!peer_established(peer)) { + if (!peer_established(connection)) { flog_err(EC_BGP_INVALID_STATUS, "%s [FSM] Update packet received under status %s", peer->host, lookup_msg(bgp_status_msg, peer->connection->status, NULL)); - bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, + bgp_notify_send(connection, BGP_NOTIFY_FSM_ERR, bgp_fsm_error_subcode(peer->connection->status)); return BGP_Stop; } @@ -1948,7 +2071,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) flog_err(EC_BGP_UPDATE_RCV, "%s [Error] Update packet error (packet length is short for unfeasible length)", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send(connection, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return BGP_Stop; } @@ -1961,7 +2084,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) flog_err(EC_BGP_UPDATE_RCV, "%s [Error] Update packet error (packet unfeasible length overflow %d)", peer->host, withdraw_len); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send(connection, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return BGP_Stop; } @@ -1981,7 +2104,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) EC_BGP_UPDATE_PACKET_SHORT, "%s [Error] Packet Error (update packet is short for attribute length)", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send(peer->connection, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return BGP_Stop; } @@ -1995,7 +2118,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) EC_BGP_UPDATE_PACKET_LONG, "%s [Error] Packet Error (update packet attribute length overflow %d)", peer->host, attribute_len); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + bgp_notify_send(connection, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return BGP_Stop; } @@ -2110,12 +2233,12 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) && nlri_ret != BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW) { flog_err(EC_BGP_UPDATE_RCV, "%s [Error] Error parsing NLRI", peer->host); - if (peer_established(peer)) - bgp_notify_send( - peer, BGP_NOTIFY_UPDATE_ERR, - i <= NLRI_WITHDRAW - ? BGP_NOTIFY_UPDATE_INVAL_NETWORK - : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); + if (peer_established(connection)) + bgp_notify_send(connection, + BGP_NOTIFY_UPDATE_ERR, + i <= NLRI_WITHDRAW + ? BGP_NOTIFY_UPDATE_INVAL_NETWORK + : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); bgp_attr_unintern_sub(&attr); return BGP_Stop; } @@ -2223,7 +2346,8 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) * @param size size of the packet * @return as in summary */ -static int bgp_notify_receive(struct peer *peer, bgp_size_t size) +static int bgp_notify_receive(struct peer_connection *connection, + struct peer *peer, bgp_size_t size) { struct bgp_notify outer = {}; struct bgp_notify inner = {}; @@ -2344,7 +2468,8 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size) * @param size size of the packet * @return as in summary */ -static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) +static int bgp_route_refresh_receive(struct peer_connection *connection, + struct peer *peer, bgp_size_t size) { iana_afi_t pkt_afi; afi_t afi; @@ -2364,19 +2489,19 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) flog_err(EC_BGP_NO_CAP, "%s [Error] BGP route refresh is not enabled", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_HEADER_ERR, + bgp_notify_send(connection, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESTYPE); return BGP_Stop; } /* Status must be Established. */ - if (!peer_established(peer)) { + if (!peer_established(connection)) { flog_err(EC_BGP_INVALID_STATUS, "%s [Error] Route refresh packet received under status %s", peer->host, lookup_msg(bgp_status_msg, peer->connection->status, NULL)); - bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, + bgp_notify_send(connection, BGP_NOTIFY_FSM_ERR, bgp_fsm_error_subcode(peer->connection->status)); return BGP_Stop; } @@ -2415,9 +2540,9 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) zlog_err( "%s Enhanced Route Refresh message length error", peer->host); - bgp_notify_send( - peer, BGP_NOTIFY_ROUTE_REFRESH_ERR, - BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN); + bgp_notify_send(connection, + BGP_NOTIFY_ROUTE_REFRESH_ERR, + BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN); } /* When the BGP speaker receives a ROUTE-REFRESH message @@ -2433,7 +2558,7 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) if (msg_length < 5) { zlog_info("%s ORF route refresh length error", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } @@ -2668,7 +2793,7 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) bgp_set_stale_route(peer, afi, safi); } - if (peer_established(peer)) + if (peer_established(peer->connection)) event_add_timer(bm->master, bgp_refresh_stalepath_timer_expire, paf, peer->bgp->stalepath_time, @@ -2753,6 +2878,226 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) return BGP_PACKET_NOOP; } +static void bgp_dynamic_capability_llgr(uint8_t *pnt, int action, + struct capability_header *hdr, + struct peer *peer) +{ + uint8_t *data = pnt + 3; + uint8_t *end = data + hdr->length; + size_t len = end - data; + afi_t afi; + safi_t safi; + + if (action == CAPABILITY_ACTION_SET) { + if (len < BGP_CAP_LLGR_MIN_PACKET_LEN) { + zlog_err("%pBP: Received invalid Long-Lived Graceful-Restart capability length %zu", + peer, len); + return; + } + + SET_FLAG(peer->cap, PEER_CAP_LLGR_RCV); + + while (data + BGP_CAP_LLGR_MIN_PACKET_LEN <= end) { + afi_t afi; + safi_t safi; + iana_afi_t pkt_afi; + iana_safi_t pkt_safi; + struct graceful_restart_af graf; + + memcpy(&graf, data, sizeof(graf)); + pkt_afi = ntohs(graf.afi); + pkt_safi = safi_int2iana(graf.safi); + + /* Stale time is after AFI/SAFI/flags. + * It's encoded as 24 bits (= 3 bytes), so we need to + * put it into 32 bits. + */ + uint32_t stale_time; + uint8_t *stale_time_ptr = data + 4; + + stale_time = stale_time_ptr[0] << 16; + stale_time |= stale_time_ptr[1] << 8; + stale_time |= stale_time_ptr[2]; + + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, + &safi)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Long-lived Graceful Restart capability for this AFI/SAFI", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + } else if (!peer->afc[afi][safi] || + !CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_RCV)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Long-lived Graceful Restart capability", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + } else { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) Long-lived Graceful Restart capability stale time %u sec", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), + stale_time); + + peer->llgr[afi][safi].flags = graf.flag; + peer->llgr[afi][safi].stale_time = + MIN(stale_time, + peer->bgp->llgr_stale_time); + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_LLGR_AF_RCV); + } + + data += BGP_CAP_LLGR_MIN_PACKET_LEN; + } + } else { + FOREACH_AFI_SAFI (afi, safi) { + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_LLGR_AF_RCV); + + peer->llgr[afi][safi].flags = 0; + peer->llgr[afi][safi].stale_time = + BGP_DEFAULT_LLGR_STALE_TIME; + } + + UNSET_FLAG(peer->cap, PEER_CAP_LLGR_RCV); + } +} + +static void bgp_dynamic_capability_graceful_restart(uint8_t *pnt, int action, + struct capability_header *hdr, + struct peer *peer) +{ +#define GRACEFUL_RESTART_CAPABILITY_PER_AFI_SAFI_SIZE 4 + uint16_t gr_restart_flag_time; + uint8_t *data = pnt + 3; + uint8_t *end = pnt + hdr->length; + size_t len = end - data; + afi_t afi; + safi_t safi; + + if (action == CAPABILITY_ACTION_SET) { + if (len < sizeof(gr_restart_flag_time)) { + zlog_err("%pBP: Received invalid Graceful-Restart capability length %d", + peer, hdr->length); + return; + } + + SET_FLAG(peer->cap, PEER_CAP_RESTART_RCV); + ptr_get_be16(data, &gr_restart_flag_time); + data += sizeof(gr_restart_flag_time); + + if (CHECK_FLAG(gr_restart_flag_time, GRACEFUL_RESTART_R_BIT)) + SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV); + else + UNSET_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV); + + if (CHECK_FLAG(gr_restart_flag_time, GRACEFUL_RESTART_N_BIT)) + SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV); + else + UNSET_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV); + + UNSET_FLAG(gr_restart_flag_time, 0xF000); + peer->v_gr_restart = gr_restart_flag_time; + + while (data + GRACEFUL_RESTART_CAPABILITY_PER_AFI_SAFI_SIZE <= + end) { + afi_t afi; + safi_t safi; + iana_afi_t pkt_afi; + iana_safi_t pkt_safi; + struct graceful_restart_af graf; + + memcpy(&graf, data, sizeof(graf)); + pkt_afi = ntohs(graf.afi); + pkt_safi = safi_int2iana(graf.safi); + + /* Convert AFI, SAFI to internal values, check. */ + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, + &safi)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP: Addr-family %s/%s(afi/safi) not supported. Ignore the Graceful Restart capability for this AFI/SAFI", + peer, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + } else if (!peer->afc[afi][safi]) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP: Addr-family %s/%s(afi/safi) not enabled. Ignore the Graceful Restart capability", + peer, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + } else { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP: Address family %s is%spreserved", + peer, + get_afi_safi_str(afi, safi, + false), + CHECK_FLAG(peer->af_cap[afi] + [safi], + PEER_CAP_RESTART_AF_PRESERVE_RCV) + ? " " + : " not "); + + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_RCV); + if (CHECK_FLAG(graf.flag, + GRACEFUL_RESTART_F_BIT)) + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_PRESERVE_RCV); + } + + data += GRACEFUL_RESTART_CAPABILITY_PER_AFI_SAFI_SIZE; + } + } else { + FOREACH_AFI_SAFI (afi, safi) { + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_RCV); + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_PRESERVE_RCV); + } + + UNSET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV); + UNSET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV); + UNSET_FLAG(peer->cap, PEER_CAP_RESTART_RCV); + } +} + +static void bgp_dynamic_capability_software_version(uint8_t *pnt, int action, + struct capability_header *hdr, + struct peer *peer) +{ + uint8_t *data = pnt + 3; + uint8_t *end = data + hdr->length; + uint8_t len = *data; + char soft_version[BGP_MAX_SOFT_VERSION + 1] = {}; + + if (action == CAPABILITY_ACTION_SET) { + if (data + len > end) { + zlog_err("%pBP: Received invalid Software Version capability length %d", + peer, len); + return; + } + data++; + + if (len > BGP_MAX_SOFT_VERSION) + len = BGP_MAX_SOFT_VERSION; + + memcpy(&soft_version, data, len); + soft_version[len] = '\0'; + + XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); + peer->soft_version = XSTRDUP(MTYPE_BGP_SOFT_VERSION, + soft_version); + + SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); + } else { + UNSET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); + XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); + } +} + /** * Parse BGP CAPABILITY message for peer. * @@ -2771,7 +3116,6 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, afi_t afi; iana_safi_t pkt_safi; safi_t safi; - char soft_version[BGP_MAX_SOFT_VERSION + 1] = {}; const char *capability; end = pnt + length; @@ -2781,7 +3125,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, * length. */ if (pnt + 3 > end) { zlog_err("%pBP: Capability length error", peer); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } @@ -2793,7 +3137,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, && action != CAPABILITY_ACTION_UNSET) { zlog_err("%pBP: Capability Action Value error %d", peer, action); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } @@ -2805,7 +3149,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, /* Capability length check. */ if ((pnt + hdr->length + 3) > end) { zlog_err("%pBP: Capability length error", peer); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } @@ -2818,22 +3162,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, switch (hdr->code) { case CAPABILITY_CODE_SOFT_VERSION: - if (action == CAPABILITY_ACTION_SET) { - SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); - - memcpy(&soft_version, pnt + 3, hdr->length); - soft_version[hdr->length] = '\0'; - - XFREE(MTYPE_BGP_SOFT_VERSION, - peer->soft_version); - peer->soft_version = - XSTRDUP(MTYPE_BGP_SOFT_VERSION, - soft_version); - } else { - UNSET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); - XFREE(MTYPE_BGP_SOFT_VERSION, - peer->soft_version); - } + bgp_dynamic_capability_software_version(pnt, action, + hdr, peer); break; case CAPABILITY_CODE_MP: if (hdr->length < sizeof(struct capability_mp_data)) { @@ -2886,14 +3216,28 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, return BGP_Stop; } break; + case CAPABILITY_CODE_RESTART: + if ((hdr->length - 2) % 4) { + zlog_err("%pBP: Received invalid Graceful-Restart capability length %d", + peer, hdr->length); + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); + return BGP_Stop; + } + + bgp_dynamic_capability_graceful_restart(pnt, action, + hdr, peer); + break; + case CAPABILITY_CODE_LLGR: + bgp_dynamic_capability_llgr(pnt, action, hdr, peer); + break; case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_ORF: - case CAPABILITY_CODE_RESTART: case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_DYNAMIC: case CAPABILITY_CODE_ADDPATH: case CAPABILITY_CODE_ENHANCED_RR: - case CAPABILITY_CODE_LLGR: case CAPABILITY_CODE_FQDN: case CAPABILITY_CODE_ENHE: case CAPABILITY_CODE_EXT_MESSAGE: @@ -2902,7 +3246,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, if (hdr->length != CAPABILITY_CODE_ROLE_LEN) { zlog_err("%pBP: Capability (%s) length error", peer, capability); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } @@ -2942,7 +3287,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, * @param size size of the packet * @return as in summary */ -int bgp_capability_receive(struct peer *peer, bgp_size_t size) +int bgp_capability_receive(struct peer_connection *connection, + struct peer *peer, bgp_size_t size) { uint8_t *pnt; @@ -2957,20 +3303,19 @@ int bgp_capability_receive(struct peer *peer, bgp_size_t size) flog_err(EC_BGP_NO_CAP, "%s [Error] BGP dynamic capability is not enabled", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_HEADER_ERR, + bgp_notify_send(connection, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESTYPE); return BGP_Stop; } /* Status must be Established. */ - if (!peer_established(peer)) { + if (!peer_established(connection)) { flog_err(EC_BGP_NO_CAP, "%s [Error] Dynamic capability packet received under status %s", peer->host, - lookup_msg(bgp_status_msg, peer->connection->status, - NULL)); - bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, - bgp_fsm_error_subcode(peer->connection->status)); + lookup_msg(bgp_status_msg, connection->status, NULL)); + bgp_notify_send(connection, BGP_NOTIFY_FSM_ERR, + bgp_fsm_error_subcode(connection->status)); return BGP_Stop; } @@ -3045,7 +3390,7 @@ void bgp_process_packet(struct event *thread) frrtrace(2, frr_bgp, open_process, peer, size); atomic_fetch_add_explicit(&peer->open_in, 1, memory_order_relaxed); - mprc = bgp_open_receive(peer, size); + mprc = bgp_open_receive(connection, peer, size); if (mprc == BGP_Stop) flog_err( EC_BGP_PKT_OPEN, @@ -3057,7 +3402,7 @@ void bgp_process_packet(struct event *thread) atomic_fetch_add_explicit(&peer->update_in, 1, memory_order_relaxed); peer->readtime = monotime(NULL); - mprc = bgp_update_receive(peer, size); + mprc = bgp_update_receive(connection, peer, size); if (mprc == BGP_Stop) flog_err( EC_BGP_UPDATE_RCV, @@ -3068,7 +3413,7 @@ void bgp_process_packet(struct event *thread) frrtrace(2, frr_bgp, notification_process, peer, size); atomic_fetch_add_explicit(&peer->notify_in, 1, memory_order_relaxed); - mprc = bgp_notify_receive(peer, size); + mprc = bgp_notify_receive(connection, peer, size); if (mprc == BGP_Stop) flog_err( EC_BGP_NOTIFY_RCV, @@ -3080,7 +3425,7 @@ void bgp_process_packet(struct event *thread) peer->readtime = monotime(NULL); atomic_fetch_add_explicit(&peer->keepalive_in, 1, memory_order_relaxed); - mprc = bgp_keepalive_receive(peer, size); + mprc = bgp_keepalive_receive(connection, peer, size); if (mprc == BGP_Stop) flog_err( EC_BGP_KEEP_RCV, @@ -3092,7 +3437,7 @@ void bgp_process_packet(struct event *thread) frrtrace(2, frr_bgp, refresh_process, peer, size); atomic_fetch_add_explicit(&peer->refresh_in, 1, memory_order_relaxed); - mprc = bgp_route_refresh_receive(peer, size); + mprc = bgp_route_refresh_receive(connection, peer, size); if (mprc == BGP_Stop) flog_err( EC_BGP_RFSH_RCV, @@ -3103,7 +3448,7 @@ void bgp_process_packet(struct event *thread) frrtrace(2, frr_bgp, capability_process, peer, size); atomic_fetch_add_explicit(&peer->dynamic_cap_in, 1, memory_order_relaxed); - mprc = bgp_capability_receive(peer, size); + mprc = bgp_capability_receive(connection, peer, size); if (mprc == BGP_Stop) flog_err( EC_BGP_CAP_RCV, @@ -3130,7 +3475,7 @@ void bgp_process_packet(struct event *thread) /* Update FSM */ if (mprc != BGP_PACKET_NOOP) - fsm_update_result = bgp_event_update(peer, mprc); + fsm_update_result = bgp_event_update(connection, mprc); else continue; @@ -3186,7 +3531,7 @@ void bgp_packet_process_error(struct event *thread) connection->fd); /* Closed connection or error on the socket */ - if (peer_established(peer)) { + if (peer_established(connection)) { if ((CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) || CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) @@ -3197,5 +3542,5 @@ void bgp_packet_process_error(struct event *thread) peer->last_reset = PEER_DOWN_CLOSE_SESSION; } - bgp_event_update(peer, code); + bgp_event_update(connection, code); } diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 04bdb81849bd..b67acf205593 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -37,17 +37,18 @@ DECLARE_HOOK(bgp_packet_send, do { \ _s = bgp_update_packet_eor(_peer, _afi, _safi); \ if (_s) { \ - bgp_packet_add(_peer, _s); \ + bgp_packet_add(_peer->connection, _peer, _s); \ } \ } while (0) /* Packet send and receive function prototypes. */ extern void bgp_keepalive_send(struct peer *peer); -extern void bgp_open_send(struct peer *peer); -extern void bgp_notify_send(struct peer *peer, uint8_t code, uint8_t sub_code); -extern void bgp_notify_send_with_data(struct peer *peer, uint8_t code, - uint8_t sub_code, uint8_t *data, - size_t datalen); +extern void bgp_open_send(struct peer_connection *connection); +extern void bgp_notify_send(struct peer_connection *connection, uint8_t code, + uint8_t sub_code); +extern void bgp_notify_send_with_data(struct peer_connection *connection, + uint8_t code, uint8_t sub_code, + uint8_t *data, size_t datalen); void bgp_notify_io_invalid(struct peer *peer, uint8_t code, uint8_t sub_code, uint8_t *data, size_t datalen); extern void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi, @@ -56,8 +57,8 @@ extern void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi, extern void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, int capabilty_code, int action); -extern int bgp_capability_receive(struct peer *peer, bgp_size_t length); - +extern int bgp_capability_receive(struct peer_connection *connection, + struct peer *peer, bgp_size_t length); extern int bgp_nlri_parse(struct peer *peer, struct attr *attr, struct bgp_nlri *nlri, bool mp_withdraw); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index c8271bf5ce7a..71b43c67568d 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -73,6 +73,7 @@ #include "bgpd/bgp_flowspec.h" #include "bgpd/bgp_flowspec_util.h" #include "bgpd/bgp_pbr.h" +#include "bgpd/bgp_linkstate_tlv.h" #include "bgpd/bgp_route_clippy.c" @@ -138,7 +139,9 @@ struct bgp_dest *bgp_afi_node_get(struct bgp_table *table, afi_t afi, bgp_dest_set_bgp_table_info( pdest, bgp_table_init(table->bgp, afi, safi)); else - bgp_dest_unlock_node(pdest); + pdest = bgp_dest_unlock_node(pdest); + + assert(pdest); table = bgp_dest_get_bgp_table_info(pdest); } @@ -438,7 +441,8 @@ void bgp_path_info_add_with_caller(const char *name, struct bgp_dest *dest, /* Do the actual removal of info from RIB, for use by bgp_process completion callback *only* */ -void bgp_path_info_reap(struct bgp_dest *dest, struct bgp_path_info *pi) +struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest, + struct bgp_path_info *pi) { if (pi->next) pi->next->prev = pi->prev; @@ -450,7 +454,8 @@ void bgp_path_info_reap(struct bgp_dest *dest, struct bgp_path_info *pi) bgp_path_info_mpath_dequeue(pi); bgp_path_info_unlock(pi); hook_call(bgp_snmp_update_stats, dest, pi, false); - bgp_dest_unlock_node(dest); + + return bgp_dest_unlock_node(dest); } void bgp_path_info_delete(struct bgp_dest *dest, struct bgp_path_info *pi) @@ -594,7 +599,7 @@ struct bgp_path_info *bgp_get_imported_bpi_ultimate(struct bgp_path_info *info) */ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, struct bgp_path_info *exist, int *paths_eq, - struct bgp_maxpaths_cfg *mpath_cfg, int debug, + struct bgp_maxpaths_cfg *mpath_cfg, bool debug, char *pfx_buf, afi_t afi, safi_t safi, enum bgp_path_selection_reason *reason) { @@ -715,16 +720,6 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, * sticky flag. */ if (newattr->sticky != existattr->sticky) { - if (!debug) { - prefix2str(new_p, pfx_buf, - sizeof(*pfx_buf) - * PREFIX2STR_BUFFER); - bgp_path_info_path_with_addpath_rx_str( - new, new_buf, sizeof(new_buf)); - bgp_path_info_path_with_addpath_rx_str( - exist, exist_buf, sizeof(exist_buf)); - } - if (newattr->sticky && !existattr->sticky) { *reason = bgp_path_selection_evpn_sticky_mac; if (debug) @@ -1499,13 +1494,18 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, int bgp_evpn_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, - struct bgp_path_info *exist, int *paths_eq) + struct bgp_path_info *exist, int *paths_eq, + bool debug) { enum bgp_path_selection_reason reason; char pfx_buf[PREFIX2STR_BUFFER] = {}; - return bgp_path_info_cmp(bgp, new, exist, paths_eq, NULL, 0, pfx_buf, - AFI_L2VPN, SAFI_EVPN, &reason); + if (debug) + prefix2str(bgp_dest_get_prefix(new->net), pfx_buf, + sizeof(pfx_buf)); + + return bgp_path_info_cmp(bgp, new, exist, paths_eq, NULL, debug, + pfx_buf, AFI_L2VPN, SAFI_EVPN, &reason); } /* Compare two bgp route entity. Return -1 if new is preferred, 1 if exist @@ -1519,8 +1519,10 @@ int bgp_path_info_cmp_compatible(struct bgp *bgp, struct bgp_path_info *new, { int paths_eq; int ret; - ret = bgp_path_info_cmp(bgp, new, exist, &paths_eq, NULL, 0, pfx_buf, - afi, safi, reason); + bool debug = false; + + ret = bgp_path_info_cmp(bgp, new, exist, &paths_eq, NULL, debug, + pfx_buf, afi, safi, reason); if (paths_eq) ret = 0; @@ -1580,7 +1582,7 @@ static enum filter_type bgp_input_filter(struct peer *peer, done: if (frrtrace_enabled(frr_bgp, input_filter)) { - char pfxprint[PREFIX2STR_BUFFER]; + char pfxprint[PREFIX_STRLEN_EXTENDED]; prefix2str(p, pfxprint, sizeof(pfxprint)); frrtrace(5, frr_bgp, input_filter, peer, pfxprint, afi, safi, @@ -1637,7 +1639,7 @@ static enum filter_type bgp_output_filter(struct peer *peer, } if (frrtrace_enabled(frr_bgp, output_filter)) { - char pfxprint[PREFIX2STR_BUFFER]; + char pfxprint[PREFIX_STRLEN_EXTENDED]; prefix2str(p, pfxprint, sizeof(pfxprint)); frrtrace(5, frr_bgp, output_filter, peer, pfxprint, afi, safi, @@ -2377,9 +2379,6 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, bgp_otc_egress(peer, attr)) return false; - bgp_peer_remove_private_as(bgp, afi, safi, peer, attr); - bgp_peer_as_override(bgp, afi, safi, peer, attr); - if (filter->advmap.update_type == UPDATE_TYPE_WITHDRAW && filter->advmap.aname && route_map_lookup_by_name(filter->advmap.aname)) { @@ -2452,6 +2451,9 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, } } + bgp_peer_remove_private_as(bgp, afi, safi, peer, attr); + bgp_peer_as_override(bgp, afi, safi, peer, attr); + /* RFC 8212 to prevent route leaks. * This specification intends to improve this situation by requiring the * explicit configuration of both BGP Import and Export Policies for any @@ -2708,9 +2710,10 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info *pi1; struct bgp_path_info *pi2; struct bgp_path_info *nextpi = NULL; - int paths_eq, do_mpath, debug; + int paths_eq, do_mpath; + bool debug; struct list mp_list; - char pfx_buf[PREFIX2STR_BUFFER] = {}; + char pfx_buf[PREFIX_STRLEN_EXTENDED] = {}; char path_buf[PATH_ADDPATH_STR_BUFFER]; bgp_mp_list_init(&mp_list); @@ -2742,7 +2745,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (pi1->peer != bgp->peer_self && !CHECK_FLAG(pi1->peer->sflags, PEER_STATUS_NSF_WAIT)) { - if (!peer_established(pi1->peer)) + if (!peer_established(pi1->peer->connection)) continue; } @@ -2757,7 +2760,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (pi2->peer != bgp->peer_self && !CHECK_FLAG(pi2->peer->sflags, PEER_STATUS_NSF_WAIT) && - !peer_established(pi2->peer)) + !peer_established( + pi2->peer->connection)) continue; if (!aspath_cmp_left(pi1->attr->aspath, @@ -2813,9 +2817,11 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, /* reap REMOVED routes, if needs be * selected route must stay for a while longer though */ - if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) - && (pi != old_select)) - bgp_path_info_reap(dest, pi); + if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) && + (pi != old_select)) { + dest = bgp_path_info_reap(dest, pi); + assert(dest); + } if (debug) zlog_debug( @@ -2828,8 +2834,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (pi->peer && pi->peer != bgp->peer_self && !CHECK_FLAG(pi->peer->sflags, PEER_STATUS_NSF_WAIT)) - if (!peer_established(pi->peer)) { - + if (!peer_established(pi->peer->connection)) { if (debug) zlog_debug( "%s: %pBD(%s) non self peer %s not estab state", @@ -2903,7 +2908,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (pi->peer && pi->peer != bgp->peer_self && !CHECK_FLAG(pi->peer->sflags, PEER_STATUS_NSF_WAIT)) - if (!peer_established(pi->peer)) + if (!peer_established(pi->peer->connection)) continue; if (!bgp_path_info_nexthop_cmp(pi, new_select)) { @@ -3502,11 +3507,12 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, /* Clear any route change flags. */ bgp_zebra_clear_route_change_flags(dest); + UNSET_FLAG(dest->flags, BGP_NODE_PROCESS_SCHEDULED); + /* Reap old select bgp_path_info, if it has been removed */ if (old_select && CHECK_FLAG(old_select->flags, BGP_PATH_REMOVED)) bgp_path_info_reap(dest, old_select); - UNSET_FLAG(dest->flags, BGP_NODE_PROCESS_SCHEDULED); return; } @@ -3724,10 +3730,8 @@ void bgp_add_eoiu_mark(struct bgp *bgp) static void bgp_maximum_prefix_restart_timer(struct event *thread) { - struct peer *peer; - - peer = EVENT_ARG(thread); - peer->t_pmax_restart = NULL; + struct peer_connection *connection = EVENT_ARG(thread); + struct peer *peer = connection->peer; if (bgp_debug_neighbor_events(peer)) zlog_debug( @@ -3785,6 +3789,7 @@ bool bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi, ? bgp_filtered_routes_count(peer, afi, safi) + peer->pcount[afi][safi] : peer->pcount[afi][safi]; + struct peer_connection *connection = peer->connection; if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) return false; @@ -3820,7 +3825,7 @@ bool bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi, ndata[6] = (peer->pmax[afi][safi]); SET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); - bgp_notify_send_with_data(peer, BGP_NOTIFY_CEASE, + bgp_notify_send_with_data(connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_MAX_PREFIX, ndata, 7); } @@ -3839,7 +3844,7 @@ bool bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi, "%pBP Maximum-prefix restart timer started for %d secs", peer, peer->v_pmax_restart); - BGP_TIMER_ON(peer->t_pmax_restart, + BGP_TIMER_ON(connection->t_pmax_restart, bgp_maximum_prefix_restart_timer, peer->v_pmax_restart); } @@ -4163,7 +4168,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, int allowas_in = 0; if (frrtrace_enabled(frr_bgp, process_update)) { - char pfxprint[PREFIX2STR_BUFFER]; + char pfxprint[PREFIX_STRLEN_EXTENDED]; prefix2str(p, pfxprint, sizeof(pfxprint)); frrtrace(6, frr_bgp, process_update, peer, pfxprint, addpath_id, @@ -4725,8 +4730,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST || (safi == SAFI_MPLS_VPN && pi->sub_type != BGP_ROUTE_IMPORTED))) || - (safi == SAFI_EVPN && - bgp_evpn_is_prefix_nht_supported(p))) { + (safi == SAFI_EVPN && bgp_evpn_is_prefix_nht_supported(p)) || + afi == AFI_LINKSTATE) { if (safi != SAFI_EVPN && peer->sort == BGP_PEER_EBGP && peer->ttl == BGP_DEFAULT_TTL && !CHECK_FLAG(peer->flags, @@ -4873,9 +4878,9 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, /* Nexthop reachability check. */ if (((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST || - (safi == SAFI_MPLS_VPN && - new->sub_type != BGP_ROUTE_IMPORTED))) || - (safi == SAFI_EVPN && bgp_evpn_is_prefix_nht_supported(p))) { + (safi == SAFI_MPLS_VPN && new->sub_type != BGP_ROUTE_IMPORTED))) || + (safi == SAFI_EVPN && bgp_evpn_is_prefix_nht_supported(p)) || + afi == AFI_LINKSTATE) { if (safi != SAFI_EVPN && peer->sort == BGP_PEER_EBGP && peer->ttl == BGP_DEFAULT_TTL && !CHECK_FLAG(peer->flags, @@ -5081,7 +5086,8 @@ void bgp_withdraw(struct peer *peer, const struct prefix *p, */ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) && peer != bgp->peer_self) - if (!bgp_adj_in_unset(dest, peer, addpath_id)) { + if (!bgp_adj_in_unset(&dest, peer, addpath_id)) { + assert(dest); peer->stat_pfx_dup_withdraw++; if (bgp_debug_update(peer, p, NULL, 1)) { @@ -5098,6 +5104,7 @@ void bgp_withdraw(struct peer *peer, const struct prefix *p, } /* Lookup withdrawn route. */ + assert(dest); for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (pi->peer == peer && pi->type == type && pi->sub_type == sub_type @@ -5173,7 +5180,7 @@ static void bgp_announce_route_timer_expired(struct event *t) paf = EVENT_ARG(t); peer = paf->peer; - if (!peer_established(peer)) + if (!peer_established(peer->connection)) return; if (!peer->afc_nego[paf->afi][paf->safi]) @@ -5589,7 +5596,7 @@ static void bgp_clear_node_complete(struct work_queue *wq) struct peer *peer = wq->spec.data; /* Tickle FSM to start moving again */ - BGP_EVENT_ADD(peer, Clearing_Completed); + BGP_EVENT_ADD(peer->connection, Clearing_Completed); peer_unlock(peer); /* bgp_clear_route */ } @@ -5671,9 +5678,11 @@ static void bgp_clear_route_table(struct peer *peer, afi_t afi, safi_t safi, ain_next = ain->next; if (ain->peer == peer) - bgp_adj_in_remove(dest, ain); + bgp_adj_in_remove(&dest, ain); ain = ain_next; + + assert(dest); } for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = next) { @@ -5681,9 +5690,10 @@ static void bgp_clear_route_table(struct peer *peer, afi_t afi, safi_t safi, if (pi->peer != peer) continue; - if (force) - bgp_path_info_reap(dest, pi); - else { + if (force) { + dest = bgp_path_info_reap(dest, pi); + assert(dest); + } else { struct bgp_clear_node_queue *cnq; /* both unlocked in bgp_clear_node_queue_del */ @@ -5778,9 +5788,11 @@ void bgp_clear_adj_in(struct peer *peer, afi_t afi, safi_t safi) ain_next = ain->next; if (ain->peer == peer) - bgp_adj_in_remove(dest, ain); + bgp_adj_in_remove(&dest, ain); ain = ain_next; + + assert(dest); } } } @@ -5998,7 +6010,8 @@ static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table, bgp_zebra_withdraw(p, pi, bgp, safi); } - bgp_path_info_reap(dest, pi); + dest = bgp_path_info_reap(dest, pi); + assert(dest); } } @@ -6027,7 +6040,9 @@ void bgp_cleanup_routes(struct bgp *bgp) bgp_cleanup_table(bgp, table, safi); bgp_table_finish(&table); bgp_dest_set_bgp_table_info(dest, NULL); - bgp_dest_unlock_node(dest); + dest = bgp_dest_unlock_node(dest); + + assert(dest); } } safi = SAFI_ENCAP; @@ -6038,7 +6053,9 @@ void bgp_cleanup_routes(struct bgp *bgp) bgp_cleanup_table(bgp, table, safi); bgp_table_finish(&table); bgp_dest_set_bgp_table_info(dest, NULL); - bgp_dest_unlock_node(dest); + dest = bgp_dest_unlock_node(dest); + + assert(dest); } } } @@ -6050,7 +6067,9 @@ void bgp_cleanup_routes(struct bgp *bgp) bgp_cleanup_table(bgp, table, SAFI_EVPN); bgp_table_finish(&table); bgp_dest_set_bgp_table_info(dest, NULL); - bgp_dest_unlock_node(dest); + dest = bgp_dest_unlock_node(dest); + + assert(dest); } } } @@ -6579,7 +6598,7 @@ int bgp_static_set(struct vty *vty, bool negate, const char *ip_str, int ret; struct prefix p; struct bgp_static *bgp_static; - struct prefix_rd prd; + struct prefix_rd prd = {}; struct bgp_dest *pdest; struct bgp_dest *dest; struct bgp_table *table; @@ -6608,7 +6627,6 @@ int bgp_static_set(struct vty *vty, bool negate, const char *ip_str, } if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN) { - memset(&prd, 0, sizeof(prd)); ret = str2prefix_rd(rd_str, &prd); if (!ret) { vty_out(vty, "%% Malformed rd\n"); @@ -6699,7 +6717,8 @@ int bgp_static_set(struct vty *vty, bool negate, const char *ip_str, } bgp_dest_set_bgp_static_info(dest, NULL); - bgp_dest_unlock_node(dest); + dest = bgp_dest_unlock_node(dest); + assert(dest); bgp_dest_unlock_node(dest); } else { dest = bgp_node_get(table, &p); @@ -6876,7 +6895,8 @@ void bgp_static_delete(struct bgp *bgp) bgp_static_free(bgp_static); bgp_dest_set_bgp_static_info(rm, NULL); - bgp_dest_unlock_node(rm); + rm = bgp_dest_unlock_node(rm); + assert(rm); } } else { bgp_static = bgp_dest_get_bgp_static_info(dest); @@ -6885,7 +6905,8 @@ void bgp_static_delete(struct bgp *bgp) afi, safi, NULL); bgp_static_free(bgp_static); bgp_dest_set_bgp_static_info(dest, NULL); - bgp_dest_unlock_node(dest); + dest = bgp_dest_unlock_node(dest); + assert(dest); } } } @@ -8216,7 +8237,8 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, bgp_dest_set_bgp_aggregate_info(dest, NULL); bgp_free_aggregate_info(aggregate); - bgp_dest_unlock_node(dest); + dest = bgp_dest_unlock_node(dest); + assert(dest); bgp_dest_unlock_node(dest); return CMD_SUCCESS; @@ -8738,8 +8760,10 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type, if (!CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) bgp_process(bgp, dest, afi, SAFI_UNICAST); - else - bgp_path_info_reap(dest, pi); + else { + dest = bgp_path_info_reap(dest, pi); + assert(dest); + } } } } @@ -8749,7 +8773,7 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p, struct vty *vty, json_object *json, bool wide) { int len = 0; - char buf[INET6_ADDRSTRLEN]; + char buf[PREFIX_STRLEN_EXTENDED]; if (p->family == AF_INET) { if (!json) { @@ -8775,6 +8799,14 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p, json ? NLRI_STRING_FORMAT_JSON_SIMPLE : NLRI_STRING_FORMAT_MIN, json); + } else if (p->family == AF_LINKSTATE) { + if (json) { + json_object_int_add(json, "version", dest->version); + bgp_linkstate_nlri_prefix_json( + json, p->u.prefix_linkstate.nlri_type, + p->u.prefix_linkstate.ptr, p->prefixlen); + } else + len = vty_out(vty, "%pFX", p); } else { if (!json) len = vty_out(vty, "%pFX", p); @@ -9341,7 +9373,7 @@ void route_vty_out(struct vty *vty, const struct prefix *p, if (json_paths) json_object_string_addf(json_path, "peerId", "%pSU", - &path->peer->su); + &path->peer->connection->su); /* Print aspath */ if (attr->aspath) { @@ -9801,7 +9833,7 @@ static void damp_route_vty_out(struct vty *vty, const struct prefix *p, { struct attr *attr = path->attr; int len; - char timebuf[BGP_UPTIME_LEN]; + char timebuf[BGP_UPTIME_LEN] = {}; json_object *json_path = NULL; if (use_json) @@ -9860,7 +9892,7 @@ static void flap_route_vty_out(struct vty *vty, const struct prefix *p, { struct attr *attr = path->attr; struct bgp_damp_info *bdi; - char timebuf[BGP_UPTIME_LEN]; + char timebuf[BGP_UPTIME_LEN] = {}; int len; json_object *json_path = NULL; @@ -9961,7 +9993,7 @@ static void route_vty_out_advertised_to(struct vty *vty, struct peer *peer, json_peer); else json_object_object_addf(json_adv_to, json_peer, "%pSU", - &peer->su); + &peer->connection->su); } else { if (*first) { vty_out(vty, "%s", header); @@ -9975,12 +10007,12 @@ static void route_vty_out_advertised_to(struct vty *vty, struct peer *peer, peer->conf_if); else vty_out(vty, " %s(%pSU)", peer->hostname, - &peer->su); + &peer->connection->su); } else { if (peer->conf_if) vty_out(vty, " %s", peer->conf_if); else - vty_out(vty, " %pSU", &peer->su); + vty_out(vty, " %pSU", &peer->connection->su); } } } @@ -10066,6 +10098,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, char tag_buf[30]; struct attr *attr = path->attr; time_t tbuf; + char timebuf[32]; json_object *json_bestpath = NULL; json_object *json_cluster_list = NULL; json_object *json_cluster_list_list = NULL; @@ -10079,6 +10112,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object *json_peer = NULL; json_object *json_string = NULL; json_object *json_adv_to = NULL; + json_object *json_bgp_ls_attr = NULL; int first = 0; struct listnode *node, *nnode; struct peer *peer; @@ -10406,7 +10440,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, if (json_paths) { json_object_string_addf(json_peer, "peerId", "%pSU", - &path->peer->su); + &path->peer->connection->su); json_object_string_addf(json_peer, "routerId", "%pI4", &path->peer->remote_id); @@ -10441,7 +10475,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, path->peer->host); else vty_out(vty, " from %pSU", - &path->peer->su); + &path->peer->connection->su); } if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) @@ -10959,11 +10993,11 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_last_update = json_object_new_object(); json_object_int_add(json_last_update, "epoch", tbuf); json_object_string_add(json_last_update, "string", - ctime(&tbuf)); + ctime_r(&tbuf, timebuf)); json_object_object_add(json_path, "lastUpdate", json_last_update); } else - vty_out(vty, " Last update: %s", ctime(&tbuf)); + vty_out(vty, " Last update: %s", ctime_r(&tbuf, timebuf)); /* Line 10 display PMSI tunnel attribute, if present */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) { @@ -10982,10 +11016,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, str, label2vni(&attr->label)); } - if (path->peer->t_gr_restart && + if (path->peer->connection->t_gr_restart && CHECK_FLAG(path->flags, BGP_PATH_STALE)) { - unsigned long gr_remaining = - event_timer_remain_second(path->peer->t_gr_restart); + unsigned long gr_remaining = event_timer_remain_second( + path->peer->connection->t_gr_restart); if (json_paths) { json_object_int_add(json_path, @@ -11013,6 +11047,28 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, llgr_remaining); } + if (safi == SAFI_LINKSTATE) { + /* BGP Link-State NLRI */ + if (json_paths) + bgp_linkstate_nlri_prefix_json( + json_path, bn->rn->p.u.prefix_linkstate.nlri_type, + bn->rn->p.u.prefix_linkstate.ptr, bn->rn->p.prefixlen); + + /* BGP Link-State Attributes */ + if (attr->link_state) { + if (json_paths) { + json_bgp_ls_attr = json_object_new_object(); + json_object_object_add(json_path, + "linkStateAttributes", + json_bgp_ls_attr); + } else { + vty_out(vty, " BGP-LS attributes:\n"); + } + bgp_linkstate_tlv_attribute_display( + vty, attr->link_state, 4, json_bgp_ls_attr); + } + } + /* Output some debug about internal state of the dest flags */ if (json_paths) { if (CHECK_FLAG(bn->flags, BGP_NODE_PROCESS_SCHEDULED)) @@ -11061,7 +11117,7 @@ static int bgp_show_community(struct vty *vty, struct bgp *bgp, const char *comstr, int exact, afi_t afi, safi_t safi, uint16_t show_flags); -static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, +static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_table *table, enum bgp_show_type type, void *output_arg, const char *rd, int is_last, unsigned long *output_cum, unsigned long *total_cum, @@ -11395,7 +11451,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, vty_out(vty, ASN_FORMAT(bgp->asnotation), &bgp->as); vty_out(vty, "\n"); - if (!detail_routes) { + if (!detail_routes && safi != SAFI_LINKSTATE) { vty_out(vty, BGP_SHOW_SCODE_HEADER); vty_out(vty, BGP_SHOW_NCODE_HEADER); vty_out(vty, BGP_SHOW_OCODE_HEADER); @@ -11422,12 +11478,12 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, if (type == bgp_show_type_dampend_paths || type == bgp_show_type_damp_neighbor) damp_route_vty_out(vty, dest_p, pi, display, - AFI_IP, safi, use_json, + afi, safi, use_json, json_paths); else if (type == bgp_show_type_flap_statistics || type == bgp_show_type_flap_neighbor) flap_route_vty_out(vty, dest_p, pi, display, - AFI_IP, safi, use_json, + afi, safi, use_json, json_paths); else { if (detail_routes || detail_json) { @@ -11583,7 +11639,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, return CMD_SUCCESS; } -int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, +int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd_match, enum bgp_show_type type, void *output_arg, uint16_t show_flags) @@ -11612,7 +11668,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, memcpy(&prd, dest_p, sizeof(struct prefix_rd)); prefix_rd2str(&prd, rd, sizeof(rd), bgp->asnotation); - bgp_show_table(vty, bgp, safi, itable, type, output_arg, + bgp_show_table(vty, bgp, afi, safi, itable, type, output_arg, rd, next == NULL, &output_cum, &total_cum, &json_header_depth, show_flags, RPKI_NOT_BEING_USED); @@ -11662,7 +11718,7 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, table = bgp->rib[afi][safi]; /* use MPLS and ENCAP specific shows until they are merged */ if (safi == SAFI_MPLS_VPN) { - return bgp_show_table_rd(vty, bgp, safi, table, NULL, type, + return bgp_show_table_rd(vty, bgp, afi, safi, table, NULL, type, output_arg, show_flags); } @@ -11675,7 +11731,7 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, if (safi == SAFI_EVPN) return bgp_evpn_show_all_routes(vty, bgp, type, use_json, 0); - return bgp_show_table(vty, bgp, safi, table, type, output_arg, NULL, 1, + return bgp_show_table(vty, bgp, afi, safi, table, type, output_arg, NULL, 1, NULL, NULL, &json_header_depth, show_flags, rpki_target_state); } @@ -11999,7 +12055,7 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd, || CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)))) route_vty_out_detail(vty, bgp, bgp_node, bgp_dest_get_prefix(bgp_node), pi, - AFI_IP, safi, rpki_curr_state, + afi, safi, rpki_curr_state, json_paths); } @@ -12028,6 +12084,8 @@ const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_LABELED_UNICAST: + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_FLOWSPEC: case SAFI_MAX: return NULL; @@ -12131,7 +12189,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, rm_p); if (type5_pfxlen == match.prefixlen) { is_exact_pfxlen_match = true; - bgp_dest_unlock_node(rm); + rm = bgp_dest_unlock_node(rm); + + assert(rm); break; } } @@ -12942,6 +13002,62 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, return CMD_SUCCESS; } +/* BGP route print out function */ +DEFPY (show_ip_bgp_link_state, show_ip_bgp_link_state_cmd, + "show [ip] bgp [ VIEWVRFNAME] link-state link-state\ + [all$all]\ + [version (1-4294967295)\ + |detail-routes$detail_routes\ + ] [json$uj [detail$detail_json] | wide$wide]", + SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR + BGP_AF_STR + BGP_AF_MODIFIER_STR + "Display the entries for all address families\n" + "Display prefixes with matching version numbers\n" + "Version number and above\n" + "Display detailed version of all routes\n" + JSON_STR + "Display detailed version of JSON output\n" + "Increase table width for longer prefixes\n") +{ + afi_t afi = AFI_LINKSTATE; + safi_t safi = SAFI_LINKSTATE; + enum bgp_show_type sh_type = bgp_show_type_normal; + void *output_arg = NULL; + struct bgp *bgp = NULL; + int idx = 0; + uint16_t show_flags = 0; + enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED; + + if (uj) { + argc--; + SET_FLAG(show_flags, BGP_SHOW_OPT_JSON); + } + + if (detail_json) + SET_FLAG(show_flags, BGP_SHOW_OPT_JSON_DETAIL); + + if (detail_routes) + SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL); + + if (wide) + SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE); + + bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, + &bgp, uj); + if (!idx) + return CMD_WARNING; + + /* Display prefixes with matching version numbers */ + if (argv_find(argv, argc, "version", &idx)) { + sh_type = bgp_show_type_prefix_version; + output_arg = argv[idx + 1]->arg; + } + + return bgp_show(vty, bgp, afi, safi, sh_type, output_arg, show_flags, + rpki_target_state); +} + DEFUN (show_ip_bgp_route, show_ip_bgp_route_cmd, "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] [] [rpki ] [json]", @@ -13022,13 +13138,13 @@ DEFUN (show_ip_bgp_route, DEFUN (show_ip_bgp_regexp, show_ip_bgp_regexp_cmd, - "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] regexp REGEX [json]", + "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_WITH_LS_CMD_STR" ["BGP_SAFI_WITH_LABEL_LS_CMD_STR"]] regexp REGEX [json]", SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR - BGP_AFI_HELP_STR - BGP_SAFI_WITH_LABEL_HELP_STR + BGP_AFI_WITH_LS_HELP_STR + BGP_SAFI_WITH_LABEL_LS_HELP_STR "Display routes matching the AS path regular expression\n" "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n" JSON_STR) @@ -13275,6 +13391,8 @@ static void bgp_table_stats_walker(struct event *t) case AFI_L2VPN: space = EVPN_ROUTE_PREFIXLEN; break; + case AFI_LINKSTATE: + /* TODO */ case AFI_UNSPEC: case AFI_MAX: return; @@ -13531,6 +13649,8 @@ static int bgp_table_stats_single(struct vty *vty, struct bgp *bgp, afi_t afi, case AFI_L2VPN: bitlen = EVPN_ROUTE_PREFIXLEN; break; + case AFI_LINKSTATE: + /* TODO */ case AFI_UNSPEC: case AFI_MAX: break; @@ -14565,13 +14685,13 @@ DEFPY (show_ip_bgp_instance_neighbor_bestpath_route, DEFPY(show_ip_bgp_instance_neighbor_advertised_route, show_ip_bgp_instance_neighbor_advertised_route_cmd, - "show [ip] bgp [ VIEWVRFNAME] [" BGP_AFI_CMD_STR " [" BGP_SAFI_WITH_LABEL_CMD_STR "]] [all$all] neighbors [route-map RMAP_NAME$route_map] [$prefix | detail$detail] [json$uj | wide$wide]", + "show [ip] bgp [ VIEWVRFNAME] [" BGP_AFI_WITH_LS_CMD_STR " [" BGP_SAFI_WITH_LABEL_LS_CMD_STR "]] [all$all] neighbors [route-map RMAP_NAME$route_map] [$prefix | detail$detail] [json$uj | wide$wide]", SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR - BGP_AFI_HELP_STR - BGP_SAFI_WITH_LABEL_HELP_STR + BGP_AFI_WITH_LS_HELP_STR + BGP_SAFI_WITH_LABEL_LS_HELP_STR "Display the entries for all address families\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" @@ -14625,6 +14745,12 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route, if (!idx) return CMD_WARNING; + if (afi == AFI_LINKSTATE && prefix_str) { + vty_out(vty, + "The prefix option cannot be selected with AFI Link-State\n"); + return CMD_WARNING; + } + /* neighbors */ argv_find(argv, argc, "neighbors", &idx); peerstr = argv[++idx]->arg; @@ -14793,8 +14919,8 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer, if (safi == SAFI_LABELED_UNICAST) safi = SAFI_UNICAST; - return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, show_flags, - RPKI_NOT_BEING_USED); + return bgp_show(vty, peer->bgp, afi, safi, type, &peer->connection->su, + show_flags, RPKI_NOT_BEING_USED); } /* @@ -15034,7 +15160,8 @@ static int bgp_distance_unset(struct vty *vty, const char *distance_str, bgp_distance_free(bdistance); bgp_dest_set_bgp_path_info(dest, NULL); - bgp_dest_unlock_node(dest); + dest = bgp_dest_unlock_node(dest); + assert(dest); bgp_dest_unlock_node(dest); return CMD_SUCCESS; @@ -15069,8 +15196,8 @@ uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo, /* Check source address. * Note: for aggregate route, peer can have unspec af type. */ - if (pinfo->sub_type != BGP_ROUTE_AGGREGATE - && !sockunion2hostprefix(&peer->su, &q)) + if (pinfo->sub_type != BGP_ROUTE_AGGREGATE && + !sockunion2hostprefix(&peer->connection->su, &q)) return 0; dest = bgp_node_match(bgp_distance_table[afi][safi], &q); @@ -15546,7 +15673,7 @@ static void show_bgp_peerhash_entry(struct hash_bucket *bucket, void *arg) struct vty *vty = arg; struct peer *peer = bucket->data; - vty_out(vty, "\tPeer: %s %pSU\n", peer->host, &peer->su); + vty_out(vty, "\tPeer: %s %pSU\n", peer->host, &peer->connection->su); } DEFUN (show_bgp_listeners, @@ -15846,6 +15973,7 @@ void bgp_route_init(void) install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_statistics_cmd); install_element(VIEW_NODE, &show_ip_bgp_dampening_params_cmd); install_element(VIEW_NODE, &show_ip_bgp_cmd); + install_element(VIEW_NODE, &show_ip_bgp_link_state_cmd); install_element(VIEW_NODE, &show_ip_bgp_route_cmd); install_element(VIEW_NODE, &show_ip_bgp_regexp_cmd); install_element(VIEW_NODE, &show_ip_bgp_statistics_all_cmd); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index e001bf4f07b2..e9f48ea64778 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -727,7 +727,8 @@ extern struct bgp_path_info * bgp_get_imported_bpi_ultimate(struct bgp_path_info *info); extern void bgp_path_info_add(struct bgp_dest *dest, struct bgp_path_info *pi); extern void bgp_path_info_extra_free(struct bgp_path_info_extra **extra); -extern void bgp_path_info_reap(struct bgp_dest *dest, struct bgp_path_info *pi); +extern struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest, + struct bgp_path_info *pi); extern void bgp_path_info_delete(struct bgp_dest *dest, struct bgp_path_info *pi); extern struct bgp_path_info_extra * @@ -886,7 +887,7 @@ extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_path_info *path, afi_t afi, safi_t safi, enum rpki_states, json_object *json_paths); -extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, +extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, uint16_t show_flags); @@ -895,7 +896,8 @@ extern bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, uint8_t type, uint8_t stype, struct attr *attr, struct bgp_dest *dest); extern int bgp_evpn_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, - struct bgp_path_info *exist, int *paths_eq); + struct bgp_path_info *exist, int *paths_eq, + bool debug); extern void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, struct bgp *bgp, const struct prefix *p, afi_t afi, @@ -914,7 +916,7 @@ extern void bgp_path_info_add_with_caller(const char *caller, extern void bgp_aggregate_free(struct bgp_aggregate *aggregate); extern int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, struct bgp_path_info *exist, int *paths_eq, - struct bgp_maxpaths_cfg *mpath_cfg, int debug, + struct bgp_maxpaths_cfg *mpath_cfg, bool debug, char *pfx_buf, afi_t afi, safi_t safi, enum bgp_path_selection_reason *reason); #define bgp_path_info_add(A, B) \ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index af9490f0b3d2..e0db43f676ad 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -282,14 +282,14 @@ route_match_peer(void *rule, const struct prefix *prefix, void *object) } if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (sockunion_same(su, &peer->su)) + if (sockunion_same(su, &peer->connection->su)) return RMAP_MATCH; return RMAP_NOMATCH; } else { group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - if (sockunion_same(su, &peer->su)) + if (sockunion_same(su, &peer->connection->su)) return RMAP_MATCH; } return RMAP_NOMATCH; @@ -574,11 +574,11 @@ route_match_ip_route_source(void *rule, const struct prefix *pfx, void *object) path = object; peer = path->peer; - if (!peer || sockunion_family(&peer->su) != AF_INET) + if (!peer || sockunion_family(&peer->connection->su) != AF_INET) return RMAP_NOMATCH; p.family = AF_INET; - p.prefix = peer->su.sin.sin_addr; + p.prefix = peer->connection->su.sin.sin_addr; p.prefixlen = IPV4_MAX_BITLEN; alist = access_list_lookup(AFI_IP, (char *)rule); @@ -927,11 +927,11 @@ route_match_ip_route_source_prefix_list(void *rule, const struct prefix *prefix, path = object; peer = path->peer; - if (!peer || sockunion_family(&peer->su) != AF_INET) + if (!peer || sockunion_family(&peer->connection->su) != AF_INET) return RMAP_NOMATCH; p.family = AF_INET; - p.prefix = peer->su.sin.sin_addr; + p.prefix = peer->connection->su.sin.sin_addr; p.prefixlen = IPV4_MAX_BITLEN; plist = prefix_list_lookup(AFI_IP, (char *)rule); @@ -1528,7 +1528,8 @@ static const struct route_map_rule_cmd route_match_aspath_cmd = { struct rmap_community { char *name; uint32_t name_hash; - int exact; + bool exact; + bool any; }; /* Match function for community match. */ @@ -1551,6 +1552,12 @@ route_match_community(void *rule, const struct prefix *prefix, void *object) if (community_list_exact_match( bgp_attr_get_community(path->attr), list)) return RMAP_MATCH; + } else if (rcom->any) { + if (!bgp_attr_get_community(path->attr)) + return RMAP_OKAY; + if (community_list_any_match(bgp_attr_get_community(path->attr), + list)) + return RMAP_MATCH; } else { if (community_list_match(bgp_attr_get_community(path->attr), list)) @@ -1574,10 +1581,15 @@ static void *route_match_community_compile(const char *arg) len = p - arg; rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1); memcpy(rcom->name, arg, len); - rcom->exact = 1; + p++; + if (*p == 'e') + rcom->exact = true; + else + rcom->any = true; } else { rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); - rcom->exact = 0; + rcom->exact = false; + rcom->any = false; } rcom->name_hash = bgp_clist_hash_key(rcom->name); @@ -1637,6 +1649,12 @@ route_match_lcommunity(void *rule, const struct prefix *prefix, void *object) if (lcommunity_list_exact_match( bgp_attr_get_lcommunity(path->attr), list)) return RMAP_MATCH; + } else if (rcom->any) { + if (!bgp_attr_get_lcommunity(path->attr)) + return RMAP_OKAY; + if (lcommunity_list_any_match(bgp_attr_get_lcommunity(path->attr), + list)) + return RMAP_MATCH; } else { if (lcommunity_list_match(bgp_attr_get_lcommunity(path->attr), list)) @@ -1660,10 +1678,15 @@ static void *route_match_lcommunity_compile(const char *arg) len = p - arg; rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1); memcpy(rcom->name, arg, len); - rcom->exact = 1; + p++; + if (*p == 'e') + rcom->exact = true; + else + rcom->any = true; } else { rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); - rcom->exact = 0; + rcom->exact = false; + rcom->any = false; } rcom->name_hash = bgp_clist_hash_key(rcom->name); @@ -4340,7 +4363,7 @@ static void bgp_route_map_process_peer(const char *rmap_name, && (strcmp(rmap_name, filter->map[RMAP_IN].name) == 0)) { filter->map[RMAP_IN].map = map; - if (route_update && peer_established(peer)) { + if (route_update && peer_established(peer->connection)) { if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) { if (bgp_debug_update(peer, NULL, NULL, 1)) @@ -5493,15 +5516,15 @@ DEFUN_YANG(no_match_alias, no_match_alias_cmd, "no match alias [ALIAS_NAME]", return nb_cli_apply_changes(vty, NULL); } -DEFPY_YANG (match_community, - match_community_cmd, - "match community <(1-99)|(100-500)|COMMUNITY_LIST_NAME> [exact-match]", - MATCH_STR - "Match BGP community list\n" - "Community-list number (standard)\n" - "Community-list number (expanded)\n" - "Community-list name\n" - "Do exact matching of communities\n") +DEFPY_YANG( + match_community, match_community_cmd, + "match community <(1-99)|(100-500)|COMMUNITY_LIST_NAME> []", + MATCH_STR "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n" + "Do exact matching of communities\n" + "Do matching of any community\n") { const char *xpath = "./match-condition[condition='frr-bgp-route-map:match-community']"; @@ -5517,35 +5540,35 @@ DEFPY_YANG (match_community, xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[idx_comm_list]->arg); - if (argc == 4) { - snprintf( - xpath_match, sizeof(xpath_match), - "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", - xpath); + snprintf(xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", + xpath); + if (exact) nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true"); - } else { - snprintf( - xpath_match, sizeof(xpath_match), - "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", - xpath); - nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, - "false"); - } + else + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false"); + + snprintf(xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any", + xpath); + if (any) + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false"); return nb_cli_apply_changes(vty, NULL); } -DEFUN_YANG (no_match_community, - no_match_community_cmd, - "no match community [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> [exact-match]]", - NO_STR - MATCH_STR - "Match BGP community list\n" - "Community-list number (standard)\n" - "Community-list number (expanded)\n" - "Community-list name\n" - "Do exact matching of communities\n") +DEFUN_YANG( + no_match_community, no_match_community_cmd, + "no match community [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> []]", + NO_STR MATCH_STR "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n" + "Do exact matching of communities\n" + "Do matching of any community\n") { const char *xpath = "./match-condition[condition='frr-bgp-route-map:match-community']"; @@ -5554,15 +5577,15 @@ DEFUN_YANG (no_match_community, return nb_cli_apply_changes(vty, NULL); } -DEFPY_YANG (match_lcommunity, - match_lcommunity_cmd, - "match large-community <(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> [exact-match]", - MATCH_STR - "Match BGP large community list\n" - "Large Community-list number (standard)\n" - "Large Community-list number (expanded)\n" - "Large Community-list name\n" - "Do exact matching of communities\n") +DEFPY_YANG( + match_lcommunity, match_lcommunity_cmd, + "match large-community <(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> []", + MATCH_STR "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n" + "Do exact matching of communities\n" + "Do matching of any community\n") { const char *xpath = "./match-condition[condition='frr-bgp-route-map:match-large-community']"; @@ -5578,35 +5601,35 @@ DEFPY_YANG (match_lcommunity, xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[idx_lcomm_list]->arg); - if (argc == 4) { - snprintf( - xpath_match, sizeof(xpath_match), - "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", - xpath); + snprintf(xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", + xpath); + if (exact) nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true"); - } else { - snprintf( - xpath_match, sizeof(xpath_match), - "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", - xpath); - nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, - "false"); - } + else + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false"); + + snprintf(xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any", + xpath); + if (any) + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false"); return nb_cli_apply_changes(vty, NULL); } -DEFUN_YANG (no_match_lcommunity, - no_match_lcommunity_cmd, - "no match large-community [<(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> [exact-match]]", - NO_STR - MATCH_STR - "Match BGP large community list\n" - "Large Community-list number (standard)\n" - "Large Community-list number (expanded)\n" - "Large Community-list name\n" - "Do exact matching of communities\n") +DEFUN_YANG( + no_match_lcommunity, no_match_lcommunity_cmd, + "no match large-community [<(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> []]", + NO_STR MATCH_STR "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n" + "Do exact matching of communities\n" + "Do matching of any community\n") { const char *xpath = "./match-condition[condition='frr-bgp-route-map:match-large-community']"; @@ -6207,27 +6230,12 @@ DEFPY_YANG( DEFUN_YANG (no_set_aspath_prepend, no_set_aspath_prepend_cmd, - "no set as-path prepend [ASNUM]", - NO_STR - SET_STR - "Transform BGP AS_PATH attribute\n" - "Prepend to the as-path\n" - AS_STR) -{ - const char *xpath = - "./set-action[action='frr-bgp-route-map:as-path-prepend']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, NULL); -} - -DEFUN_YANG (no_set_aspath_prepend_lastas, - no_set_aspath_prepend_lastas_cmd, - "no set as-path prepend last-as [(1-10)]", + "no set as-path prepend [ASNUM] [last-as [(1-10)]]", NO_STR SET_STR "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" + AS_STR "Use the peers AS-number\n" "Number of times to insert\n") { @@ -7915,7 +7923,6 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &set_aspath_replace_asn_cmd); install_element(RMAP_NODE, &set_aspath_replace_access_list_cmd); install_element(RMAP_NODE, &no_set_aspath_prepend_cmd); - install_element(RMAP_NODE, &no_set_aspath_prepend_lastas_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_all_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_access_list_cmd); diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c index ae695a6f80a1..abebfe5155c1 100644 --- a/bgpd/bgp_routemap_nb.c +++ b/bgpd/bgp_routemap_nb.c @@ -164,6 +164,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy, } }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_destroy, + } + }, { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:ipv4-address", .cbs = { diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h index 3ff58f71a733..28e4188026c4 100644 --- a/bgpd/bgp_routemap_nb.h +++ b/bgpd/bgp_routemap_nb.h @@ -65,6 +65,10 @@ int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify( + struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_destroy( + struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_ipv6_address_modify(struct nb_cb_modify_args *args); diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index 9ef9031e54a5..370295b6c31e 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -1127,6 +1127,7 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish( struct routemap_hook_context *rhc; const char *value; bool exact_match = false; + bool any = false; char *argstr; const char *condition; route_map_event_t event; @@ -1140,12 +1141,21 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish( exact_match = yang_dnode_get_bool( args->dnode, "./comm-list-name-exact-match"); + if (yang_dnode_exists(args->dnode, "./comm-list-name-any")) + any = yang_dnode_get_bool(args->dnode, "./comm-list-name-any"); + if (exact_match) { argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, strlen(value) + strlen("exact-match") + 2); snprintf(argstr, (strlen(value) + strlen("exact-match") + 2), "%s exact-match", value); + } else if (any) { + argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, + strlen(value) + strlen("any") + 2); + + snprintf(argstr, (strlen(value) + strlen("any") + 2), "%s any", + value); } else argstr = (char *)value; @@ -1217,6 +1227,39 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam } +/* + * XPath: + * /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any + */ +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + /* * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match */ diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index c6e3131e02fa..f0b2ffdee522 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -520,7 +520,7 @@ static void revalidate_all_routes(void) if (!bgp->rib[afi][safi]) continue; - if (!peer_established(peer)) + if (!peer_established(peer->connection)) continue; rvp = XCALLOC(MTYPE_BGP_RPKI_REVALIDATE, diff --git a/bgpd/bgp_snmp_bgp4.c b/bgpd/bgp_snmp_bgp4.c index 8af87ae4b245..692e232a83c2 100644 --- a/bgpd/bgp_snmp_bgp4.c +++ b/bgpd/bgp_snmp_bgp4.c @@ -83,10 +83,10 @@ static struct peer *peer_lookup_addr_ipv4(struct in_addr *src) for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) { for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { - if (sockunion_family(&peer->su) != AF_INET) + if (sockunion_family(&peer->connection->su) != AF_INET) continue; - if (sockunion2ip(&peer->su) == src->s_addr) + if (sockunion2ip(&peer->connection->su) == src->s_addr) return peer; } } @@ -104,22 +104,22 @@ static struct peer *bgp_peer_lookup_next(struct in_addr *src) for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) { for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { - if (sockunion_family(&peer->su) != AF_INET) + if (sockunion_family(&peer->connection->su) != AF_INET) continue; - if (ntohl(sockunion2ip(&peer->su)) <= + if (ntohl(sockunion2ip(&peer->connection->su)) <= ntohl(src->s_addr)) continue; if (!next_peer || - ntohl(sockunion2ip(&next_peer->su)) > - ntohl(sockunion2ip(&peer->su))) { + ntohl(sockunion2ip(&next_peer->connection->su)) > + ntohl(sockunion2ip(&peer->connection->su))) { next_peer = peer; } } } if (next_peer) { - src->s_addr = sockunion2ip(&next_peer->su); + src->s_addr = sockunion2ip(&next_peer->connection->su); return next_peer; } @@ -173,6 +173,7 @@ static int write_bgpPeerTable(int action, uint8_t *var_val, { struct in_addr addr; struct peer *peer; + struct peer_connection *connection; long intval; if (var_val_type != ASN_INTEGER) { @@ -190,6 +191,8 @@ static int write_bgpPeerTable(int action, uint8_t *var_val, if (!peer) return SNMP_ERR_NOSUCHNAME; + connection = peer->connection; + if (action != SNMP_MSG_INTERNAL_SET_COMMIT) return SNMP_ERR_NOERROR; @@ -202,7 +205,7 @@ static int write_bgpPeerTable(int action, uint8_t *var_val, #define BGP_PeerAdmin_start 2 /* When the peer is established, */ if (intval == BGP_PeerAdmin_stop) - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(connection, BGP_Stop); else if (intval == BGP_PeerAdmin_start) ; /* Do nothing. */ else @@ -398,7 +401,7 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[], /* Set OID offset for prefix. */ offset = name + v->namelen; oid2in_addr(offset, IN_ADDR_SIZE, &addr->prefix); - offset += IN_ADDR_SIZE; + offset++; /* Prefix length. */ addr->prefixlen = *offset; @@ -414,7 +417,8 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[], if (dest) { for (path = bgp_dest_get_bgp_path_info(dest); path; path = path->next) - if (sockunion_same(&path->peer->su, &su)) + if (sockunion_same(&path->peer->connection->su, + &su)) return path; bgp_dest_unlock_node(dest); @@ -464,15 +468,18 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[], for (path = bgp_dest_get_bgp_path_info(dest); path; path = path->next) { - if (path->peer->su.sin.sin_family == AF_INET && + if (path->peer->connection->su.sin.sin_family == + AF_INET && ntohl(paddr.s_addr) < - ntohl(path->peer->su.sin.sin_addr - .s_addr)) { + ntohl(path->peer->connection->su.sin + .sin_addr.s_addr)) { if (min) { - if (ntohl(path->peer->su.sin + if (ntohl(path->peer->connection + ->su.sin .sin_addr .s_addr) < - ntohl(min->peer->su.sin + ntohl(min->peer->connection + ->su.sin .sin_addr .s_addr)) min = path; @@ -490,11 +497,12 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[], offset = name + v->namelen; oid_copy_in_addr(offset, &rn_p->u.prefix4); - offset += IN_ADDR_SIZE; + offset++; *offset = rn_p->prefixlen; offset++; oid_copy_in_addr(offset, - &min->peer->su.sin.sin_addr); + &min->peer->connection->su.sin + .sin_addr); addr->prefix = rn_p->u.prefix4; addr->prefixlen = rn_p->prefixlen; @@ -532,7 +540,7 @@ static uint8_t *bgp4PathAttrTable(struct variable *v, oid name[], switch (v->magic) { case BGP4PATHATTRPEER: /* 1 */ - return SNMP_IPADDRESS(path->peer->su.sin.sin_addr); + return SNMP_IPADDRESS(path->peer->connection->su.sin.sin_addr); case BGP4PATHATTRIPADDRPREFIXLEN: /* 2 */ return SNMP_INTEGER(addr.prefixlen); case BGP4PATHATTRIPADDRPREFIX: /* 3 */ @@ -754,10 +762,11 @@ int bgpTrapEstablished(struct peer *peer) int ret; struct in_addr addr; oid index[sizeof(oid) * IN_ADDR_SIZE]; + struct peer_connection *connection = peer->connection; /* Check if this peer just went to Established */ - if ((peer->connection->ostatus != OpenConfirm) || - !(peer_established(peer))) + if ((connection->ostatus != OpenConfirm) || + !(peer_established(connection))) return 0; ret = inet_aton(peer->host, &addr); diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c index 5e77a9297b50..fb6f13a6ca21 100644 --- a/bgpd/bgp_snmp_bgp4v2.c +++ b/bgpd/bgp_snmp_bgp4v2.c @@ -43,14 +43,16 @@ static struct peer *peer_lookup_all_vrf(struct ipaddr *addr) for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) { for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { - switch (sockunion_family(&peer->su)) { + switch (sockunion_family(&peer->connection->su)) { case AF_INET: - if (IPV4_ADDR_SAME(&peer->su.sin.sin_addr, + if (IPV4_ADDR_SAME(&peer->connection->su.sin + .sin_addr, &addr->ip._v4_addr)) return peer; break; case AF_INET6: - if (IPV6_ADDR_SAME(&peer->su.sin6.sin6_addr, + if (IPV6_ADDR_SAME(&peer->connection->su.sin6 + .sin6_addr, &addr->ip._v6_addr)) return peer; break; @@ -74,38 +76,47 @@ static struct peer *peer_lookup_all_vrf_next(struct ipaddr *addr, oid *offset, for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) { for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { - sa_family_t peer_family = sockunion_family(&peer->su); + sa_family_t peer_family = + sockunion_family(&peer->connection->su); if (peer_family != family) continue; - switch (sockunion_family(&peer->su)) { + switch (peer_family) { case AF_INET: oid2in_addr(offset, IN_ADDR_SIZE, &addr->ip._v4_addr); - if (IPV4_ADDR_CMP(&peer->su.sin.sin_addr, + if (IPV4_ADDR_CMP(&peer->connection->su.sin + .sin_addr, &addr->ip._v4_addr) < 0 || - IPV4_ADDR_SAME(&peer->su.sin.sin_addr, + IPV4_ADDR_SAME(&peer->connection->su.sin + .sin_addr, &addr->ip._v4_addr)) continue; if (!next_peer || - IPV4_ADDR_CMP(&next_peer->su.sin.sin_addr, - &peer->su.sin.sin_addr) > 0) + IPV4_ADDR_CMP(&next_peer->connection->su.sin + .sin_addr, + &peer->connection->su.sin + .sin_addr) > 0) next_peer = peer; break; case AF_INET6: oid2in6_addr(offset, &addr->ip._v6_addr); - if (IPV6_ADDR_CMP(&peer->su.sin6.sin6_addr, + if (IPV6_ADDR_CMP(&peer->connection->su.sin6 + .sin6_addr, &addr->ip._v6_addr) < 0 || - IPV6_ADDR_SAME(&peer->su.sin6.sin6_addr, + IPV6_ADDR_SAME(&peer->connection->su.sin6 + .sin6_addr, &addr->ip._v6_addr)) continue; if (!next_peer || - IPV6_ADDR_CMP(&next_peer->su.sin6.sin6_addr, - &peer->su.sin6.sin6_addr) > 0) + IPV6_ADDR_CMP(&next_peer->connection->su + .sin6.sin6_addr, + &peer->connection->su.sin6 + .sin6_addr) > 0) next_peer = peer; break; @@ -128,7 +139,7 @@ static struct peer *bgpv2PeerTable_lookup(struct variable *v, oid name[], struct peer *peer = NULL; size_t namelen = v ? v->namelen : BGP4V2_PEER_ENTRY_OFFSET; oid *offset = name + namelen; - sa_family_t family = name[namelen - 1] == 4 ? AF_INET : AF_INET6; + sa_family_t family = name[namelen - 1] == 1 ? AF_INET : AF_INET6; int afi_len = IN_ADDR_SIZE; size_t offsetlen = *length - namelen; @@ -158,13 +169,15 @@ static struct peer *bgpv2PeerTable_lookup(struct variable *v, oid name[], if (peer == NULL) return NULL; - switch (sockunion_family(&peer->su)) { + switch (sockunion_family(&peer->connection->su)) { case AF_INET: - oid_copy_in_addr(offset, &peer->su.sin.sin_addr); + oid_copy_in_addr(offset, + &peer->connection->su.sin.sin_addr); *length = afi_len + namelen; return peer; case AF_INET6: - oid_copy_in6_addr(offset, &peer->su.sin6.sin6_addr); + oid_copy_in6_addr(offset, + &peer->connection->su.sin6.sin6_addr); *length = afi_len + namelen; return peer; default: @@ -425,7 +438,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, unsigned int len; struct ipaddr paddr = {}; size_t namelen = v ? v->namelen : BGP4V2_NLRI_ENTRY_OFFSET; - sa_family_t family = name[namelen - 1] == 4 ? AF_INET : AF_INET6; + sa_family_t family = name[namelen - 1] == 1 ? AF_INET : AF_INET6; afi_t afi = AFI_IP; size_t afi_len = IN_ADDR_SIZE; @@ -467,7 +480,8 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, if (dest) { for (path = bgp_dest_get_bgp_path_info(dest); path; path = path->next) - if (sockunion_same(&path->peer->su, &su)) + if (sockunion_same(&path->peer->connection->su, + &su)) return path; bgp_dest_unlock_node(dest); @@ -532,27 +546,29 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, for (path = bgp_dest_get_bgp_path_info(dest); path; path = path->next) { sa_family_t path_family = - sockunion_family(&path->peer->su); + sockunion_family(&path->peer->connection->su); if (path_family == AF_INET && IPV4_ADDR_CMP(&paddr.ip._v4_addr, - &path->peer->su.sin.sin_addr) < 0) { + &path->peer->connection->su.sin + .sin_addr) < 0) { if (!min || (min && - IPV4_ADDR_CMP( - &path->peer->su.sin.sin_addr, - &min->peer->su.sin.sin_addr) < 0)) + IPV4_ADDR_CMP(&path->peer->connection->su + .sin.sin_addr, + &min->peer->connection->su + .sin.sin_addr) < 0)) min = path; } else if (path_family == AF_INET6 && - IPV6_ADDR_CMP( - &paddr.ip._v6_addr, - &path->peer->su.sin6.sin6_addr) < - 0) { + IPV6_ADDR_CMP(&paddr.ip._v6_addr, + &path->peer->connection->su + .sin6.sin6_addr) < 0) { if (!min || (min && - IPV6_ADDR_CMP( - &path->peer->su.sin6.sin6_addr, - &min->peer->su.sin6.sin6_addr) < + IPV6_ADDR_CMP(&path->peer->connection->su + .sin6.sin6_addr, + &min->peer->connection->su + .sin6.sin6_addr) < 0)) min = path; } @@ -578,11 +594,13 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, /* Encode peer's IP into OID */ if (family == AF_INET) { oid_copy_in_addr(offset, - &min->peer->su.sin.sin_addr); + &min->peer->connection->su.sin + .sin_addr); addr->u.prefix4 = rn_p->u.prefix4; } else { - oid_copy_in6_addr( - offset, &min->peer->su.sin6.sin6_addr); + oid_copy_in6_addr(offset, + &min->peer->connection->su + .sin6.sin6_addr); addr->u.prefix6 = rn_p->u.prefix6; } @@ -782,616 +800,616 @@ static struct variable bgpv2_variables[] = { RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_INSTANCE, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_INSTANCE, 1, 1}}, {BGP4V2_PEER_INSTANCE, ASN_UNSIGNED, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_INSTANCE, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_INSTANCE, 1, 2}}, {BGP4V2_PEER_LOCAL_ADDR_TYPE, ASN_INTEGER, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR_TYPE, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR_TYPE, 1, 1}}, {BGP4V2_PEER_LOCAL_ADDR_TYPE, ASN_INTEGER, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR_TYPE, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR_TYPE, 1, 2}}, {BGP4V2_PEER_LOCAL_ADDR, ASN_OCTET_STR, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR, 1, 1}}, {BGP4V2_PEER_LOCAL_ADDR, ASN_OCTET_STR, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR, 1, 2}}, {BGP4V2_PEER_REMOTE_ADDR_TYPE, ASN_INTEGER, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR_TYPE, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR_TYPE, 1, 1}}, {BGP4V2_PEER_REMOTE_ADDR_TYPE, ASN_INTEGER, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR_TYPE, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR_TYPE, 1, 2}}, {BGP4V2_PEER_REMOTE_ADDR, ASN_OCTET_STR, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR, 1, 1}}, {BGP4V2_PEER_REMOTE_ADDR, ASN_OCTET_STR, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR, 1, 2}}, {BGP4V2_PEER_LOCAL_PORT, ASN_UNSIGNED, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 1}}, {BGP4V2_PEER_LOCAL_PORT, ASN_UNSIGNED, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 2}}, {BGP4V2_PEER_LOCAL_AS, ASN_UNSIGNED, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_LOCAL_AS, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_LOCAL_AS, 1, 1}}, {BGP4V2_PEER_LOCAL_AS, ASN_UNSIGNED, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_LOCAL_AS, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_LOCAL_AS, 1, 2}}, {BGP4V2_PEER_LOCAL_IDENTIFIER, ASN_OCTET_STR, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_LOCAL_IDENTIFIER, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_LOCAL_IDENTIFIER, 1, 1}}, {BGP4V2_PEER_LOCAL_IDENTIFIER, ASN_OCTET_STR, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_LOCAL_IDENTIFIER, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_LOCAL_IDENTIFIER, 1, 2}}, {BGP4V2_PEER_REMOTE_PORT, ASN_UNSIGNED, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 1}}, {BGP4V2_PEER_REMOTE_PORT, ASN_UNSIGNED, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 2}}, {BGP4V2_PEER_REMOTE_AS, ASN_UNSIGNED, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_REMOTE_AS, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_REMOTE_AS, 1, 1}}, {BGP4V2_PEER_REMOTE_AS, ASN_UNSIGNED, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_REMOTE_AS, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_REMOTE_AS, 1, 2}}, {BGP4V2_PEER_REMOTE_IDENTIFIER, ASN_OCTET_STR, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_REMOTE_IDENTIFIER, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_REMOTE_IDENTIFIER, 1, 1}}, {BGP4V2_PEER_REMOTE_IDENTIFIER, ASN_OCTET_STR, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_REMOTE_IDENTIFIER, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_REMOTE_IDENTIFIER, 1, 2}}, {BGP4V2_PEER_ADMIN_STATUS, ASN_INTEGER, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_ADMIN_STATUS, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_ADMIN_STATUS, 1, 1}}, {BGP4V2_PEER_ADMIN_STATUS, ASN_INTEGER, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_ADMIN_STATUS, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_ADMIN_STATUS, 1, 2}}, {BGP4V2_PEER_STATE, ASN_INTEGER, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_STATE, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_STATE, 1, 1}}, {BGP4V2_PEER_STATE, ASN_INTEGER, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_STATE, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_STATE, 1, 2}}, {BGP4V2_PEER_DESCRIPTION, ASN_OCTET_STR, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_DESCRIPTION, 1, 4}}, + {1, 2, 1, BGP4V2_PEER_DESCRIPTION, 1, 1}}, {BGP4V2_PEER_DESCRIPTION, ASN_OCTET_STR, RONLY, bgpv2PeerTable, 6, - {1, 2, 1, BGP4V2_PEER_DESCRIPTION, 2, 16}}, + {1, 2, 1, BGP4V2_PEER_DESCRIPTION, 1, 2}}, /* bgp4V2PeerErrorsEntry */ {BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, ASN_UNSIGNED, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 4}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 1}}, {BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, ASN_UNSIGNED, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 2, 16}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 2}}, {BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, ASN_UNSIGNED, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 4}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 1}}, {BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, ASN_UNSIGNED, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 2, 16}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 2}}, {BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, - ASN_UNSIGNED, + ASN_TIMETICKS, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, 1, 4}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, 1, 1}}, {BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, - ASN_UNSIGNED, + ASN_TIMETICKS, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, 2, 16}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, 1, 2}}, {BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, ASN_OCTET_STR, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 4}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 1}}, {BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, ASN_OCTET_STR, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 2, 16}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 2}}, {BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, ASN_OCTET_STR, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, 1, 4}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, 1, 1}}, {BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, ASN_OCTET_STR, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, 2, 16}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, 1, 2}}, {BGP4V2_PEER_LAST_ERROR_CODE_SENT, ASN_UNSIGNED, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_SENT, 1, 4}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_SENT, 1, 1}}, {BGP4V2_PEER_LAST_ERROR_CODE_SENT, ASN_UNSIGNED, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_SENT, 2, 16}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_SENT, 1, 2}}, {BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, ASN_UNSIGNED, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, 1, 4}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, 1, 1}}, {BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, ASN_UNSIGNED, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, 2, 16}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, 1, 2}}, {BGP4V2_PEER_LAST_ERROR_SENT_TIME, - ASN_UNSIGNED, + ASN_TIMETICKS, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TIME, 1, 4}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TIME, 1, 1}}, {BGP4V2_PEER_LAST_ERROR_SENT_TIME, - ASN_UNSIGNED, + ASN_TIMETICKS, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TIME, 2, 16}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TIME, 1, 2}}, {BGP4V2_PEER_LAST_ERROR_SENT_TEXT, ASN_OCTET_STR, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TEXT, 1, 4}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TEXT, 1, 1}}, {BGP4V2_PEER_LAST_ERROR_SENT_TEXT, ASN_OCTET_STR, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TEXT, 2, 16}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TEXT, 1, 2}}, {BGP4V2_PEER_LAST_ERROR_SENT_DATA, ASN_OCTET_STR, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_DATA, 1, 4}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_DATA, 1, 1}}, {BGP4V2_PEER_LAST_ERROR_SENT_DATA, ASN_OCTET_STR, RONLY, bgpv2PeerErrorsTable, 6, - {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_DATA, 2, 16}}, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_DATA, 1, 2}}, /* bgp4V2PeerEventTimesEntry */ {BGP4V2_PEER_FSM_ESTABLISHED_TIME, ASN_UNSIGNED, RONLY, bgpv2PeerEventTimesTable, 6, - {1, 4, 1, BGP4V2_PEER_FSM_ESTABLISHED_TIME, 1, 4}}, + {1, 4, 1, BGP4V2_PEER_FSM_ESTABLISHED_TIME, 1, 1}}, {BGP4V2_PEER_FSM_ESTABLISHED_TIME, ASN_UNSIGNED, RONLY, bgpv2PeerEventTimesTable, 6, - {1, 4, 1, BGP4V2_PEER_FSM_ESTABLISHED_TIME, 2, 16}}, + {1, 4, 1, BGP4V2_PEER_FSM_ESTABLISHED_TIME, 1, 2}}, {BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME, ASN_UNSIGNED, RONLY, bgpv2PeerEventTimesTable, 6, - {1, 4, 1, BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME, 1, 4}}, + {1, 4, 1, BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME, 1, 1}}, {BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME, ASN_UNSIGNED, RONLY, bgpv2PeerEventTimesTable, 6, - {1, 4, 1, BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME, 2, 16}}, + {1, 4, 1, BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME, 1, 2}}, /* bgp4V2NlriTable */ {BGP4V2_NLRI_INDEX, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_INDEX, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_INDEX, 1, 1}}, {BGP4V2_NLRI_INDEX, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_INDEX, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_INDEX, 1, 2}}, {BGP4V2_NLRI_AFI, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AFI, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_AFI, 1, 1}}, {BGP4V2_NLRI_AFI, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AFI, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_AFI, 1, 2}}, {BGP4V2_NLRI_SAFI, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_SAFI, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_SAFI, 1, 1}}, {BGP4V2_NLRI_SAFI, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_SAFI, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_SAFI, 1, 2}}, {BGP4V2_NLRI_PREFIX_TYPE, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_PREFIX_TYPE, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_PREFIX_TYPE, 1, 1}}, {BGP4V2_NLRI_PREFIX_TYPE, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_PREFIX_TYPE, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_PREFIX_TYPE, 1, 2}}, {BGP4V2_NLRI_PREFIX, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_PREFIX, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_PREFIX, 1, 1}}, {BGP4V2_NLRI_PREFIX, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_PREFIX, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_PREFIX, 1, 2}}, {BGP4V2_NLRI_PREFIX_LEN, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_PREFIX_LEN, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_PREFIX_LEN, 1, 1}}, {BGP4V2_NLRI_PREFIX_LEN, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_PREFIX_LEN, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_PREFIX_LEN, 1, 2}}, {BGP4V2_NLRI_BEST, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_BEST, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_BEST, 1, 1}}, {BGP4V2_NLRI_BEST, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_BEST, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_BEST, 1, 2}}, {BGP4V2_NLRI_CALC_LOCAL_PREF, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_CALC_LOCAL_PREF, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_CALC_LOCAL_PREF, 1, 1}}, {BGP4V2_NLRI_CALC_LOCAL_PREF, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_CALC_LOCAL_PREF, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_CALC_LOCAL_PREF, 1, 2}}, {BGP4V2_NLRI_ORIGIN, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_ORIGIN, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_ORIGIN, 1, 1}}, {BGP4V2_NLRI_ORIGIN, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_ORIGIN, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_ORIGIN, 1, 2}}, {BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE, 1, 1}}, {BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE, 1, 2}}, {BGP4V2_NLRI_NEXT_HOP_ADDR, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR, 1, 1}}, {BGP4V2_NLRI_NEXT_HOP_ADDR, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR, 1, 2}}, {BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE, 1, 1}}, {BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE, 1, 2}}, {BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR, 1, 1}}, {BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR, 1, 2}}, {BGP4V2_NLRI_LOCAL_PREF_PRESENT, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF_PRESENT, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF_PRESENT, 1, 1}}, {BGP4V2_NLRI_LOCAL_PREF_PRESENT, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF_PRESENT, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF_PRESENT, 1, 2}}, {BGP4V2_NLRI_LOCAL_PREF, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF, 1, 1}}, {BGP4V2_NLRI_LOCAL_PREF, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF, 1, 2}}, {BGP4V2_NLRI_MED_PRESENT, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_MED_PRESENT, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_MED_PRESENT, 1, 1}}, {BGP4V2_NLRI_MED_PRESENT, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_MED_PRESENT, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_MED_PRESENT, 1, 2}}, {BGP4V2_NLRI_MED, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_MED, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_MED, 1, 1}}, {BGP4V2_NLRI_MED, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_MED, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_MED, 1, 2}}, {BGP4V2_NLRI_ATOMIC_AGGREGATE, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_ATOMIC_AGGREGATE, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_ATOMIC_AGGREGATE, 1, 1}}, {BGP4V2_NLRI_ATOMIC_AGGREGATE, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_ATOMIC_AGGREGATE, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_ATOMIC_AGGREGATE, 1, 2}}, {BGP4V2_NLRI_AGGREGATOR_PRESENT, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_PRESENT, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_PRESENT, 1, 1}}, {BGP4V2_NLRI_AGGREGATOR_PRESENT, ASN_INTEGER, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_PRESENT, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_PRESENT, 1, 2}}, {BGP4V2_NLRI_AGGREGATOR_AS, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_AS, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_AS, 1, 1}}, {BGP4V2_NLRI_AGGREGATOR_AS, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_AS, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_AS, 1, 2}}, {BGP4V2_NLRI_AGGREGATOR_ADDR, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_ADDR, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_ADDR, 1, 1}}, {BGP4V2_NLRI_AGGREGATOR_ADDR, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_ADDR, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_ADDR, 1, 2}}, {BGP4V2_NLRI_AS_PATH_CALC_LENGTH, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AS_PATH_CALC_LENGTH, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_AS_PATH_CALC_LENGTH, 1, 1}}, {BGP4V2_NLRI_AS_PATH_CALC_LENGTH, ASN_UNSIGNED, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AS_PATH_CALC_LENGTH, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_AS_PATH_CALC_LENGTH, 1, 2}}, {BGP4V2_NLRI_AS_PATH_STRING, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AS_PATH_STRING, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_AS_PATH_STRING, 1, 1}}, {BGP4V2_NLRI_AS_PATH_STRING, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AS_PATH_STRING, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_AS_PATH_STRING, 1, 2}}, {BGP4V2_NLRI_AS_PATH, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AS_PATH, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_AS_PATH, 1, 1}}, {BGP4V2_NLRI_AS_PATH, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_AS_PATH, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_AS_PATH, 1, 2}}, {BGP4V2_NLRI_PATH_ATTR_UNKNOWN, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_PATH_ATTR_UNKNOWN, 1, 4}}, + {1, 9, 1, BGP4V2_NLRI_PATH_ATTR_UNKNOWN, 1, 1}}, {BGP4V2_NLRI_PATH_ATTR_UNKNOWN, ASN_OCTET_STR, RONLY, bgp4v2PathAttrTable, 6, - {1, 9, 1, BGP4V2_NLRI_PATH_ATTR_UNKNOWN, 2, 16}}, + {1, 9, 1, BGP4V2_NLRI_PATH_ATTR_UNKNOWN, 1, 2}}, }; int bgp_snmp_bgp4v2_init(struct event_loop *tm) diff --git a/bgpd/bgp_snmp_bgp4v2.h b/bgpd/bgp_snmp_bgp4v2.h index 7cdad586bc91..6587a825c585 100644 --- a/bgpd/bgp_snmp_bgp4v2.h +++ b/bgpd/bgp_snmp_bgp4v2.h @@ -14,6 +14,7 @@ /* bgp4V2PeerEntry: * offset 1.3.6.1.3.5.1.1.2.1.x.(1|2).(4|16) = 13 + * offset 1.3.6.1.4.1.7336.3.2.1.1.2.1.x.1.(1|2) = 16 */ #define BGP4V2_PEER_ENTRY_OFFSET 13 #define BGP4V2_PEER_INSTANCE 1 @@ -49,6 +50,7 @@ /* bgp4V2NlriEntry * offset 1.3.6.1.3.5.1.1.9.1.x.(1|2).(4|16) = 13 + * offset 1.3.6.1.4.1.7336.3.2.1.1.9.1.x.1.(1|2) = 16 */ #define BGP4V2_NLRI_ENTRY_OFFSET 13 #define BGP4V2_NLRI_INDEX 1 diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 149a5b9142b6..e01bf3911349 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -63,7 +63,7 @@ struct bgp_dest *bgp_dest_lock_node(struct bgp_dest *dest) const char *bgp_dest_get_prefix_str(struct bgp_dest *dest) { const struct prefix *p = NULL; - static char str[PREFIX_STRLEN] = {0}; + static char str[PREFIX_STRLEN_EXTENDED] = {0}; p = bgp_dest_get_prefix(dest); if (p) @@ -75,7 +75,7 @@ const char *bgp_dest_get_prefix_str(struct bgp_dest *dest) /* * bgp_dest_unlock_node */ -inline void bgp_dest_unlock_node(struct bgp_dest *dest) +inline struct bgp_dest *bgp_dest_unlock_node(struct bgp_dest *dest) { frrtrace(1, frr_bgp, bgp_dest_unlock, dest); bgp_delete_listnode(dest); @@ -89,9 +89,12 @@ inline void bgp_dest_unlock_node(struct bgp_dest *dest) rt->safi); } XFREE(MTYPE_BGP_NODE, dest); + dest = NULL; rn->info = NULL; } route_unlock_node(rn); + + return dest; } /* @@ -114,6 +117,9 @@ static void bgp_node_destroy(route_table_delegate_t *delegate, node->info = NULL; } + if (family2afi(node->p.family) == AFI_LINKSTATE) + prefix_linkstate_ptr_free(&node->p); + XFREE(MTYPE_ROUTE_NODE, node); } diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 1f28624c16ea..5b4c3be21224 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -112,7 +112,7 @@ extern struct bgp_table *bgp_table_init(struct bgp *bgp, afi_t, safi_t); extern void bgp_table_lock(struct bgp_table *); extern void bgp_table_unlock(struct bgp_table *); extern void bgp_table_finish(struct bgp_table **); -extern void bgp_dest_unlock_node(struct bgp_dest *dest); +extern struct bgp_dest *bgp_dest_unlock_node(struct bgp_dest *dest); extern struct bgp_dest *bgp_dest_lock_node(struct bgp_dest *dest); extern const char *bgp_dest_get_prefix_str(struct bgp_dest *dest); diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index a55e48d8edf9..a2006c3508d4 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -279,6 +279,8 @@ static void *updgrp_hash_alloc(void *p) updgrp = XCALLOC(MTYPE_BGP_UPDGRP, sizeof(struct update_group)); memcpy(updgrp, in, sizeof(struct update_group)); updgrp->conf = XCALLOC(MTYPE_BGP_PEER, sizeof(struct peer)); + updgrp->conf->connection = XCALLOC(MTYPE_BGP_PEER_CONNECTION, + sizeof(struct peer_connection)); conf_copy(updgrp->conf, in->conf, in->afi, in->safi); return updgrp; } @@ -634,7 +636,7 @@ static bool updgrp_hash_cmp(const void *p1, const void *p2) if ((CHECK_FLAG(pe1->flags, PEER_FLAG_LONESOUL) || CHECK_FLAG(pe1->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)) && - !sockunion_same(&pe1->su, &pe2->su)) + !sockunion_same(&pe1->connection->su, &pe2->connection->su)) return false; return true; @@ -687,6 +689,7 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) json_object *json_peers = NULL; json_object *json_pkt_info = NULL; time_t epoch_tbuf, tbuf; + char timebuf[32]; if (!ctx) return CMD_SUCCESS; @@ -722,7 +725,7 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) json_time = json_object_new_object(); json_object_int_add(json_time, "epoch", epoch_tbuf); json_object_string_add(json_time, "epochString", - ctime(&epoch_tbuf)); + ctime_r(&epoch_tbuf, timebuf)); json_object_object_add(json_updgrp, "groupCreateTime", json_time); json_object_string_add(json_updgrp, "afi", @@ -731,7 +734,8 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) safi2str(updgrp->safi)); } else { vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id); - vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime)); + vty_out(vty, " Created: %s", + timestamp_string(updgrp->uptime, timebuf)); } filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi]; @@ -792,7 +796,7 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) json_object_int_add(json_subgrp_time, "epoch", epoch_tbuf); json_object_string_add(json_subgrp_time, "epochString", - ctime(&epoch_tbuf)); + ctime_r(&epoch_tbuf, timebuf)); json_object_object_add(json_subgrp, "groupCreateTime", json_subgrp_time); } else { @@ -800,7 +804,7 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) vty_out(vty, " Update-subgroup %" PRIu64 ":\n", subgrp->id); vty_out(vty, " Created: %s", - timestamp_string(subgrp->uptime)); + timestamp_string(subgrp->uptime, timebuf)); } if (subgrp->split_from.update_group_id @@ -987,13 +991,18 @@ static struct update_group *update_group_find(struct peer_af *paf) struct update_group *updgrp; struct update_group tmp; struct peer tmp_conf; + struct peer_connection tmp_connection; - if (!peer_established(PAF_PEER(paf))) + if (!peer_established((PAF_PEER(paf))->connection)) return NULL; memset(&tmp, 0, sizeof(tmp)); memset(&tmp_conf, 0, sizeof(tmp_conf)); + memset(&tmp_connection, 0, sizeof(struct peer_connection)); + tmp.conf = &tmp_conf; + tmp_conf.connection = &tmp_connection; + peer2_updgrp_copy(&tmp, paf); updgrp = hash_lookup(paf->peer->bgp->update_groups[paf->afid], &tmp); @@ -1006,10 +1015,14 @@ static struct update_group *update_group_create(struct peer_af *paf) struct update_group *updgrp; struct update_group tmp; struct peer tmp_conf; + struct peer_connection tmp_connection; memset(&tmp, 0, sizeof(tmp)); memset(&tmp_conf, 0, sizeof(tmp_conf)); + memset(&tmp_connection, 0, sizeof(tmp_connection)); + tmp.conf = &tmp_conf; + tmp_conf.connection = &tmp_connection; peer2_updgrp_copy(&tmp, paf); updgrp = hash_get(paf->peer->bgp->update_groups[paf->afid], &tmp, @@ -1039,6 +1052,7 @@ static void update_group_delete(struct update_group *updgrp) XFREE(MTYPE_BGP_PEER_IFNAME, updgrp->conf->ifname); + XFREE(MTYPE_BGP_PEER_CONNECTION, updgrp->conf->connection); XFREE(MTYPE_BGP_PEER, updgrp->conf); XFREE(MTYPE_BGP_UPDGRP, updgrp); } @@ -1251,7 +1265,7 @@ static struct update_subgroup *update_subgroup_find(struct update_group *updgrp, } else version = 0; - if (!peer_established(PAF_PEER(paf))) + if (!peer_established(PAF_PEER(paf)->connection)) return NULL; UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) { @@ -1945,7 +1959,7 @@ void update_group_adjust_peer(struct peer_af *paf) return; peer = PAF_PEER(paf); - if (!peer_established(peer)) { + if (!peer_established(peer->connection)) { return; } @@ -2000,13 +2014,13 @@ int update_group_adjust_soloness(struct peer *peer, int set) if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { peer_lonesoul_or_not(peer, set); - if (peer_established(peer)) + if (peer_established(peer->connection)) bgp_announce_route_all(peer); } else { group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { peer_lonesoul_or_not(peer, set); - if (peer_established(peer)) + if (peer_established(peer->connection)) bgp_announce_route_all(peer); } } @@ -2199,12 +2213,15 @@ void subgroup_trigger_write(struct update_subgroup *subgrp) * the subgroup output queue into their own output queue. This action * will trigger a write job on the I/O thread. */ - SUBGRP_FOREACH_PEER (subgrp, paf) - if (peer_established(paf->peer)) - event_add_timer_msec( - bm->master, bgp_generate_updgrp_packets, - paf->peer, 0, - &paf->peer->t_generate_updgrp_packets); + SUBGRP_FOREACH_PEER (subgrp, paf) { + struct peer_connection *connection = paf->peer->connection; + + if (peer_established(connection)) + event_add_timer_msec(bm->master, + bgp_generate_updgrp_packets, + connection, 0, + &connection->t_generate_updgrp_packets); + } } int update_group_clear_update_dbg(struct update_group *updgrp, void *arg) diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 68fd11a042a2..ccbb23ebb4d6 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -384,8 +384,11 @@ static void subgroup_coalesce_timer(struct event *thread) SUBGRP_FOREACH_PEER (subgrp, paf) { peer = PAF_PEER(paf); - EVENT_OFF(peer->t_routeadv); - BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0); + struct peer_connection *connection = peer->connection; + + EVENT_OFF(connection->t_routeadv); + BGP_TIMER_ON(connection->t_routeadv, bgp_routeadv_timer, + 0); } } } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 1c902149711e..9b4d8936828a 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -168,6 +168,8 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) return BGP_VPNV4_NODE; case SAFI_FLOWSPEC: return BGP_FLOWSPECV4_NODE; + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_UNSPEC: case SAFI_ENCAP: case SAFI_EVPN: @@ -188,6 +190,8 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) return BGP_VPNV6_NODE; case SAFI_FLOWSPEC: return BGP_FLOWSPECV6_NODE; + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_UNSPEC: case SAFI_ENCAP: case SAFI_EVPN: @@ -198,6 +202,23 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) break; case AFI_L2VPN: return BGP_EVPN_NODE; + case AFI_LINKSTATE: + switch (safi) { + case SAFI_LINKSTATE: + return BGP_LS_NODE; + case SAFI_LINKSTATE_VPN: /* Not yet supported */ + case SAFI_UNICAST: + case SAFI_MULTICAST: + case SAFI_LABELED_UNICAST: + case SAFI_MPLS_VPN: + case SAFI_FLOWSPEC: + case SAFI_UNSPEC: + case SAFI_ENCAP: + case SAFI_EVPN: + case SAFI_MAX: + return BGP_IPV4_NODE; + } + break; case AFI_UNSPEC: case AFI_MAX: // We should never be here but to clarify the switch statement.. @@ -239,6 +260,11 @@ static const char *get_afi_safi_vty_str(afi_t afi, safi_t safi) } else if (afi == AFI_L2VPN) { if (safi == SAFI_EVPN) return "L2VPN EVPN"; + } else if (afi == AFI_LINKSTATE) { + if (safi == SAFI_LINKSTATE) + return "Link State"; + if (safi == SAFI_LINKSTATE_VPN) + return "Link State VPN"; } return "Unknown"; @@ -281,6 +307,11 @@ static const char *get_afi_safi_json_str(afi_t afi, safi_t safi) } else if (afi == AFI_L2VPN) { if (safi == SAFI_EVPN) return "l2VpnEvpn"; + } else if (afi == AFI_LINKSTATE) { + if (safi == SAFI_LINKSTATE) + return "linkState"; + if (safi == SAFI_LINKSTATE_VPN) + return "linkStateVPN"; } return "Unknown"; @@ -371,6 +402,9 @@ afi_t bgp_node_afi(struct vty *vty) case BGP_EVPN_NODE: afi = AFI_L2VPN; break; + case BGP_LS_NODE: + afi = AFI_LINKSTATE; + break; default: afi = AFI_IP; break; @@ -403,6 +437,9 @@ safi_t bgp_node_safi(struct vty *vty) case BGP_FLOWSPECV6_NODE: safi = SAFI_FLOWSPEC; break; + case BGP_LS_NODE: + safi = SAFI_LINKSTATE; + break; default: safi = SAFI_UNICAST; break; @@ -428,6 +465,8 @@ afi_t bgp_vty_afi_from_str(const char *afi_str) afi = AFI_IP6; else if (strmatch(afi_str, "l2vpn")) afi = AFI_L2VPN; + else if (strmatch(afi_str, "link-state")) + afi = AFI_LINKSTATE; return afi; } @@ -447,6 +486,10 @@ int argv_find_and_parse_afi(struct cmd_token **argv, int argc, int *index, ret = 1; if (afi) *afi = AFI_L2VPN; + } else if (argv_find(argv, argc, "link-state", index)) { + ret = 1; + if (afi) + *afi = AFI_LINKSTATE; } return ret; } @@ -467,6 +510,10 @@ safi_t bgp_vty_safi_from_str(const char *safi_str) safi = SAFI_LABELED_UNICAST; else if (strmatch(safi_str, "flowspec")) safi = SAFI_FLOWSPEC; + else if (strmatch(safi_str, "link-state")) + safi = SAFI_LINKSTATE; + else if (strmatch(safi_str, "link-state-vpn")) + safi = SAFI_LINKSTATE_VPN; return safi; } @@ -498,6 +545,10 @@ int argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, ret = 1; if (safi) *safi = SAFI_FLOWSPEC; + } else if (argv_find(argv, argc, "link-state", index)) { + ret = 1; + if (safi) + *safi = SAFI_LINKSTATE; } return ret; } @@ -534,6 +585,8 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi) case SAFI_FLOWSPEC: return "ipv4-flowspec"; case SAFI_UNSPEC: + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_EVPN: case SAFI_MAX: return "unknown-afi/safi"; @@ -553,6 +606,8 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi) return "ipv6-labeled-unicast"; case SAFI_FLOWSPEC: return "ipv6-flowspec"; + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_UNSPEC: case SAFI_EVPN: case SAFI_MAX: @@ -568,9 +623,30 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi) case SAFI_MPLS_VPN: case SAFI_ENCAP: case SAFI_LABELED_UNICAST: + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: + case SAFI_FLOWSPEC: + case SAFI_UNSPEC: + case SAFI_MAX: + return "unknown-afi/safi"; + } + break; + case AFI_LINKSTATE: + switch (safi) { + case SAFI_EVPN: + case SAFI_UNICAST: + case SAFI_MULTICAST: + case SAFI_MPLS_VPN: + case SAFI_ENCAP: + case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: case SAFI_UNSPEC: case SAFI_MAX: + case SAFI_LINKSTATE: + return "link-state"; + case SAFI_LINKSTATE_VPN: + return "link-state-vpn"; + default: return "unknown-afi/safi"; } break; @@ -2890,7 +2966,7 @@ DEFUN(bgp_reject_as_sets, bgp_reject_as_sets_cmd, for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_AS_SETS_REJECT; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } @@ -2916,7 +2992,7 @@ DEFUN(no_bgp_reject_as_sets, no_bgp_reject_as_sets_cmd, for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_AS_SETS_REJECT; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } @@ -3066,9 +3142,17 @@ DEFUN (bgp_graceful_restart_restart_time, VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t restart; + struct listnode *node, *nnode; + struct peer *peer; restart = strtoul(argv[idx_number]->arg, NULL, 10); bgp->restart_time = restart; + + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_SET); + return CMD_SUCCESS; } @@ -3119,8 +3203,16 @@ DEFUN (no_bgp_graceful_restart_restart_time, "Delay value (seconds)\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); + struct listnode *node, *nnode; + struct peer *peer; bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_UNSET); + return CMD_SUCCESS; } @@ -3175,12 +3267,19 @@ DEFPY (bgp_graceful_restart_notification, "Indicate Graceful Restart support for BGP NOTIFICATION messages\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); + struct listnode *node, *nnode; + struct peer *peer; if (no) UNSET_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION); else SET_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION); + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_SET); + return CMD_SUCCESS; } @@ -3596,10 +3695,16 @@ DEFUN(bgp_llgr_stalepath_time, bgp_llgr_stalepath_time_cmd, VTY_DECLVAR_CONTEXT(bgp, bgp); uint32_t llgr_stale_time; + struct listnode *node, *nnode; + struct peer *peer; llgr_stale_time = strtoul(argv[3]->arg, NULL, 10); bgp->llgr_stale_time = llgr_stale_time; + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_LLGR, CAPABILITY_ACTION_SET); + return CMD_SUCCESS; } @@ -3611,9 +3716,16 @@ DEFUN(no_bgp_llgr_stalepath_time, no_bgp_llgr_stalepath_time_cmd, "Stale time value (seconds)\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); + struct listnode *node, *nnode; + struct peer *peer; bgp->llgr_stale_time = BGP_DEFAULT_LLGR_STALE_TIME; + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_LLGR, + CAPABILITY_ACTION_UNSET); + return CMD_SUCCESS; } @@ -4100,6 +4212,7 @@ DEFPY(bgp_default_afi_safi, bgp_default_afi_safi_cmd, "ipv6-vpn|" "ipv6-labeled-unicast|" "ipv6-flowspec|" + "link-state|" "l2vpn-evpn>$afi_safi", NO_STR BGP_STR @@ -4114,6 +4227,7 @@ DEFPY(bgp_default_afi_safi, bgp_default_afi_safi_cmd, "Activate ipv6-vpn for a peer by default\n" "Activate ipv6-labeled-unicast for a peer by default\n" "Activate ipv6-flowspec for a peer by default\n" + "Activate link-state for a peer by default\n" "Activate l2vpn-evpn for a peer by default\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); @@ -4123,9 +4237,14 @@ DEFPY(bgp_default_afi_safi, bgp_default_afi_safi_cmd, strlcpy(afi_safi_str, afi_safi, sizeof(afi_safi_str)); char *afi_str = strtok_r(afi_safi_str, "-", &afi_safi_str_tok); char *safi_str = strtok_r(NULL, "-", &afi_safi_str_tok); - afi_t afi = bgp_vty_afi_from_str(afi_str); + afi_t afi; safi_t safi; + if (strmatch(afi_safi, "link-state")) + afi = bgp_vty_afi_from_str("link-state"); + else + afi = bgp_vty_afi_from_str(afi_str); + /* * Impossible situation but making coverity happy */ @@ -4133,6 +4252,8 @@ DEFPY(bgp_default_afi_safi, bgp_default_afi_safi_cmd, if (strmatch(safi_str, "labeled")) safi = bgp_vty_safi_from_str("labeled-unicast"); + else if (strmatch(afi_safi, "link-state")) + safi = bgp_vty_safi_from_str("link-state"); else safi = bgp_vty_safi_from_str(safi_str); @@ -4853,7 +4974,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, /* v6only flag changed. Reset bgp seesion */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_V6ONLY_CHANGE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(peer); @@ -10242,6 +10363,15 @@ DEFUN_NOSH (address_family_evpn, return CMD_SUCCESS; } +DEFUN_NOSH(address_family_linkstate, address_family_linkstate_cmd, + "address-family link-state link-state", + "Enter Address Family command mode\n" BGP_AF_STR BGP_AF_MODIFIER_STR) +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + vty->node = BGP_LS_NODE; + return CMD_SUCCESS; +} + DEFUN_NOSH (bgp_segment_routing_srv6, bgp_segment_routing_srv6_cmd, "segment-routing srv6", @@ -10382,7 +10512,8 @@ DEFUN_NOSH (exit_address_family, || vty->node == BGP_IPV6L_NODE || vty->node == BGP_VPNV6_NODE || vty->node == BGP_EVPN_NODE || vty->node == BGP_FLOWSPECV4_NODE - || vty->node == BGP_FLOWSPECV6_NODE) + || vty->node == BGP_FLOWSPECV6_NODE + || vty->node == BGP_LS_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; } @@ -10699,7 +10830,7 @@ static inline void calc_peers_cfgd_estbd(struct bgp *bgp, int *peers_cfgd, if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) continue; (*peers_cfgd)++; - if (peer_established(peer)) + if (peer_established(peer->connection)) (*peers_estbd)++; } } @@ -11179,11 +11310,9 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer, msgbuf, sizeof(msgbuf), (uint8_t *)peer->notify.data, peer->notify.length); - if (msg_str) - json_object_string_add( - json_peer, - "lastShutdownDescription", - msg_str); + json_object_string_add(json_peer, + "lastShutdownDescription", + msg_str); } } @@ -11223,7 +11352,8 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer, static inline bool bgp_has_peer_failed(struct peer *peer, afi_t afi, safi_t safi) { - return ((!peer_established(peer)) || !peer->afc_recv[afi][safi]); + return ((!peer_established(peer->connection)) || + !peer->afc_recv[afi][safi]); } static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp, @@ -11250,7 +11380,7 @@ static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp, peer->dropped); peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN, use_json, json_peer); - if (peer_established(peer)) + if (peer_established(peer->connection)) json_object_string_add(json_peer, "lastResetDueTo", "AFI/SAFI Not Negotiated"); else @@ -11273,7 +11403,7 @@ static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp, peer->dropped, peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL)); - if (peer_established(peer)) + if (peer_established(peer->connection)) vty_out(vty, " AFI/SAFI Not Negotiated\n"); else bgp_show_peer_reset(vty, peer, NULL, @@ -11860,10 +11990,10 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (peer->conf_if) json_object_string_add(json_peer, "idType", "interface"); - else if (peer->su.sa.sa_family == AF_INET) + else if (peer->connection->su.sa.sa_family == AF_INET) json_object_string_add(json_peer, "idType", "ipv4"); - else if (peer->su.sa.sa_family == AF_INET6) + else if (peer->connection->su.sa.sa_family == AF_INET6) json_object_string_add(json_peer, "idType", "ipv6"); json_object_object_add(json_peers, peer->host, @@ -11954,7 +12084,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL)); - if (peer_established(peer)) { + if (peer_established(peer->connection)) { if (peer->afc_recv[afi][safi]) { if (CHECK_FLAG( bgp->flags, @@ -12255,11 +12385,11 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, /* `show [ip] bgp summary' commands. */ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd, - "show [ip] bgp [ VIEWVRFNAME] [" BGP_AFI_CMD_STR - " [" BGP_SAFI_WITH_LABEL_CMD_STR + "show [ip] bgp [ VIEWVRFNAME] [" BGP_AFI_WITH_LS_CMD_STR + " [" BGP_SAFI_WITH_LABEL_LS_CMD_STR "]] [all$all] summary [established|failed] [|remote-as >] [terse] [wide] [json$uj]", - SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR - BGP_SAFI_WITH_LABEL_HELP_STR + SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_WITH_LS_HELP_STR + BGP_SAFI_WITH_LABEL_LS_HELP_STR "Display the entries for all address families\n" "Summary of BGP neighbor status\n" "Show only sessions in Established state\n" @@ -12410,9 +12540,9 @@ static void bgp_show_neighnor_graceful_restart_flags(struct vty *vty, bool rbit = false; bool nbit = false; - if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) - && (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) - && (peer_established(p))) { + if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) && + (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) && + (peer_established(p->connection))) { rbit = CHECK_FLAG(p->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV); nbit = CHECK_FLAG(p->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV); } @@ -12435,9 +12565,8 @@ static void bgp_show_neighbor_graceful_restart_remote_mode(struct vty *vty, if (!json) vty_out(vty, "\n Remote GR Mode: "); - if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) - && (peer_established(peer))) { - + if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) && + (peer_established(peer->connection))) { if ((peer->nsf_af_count == 0) && !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) { @@ -12599,12 +12728,15 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( if (json) { json_object_int_add(json_timer, "stalePathTimer", peer->bgp->stalepath_time); + json_object_int_add(json_timer, "llgrStaleTime", + peer->llgr[afi][safi].stale_time); - if (peer->t_gr_stale != NULL) { + if (peer->connection->t_gr_stale != NULL) { json_object_int_add(json_timer, "stalePathTimerRemaining", event_timer_remain_second( - peer->t_gr_stale)); + peer->connection + ->t_gr_stale)); } /* Display Configured Selection @@ -12634,11 +12766,11 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( " Configured Stale Path Time(sec): %u\n", peer->bgp->stalepath_time); - if (peer->t_gr_stale != NULL) + if (peer->connection->t_gr_stale != NULL) vty_out(vty, " Stale Path Remaining(sec): %ld\n", event_timer_remain_second( - peer->t_gr_stale)); + peer->connection->t_gr_stale)); /* Display Configured Selection * Deferral only when when * Gr mode is enabled. @@ -12648,6 +12780,9 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( " Configured Selection Deferral Time(sec): %u\n", peer->bgp->select_defer_time); + vty_out(vty, " LLGR Stale Path Time(sec): %u\n", + peer->llgr[afi][safi].stale_time); + if (peer->bgp->gr_info[afi][safi].t_select_deferral != NULL) vty_out(vty, @@ -12679,14 +12814,16 @@ static void bgp_show_neighbor_graceful_restart_time(struct vty *vty, json_object_int_add(json_timer, "configuredRestartTimer", p->bgp->restart_time); + json_object_int_add(json_timer, "configuredLlgrStaleTime", + p->bgp->llgr_stale_time); json_object_int_add(json_timer, "receivedRestartTimer", p->v_gr_restart); - if (p->t_gr_restart != NULL) - json_object_int_add( - json_timer, "restartTimerRemaining", - event_timer_remain_second(p->t_gr_restart)); + if (p->connection->t_gr_restart != NULL) + json_object_int_add(json_timer, "restartTimerRemaining", + event_timer_remain_second( + p->connection->t_gr_restart)); json_object_object_add(json, "timers", json_timer); } else { @@ -12697,12 +12834,16 @@ static void bgp_show_neighbor_graceful_restart_time(struct vty *vty, vty_out(vty, " Received Restart Time(sec): %u\n", p->v_gr_restart); - if (p->t_gr_restart != NULL) + vty_out(vty, " Configured LLGR Stale Path Time(sec): %u\n", + p->bgp->llgr_stale_time); + if (p->connection->t_gr_restart != NULL) vty_out(vty, " Restart Time Remaining(sec): %ld\n", - event_timer_remain_second(p->t_gr_restart)); - if (p->t_gr_restart != NULL) { + event_timer_remain_second( + p->connection->t_gr_restart)); + if (p->connection->t_gr_restart != NULL) { vty_out(vty, " Restart Time Remaining(sec): %ld\n", - event_timer_remain_second(p->t_gr_restart)); + event_timer_remain_second( + p->connection->t_gr_restart)); } } } @@ -12720,10 +12861,10 @@ static void bgp_show_peer_gr_status(struct vty *vty, struct peer *p, if (p->conf_if) { if (json) json_object_string_addf(json, "neighborAddr", "%pSU", - &p->su); + &p->connection->su); else vty_out(vty, "BGP neighbor on %s: %pSU\n", p->conf_if, - &p->su); + &p->connection->su); } else { snprintf(neighborAddr, sizeof(neighborAddr), "%s%s", dn_flag, p->host); @@ -13391,19 +13532,19 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, if (!use_json) { if (p->conf_if) /* Configured interface name. */ vty_out(vty, "BGP neighbor on %s: %pSU, ", p->conf_if, - &p->su); + &p->connection->su); else /* Configured IP address. */ vty_out(vty, "BGP neighbor is %s%s, ", dn_flag, p->host); } if (use_json) { - if (p->conf_if && BGP_PEER_SU_UNSPEC(p)) + if (p->conf_if && BGP_CONNECTION_SU_UNSPEC(p->connection)) json_object_string_add(json_neigh, "bgpNeighborAddr", "none"); - else if (p->conf_if && !BGP_PEER_SU_UNSPEC(p)) + else if (p->conf_if && !BGP_CONNECTION_SU_UNSPEC(p->connection)) json_object_string_addf(json_neigh, "bgpNeighborAddr", - "%pSU", &p->su); + "%pSU", &p->connection->su); asn_asn2json(json_neigh, "remoteAs", p->as, bgp->asnotation); @@ -13532,7 +13673,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, if (dn_flag[0]) { struct prefix prefix, *range = NULL; - if (sockunion2hostprefix(&(p->su), &prefix)) + if (sockunion2hostprefix(&p->connection->su, + &prefix)) range = peer_group_lookup_dynamic_neighbor_range( p->group, &prefix); @@ -13551,7 +13693,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, if (dn_flag[0]) { struct prefix prefix, *range = NULL; - if (sockunion2hostprefix(&(p->su), &prefix)) + if (sockunion2hostprefix(&p->connection->su, + &prefix)) range = peer_group_lookup_dynamic_neighbor_range( p->group, &prefix); @@ -13589,7 +13732,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, lookup_msg(bgp_status_msg, p->connection->status, NULL)); - if (peer_established(p)) { + if (peer_established(p->connection)) { time_t uptime; uptime = monotime(NULL); @@ -13665,13 +13808,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, } /* Configured and Synced tcp-mss value for peer */ - if (CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) { - sync_tcp_mss = sockopt_tcp_mss_get(p->connection->fd); - json_object_int_add(json_neigh, "bgpTcpMssConfigured", - p->tcp_mss); - json_object_int_add(json_neigh, "bgpTcpMssSynced", - sync_tcp_mss); - } + sync_tcp_mss = sockopt_tcp_mss_get(p->connection->fd); + json_object_int_add(json_neigh, "bgpTcpMssConfigured", + p->tcp_mss); + json_object_int_add(json_neigh, "bgpTcpMssSynced", sync_tcp_mss); /* Extended Optional Parameters Length for BGP OPEN Message */ if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(p)) @@ -13713,7 +13853,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, " BGP state = %s", lookup_msg(bgp_status_msg, p->connection->status, NULL)); - if (peer_established(p)) + if (peer_established(p->connection)) vty_out(vty, ", up for %8s", peer_uptime(p->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL)); @@ -13751,11 +13891,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, p->delayopen); /* Configured and synced tcp-mss value for peer */ - if (CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) { - sync_tcp_mss = sockopt_tcp_mss_get(p->connection->fd); - vty_out(vty, " Configured tcp-mss is %d", p->tcp_mss); - vty_out(vty, ", synced tcp-mss is %d\n", sync_tcp_mss); - } + sync_tcp_mss = sockopt_tcp_mss_get(p->connection->fd); + vty_out(vty, " Configured tcp-mss is %d", p->tcp_mss); + vty_out(vty, ", synced tcp-mss is %d\n", sync_tcp_mss); /* Extended Optional Parameters Length for BGP OPEN Message */ if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(p)) @@ -13773,7 +13911,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, bgp->t_condition_check)); } /* Capability. */ - if (peer_established(p) && + if (peer_established(p->connection) && (p->cap || peer_afc_advertised(p) || peer_afc_received(p))) { if (use_json) { json_object *json_cap = NULL; @@ -14630,7 +14768,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_grace_send = json_object_new_object(); json_grace_recv = json_object_new_object(); - if ((peer_established(p)) && + if ((peer_established(p->connection)) && CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) { FOREACH_AFI_SAFI (afi, safi) { if (CHECK_FLAG(p->af_sflags[afi][safi], @@ -14659,26 +14797,27 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_grace_recv); - if (p->t_gr_restart) - json_object_int_add( - json_grace, "gracefulRestartTimerMsecs", - event_timer_remain_second(p->t_gr_restart) * - 1000); + if (p->connection->t_gr_restart) + json_object_int_add(json_grace, + "gracefulRestartTimerMsecs", + event_timer_remain_second( + p->connection->t_gr_restart) * + 1000); - if (p->t_gr_stale) - json_object_int_add( - json_grace, "gracefulStalepathTimerMsecs", - event_timer_remain_second(p->t_gr_stale) * - 1000); + if (p->connection->t_gr_stale) + json_object_int_add(json_grace, + "gracefulStalepathTimerMsecs", + event_timer_remain_second( + p->connection->t_gr_stale) * + 1000); /* more gr info in new format */ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, json_grace); json_object_object_add(json_neigh, "gracefulRestartInfo", json_grace); } else { vty_out(vty, " Graceful restart information:\n"); - if ((peer_established(p)) && + if ((peer_established(p->connection)) && CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) { - vty_out(vty, " End-of-RIB send: "); FOREACH_AFI_SAFI (afi, safi) { if (CHECK_FLAG(p->af_sflags[afi][safi], @@ -14706,15 +14845,17 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, "\n"); } - if (p->t_gr_restart) + if (p->connection->t_gr_restart) vty_out(vty, " The remaining time of restart timer is %ld\n", - event_timer_remain_second(p->t_gr_restart)); + event_timer_remain_second( + p->connection->t_gr_restart)); - if (p->t_gr_stale) + if (p->connection->t_gr_stale) vty_out(vty, " The remaining time of stalepath timer is %ld\n", - event_timer_remain_second(p->t_gr_stale)); + event_timer_remain_second( + p->connection->t_gr_stale)); /* more gr info in new format */ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, NULL); @@ -14942,21 +15083,22 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, " Peer had exceeded the max. no. of prefixes configured.\n"); - if (p->t_pmax_restart) { + if (p->connection->t_pmax_restart) { if (use_json) { json_object_boolean_true_add( json_neigh, "reducePrefixNumFrom"); json_object_int_add(json_neigh, "restartInTimerMsec", event_timer_remain_second( - p->t_pmax_restart) * + p->connection + ->t_pmax_restart) * 1000); } else vty_out(vty, " Reduce the no. of prefix from %s, will restart in %ld seconds\n", p->host, event_timer_remain_second( - p->t_pmax_restart)); + p->connection->t_pmax_restart)); } else { if (use_json) json_object_boolean_true_add( @@ -15093,7 +15235,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, if (use_json) { json_object_int_add(json_neigh, "connectRetryTimer", p->v_connect); - if (peer_established(p)) { + if (peer_established(p->connection)) { json_object_int_add(json_neigh, "estimatedRttInMsecs", p->rtt); if (CHECK_FLAG(p->flags, PEER_FLAG_RTT_SHUTDOWN)) { @@ -15105,21 +15247,25 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, p->rtt_keepalive_rcv); } } - if (p->t_start) - json_object_int_add( - json_neigh, "nextStartTimerDueInMsecs", - event_timer_remain_second(p->t_start) * 1000); - if (p->t_connect) - json_object_int_add( - json_neigh, "nextConnectTimerDueInMsecs", - event_timer_remain_second(p->t_connect) * 1000); - if (p->t_routeadv) { + if (p->connection->t_start) + json_object_int_add(json_neigh, + "nextStartTimerDueInMsecs", + event_timer_remain_second( + p->connection->t_start) * + 1000); + if (p->connection->t_connect) + json_object_int_add(json_neigh, + "nextConnectTimerDueInMsecs", + event_timer_remain_second( + p->connection->t_connect) * + 1000); + if (p->connection->t_routeadv) { json_object_int_add(json_neigh, "mraiInterval", p->v_routeadv); - json_object_int_add( - json_neigh, "mraiTimerExpireInMsecs", - event_timer_remain_second(p->t_routeadv) * - 1000); + json_object_int_add(json_neigh, "mraiTimerExpireInMsecs", + event_timer_remain_second( + p->connection->t_routeadv) * + 1000); } if (p->password) json_object_int_add(json_neigh, "authenticationEnabled", @@ -15139,7 +15285,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, } else { vty_out(vty, "BGP Connect Retry Timer in Seconds: %d\n", p->v_connect); - if (peer_established(p)) { + if (peer_established(p->connection)) { vty_out(vty, "Estimated round trip time: %d ms\n", p->rtt); if (CHECK_FLAG(p->flags, PEER_FLAG_RTT_SHUTDOWN)) @@ -15147,17 +15293,20 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, "Shutdown when RTT > %dms, count > %u\n", p->rtt_expected, p->rtt_keepalive_rcv); } - if (p->t_start) + if (p->connection->t_start) vty_out(vty, "Next start timer due in %ld seconds\n", - event_timer_remain_second(p->t_start)); - if (p->t_connect) + event_timer_remain_second( + p->connection->t_start)); + if (p->connection->t_connect) vty_out(vty, "Next connect timer due in %ld seconds\n", - event_timer_remain_second(p->t_connect)); - if (p->t_routeadv) + event_timer_remain_second( + p->connection->t_connect)); + if (p->connection->t_routeadv) vty_out(vty, "MRAI (interval %u) timer expires in %ld seconds\n", p->v_routeadv, - event_timer_remain_second(p->t_routeadv)); + event_timer_remain_second( + p->connection->t_routeadv)); if (p->password) vty_out(vty, "Peer Authentication Enabled\n"); @@ -15230,7 +15379,7 @@ static int bgp_show_neighbor_graceful_restart(struct vty *vty, struct bgp *bgp, json_neighbor); } } else { - if (sockunion_same(&peer->su, su)) { + if (sockunion_same(&peer->connection->su, su)) { found = true; bgp_show_peer_gr_status(vty, peer, json_neighbor); @@ -15300,7 +15449,7 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp, json); } } else { - if (sockunion_same(&peer->su, su)) { + if (sockunion_same(&peer->connection->su, su)) { find = 1; bgp_show_peer(vty, peer, use_json, json); @@ -15322,7 +15471,9 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp, break; } } else { - if (sockunion_same(&peer->su, su)) { + if (sockunion_same(&peer->connection + ->su, + su)) { find = 1; bgp_show_peer(vty, peer, use_json, json); @@ -16740,8 +16891,15 @@ DEFUN (bgp_redistribute_ipv4_ospf, if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; - else + else { + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "%% Only default BGP instance can use '%s'\n", + argv[idx_ospf_table]->arg); + return CMD_WARNING_CONFIG_FAILED; + } protocol = ZEBRA_ROUTE_TABLE; + } bgp_redist_add(bgp, AFI_IP, protocol, instance); return bgp_redistribute_set(bgp, AFI_IP, protocol, instance, false); @@ -16777,8 +16935,15 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap, if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; - else + else { + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "%% Only default BGP instance can use '%s'\n", + argv[idx_ospf_table]->arg); + return CMD_WARNING_CONFIG_FAILED; + } protocol = ZEBRA_ROUTE_TABLE; + } instance = strtoul(argv[idx_number]->arg, NULL, 10); red = bgp_redist_add(bgp, AFI_IP, protocol, instance); @@ -16819,8 +16984,15 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric, if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; - else + else { + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "%% Only default BGP instance can use '%s'\n", + argv[idx_ospf_table]->arg); + return CMD_WARNING_CONFIG_FAILED; + } protocol = ZEBRA_ROUTE_TABLE; + } instance = strtoul(argv[idx_number]->arg, NULL, 10); metric = strtoul(argv[idx_number_2]->arg, NULL, 10); @@ -16868,8 +17040,15 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; - else + else { + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "%% Only default BGP instance can use '%s'\n", + argv[idx_ospf_table]->arg); + return CMD_WARNING_CONFIG_FAILED; + } protocol = ZEBRA_ROUTE_TABLE; + } instance = strtoul(argv[idx_number]->arg, NULL, 10); metric = strtoul(argv[idx_number_2]->arg, NULL, 10); @@ -16922,8 +17101,15 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; - else + else { + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "%% Only default BGP instance can use '%s'\n", + argv[idx_ospf_table]->arg); + return CMD_WARNING_CONFIG_FAILED; + } protocol = ZEBRA_ROUTE_TABLE; + } instance = strtoul(argv[idx_number]->arg, NULL, 10); metric = strtoul(argv[idx_number_2]->arg, NULL, 10); @@ -16970,8 +17156,15 @@ DEFUN (no_bgp_redistribute_ipv4_ospf, if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; - else + else { + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "%% Only default BGP instance can use '%s'\n", + argv[idx_ospf_table]->arg); + return CMD_WARNING_CONFIG_FAILED; + } protocol = ZEBRA_ROUTE_TABLE; + } instance = strtoul(argv[idx_number]->arg, NULL, 10); bgp_redistribute_unset(bgp, AFI_IP, protocol, instance); @@ -18265,6 +18458,11 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, } else if (afi == AFI_L2VPN) { if (safi == SAFI_EVPN) vty_frame(vty, "l2vpn evpn"); + } else if (afi == AFI_LINKSTATE) { + if (safi == SAFI_LINKSTATE) + vty_frame(vty, "link-state link-state"); + else if (safi == SAFI_LINKSTATE_VPN) + vty_frame(vty, "link-state link-state-vpn"); } vty_frame(vty, "\n"); @@ -18808,6 +19006,11 @@ int bgp_config_write(struct vty *vty) /* EVPN configuration. */ bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN); + bgp_config_write_family(vty, bgp, AFI_LINKSTATE, + SAFI_LINKSTATE); + bgp_config_write_family(vty, bgp, AFI_LINKSTATE, + SAFI_LINKSTATE_VPN); + hook_call(bgp_inst_config_write, bgp, vty); #ifdef ENABLE_BGP_VNC @@ -18932,6 +19135,13 @@ static struct cmd_node bgp_srv6_node = { .prompt = "%s(config-router-srv6)# ", }; +static struct cmd_node bgp_ls_node = { + .name = "bgp link-state", + .node = BGP_LS_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-af-ls)# ", +}; + static void community_list_vty(void); static void bgp_ac_peergroup(vector comps, struct cmd_token *token) @@ -19246,6 +19456,7 @@ void bgp_vty_init(void) install_node(&bgp_flowspecv4_node); install_node(&bgp_flowspecv6_node); install_node(&bgp_srv6_node); + install_node(&bgp_ls_node); /* Install default VTY commands to new nodes. */ install_default(BGP_NODE); @@ -19262,6 +19473,7 @@ void bgp_vty_init(void) install_default(BGP_EVPN_NODE); install_default(BGP_EVPN_VNI_NODE); install_default(BGP_SRV6_NODE); + install_default(BGP_LS_NODE); /* "global bgp inq-limit command */ install_element(CONFIG_NODE, &bgp_inq_limit_cmd); @@ -19393,6 +19605,13 @@ void bgp_vty_init(void) install_element(BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cluster_cmd); install_element(BGP_IPV6L_NODE, &no_bgp_maxpaths_ibgp_cmd); + install_element(BGP_LS_NODE, &bgp_maxpaths_cmd); + install_element(BGP_LS_NODE, &no_bgp_maxpaths_cmd); + install_element(BGP_LS_NODE, &bgp_maxpaths_ibgp_cmd); + install_element(BGP_LS_NODE, &no_bgp_maxpaths_ibgp_cmd); + install_element(BGP_LS_NODE, &bgp_maxpaths_ibgp_cluster_cmd); + + /* "timers bgp" commands. */ install_element(BGP_NODE, &bgp_timers_cmd); install_element(BGP_NODE, &no_bgp_timers_cmd); @@ -19615,6 +19834,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &neighbor_activate_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_activate_cmd); install_element(BGP_EVPN_NODE, &neighbor_activate_cmd); + install_element(BGP_LS_NODE, &neighbor_activate_cmd); /* "no neighbor activate" commands. */ install_element(BGP_NODE, &no_neighbor_activate_hidden_cmd); @@ -19629,6 +19849,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_activate_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_activate_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_activate_cmd); + install_element(BGP_LS_NODE, &no_neighbor_activate_cmd); /* "neighbor peer-group" set commands. */ install_element(BGP_NODE, &neighbor_set_peer_group_cmd); @@ -19643,6 +19864,8 @@ void bgp_vty_init(void) &neighbor_set_peer_group_hidden_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_set_peer_group_hidden_cmd); + install_element(BGP_LS_NODE, &neighbor_set_peer_group_hidden_cmd); + /* "no neighbor peer-group unset" commands. */ install_element(BGP_NODE, &no_neighbor_set_peer_group_cmd); @@ -19657,6 +19880,7 @@ void bgp_vty_init(void) &no_neighbor_set_peer_group_hidden_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_set_peer_group_hidden_cmd); + install_element(BGP_LS_NODE, &no_neighbor_set_peer_group_hidden_cmd); /* "neighbor softreconfiguration inbound" commands.*/ install_element(BGP_NODE, &neighbor_soft_reconfiguration_hidden_cmd); @@ -19687,6 +19911,8 @@ void bgp_vty_init(void) &no_neighbor_soft_reconfiguration_cmd); install_element(BGP_EVPN_NODE, &neighbor_soft_reconfiguration_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element(BGP_LS_NODE, &neighbor_soft_reconfiguration_cmd); + install_element(BGP_LS_NODE, &no_neighbor_soft_reconfiguration_cmd); /* "neighbor attribute-unchanged" commands. */ install_element(BGP_NODE, &neighbor_attr_unchanged_hidden_cmd); @@ -19707,9 +19933,10 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd); install_element(BGP_VPNV6_NODE, &neighbor_attr_unchanged_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_attr_unchanged_cmd); - install_element(BGP_EVPN_NODE, &neighbor_attr_unchanged_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_attr_unchanged_cmd); + install_element(BGP_LS_NODE, &neighbor_attr_unchanged_cmd); + install_element(BGP_LS_NODE, &no_neighbor_attr_unchanged_cmd); install_element(BGP_FLOWSPECV4_NODE, &neighbor_attr_unchanged_cmd); install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_attr_unchanged_cmd); @@ -19742,6 +19969,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &no_neighbor_nexthop_self_cmd); install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_cmd); + install_element(BGP_LS_NODE, &neighbor_nexthop_self_cmd); + install_element(BGP_LS_NODE, &no_neighbor_nexthop_self_cmd); /* "neighbor next-hop-self force" commands. */ install_element(BGP_NODE, &neighbor_nexthop_self_force_hidden_cmd); @@ -19790,6 +20019,8 @@ void bgp_vty_init(void) &no_neighbor_nexthop_self_all_hidden_cmd); install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_force_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_force_cmd); + install_element(BGP_LS_NODE, &neighbor_nexthop_self_force_cmd); + install_element(BGP_LS_NODE, &no_neighbor_nexthop_self_force_cmd); /* "neighbor as-override" commands. */ install_element(BGP_NODE, &neighbor_as_override_hidden_cmd); @@ -19922,6 +20153,18 @@ void bgp_vty_init(void) &neighbor_remove_private_as_all_replace_as_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd); + install_element(BGP_LS_NODE, &neighbor_remove_private_as_cmd); + install_element(BGP_LS_NODE, &no_neighbor_remove_private_as_cmd); + install_element(BGP_LS_NODE, &neighbor_remove_private_as_all_cmd); + install_element(BGP_LS_NODE, &no_neighbor_remove_private_as_all_cmd); + install_element(BGP_LS_NODE, + &neighbor_remove_private_as_replace_as_cmd); + install_element(BGP_LS_NODE, + &no_neighbor_remove_private_as_replace_as_cmd); + install_element(BGP_LS_NODE, + &neighbor_remove_private_as_all_replace_as_cmd); + install_element(BGP_LS_NODE, + &no_neighbor_remove_private_as_all_replace_as_cmd); /* "neighbor send-community" commands.*/ install_element(BGP_NODE, &neighbor_send_community_hidden_cmd); @@ -19960,6 +20203,10 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &neighbor_send_community_type_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_send_community_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_send_community_type_cmd); + install_element(BGP_LS_NODE, &neighbor_send_community_cmd); + install_element(BGP_LS_NODE, &neighbor_send_community_type_cmd); + install_element(BGP_LS_NODE, &no_neighbor_send_community_cmd); + install_element(BGP_LS_NODE, &no_neighbor_send_community_type_cmd); /* "neighbor route-reflector" commands.*/ install_element(BGP_NODE, &neighbor_route_reflector_client_hidden_cmd); @@ -19997,6 +20244,8 @@ void bgp_vty_init(void) &no_neighbor_route_reflector_client_cmd); install_element(BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd); + install_element(BGP_LS_NODE, &neighbor_route_reflector_client_cmd); + install_element(BGP_LS_NODE, &no_neighbor_route_reflector_client_cmd); /* "neighbor route-server" commands.*/ install_element(BGP_NODE, &neighbor_route_server_client_hidden_cmd); @@ -20025,6 +20274,8 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV6_NODE, &neighbor_route_server_client_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_route_server_client_cmd); + install_element(BGP_LS_NODE, &neighbor_route_server_client_cmd); + install_element(BGP_LS_NODE, &no_neighbor_route_server_client_cmd); /* "neighbor disable-addpath-rx" commands. */ install_element(BGP_IPV4_NODE, &neighbor_disable_addpath_rx_cmd); @@ -20186,6 +20437,8 @@ void bgp_vty_init(void) install_element(BGP_IPV6M_NODE, &no_neighbor_capability_orf_prefix_cmd); install_element(BGP_IPV6L_NODE, &neighbor_capability_orf_prefix_cmd); install_element(BGP_IPV6L_NODE, &no_neighbor_capability_orf_prefix_cmd); + install_element(BGP_LS_NODE, &neighbor_capability_orf_prefix_cmd); + install_element(BGP_LS_NODE, &no_neighbor_capability_orf_prefix_cmd); /* "neighbor capability dynamic" commands.*/ install_element(BGP_NODE, &neighbor_capability_dynamic_cmd); @@ -20322,6 +20575,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd); install_element(BGP_VPNV6_NODE, &neighbor_distribute_list_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_distribute_list_cmd); + install_element(BGP_LS_NODE, &neighbor_distribute_list_cmd); + install_element(BGP_LS_NODE, &no_neighbor_distribute_list_cmd); /* "neighbor prefix-list" commands. */ install_element(BGP_NODE, &neighbor_prefix_list_hidden_cmd); @@ -20346,6 +20601,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_prefix_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_prefix_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_prefix_list_cmd); + install_element(BGP_LS_NODE, &neighbor_prefix_list_cmd); /* "neighbor filter-list" commands. */ install_element(BGP_NODE, &neighbor_filter_list_hidden_cmd); @@ -20370,6 +20626,8 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_filter_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_filter_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_filter_list_cmd); + install_element(BGP_LS_NODE, &neighbor_filter_list_cmd); + install_element(BGP_LS_NODE, &no_neighbor_filter_list_cmd); /* "neighbor route-map" commands. */ install_element(BGP_NODE, &neighbor_route_map_hidden_cmd); @@ -20396,6 +20654,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_route_map_cmd); install_element(BGP_EVPN_NODE, &neighbor_route_map_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_route_map_cmd); + install_element(BGP_LS_NODE, &neighbor_route_map_cmd); /* "neighbor unsuppress-map" commands. */ install_element(BGP_NODE, &neighbor_unsuppress_map_hidden_cmd); @@ -20416,6 +20675,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd); install_element(BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd); + install_element(BGP_LS_NODE, &neighbor_unsuppress_map_cmd); + install_element(BGP_LS_NODE, &no_neighbor_unsuppress_map_cmd); /* "neighbor advertise-map" commands. */ install_element(BGP_NODE, &bgp_condadv_period_cmd); @@ -20535,6 +20796,15 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_cmd); + install_element(BGP_LS_NODE, &neighbor_maximum_prefix_cmd); + install_element(BGP_LS_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element(BGP_LS_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element(BGP_LS_NODE, + &neighbor_maximum_prefix_threshold_warning_cmd); + install_element(BGP_LS_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element(BGP_LS_NODE, + &neighbor_maximum_prefix_threshold_restart_cmd); + install_element(BGP_LS_NODE, &no_neighbor_maximum_prefix_cmd); /* "neighbor allowas-in" */ install_element(BGP_NODE, &neighbor_allowas_in_hidden_cmd); @@ -20557,6 +20827,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &no_neighbor_allowas_in_cmd); install_element(BGP_EVPN_NODE, &neighbor_allowas_in_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_allowas_in_cmd); + install_element(BGP_LS_NODE, &neighbor_allowas_in_cmd); + install_element(BGP_LS_NODE, &no_neighbor_allowas_in_cmd); /* neighbor accept-own */ install_element(BGP_VPNV4_NODE, &neighbor_accept_own_cmd); @@ -20592,6 +20864,8 @@ void bgp_vty_init(void) install_element(BGP_NODE, &address_family_evpn_cmd); + install_element(BGP_NODE, &address_family_linkstate_cmd); + /* "exit-address-family" command. */ install_element(BGP_IPV4_NODE, &exit_address_family_cmd); install_element(BGP_IPV4M_NODE, &exit_address_family_cmd); @@ -20604,6 +20878,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd); install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd); install_element(BGP_EVPN_NODE, &exit_address_family_cmd); + install_element(BGP_LS_NODE, &exit_address_family_cmd); /* BGP retain all route-target */ install_element(BGP_VPNV4_NODE, &bgp_retain_route_target_cmd); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index a105b6de3fa9..955752f85a93 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -17,6 +17,8 @@ struct bgp; #define BGP_AF_MODIFIER_STR "Address Family modifier\n" #define BGP_AFI_CMD_STR "" #define BGP_AFI_HELP_STR BGP_AF_STR BGP_AF_STR +#define BGP_AFI_WITH_LS_CMD_STR "" +#define BGP_AFI_WITH_LS_HELP_STR BGP_AF_STR BGP_AF_STR BGP_AF_STR #define BGP_SAFI_CMD_STR "" #define BGP_SAFI_HELP_STR \ BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR @@ -28,6 +30,12 @@ struct bgp; BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR \ BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR +#define BGP_SAFI_WITH_LABEL_LS_CMD_STR \ + "" +#define BGP_SAFI_WITH_LABEL_LS_HELP_STR \ + BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR \ + BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR + #define BGP_SELF_ORIG_CMD_STR "self-originate" #define BGP_SELF_ORIG_HELP_STR "Display only self-originated routes\n" diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 105c1080bc7f..a04d54fa92e4 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -140,11 +140,11 @@ static void bgp_start_interface_nbrs(struct bgp *bgp, struct interface *ifp) struct peer *peer; for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (peer->conf_if && (strcmp(peer->conf_if, ifp->name) == 0) - && !peer_established(peer)) { + if (peer->conf_if && (strcmp(peer->conf_if, ifp->name) == 0) && + !peer_established(peer->connection)) { if (peer_active(peer)) - BGP_EVENT_ADD(peer, BGP_Stop); - BGP_EVENT_ADD(peer, BGP_Start); + BGP_EVENT_ADD(peer->connection, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Start); } } } @@ -183,7 +183,7 @@ static void bgp_nbr_connected_delete(struct bgp *bgp, struct nbr_connected *ifc, if (peer->conf_if && (strcmp(peer->conf_if, ifc->ifp->name) == 0)) { peer->last_reset = PEER_DOWN_NBR_ADDR_DEL; - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Stop); } } /* Free neighbor also, if we're asked to. */ @@ -279,7 +279,7 @@ static int bgp_ifp_down(struct interface *ifp) continue; if (ifp == peer->nexthop.ifp) { - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Stop); peer->last_reset = PEER_DOWN_IF_DOWN; } } @@ -477,65 +477,6 @@ static int bgp_interface_nbr_address_delete(ZAPI_CALLBACK_ARGS) return 0; } -/* VRF update for an interface. */ -static int bgp_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - struct connected *c; - struct nbr_connected *nc; - struct listnode *node, *nnode; - struct bgp *bgp; - struct peer *peer; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - if (!ifp) - return 0; - - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf VRF change VRF %u IF %s NewVRF %u", vrf_id, - ifp->name, new_vrf_id); - - bgp = bgp_lookup_by_vrf_id(vrf_id); - - if (bgp) { - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) - bgp_connected_delete(bgp, c); - - for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) - bgp_nbr_connected_delete(bgp, nc, 1); - - /* Fast external-failover */ - if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) { - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if ((peer->ttl != BGP_DEFAULT_TTL) - && (peer->gtsm_hops - != BGP_GTSM_HOPS_CONNECTED)) - continue; - - if (ifp == peer->nexthop.ifp) - BGP_EVENT_ADD(peer, BGP_Stop); - } - } - } - - if_update_to_new_vrf(ifp, new_vrf_id); - - bgp = bgp_lookup_by_vrf_id(new_vrf_id); - if (!bgp) - return 0; - - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) - bgp_connected_add(bgp, c); - - for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) - bgp_nbr_connected_add(bgp, nc); - - hook_call(bgp_vrf_status_changed, bgp, ifp); - return 0; -} - /* Zebra route add and delete treatment. */ static int zebra_read_route(ZAPI_CALLBACK_ARGS) { @@ -1321,6 +1262,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, uint32_t bos = 0; uint32_t exp = 0; + if (afi == AFI_LINKSTATE) + /* nothing to install */ + return; + /* * BGP is installing this route and bgp has been configured * to suppress announcements until the route has been installed @@ -1556,17 +1501,17 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, api_nh->weight = nh_weight; if (((mpinfo->attr->srv6_l3vpn && - !sid_zero(&mpinfo->attr->srv6_l3vpn->sid)) || + !sid_zero_ipv6(&mpinfo->attr->srv6_l3vpn->sid)) || (mpinfo->attr->srv6_vpn && - !sid_zero(&mpinfo->attr->srv6_vpn->sid))) && + !sid_zero_ipv6(&mpinfo->attr->srv6_vpn->sid))) && !is_evpn && bgp_is_valid_label(&labels[0])) { struct in6_addr *sid_tmp = mpinfo->attr->srv6_l3vpn ? (&mpinfo->attr->srv6_l3vpn->sid) : (&mpinfo->attr->srv6_vpn->sid); - memcpy(&api_nh->seg6_segs, sid_tmp, - sizeof(api_nh->seg6_segs)); + memcpy(&api_nh->seg6_segs[0], sid_tmp, + sizeof(api_nh->seg6_segs[0])); if (mpinfo->attr->srv6_l3vpn && mpinfo->attr->srv6_l3vpn->transposition_len != 0) { @@ -1580,13 +1525,14 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, continue; } - transpose_sid(&api_nh->seg6_segs, nh_label, + transpose_sid(&api_nh->seg6_segs[0], nh_label, mpinfo->attr->srv6_l3vpn ->transposition_offset, mpinfo->attr->srv6_l3vpn ->transposition_len); } + api_nh->seg_num = 1; SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6); } @@ -1703,7 +1649,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6) && !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) { - inet_ntop(AF_INET6, &api_nh->seg6_segs, + inet_ntop(AF_INET6, &api_nh->seg6_segs[0], sid_buf, sizeof(sid_buf)); snprintf(segs_buf, sizeof(segs_buf), "segs %s", sid_buf); @@ -3395,7 +3341,6 @@ static zclient_handler *const bgp_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_DELETE] = bgp_interface_address_delete, [ZEBRA_INTERFACE_NBR_ADDRESS_ADD] = bgp_interface_nbr_address_add, [ZEBRA_INTERFACE_NBR_ADDRESS_DELETE] = bgp_interface_nbr_address_delete, - [ZEBRA_INTERFACE_VRF_UPDATE] = bgp_interface_vrf_update, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = zebra_read_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = zebra_read_route, [ZEBRA_NEXTHOP_UPDATE] = bgp_read_nexthop_update, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 60b394b6971f..e760d4158768 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -71,6 +71,8 @@ #include "bgpd/bgp_io.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_flowspec.h" +#include "bgpd/bgp_linkstate.h" +#include "bgpd/bgp_linkstate_vty.h" #include "bgpd/bgp_labelpool.h" #include "bgpd/bgp_pbr.h" #include "bgpd/bgp_addpath.h" @@ -80,7 +82,6 @@ #include "bgp_trace.h" DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)"); -DEFINE_MTYPE_STATIC(BGPD, BGP_PEER_CONNECTION, "BGP Connection information"); DEFINE_QOBJ_TYPE(bgp_master); DEFINE_QOBJ_TYPE(bgp); DEFINE_QOBJ_TYPE(peer); @@ -140,7 +141,7 @@ void bgp_session_reset(struct peer *peer) !(CHECK_FLAG(peer->doppelganger->flags, PEER_FLAG_CONFIG_NODE))) peer_delete(peer->doppelganger); - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Stop); } /* @@ -166,7 +167,7 @@ static void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode) peer_delete(peer->doppelganger); } - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Stop); } /* BGP global flag manipulation. */ @@ -309,7 +310,7 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id, if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_RID_CHANGE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } @@ -488,7 +489,7 @@ void bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id) if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_CLID_CHANGE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } @@ -512,7 +513,7 @@ void bgp_cluster_id_unset(struct bgp *bgp) if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_CLID_CHANGE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } @@ -597,9 +598,9 @@ void bgp_confederation_id_set(struct bgp *bgp, as_t as, const char *as_str) peer->connection->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; - bgp_notify_send( - peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_CONFIG_CHANGE); + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset_safe(peer, &nnode); } @@ -615,9 +616,9 @@ void bgp_confederation_id_set(struct bgp *bgp, as_t as, const char *as_str) peer->connection->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; - bgp_notify_send( - peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_CONFIG_CHANGE); + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset_safe(peer, &nnode); } @@ -642,7 +643,8 @@ void bgp_confederation_id_unset(struct bgp *bgp) if (BGP_IS_VALID_STATE_FOR_NOTIF( peer->connection->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } @@ -697,9 +699,9 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as, const char *as_str) peer->connection->status)) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; - bgp_notify_send( - peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_CONFIG_CHANGE); + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset_safe(peer, &nnode); } @@ -754,9 +756,9 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as) peer->connection->status)) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; - bgp_notify_send( - peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_CONFIG_CHANGE); + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset_safe(peer, &nnode); } @@ -947,13 +949,13 @@ int peer_cmp(struct peer *p1, struct peer *p2) } else return strcmp(p1->group->name, p2->group->name); - return sockunion_cmp(&p1->su, &p2->su); + return sockunion_cmp(&p1->connection->su, &p2->connection->su); } static unsigned int peer_hash_key_make(const void *p) { const struct peer *peer = p; - return sockunion_hash(&peer->su); + return sockunion_hash(&peer->connection->su); } static bool peer_hash_same(const void *p1, const void *p2) @@ -961,9 +963,9 @@ static bool peer_hash_same(const void *p1, const void *p2) const struct peer *peer1 = p1; const struct peer *peer2 = p2; - return (sockunion_same(&peer1->su, &peer2->su) - && CHECK_FLAG(peer1->flags, PEER_FLAG_CONFIG_NODE) - == CHECK_FLAG(peer2->flags, PEER_FLAG_CONFIG_NODE)); + return (sockunion_same(&peer1->connection->su, &peer2->connection->su) && + CHECK_FLAG(peer1->flags, PEER_FLAG_CONFIG_NODE) == + CHECK_FLAG(peer2->flags, PEER_FLAG_CONFIG_NODE)); } void peer_flag_inherit(struct peer *peer, uint64_t flag) @@ -1148,13 +1150,15 @@ void bgp_peer_connection_buffers_free(struct peer_connection *connection) } } -static void bgp_peer_connection_free(struct peer_connection *connection) +void bgp_peer_connection_free(struct peer_connection **connection) { - bgp_peer_connection_buffers_free(connection); - pthread_mutex_destroy(&connection->io_mtx); + bgp_peer_connection_buffers_free(*connection); + pthread_mutex_destroy(&(*connection)->io_mtx); + + memset(*connection, 0, sizeof(struct peer_connection)); + XFREE(MTYPE_BGP_PEER_CONNECTION, *connection); - memset(connection, 0, sizeof(struct peer_connection)); - XFREE(MTYPE_BGP_PEER_CONNECTION, connection); + connection = NULL; } struct peer_connection *bgp_peer_connection_new(struct peer *peer) @@ -1204,20 +1208,21 @@ static void peer_free(struct peer *peer) /* this /ought/ to have been done already through bgp_stop earlier, * but just to be sure.. */ - bgp_timer_set(peer); + bgp_timer_set(peer->connection); bgp_reads_off(peer->connection); bgp_writes_off(peer->connection); - event_cancel_event_ready(bm->master, peer); + event_cancel_event_ready(bm->master, peer->connection); FOREACH_AFI_SAFI (afi, safi) EVENT_OFF(peer->t_revalidate_all[afi][safi]); assert(!peer->connection->t_write); assert(!peer->connection->t_read); - BGP_EVENT_FLUSH(peer); + event_cancel_event_ready(bm->master, peer->connection); /* Free connected nexthop, if present */ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) && !peer_dynamic_neighbor(peer)) - bgp_delete_connected_nexthop(family2afi(peer->su.sa.sa_family), + bgp_delete_connected_nexthop(family2afi(peer->connection->su.sa + .sa_family), peer); FOREACH_AFI_SAFI (afi, safi) { @@ -1267,7 +1272,7 @@ static void peer_free(struct peer *peer) if (peer->as_pretty) XFREE(MTYPE_BGP, peer->as_pretty); - bgp_peer_connection_free(peer->connection); + bgp_peer_connection_free(&peer->connection); bgp_unlock(peer->bgp); @@ -1602,7 +1607,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) peer_dst->ttl = peer_src->ttl; } -static int bgp_peer_conf_if_to_su_update_v4(struct peer *peer, +static int bgp_peer_conf_if_to_su_update_v4(struct peer_connection *connection, struct interface *ifp) { struct connected *ifc; @@ -1617,44 +1622,43 @@ static int bgp_peer_conf_if_to_su_update_v4(struct peer *peer, if (ifc->address && (ifc->address->family == AF_INET)) { prefix_copy(&p, CONNECTED_PREFIX(ifc)); if (p.prefixlen == 30) { - peer->su.sa.sa_family = AF_INET; + connection->su.sa.sa_family = AF_INET; addr = ntohl(p.u.prefix4.s_addr); if (addr % 4 == 1) - peer->su.sin.sin_addr.s_addr = + connection->su.sin.sin_addr.s_addr = htonl(addr + 1); else if (addr % 4 == 2) - peer->su.sin.sin_addr.s_addr = + connection->su.sin.sin_addr.s_addr = htonl(addr - 1); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - peer->su.sin.sin_len = + connection->su.sin.sin_len = sizeof(struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ return 1; } else if (p.prefixlen == 31) { - peer->su.sa.sa_family = AF_INET; + connection->su.sa.sa_family = AF_INET; addr = ntohl(p.u.prefix4.s_addr); if (addr % 2 == 0) - peer->su.sin.sin_addr.s_addr = + connection->su.sin.sin_addr.s_addr = htonl(addr + 1); else - peer->su.sin.sin_addr.s_addr = + connection->su.sin.sin_addr.s_addr = htonl(addr - 1); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - peer->su.sin.sin_len = + connection->su.sin.sin_len = sizeof(struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ return 1; - } else if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s: IPv4 interface address is not /30 or /31, v4 session not started", - peer->conf_if); + } else if (bgp_debug_neighbor_events(connection->peer)) + zlog_debug("%s: IPv4 interface address is not /30 or /31, v4 session not started", + connection->peer->conf_if); } } return 0; } -static bool bgp_peer_conf_if_to_su_update_v6(struct peer *peer, +static bool bgp_peer_conf_if_to_su_update_v6(struct peer_connection *connection, struct interface *ifp) { struct nbr_connected *ifc_nbr; @@ -1662,13 +1666,13 @@ static bool bgp_peer_conf_if_to_su_update_v6(struct peer *peer, /* Have we learnt the peer's IPv6 link-local address? */ if (ifp->nbr_connected && (ifc_nbr = listnode_head(ifp->nbr_connected))) { - peer->su.sa.sa_family = AF_INET6; - memcpy(&peer->su.sin6.sin6_addr, &ifc_nbr->address->u.prefix, - sizeof(struct in6_addr)); + connection->su.sa.sa_family = AF_INET6; + memcpy(&connection->su.sin6.sin6_addr, + &ifc_nbr->address->u.prefix, sizeof(struct in6_addr)); #ifdef SIN6_LEN - peer->su.sin6.sin6_len = sizeof(struct sockaddr_in6); + connection->su.sin6.sin6_len = sizeof(struct sockaddr_in6); #endif - peer->su.sin6.sin6_scope_id = ifp->ifindex; + connection->su.sin6.sin6_scope_id = ifp->ifindex; return true; } @@ -1680,13 +1684,14 @@ static bool bgp_peer_conf_if_to_su_update_v6(struct peer *peer, * learnt/derived peer address. If the address has changed, update the * password on the listen socket, if needed. */ -void bgp_peer_conf_if_to_su_update(struct peer *peer) +void bgp_peer_conf_if_to_su_update(struct peer_connection *connection) { struct interface *ifp; int prev_family; int peer_addr_updated = 0; struct listnode *node; union sockunion old_su; + struct peer *peer = connection->peer; /* * This function is only ever needed when FRR an interface @@ -1696,9 +1701,9 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer) if (!peer->conf_if) return; - old_su = peer->su; + old_su = connection->su; - prev_family = peer->su.sa.sa_family; + prev_family = connection->su.sa.sa_family; if ((ifp = if_lookup_by_name(peer->conf_if, peer->bgp->vrf_id))) { peer->ifp = ifp; /* If BGP unnumbered is not "v6only", we first see if we can @@ -1707,7 +1712,8 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer) */ if (!CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) peer_addr_updated = - bgp_peer_conf_if_to_su_update_v4(peer, ifp); + bgp_peer_conf_if_to_su_update_v4(connection, + ifp); /* If "v6only" or we can't derive peer's IPv4 address, see if * we've @@ -1717,7 +1723,8 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer) */ if (!peer_addr_updated) peer_addr_updated = - bgp_peer_conf_if_to_su_update_v6(peer, ifp); + bgp_peer_conf_if_to_su_update_v6(connection, + ifp); } /* If we could derive the peer address, we may need to install the * password @@ -1729,20 +1736,21 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer) if (peer_addr_updated) { if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD) && prev_family == AF_UNSPEC) - bgp_md5_set(peer); + bgp_md5_set(connection); } else { if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD) && prev_family != AF_UNSPEC) - bgp_md5_unset(peer); - peer->su.sa.sa_family = AF_UNSPEC; - memset(&peer->su.sin6.sin6_addr, 0, sizeof(struct in6_addr)); + bgp_md5_unset(connection); + connection->su.sa.sa_family = AF_UNSPEC; + memset(&connection->su.sin6.sin6_addr, 0, + sizeof(struct in6_addr)); } /* * If they are the same, nothing to do here, move along */ - if (!sockunion_same(&old_su, &peer->su)) { - union sockunion new_su = peer->su; + if (!sockunion_same(&old_su, &connection->su)) { + union sockunion new_su = connection->su; struct bgp *bgp = peer->bgp; /* @@ -1771,11 +1779,11 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer) * scan through looking for a matching * su if needed. */ - peer->su = old_su; + connection->su = old_su; hash_release(peer->bgp->peerhash, peer); listnode_delete(peer->bgp->peer, peer); - peer->su = new_su; + connection->su = new_su; (void)hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); listnode_add_sort(peer->bgp->peer, peer); @@ -1842,13 +1850,13 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, if (conf_if) { peer->conf_if = XSTRDUP(MTYPE_PEER_CONF_IF, conf_if); if (su) - peer->su = *su; + peer->connection->su = *su; else - bgp_peer_conf_if_to_su_update(peer); + bgp_peer_conf_if_to_su_update(peer->connection); XFREE(MTYPE_BGP_PEER_HOST, peer->host); peer->host = XSTRDUP(MTYPE_BGP_PEER_HOST, conf_if); } else if (su) { - peer->su = *su; + peer->connection->su = *su; sockunion2str(su, buf, SU_ADDRSTRLEN); XFREE(MTYPE_BGP_PEER_HOST, peer->host); peer->host = XSTRDUP(MTYPE_BGP_PEER_HOST, buf); @@ -1887,7 +1895,7 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, active = peer_active(peer); if (!active) { - if (peer->su.sa.sa_family == AF_UNSPEC) + if (peer->connection->su.sa.sa_family == AF_UNSPEC) peer->last_reset = PEER_DOWN_NBR_ADDR; else peer->last_reset = PEER_DOWN_NOAFI_ACTIVATED; @@ -1919,7 +1927,7 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, peer_flag_set(peer, PEER_FLAG_SHUTDOWN); /* Set up peer's events and timers. */ else if (!active && peer_active(peer)) - bgp_timer_set(peer); + bgp_timer_set(peer->connection); bgp_peer_gr_flags_update(peer); BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer); @@ -1970,7 +1978,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(peer); @@ -2034,6 +2042,10 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_L2VPN][SAFI_EVPN], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG(peer->af_flags[AFI_LINKSTATE][SAFI_LINKSTATE], + PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG(peer->af_flags[AFI_LINKSTATE][SAFI_LINKSTATE_VPN], + PEER_FLAG_REFLECTOR_CLIENT); } } @@ -2321,9 +2333,9 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) peer_group2peer_config_copy_af(peer->group, peer, afi, safi); if (!active && peer_active(peer)) { - bgp_timer_set(peer); + bgp_timer_set(peer->connection); } else { - if (peer_established(peer)) { + if (peer_established(peer->connection)) { if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 1; bgp_capability_send(peer, afi, safi, @@ -2336,14 +2348,15 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) } } else { peer->last_reset = PEER_DOWN_AF_ACTIVATE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } if (peer->connection->status == OpenSent || peer->connection->status == OpenConfirm) { peer->last_reset = PEER_DOWN_AF_ACTIVATE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } /* @@ -2359,7 +2372,7 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) if (other && (other->connection->status == OpenSent || other->connection->status == OpenConfirm)) { other->last_reset = PEER_DOWN_AF_ACTIVATE; - bgp_notify_send(other, BGP_NOTIFY_CEASE, + bgp_notify_send(other->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } @@ -2454,7 +2467,7 @@ static bool non_peergroup_deactivate_af(struct peer *peer, afi_t afi, return true; } - if (peer_established(peer)) { + if (peer_established(peer->connection)) { if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 0; peer->afc_nego[afi][safi] = 0; @@ -2467,12 +2480,13 @@ static bool non_peergroup_deactivate_af(struct peer *peer, afi_t afi, peer->pcount[afi][safi] = 0; } else { peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } else { peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } @@ -2542,13 +2556,13 @@ void peer_nsf_stop(struct peer *peer) EVENT_OFF(peer->t_llgr_stale[afi][safi]); } - if (peer->t_gr_restart) { - EVENT_OFF(peer->t_gr_restart); + if (peer->connection->t_gr_restart) { + EVENT_OFF(peer->connection->t_gr_restart); if (bgp_debug_neighbor_events(peer)) zlog_debug("%pBP graceful restart timer stopped", peer); } - if (peer->t_gr_stale) { - EVENT_OFF(peer->t_gr_stale); + if (peer->connection->t_gr_stale) { + EVENT_OFF(peer->connection->t_gr_stale); if (bgp_debug_neighbor_events(peer)) zlog_debug( "%pBP graceful restart stalepath timer stopped", @@ -2585,10 +2599,10 @@ int peer_delete(struct peer *peer) bgp_soft_reconfig_table_task_cancel(bgp, NULL, peer); - bgp_keepalives_off(peer); + bgp_keepalives_off(peer->connection); bgp_reads_off(peer->connection); bgp_writes_off(peer->connection); - event_cancel_event_ready(bm->master, peer); + event_cancel_event_ready(bm->master, peer->connection); FOREACH_AFI_SAFI (afi, safi) EVENT_OFF(peer->t_revalidate_all[afi][safi]); assert(!CHECK_FLAG(peer->connection->thread_flags, @@ -2634,7 +2648,7 @@ int peer_delete(struct peer *peer) } UNSET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER); - bgp_fsm_change_status(peer, Deleted); + bgp_fsm_change_status(peer->connection, Deleted); /* Remove from NHT */ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) @@ -2643,13 +2657,14 @@ int peer_delete(struct peer *peer) /* Password configuration */ if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD)) { XFREE(MTYPE_PEER_PASSWORD, peer->password); - if (!accept_peer && !BGP_PEER_SU_UNSPEC(peer) - && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) - && !CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR)) - bgp_md5_unset(peer); + if (!accept_peer && + !BGP_CONNECTION_SU_UNSPEC(peer->connection) && + !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) && + !CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR)) + bgp_md5_unset(peer->connection); } - bgp_timer_set(peer); /* stops all timers for Deleted */ + bgp_timer_set(peer->connection); /* stops all timers for Deleted */ /* Delete from all peer list. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) @@ -2857,8 +2872,8 @@ static void peer_group2peer_config_copy(struct peer_group *group, PEER_STR_ATTR_INHERIT(peer, group, password, MTYPE_PEER_PASSWORD); - if (!BGP_PEER_SU_UNSPEC(peer)) - bgp_md5_set(peer); + if (!BGP_CONNECTION_SU_UNSPEC(peer->connection)) + bgp_md5_set(peer->connection); /* update-source apply */ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_UPDATE_SOURCE)) { @@ -2917,7 +2932,7 @@ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as, void peer_notify_unconfig(struct peer *peer) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_PEER_UNCONFIG); } @@ -2932,7 +2947,7 @@ static void peer_notify_shutdown(struct peer *peer) } if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); } @@ -3084,8 +3099,8 @@ int peer_group_listen_range_del(struct peer_group *group, struct prefix *range) if (!peer_dynamic_neighbor(peer)) continue; - if (sockunion2hostprefix(&peer->su, &prefix2) - && prefix_match(prefix, &prefix2)) { + if (sockunion2hostprefix(&peer->connection->su, &prefix2) && + prefix_match(prefix, &prefix2)) { if (bgp_debug_neighbor_events(peer)) zlog_debug( "Deleting dynamic neighbor %s group %s upon delete of listen range %pFX", @@ -3200,7 +3215,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_RMAP_BIND; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else { bgp_session_reset(peer); @@ -3239,7 +3254,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, /* Set up peer's events and timers. */ if (peer_active(peer)) - bgp_timer_set(peer); + bgp_timer_set(peer->connection); } return 0; @@ -3731,7 +3746,7 @@ void bgp_instance_up(struct bgp *bgp) /* Kick off any peers that may have been configured. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer)) { if (!BGP_PEER_START_SUPPRESSED(peer)) - BGP_EVENT_ADD(peer, BGP_Start); + BGP_EVENT_ADD(peer->connection, BGP_Start); } /* Process any networks that have been configured. */ @@ -3755,7 +3770,7 @@ void bgp_instance_down(struct bgp *bgp) /* Bring down peers, so corresponding routes are purged. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); else bgp_session_reset(peer); @@ -4116,8 +4131,11 @@ struct peer *peer_lookup(struct bgp *bgp, union sockunion *su) { struct peer *peer = NULL; struct peer tmp_peer; + struct peer_connection connection; + memset(&connection, 0, sizeof(struct peer_connection)); memset(&tmp_peer, 0, sizeof(struct peer)); + tmp_peer.connection = &connection; /* * We do not want to find the doppelganger peer so search for the peer @@ -4126,7 +4144,7 @@ struct peer *peer_lookup(struct bgp *bgp, union sockunion *su) */ SET_FLAG(tmp_peer.flags, PEER_FLAG_CONFIG_NODE); - tmp_peer.su = *su; + connection.su = *su; if (bgp != NULL) { peer = hash_lookup(bgp->peerhash, &tmp_peer); @@ -4325,7 +4343,7 @@ bool bgp_path_attribute_discard(struct peer *peer, char *buf, size_t size) buf[0] = '\0'; - for (unsigned int i = 0; i < BGP_ATTR_MAX; i++) { + for (unsigned int i = 1; i <= BGP_ATTR_MAX; i++) { if (peer->discard_attrs[i]) snprintf(buf + strlen(buf), size - strlen(buf), "%s%d", (strlen(buf) > 0) ? " " : "", i); @@ -4345,7 +4363,7 @@ bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf, buf[0] = '\0'; - for (unsigned int i = 0; i < BGP_ATTR_MAX; i++) { + for (unsigned int i = 1; i <= BGP_ATTR_MAX; i++) { if (peer->withdraw_attrs[i]) snprintf(buf + strlen(buf), size - strlen(buf), "%s%d", (strlen(buf) > 0) ? " " : "", i); @@ -4360,7 +4378,7 @@ bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf, /* If peer is configured at least one address family return 1. */ bool peer_active(struct peer *peer) { - if (BGP_PEER_SU_UNSPEC(peer)) + if (BGP_CONNECTION_SU_UNSPEC(peer->connection)) return false; if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] @@ -4372,7 +4390,9 @@ bool peer_active(struct peer *peer) || peer->afc[AFI_IP6][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_FLOWSPEC] - || peer->afc[AFI_L2VPN][SAFI_EVPN]) + || peer->afc[AFI_L2VPN][SAFI_EVPN] + || peer->afc[AFI_LINKSTATE][SAFI_LINKSTATE] + || peer->afc[AFI_LINKSTATE][SAFI_LINKSTATE_VPN]) return true; return false; } @@ -4392,7 +4412,9 @@ bool peer_active_nego(struct peer *peer) || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP6][SAFI_ENCAP] || peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] - || peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) + || peer->afc_nego[AFI_L2VPN][SAFI_EVPN] + || peer->afc_nego[AFI_LINKSTATE][SAFI_LINKSTATE] + || peer->afc_nego[AFI_LINKSTATE][SAFI_LINKSTATE_VPN]) return true; return false; } @@ -4431,7 +4453,7 @@ void peer_change_action(struct peer *peer, afi_t afi, safi_t safi, if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) return; - if (!peer_established(peer)) + if (!peer_established(peer->connection)) return; if (type == peer_change_reset) { @@ -4443,7 +4465,7 @@ void peer_change_action(struct peer *peer, afi_t afi, safi_t safi, PEER_FLAG_CONFIG_NODE))) peer_delete(peer->doppelganger); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else if (type == peer_change_reset_in) { if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_RCV)) @@ -4456,7 +4478,7 @@ void peer_change_action(struct peer *peer, afi_t afi, safi_t safi, PEER_FLAG_CONFIG_NODE))) peer_delete(peer->doppelganger); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } else if (type == peer_change_reset_out) { @@ -4601,8 +4623,8 @@ static void peer_flag_modify_action(struct peer *peer, uint64_t flag) UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); - if (peer->t_pmax_restart) { - EVENT_OFF(peer->t_pmax_restart); + if (peer->connection->t_pmax_restart) { + EVENT_OFF(peer->connection->t_pmax_restart); if (bgp_debug_neighbor_events(peer)) zlog_debug( "%pBP Maximum-prefix restart timer canceled", @@ -4627,18 +4649,19 @@ static void peer_flag_modify_action(struct peer *peer, uint64_t flag) memcpy(msgbuf + 1, msg, msglen); bgp_notify_send_with_data( - peer, BGP_NOTIFY_CEASE, + peer->connection, + BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, msgbuf, msglen + 1); } else - bgp_notify_send( - peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); } else bgp_session_reset(peer); } else { peer->v_start = BGP_INIT_START_TIMER; - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Stop); } } else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) @@ -4648,7 +4671,7 @@ static void peer_flag_modify_action(struct peer *peer, uint64_t flag) else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(peer); @@ -4687,14 +4710,14 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg) data[0] = datalen; memcpy(data + 1, msg, datalen); - bgp_notify_send_with_data( - peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, data, - datalen + 1); + bgp_notify_send_with_data(peer->connection, + BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, + data, datalen + 1); } else { - bgp_notify_send( - peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); } } @@ -4702,7 +4725,7 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg) peer->v_start = BGP_INIT_START_TIMER; /* trigger a RFC 4271 ManualStop event */ - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Stop); } /* set the BGP instances shutdown flag */ @@ -4727,7 +4750,7 @@ void bgp_shutdown_disable(struct bgp *bgp) UNSET_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN); for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) - bgp_timer_set(peer); + bgp_timer_set(peer->connection); } /* Change specified peer flag. */ @@ -4952,8 +4975,8 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, COND_FLAG(peer->af_flags[afi][safi], flag, set); /* Execute action when peer is established. */ - if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) - && peer_established(peer)) { + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) && + peer_established(peer->connection)) { if (!set && flag == PEER_FLAG_SOFT_RECONFIG) bgp_clear_adj_in(peer, afi, safi); else { @@ -5006,7 +5029,7 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, set != member_invert); /* Execute flag action on peer-group member. */ - if (peer_established(member)) { + if (peer_established(member->connection)) { if (!set && flag == PEER_FLAG_SOFT_RECONFIG) bgp_clear_adj_in(member, afi, safi); else { @@ -5101,7 +5124,8 @@ int peer_ebgp_multihop_set(struct peer *peer, int ttl) if (peer->sort != BGP_PEER_IBGP) { if (BGP_IS_VALID_STATE_FOR_NOTIF( peer->connection->status)) - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else bgp_session_reset(peer); @@ -5120,7 +5144,8 @@ int peer_ebgp_multihop_set(struct peer *peer, int ttl) if (BGP_IS_VALID_STATE_FOR_NOTIF( peer->connection->status)) - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else bgp_session_reset(peer); @@ -5157,7 +5182,7 @@ int peer_ebgp_multihop_unset(struct peer *peer) if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else bgp_session_reset(peer); @@ -5176,9 +5201,9 @@ int peer_ebgp_multihop_unset(struct peer *peer) if (peer->connection->fd >= 0) { if (BGP_IS_VALID_STATE_FOR_NOTIF( peer->connection->status)) - bgp_notify_send( - peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_CONFIG_CHANGE); + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); else bgp_session_reset(peer); } @@ -5332,7 +5357,7 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(peer); @@ -5370,7 +5395,7 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; - bgp_notify_send(member, BGP_NOTIFY_CEASE, + bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(member); @@ -5403,7 +5428,7 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(peer); @@ -5440,7 +5465,7 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; - bgp_notify_send(member, BGP_NOTIFY_CEASE, + bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(member); @@ -5491,7 +5516,7 @@ void peer_update_source_unset(struct peer *peer) /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(peer); @@ -5527,7 +5552,7 @@ void peer_update_source_unset(struct peer *peer) /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; - bgp_notify_send(member, BGP_NOTIFY_CEASE, + bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(member); @@ -5606,7 +5631,8 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Update peer route announcements. */ - if (peer_established(peer) && peer->afc_nego[afi][safi]) { + if (peer_established(peer->connection) && + peer->afc_nego[afi][safi]) { update_group_adjust_peer(peer_af_find(peer, afi, safi)); bgp_default_originate(peer, afi, safi, 0); bgp_announce_route(peer, afi, safi, false); @@ -5647,7 +5673,8 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, } /* Update peer route announcements. */ - if (peer_established(member) && member->afc_nego[afi][safi]) { + if (peer_established(member->connection) && + member->afc_nego[afi][safi]) { update_group_adjust_peer( peer_af_find(member, afi, safi)); bgp_default_originate(member, afi, safi, 0); @@ -5692,7 +5719,8 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Update peer route announcements. */ - if (peer_established(peer) && peer->afc_nego[afi][safi]) { + if (peer_established(peer->connection) && + peer->afc_nego[afi][safi]) { update_group_adjust_peer(peer_af_find(peer, afi, safi)); bgp_default_originate(peer, afi, safi, 1); bgp_announce_route(peer, afi, safi, false); @@ -5730,7 +5758,8 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi) member->default_rmap[afi][safi].map = NULL; /* Update peer route announcements. */ - if (peer_established(member) && member->afc_nego[afi][safi]) { + if (peer_established(member->connection) && + member->afc_nego[afi][safi]) { update_group_adjust_peer(peer_af_find(member, afi, safi)); bgp_default_originate(member, afi, safi, 1); bgp_announce_route(member, afi, safi, false); @@ -5760,6 +5789,7 @@ void peer_tcp_mss_set(struct peer *peer, uint32_t tcp_mss) { peer->tcp_mss = tcp_mss; SET_FLAG(peer->flags, PEER_FLAG_TCP_MSS); + bgp_tcp_mss_set(peer); } /* Reset the TCP-MSS value in the peer structure, @@ -5770,6 +5800,7 @@ void peer_tcp_mss_unset(struct peer *peer) { UNSET_FLAG(peer->flags, PEER_FLAG_TCP_MSS); peer->tcp_mss = 0; + bgp_tcp_mss_set(peer); } /* @@ -5782,10 +5813,10 @@ void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi, { if (outbound) { update_group_adjust_peer(peer_af_find(peer, afi, safi)); - if (peer_established(peer)) + if (peer_established(peer->connection)) bgp_announce_route(peer, afi, safi, false); } else { - if (!peer_established(peer)) + if (!peer_established(peer->connection)) return; if (bgp_soft_reconfig_in(peer, afi, safi)) @@ -5980,10 +6011,10 @@ int peer_timers_connect_set(struct peer *peer, uint32_t connect) /* Skip peer-group mechanics for regular peers. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (!peer_established(peer)) { + if (!peer_established(peer->connection)) { if (peer_active(peer)) - BGP_EVENT_ADD(peer, BGP_Stop); - BGP_EVENT_ADD(peer, BGP_Start); + BGP_EVENT_ADD(peer->connection, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Start); } return 0; } @@ -6001,10 +6032,10 @@ int peer_timers_connect_set(struct peer *peer, uint32_t connect) member->connect = connect; member->v_connect = connect; - if (!peer_established(member)) { + if (!peer_established(member->connection)) { if (peer_active(member)) - BGP_EVENT_ADD(member, BGP_Stop); - BGP_EVENT_ADD(member, BGP_Start); + BGP_EVENT_ADD(member->connection, BGP_Stop); + BGP_EVENT_ADD(member->connection, BGP_Start); } } @@ -6034,10 +6065,10 @@ int peer_timers_connect_unset(struct peer *peer) /* Skip peer-group mechanics for regular peers. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (!peer_established(peer)) { + if (!peer_established(peer->connection)) { if (peer_active(peer)) - BGP_EVENT_ADD(peer, BGP_Stop); - BGP_EVENT_ADD(peer, BGP_Start); + BGP_EVENT_ADD(peer->connection, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Start); } return 0; } @@ -6055,10 +6086,10 @@ int peer_timers_connect_unset(struct peer *peer) member->connect = 0; member->v_connect = peer->bgp->default_connect_retry; - if (!peer_established(member)) { + if (!peer_established(member->connection)) { if (peer_active(member)) - BGP_EVENT_ADD(member, BGP_Stop); - BGP_EVENT_ADD(member, BGP_Start); + BGP_EVENT_ADD(member->connection, BGP_Stop); + BGP_EVENT_ADD(member->connection, BGP_Start); } } @@ -6082,7 +6113,7 @@ int peer_advertise_interval_set(struct peer *peer, uint32_t routeadv) if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Update peer route announcements. */ update_group_adjust_peer_afs(peer); - if (peer_established(peer)) + if (peer_established(peer->connection)) bgp_announce_route_all(peer); /* Skip peer-group mechanics for regular peers. */ @@ -6105,7 +6136,7 @@ int peer_advertise_interval_set(struct peer *peer, uint32_t routeadv) /* Update peer route announcements. */ update_group_adjust_peer_afs(member); - if (peer_established(member)) + if (peer_established(member->connection)) bgp_announce_route_all(member); } @@ -6139,7 +6170,7 @@ int peer_advertise_interval_unset(struct peer *peer) if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Update peer route announcements. */ update_group_adjust_peer_afs(peer); - if (peer_established(peer)) + if (peer_established(peer->connection)) bgp_announce_route_all(peer); /* Skip peer-group mechanics for regular peers. */ @@ -6164,7 +6195,7 @@ int peer_advertise_interval_unset(struct peer *peer) /* Update peer route announcements. */ update_group_adjust_peer_afs(member); - if (peer_established(member)) + if (peer_established(member->connection)) bgp_announce_route_all(member); } @@ -6492,10 +6523,10 @@ int peer_local_as_unset(struct peer *peer) /* Send notification or stop peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else - BGP_EVENT_ADD(peer, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Stop); /* Skip peer-group mechanics for regular peers. */ return 0; @@ -6520,7 +6551,7 @@ int peer_local_as_unset(struct peer *peer) /* Send notification or stop peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; - bgp_notify_send(member, BGP_NOTIFY_CEASE, + bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(member); @@ -6551,7 +6582,7 @@ int peer_password_set(struct peer *peer, const char *password) if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else bgp_session_reset(peer); @@ -6560,10 +6591,11 @@ int peer_password_set(struct peer *peer, const char *password) * Attempt to install password on socket and skip peer-group * mechanics. */ - if (BGP_PEER_SU_UNSPEC(peer)) + if (BGP_CONNECTION_SU_UNSPEC(peer->connection)) return BGP_SUCCESS; - return (bgp_md5_set(peer) >= 0) ? BGP_SUCCESS - : BGP_ERR_TCPSIG_FAILED; + return (bgp_md5_set(peer->connection) >= 0) + ? BGP_SUCCESS + : BGP_ERR_TCPSIG_FAILED; } /* @@ -6587,13 +6619,14 @@ int peer_password_set(struct peer *peer, const char *password) /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) - bgp_notify_send(member, BGP_NOTIFY_CEASE, + bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else bgp_session_reset(member); /* Attempt to install password on socket. */ - if (!BGP_PEER_SU_UNSPEC(member) && bgp_md5_set(member) < 0) + if (!BGP_CONNECTION_SU_UNSPEC(member->connection) && + bgp_md5_set(member->connection) < 0) ret = BGP_ERR_TCPSIG_FAILED; } @@ -6632,14 +6665,14 @@ int peer_password_unset(struct peer *peer) if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else bgp_session_reset(peer); /* Attempt to uninstall password on socket. */ - if (!BGP_PEER_SU_UNSPEC(peer)) - bgp_md5_unset(peer); + if (!BGP_CONNECTION_SU_UNSPEC(peer->connection)) + bgp_md5_unset(peer->connection); /* Skip peer-group mechanics for regular peers. */ return 0; } @@ -6659,14 +6692,14 @@ int peer_password_unset(struct peer *peer) /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) - bgp_notify_send(member, BGP_NOTIFY_CEASE, + bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else bgp_session_reset(member); /* Attempt to uninstall password on socket. */ - if (!BGP_PEER_SU_UNSPEC(member)) - bgp_md5_unset(member); + if (!BGP_CONNECTION_SU_UNSPEC(member->connection)) + bgp_md5_unset(member->connection); } /* Set flag and configuration on all peer-group listen ranges */ @@ -7537,14 +7570,14 @@ static bool peer_maximum_prefix_clear_overflow(struct peer *peer) return false; UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); - if (peer->t_pmax_restart) { - EVENT_OFF(peer->t_pmax_restart); + if (peer->connection->t_pmax_restart) { + EVENT_OFF(peer->connection->t_pmax_restart); if (bgp_debug_neighbor_events(peer)) zlog_debug( "%pBP Maximum-prefix restart timer cancelled", peer); } - BGP_EVENT_ADD(peer, BGP_Start); + BGP_EVENT_ADD(peer->connection, BGP_Start); return true; } @@ -7576,7 +7609,8 @@ int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi, /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { /* Re-check if peer violates maximum-prefix. */ - if ((peer_established(peer)) && (peer->afc[afi][safi])) + if ((peer_established(peer->connection)) && + (peer->afc[afi][safi])) bgp_maximum_prefix_overflow(peer, afi, safi, 1); /* Skip peer-group mechanics for regular peers. */ @@ -7613,7 +7647,8 @@ int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi, PEER_FLAG_MAX_PREFIX_WARNING); /* Re-check if peer violates maximum-prefix. */ - if ((peer_established(member)) && (member->afc[afi][safi])) + if ((peer_established(member->connection)) && + (member->afc[afi][safi])) bgp_maximum_prefix_overflow(member, afi, safi, 1); } @@ -7684,7 +7719,7 @@ void peer_maximum_prefix_out_refresh_routes(struct peer *peer, afi_t afi, { update_group_adjust_peer(peer_af_find(peer, afi, safi)); - if (peer_established(peer)) + if (peer_established(peer->connection)) bgp_announce_route(peer, afi, safi, false); } @@ -7802,8 +7837,9 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) struct listnode *node, *nnode; int ret; - zlog_debug("%s: set gtsm_hops to %d for %s", __func__, gtsm_hops, - peer->host); + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s: set gtsm_hops to %d for %s", __func__, + gtsm_hops, peer->host); /* We cannot configure ttl-security hops when ebgp-multihop is already set. For non peer-groups, the check is simple. For peer-groups, @@ -7860,13 +7896,13 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) peer->gtsm_hops = gtsm_hops; if (peer->connection->fd >= 0) - sockopt_minttl(peer->su.sa.sa_family, + sockopt_minttl(peer->connection->su.sa.sa_family, peer->connection->fd, MAXTTL + 1 - gtsm_hops); if ((peer->connection->status < Established) && peer->doppelganger && (peer->doppelganger->connection->fd >= 0)) - sockopt_minttl(peer->su.sa.sa_family, + sockopt_minttl(peer->connection->su.sa.sa_family, peer->doppelganger->connection->fd, MAXTTL + 1 - gtsm_hops); } else { @@ -7874,6 +7910,8 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) group->conf->gtsm_hops = gtsm_hops; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, gpeer)) { + struct peer_connection *connection = + gpeer->connection; gpeer->gtsm_hops = group->conf->gtsm_hops; /* Change setting of existing peer @@ -7884,16 +7922,16 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) * no session then do nothing (will get * handled by next connection) */ - if (gpeer->connection->fd >= 0 && + if (connection->fd >= 0 && gpeer->gtsm_hops != BGP_GTSM_HOPS_DISABLED) - sockopt_minttl(gpeer->su.sa.sa_family, - gpeer->connection->fd, + sockopt_minttl(connection->su.sa.sa_family, + connection->fd, MAXTTL + 1 - gpeer->gtsm_hops); - if ((gpeer->connection->status < Established) && + if ((connection->status < Established) && gpeer->doppelganger && (gpeer->doppelganger->connection->fd >= 0)) - sockopt_minttl(gpeer->su.sa.sa_family, + sockopt_minttl(connection->su.sa.sa_family, gpeer->doppelganger ->connection->fd, MAXTTL + 1 - gtsm_hops); @@ -7910,7 +7948,9 @@ int peer_ttl_security_hops_unset(struct peer *peer) struct listnode *node, *nnode; int ret = 0; - zlog_debug("%s: set gtsm_hops to zero for %s", __func__, peer->host); + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s: set gtsm_hops to zero for %s", __func__, + peer->host); /* if a peer-group member, then reset to peer-group default rather than * 0 */ @@ -7929,13 +7969,13 @@ int peer_ttl_security_hops_unset(struct peer *peer) ret = peer_ebgp_multihop_unset(peer); else { if (peer->connection->fd >= 0) - sockopt_minttl(peer->su.sa.sa_family, + sockopt_minttl(peer->connection->su.sa.sa_family, peer->connection->fd, 0); if ((peer->connection->status < Established) && peer->doppelganger && (peer->doppelganger->connection->fd >= 0)) - sockopt_minttl(peer->su.sa.sa_family, + sockopt_minttl(peer->connection->su.sa.sa_family, peer->doppelganger->connection->fd, 0); } @@ -7947,13 +7987,15 @@ int peer_ttl_security_hops_unset(struct peer *peer) ret = peer_ebgp_multihop_unset(peer); else { if (peer->connection->fd >= 0) - sockopt_minttl(peer->su.sa.sa_family, + sockopt_minttl(peer->connection->su.sa + .sa_family, peer->connection->fd, 0); if ((peer->connection->status < Established) && peer->doppelganger && (peer->doppelganger->connection->fd >= 0)) - sockopt_minttl(peer->su.sa.sa_family, + sockopt_minttl(peer->connection->su.sa + .sa_family, peer->doppelganger ->connection->fd, 0); @@ -8008,7 +8050,7 @@ int peer_clear(struct peer *peer, struct listnode **nnode) peer->v_start = BGP_INIT_START_TIMER; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_RESET); else bgp_session_reset_safe(peer, nnode); @@ -8021,7 +8063,7 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi, { struct peer_af *paf; - if (!peer_established(peer)) + if (!peer_established(peer->connection)) return 0; if (!peer->afc[afi][safi]) @@ -8313,8 +8355,8 @@ static int peer_unshut_after_cfg(struct bgp *bgp) if (peer_active(peer) && peer->connection->status != Established) { if (peer->connection->status != Idle) - BGP_EVENT_ADD(peer, BGP_Stop); - BGP_EVENT_ADD(peer, BGP_Start); + BGP_EVENT_ADD(peer->connection, BGP_Stop); + BGP_EVENT_ADD(peer->connection, BGP_Start); } } @@ -8355,6 +8397,8 @@ void bgp_init(unsigned short instance) #endif bgp_ethernetvpn_init(); bgp_flowspec_vty_init(); + bgp_linkstate_init(); + bgp_linkstate_vty_init(); /* Access list initialize. */ access_list_init(); @@ -8415,7 +8459,8 @@ void bgp_terminate(void) } if (BGP_IS_VALID_STATE_FOR_NOTIF( peer->connection->status)) - bgp_notify_send(peer, BGP_NOTIFY_CEASE, + bgp_notify_send(peer->connection, + BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_PEER_UNCONFIG); } } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index dd8096c574e3..8f78e33f6517 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -81,6 +81,8 @@ enum bgp_af_index { BGP_AF_IPV6_LBL_UNICAST, BGP_AF_IPV4_FLOWSPEC, BGP_AF_IPV6_FLOWSPEC, + BGP_AF_LINKSTATE, + BGP_AF_LINKSTATE_VPN, BGP_AF_MAX }; @@ -1138,16 +1140,35 @@ struct peer_connection { struct event *t_read; struct event *t_write; + struct event *t_connect; + struct event *t_delayopen; + struct event *t_start; + struct event *t_holdtime; + struct event *t_connect_check_r; + struct event *t_connect_check_w; + + struct event *t_gr_restart; + struct event *t_gr_stale; + + struct event *t_generate_updgrp_packets; + struct event *t_pmax_restart; + + struct event *t_routeadv; struct event *t_process_packet; struct event *t_process_packet_error; + union sockunion su; +#define BGP_CONNECTION_SU_UNSPEC(connection) \ + (connection->su.sa.sa_family == AF_UNSPEC) + /* Thread flags */ _Atomic uint32_t thread_flags; #define PEER_THREAD_WRITES_ON (1U << 0) #define PEER_THREAD_READS_ON (1U << 1) }; extern struct peer_connection *bgp_peer_connection_new(struct peer *peer); +extern void bgp_peer_connection_free(struct peer_connection **connection); extern void bgp_peer_connection_buffers_free(struct peer_connection *connection); /* BGP neighbor structure. */ @@ -1225,8 +1246,7 @@ struct peer { char *desc; /* Description of the peer. */ unsigned short port; /* Destination port for peer */ char *host; /* Printable address of the peer. */ - union sockunion su; /* Sockunion address of the peer. */ -#define BGP_PEER_SU_UNSPEC(peer) (peer->su.sa.sa_family == AF_UNSPEC) + time_t uptime; /* Last Up/Down time */ time_t readtime; /* Last read time */ time_t resettime; /* Last reset time */ @@ -1548,19 +1568,8 @@ struct peer { _Atomic uint32_t v_gr_restart; /* Threads. */ - struct event *t_start; - struct event *t_connect_check_r; - struct event *t_connect_check_w; - struct event *t_connect; - struct event *t_holdtime; - struct event *t_routeadv; - struct event *t_delayopen; - struct event *t_pmax_restart; - struct event *t_gr_restart; - struct event *t_gr_stale; struct event *t_llgr_stale[AFI_MAX][SAFI_MAX]; struct event *t_revalidate_all[AFI_MAX][SAFI_MAX]; - struct event *t_generate_updgrp_packets; struct event *t_refresh_stalepath; /* Thread flags. */ @@ -1802,10 +1811,10 @@ struct peer { #define BGP_ATTR_MAX 255 /* Path attributes discard */ - bool discard_attrs[BGP_ATTR_MAX]; + bool discard_attrs[BGP_ATTR_MAX + 1]; /* Path attributes treat-as-withdraw */ - bool withdraw_attrs[BGP_ATTR_MAX]; + bool withdraw_attrs[BGP_ATTR_MAX + 1]; /* BGP Software Version Capability */ #define BGP_MAX_SOFT_VERSION 64 @@ -1917,6 +1926,7 @@ struct bgp_nlri { #define BGP_ATTR_ENCAP 23 #define BGP_ATTR_IPV6_EXT_COMMUNITIES 25 #define BGP_ATTR_AIGP 26 +#define BGP_ATTR_LINK_STATE 29 #define BGP_ATTR_LARGE_COMMUNITIES 32 #define BGP_ATTR_OTC 35 #define BGP_ATTR_PREFIX_SID 40 @@ -2164,7 +2174,7 @@ extern void bgp_set_evpn(struct bgp *bgp); extern struct peer *peer_lookup(struct bgp *, union sockunion *); extern struct peer *peer_lookup_by_conf_if(struct bgp *, const char *); extern struct peer *peer_lookup_by_hostname(struct bgp *, const char *); -extern void bgp_peer_conf_if_to_su_update(struct peer *); +extern void bgp_peer_conf_if_to_su_update(struct peer_connection *connection); extern int peer_group_listen_range_del(struct peer_group *, struct prefix *); extern struct peer_group *peer_group_lookup(struct bgp *, const char *); extern struct peer_group *peer_group_get(struct bgp *, const char *); @@ -2497,6 +2507,8 @@ static inline int afindex(afi_t afi, safi_t safi) return BGP_AF_IPV4_ENCAP; case SAFI_FLOWSPEC: return BGP_AF_IPV4_FLOWSPEC; + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_EVPN: case SAFI_UNSPEC: case SAFI_MAX: @@ -2517,6 +2529,8 @@ static inline int afindex(afi_t afi, safi_t safi) return BGP_AF_IPV6_ENCAP; case SAFI_FLOWSPEC: return BGP_AF_IPV6_FLOWSPEC; + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_EVPN: case SAFI_UNSPEC: case SAFI_MAX: @@ -2534,6 +2548,26 @@ static inline int afindex(afi_t afi, safi_t safi) case SAFI_ENCAP: case SAFI_FLOWSPEC: case SAFI_UNSPEC: + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: + case SAFI_MAX: + return BGP_AF_MAX; + } + break; + case AFI_LINKSTATE: + switch (safi) { + case SAFI_LINKSTATE: + return BGP_AF_LINKSTATE; + case SAFI_LINKSTATE_VPN: + return BGP_AF_LINKSTATE_VPN; + case SAFI_EVPN: + case SAFI_UNICAST: + case SAFI_MULTICAST: + case SAFI_LABELED_UNICAST: + case SAFI_MPLS_VPN: + case SAFI_ENCAP: + case SAFI_FLOWSPEC: + case SAFI_UNSPEC: case SAFI_MAX: return BGP_AF_MAX; } @@ -2563,7 +2597,9 @@ static inline int peer_afi_active_nego(const struct peer *peer, afi_t afi) || peer->afc_nego[afi][SAFI_MPLS_VPN] || peer->afc_nego[afi][SAFI_ENCAP] || peer->afc_nego[afi][SAFI_FLOWSPEC] - || peer->afc_nego[afi][SAFI_EVPN]) + || peer->afc_nego[afi][SAFI_EVPN] + || peer->afc_nego[afi][SAFI_LINKSTATE] + || peer->afc_nego[afi][SAFI_LINKSTATE_VPN]) return 1; return 0; } @@ -2583,21 +2619,24 @@ static inline int peer_group_af_configured(struct peer_group *group) || peer->afc[AFI_IP6][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_FLOWSPEC] - || peer->afc[AFI_L2VPN][SAFI_EVPN]) + || peer->afc[AFI_L2VPN][SAFI_EVPN] + || peer->afc[AFI_LINKSTATE][SAFI_LINKSTATE] + || peer->afc[AFI_LINKSTATE][SAFI_LINKSTATE_VPN]) return 1; return 0; } -static inline char *timestamp_string(time_t ts) +static inline char *timestamp_string(time_t ts, char *timebuf) { time_t tbuf; + tbuf = time(NULL) - (monotime(NULL) - ts); - return ctime(&tbuf); + return ctime_r(&tbuf, timebuf); } -static inline bool peer_established(struct peer *peer) +static inline bool peer_established(struct peer_connection *connection) { - return peer->connection->status == Established; + return connection->status == Established; } static inline bool peer_dynamic_neighbor(struct peer *peer) diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 27f7c88d7be1..126ba225cb66 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -248,6 +248,8 @@ void rfapiCheckRefcount(struct agg_node *rn, safi_t safi, int lockoffset) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_MAX: assert(!"Passed in safi should be impossible"); } @@ -2972,6 +2974,7 @@ static void rfapiBgpInfoFilteredImportEncap( case AFI_UNSPEC: case AFI_L2VPN: + case AFI_LINKSTATE: case AFI_MAX: flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi); return; @@ -3420,6 +3423,7 @@ void rfapiBgpInfoFilteredImportVPN( rt = import_table->imported_vpn[afi]; break; + case AFI_LINKSTATE: case AFI_UNSPEC: case AFI_MAX: flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi); @@ -3729,8 +3733,9 @@ void rfapiBgpInfoFilteredImportVPN( prefix_same(&pfx_un, &un_prefix)) { /* compare */ un_match = 1; } - if (!RFAPI_LOCAL_BI(bpi) && !RFAPI_LOCAL_BI(info_new) - && sockunion_same(&bpi->peer->su, &info_new->peer->su)) { + if (!RFAPI_LOCAL_BI(bpi) && !RFAPI_LOCAL_BI(info_new) && + sockunion_same(&bpi->peer->connection->su, + &info_new->peer->connection->su)) { /* old & new are both remote, same peer */ remote_peer_match = 1; } @@ -3818,6 +3823,8 @@ rfapiBgpInfoFilteredImportFunction(safi_t safi) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_MAX: /* not expected */ flog_err(EC_LIB_DEVELOPMENT, "%s: bad safi %d", __func__, safi); @@ -4062,6 +4069,8 @@ static void rfapiProcessPeerDownRt(struct peer *peer, case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_MAX: /* Suppress uninitialized variable warning */ rt = NULL; diff --git a/bgpd/rfapi/rfapi_monitor.c b/bgpd/rfapi/rfapi_monitor.c index 3fe957ba4de7..766b5d5360d9 100644 --- a/bgpd/rfapi/rfapi_monitor.c +++ b/bgpd/rfapi/rfapi_monitor.c @@ -237,6 +237,8 @@ void rfapiMonitorExtraFlush(safi_t safi, struct agg_node *rn) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_MAX: assert(0); } @@ -305,6 +307,8 @@ void rfapiMonitorExtraPrune(safi_t safi, struct agg_node *rn) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_LINKSTATE: + case SAFI_LINKSTATE_VPN: case SAFI_MAX: assert(0); } diff --git a/bgpd/subdir.am b/bgpd/subdir.am index c2dd207a49d1..8b6b5ae7435a 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -51,6 +51,9 @@ bgpd_libbgp_a_SOURCES = \ bgpd/bgp_label.c \ bgpd/bgp_labelpool.c \ bgpd/bgp_lcommunity.c \ + bgpd/bgp_linkstate.c \ + bgpd/bgp_linkstate_tlv.c \ + bgpd/bgp_linkstate_vty.c \ bgpd/bgp_mac.c \ bgpd/bgp_memory.c \ bgpd/bgp_mpath.c \ @@ -133,6 +136,9 @@ noinst_HEADERS += \ bgpd/bgp_label.h \ bgpd/bgp_labelpool.h \ bgpd/bgp_lcommunity.h \ + bgpd/bgp_linkstate.h \ + bgpd/bgp_linkstate_tlv.h \ + bgpd/bgp_linkstate_vty.h \ bgpd/bgp_mac.h \ bgpd/bgp_memory.h \ bgpd/bgp_mpath.h \ @@ -209,6 +215,7 @@ clippy_scan += \ bgpd/bgp_debug.c \ bgpd/bgp_evpn_vty.c \ bgpd/bgp_labelpool.c \ + bgpd/bgp_linkstate_vty.c \ bgpd/bgp_route.c \ bgpd/bgp_routemap.c \ bgpd/bgp_rpki.c \ diff --git a/configure.ac b/configure.ac index cea7571fe058..b28fc737e0b2 100644 --- a/configure.ac +++ b/configure.ac @@ -721,10 +721,6 @@ AC_ARG_ENABLE([gcc_ultra_verbose], AS_HELP_STRING([--enable-gcc-ultra-verbose], [enable ultra verbose GCC warnings])) AC_ARG_ENABLE([backtrace], AS_HELP_STRING([--disable-backtrace], [disable crash backtraces (default autodetect)])) -AC_ARG_ENABLE([time-check], - AS_HELP_STRING([--disable-time-check], [disable slow thread warning messages])) -AC_ARG_ENABLE([cpu-time], - AS_HELP_STRING([--disable-cpu-time], [disable cpu usage data gathering])) AC_ARG_ENABLE([pcreposix], AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions])) AC_ARG_ENABLE([pcre2posix], @@ -737,8 +733,6 @@ AC_ARG_ENABLE([cumulus], AS_HELP_STRING([--enable-cumulus], [enable Cumulus Switch Special Extensions])) AC_ARG_ENABLE([datacenter], AS_HELP_STRING([--enable-datacenter], [enable Compilation for Data Center Extensions])) -AC_ARG_ENABLE([rr-semantics], - AS_HELP_STRING([--disable-rr-semantics], [disable the v6 Route Replace semantics])) AC_ARG_ENABLE([protobuf], AS_HELP_STRING([--enable-protobuf], [Enable experimental protobuf support])) AC_ARG_ENABLE([oldvpn_commands], @@ -812,26 +806,6 @@ fi AM_CONDITIONAL([NETLINK_DEBUG], [test "$enable_netlink_debug" != "no"]) -if test "$enable_time_check" != "no" ; then - if test "$enable_time_check" = "yes" -o "$enable_time_check" = "" ; then - AC_DEFINE([CONSUMED_TIME_CHECK], [5000000], [Consumed Time Check]) - else - AC_DEFINE_UNQUOTED([CONSUMED_TIME_CHECK], [$enable_time_check], [Consumed Time Check]) - fi -fi - -case "${enable_cpu_time}" in - "no") - AC_DEFINE([EXCLUDE_CPU_TIME], [1], [Exclude getrusage data gathering]) - ;; - "*") - ;; -esac - -if test "$enable_rr_semantics" != "no" ; then - AC_DEFINE([HAVE_V6_RR_SEMANTICS], [1], [Compile in v6 Route Replacement Semantics]) -fi - if test "$enable_datacenter" = "yes" ; then AC_DEFINE([HAVE_DATACENTER], [1], [Compile extensions for a DataCenter]) DFLT_NAME="datacenter" @@ -2918,12 +2892,6 @@ directory and to the config files in the config file directory." if test -n "$enable_datacenter"; then AC_MSG_WARN([The --enable-datacenter compile time option is deprecated. Please modify the init script to pass -F datacenter to the daemons instead.]) fi -if test -n "$enable_time_check"; then - AC_MSG_WARN([The --enable-time-check compile time option is deprecated. Please use the service cputime-stats configuration option instead.]) -fi -if test -n "$enable_cpu_time"; then - AC_MSG_WARN([The --enable-cpu-time compile time option is deprecated. Please use the service cputime-warning NNN configuration option instead.]) -fi if test "$enable_doc" != "no" -a "$frr_py_mod_sphinx" = "false"; then AC_MSG_WARN([sphinx is missing but required to build documentation]) diff --git a/doc/developer/.readthedocs.yaml b/doc/developer/.readthedocs.yaml new file mode 100644 index 000000000000..113672fadbc3 --- /dev/null +++ b/doc/developer/.readthedocs.yaml @@ -0,0 +1,12 @@ +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: doc/developer/conf.py diff --git a/doc/developer/building-frr-for-debian12.rst b/doc/developer/building-frr-for-debian12.rst new file mode 100644 index 000000000000..ca882eedbcd8 --- /dev/null +++ b/doc/developer/building-frr-for-debian12.rst @@ -0,0 +1,119 @@ +Debian 12 +========= + +Install required packages +------------------------- + +Add packages: + +:: + + sudo apt-get install git autoconf automake libtool make \ + libprotobuf-c-dev protobuf-c-compiler build-essential \ + python3-dev python3-pytest python3-sphinx libjson-c-dev \ + libelf-dev libreadline-dev cmake libcap-dev bison flex \ + pkg-config texinfo gdb libgrpc-dev python3-grpc-tools + +.. include:: building-libunwind-note.rst + +.. include:: building-libyang.rst + +Get FRR, compile it and install it (from Git) +--------------------------------------------- + +**This assumes you want to build and install FRR from source and not +using any packages** + +Add frr groups and user +^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + sudo addgroup --system --gid 92 frr + sudo addgroup --system --gid 85 frrvty + sudo adduser --system --ingroup frr --home /var/opt/frr/ \ + --gecos "FRR suite" --shell /bin/false frr + sudo usermod -a -G frrvty frr + +Download Source, configure and compile it +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +(You may prefer different options on configure statement. These are just +an example.) + +:: + + git clone https://github.com/frrouting/frr.git frr + cd frr + ./bootstrap.sh + ./configure \ + --localstatedir=/var/opt/frr \ + --sbindir=/usr/lib/frr \ + --sysconfdir=/etc/frr \ + --enable-multipath=64 \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --enable-configfile-mask=0640 \ + --enable-logfile-mask=0640 \ + --enable-fpm \ + --with-pkg-git-version \ + --with-pkg-extra-version=-MyOwnFRRVersion + make + make check + sudo make install + +For more compile options, see ``./configure --help`` + +Create empty FRR configuration files +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/frr.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons + +Edit ``/etc/frr/daemons`` and enable the FRR daemons for the protocols you need + +Enable IP & IPv6 forwarding +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the +other settings) + +:: + + # Uncomment the next line to enable packet forwarding for IPv4 + net.ipv4.ip_forward=1 + + # Uncomment the next line to enable packet forwarding for IPv6 + # Enabling this option disables Stateless Address Autoconfiguration + # based on Router Advertisements for this host + net.ipv6.conf.all.forwarding=1 + +**Reboot** or use ``sysctl -p`` to apply the same config to the running +system + +Troubleshooting +--------------- + +Shared library error +^^^^^^^^^^^^^^^^^^^^ + +If you try and start any of the frrouting daemons you may see the below +error due to the frrouting shared library directory not being found: + +:: + + ./zebra: error while loading shared libraries: libfrr.so.0: cannot open + shared object file: No such file or directory + +The fix is to add the following line to /etc/ld.so.conf which will +continue to reference the library directory after the system reboots. To +load the library directory path immediately run the ldconfig command +after adding the line to the file eg: + +:: + + echo include /usr/local/lib >> /etc/ld.so.conf + ldconfig diff --git a/doc/developer/building-frr-for-ubuntu2204.rst b/doc/developer/building-frr-for-ubuntu2204.rst index 7e62d85763e7..97bdf8806bef 100644 --- a/doc/developer/building-frr-for-ubuntu2204.rst +++ b/doc/developer/building-frr-for-ubuntu2204.rst @@ -58,6 +58,7 @@ If config rollbacks are enabled using ``--enable-config-rollbacks`` the sqlite3 developer package also should be installed. .. code-block:: console + sudo apt install libsqlite3-dev diff --git a/doc/developer/building.rst b/doc/developer/building.rst index dac0f9a84d19..8ca0c134b7d6 100644 --- a/doc/developer/building.rst +++ b/doc/developer/building.rst @@ -15,6 +15,7 @@ Building FRR building-frr-for-centos8 building-frr-for-debian8 building-frr-for-debian9 + building-frr-for-debian12 building-frr-for-fedora building-frr-for-freebsd9 building-frr-for-freebsd10 diff --git a/doc/developer/checkpatch.rst b/doc/developer/checkpatch.rst index b52452bc2963..d8fe007c3131 100644 --- a/doc/developer/checkpatch.rst +++ b/doc/developer/checkpatch.rst @@ -1,5 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0-only +.. _checkpatch: + ========== Checkpatch ========== diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst index 61b9cf6acb53..59073b39ab44 100644 --- a/doc/developer/cli.rst +++ b/doc/developer/cli.rst @@ -639,13 +639,14 @@ in order into ``*argv[]``. Before this happens the ``->arg`` field is set to point at the snippet of user input that matched it. For most nontrivial commands the handler function will need to determine which -of the possible matching inputs was entered. Previously this was done by looking -at the first few characters of input. This is now considered an anti-pattern and -should be avoided. Instead, the ``->type`` or ``->text`` fields for this logic. -The ``->type`` field can be used when the possible inputs differ in type. When -the possible types are the same, use the ``->text`` field. This field has the -full text of the corresponding token in the definition string and using it makes -for much more readable code. An example is helpful. +of the possible matching inputs was entered. Previously this was done by +looking at the first few characters of input. This is now considered an +anti-pattern and should be avoided. Instead, use the ``->type`` or ``->text`` +fields for this logic. The ``->type`` field can be used when the possible +inputs differ in type. When the possible types are the same, use the ``->text`` +field. This field has the full text of the corresponding token in the +definition string and using it makes for much more readable code. An example is +helpful. Command definition: @@ -654,9 +655,10 @@ Command definition: command <(1-10)|foo|BAR> In this example, the user may enter any one of: -- an integer between 1 and 10 -- "foo" -- anything at all + +* an integer between 1 and 10 +* "foo" +* anything at all If the user enters "command f", then: @@ -793,12 +795,12 @@ Adding a CLI Node To add a new CLI node, you should: -- define a new numerical node constant -- define a node structure in the relevant daemon -- call ``install_node()`` in the relevant daemon -- define and install the new node in vtysh -- define corresponding node entry commands in daemon and vtysh -- add a new entry to the ``ctx_keywords`` dictionary in ``tools/frr-reload.py`` +#. define a new numerical node constant +#. define a node structure in the relevant daemon +#. call ``install_node()`` in the relevant daemon +#. define and install the new node in vtysh +#. define corresponding node entry commands in daemon and vtysh +#. add a new entry to the ``ctx_keywords`` dictionary in ``tools/frr-reload.py`` Defining the numerical node constant ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/developer/cspf.rst b/doc/developer/cspf.rst index 9ff673a23944..7a5a55ee31b0 100644 --- a/doc/developer/cspf.rst +++ b/doc/developer/cspf.rst @@ -24,59 +24,59 @@ to the cost of the cuurent path from the source up to the current node. The algorithm is as followed: -``` - cost = MAX_COST; - Priority_Queue.empty(); - Visited_Node.empty(); - Processed_Path.empty(); - src = new_path(source_address); - src.cost = 0; - dst = new_destinatio(destination_address); - dst.cost = MAX_COST; - Processed_Path.add(src); - Processed_Path.add(dst); - while (Priority_Queue.count != 0) { - current_path = Priority_Queue.pop(); - current_node = next_path.destination; - Visited_Node.add(current_node); - for (current_node.edges: edge) { - if (prune_edge(current_path, edge) - continue; - if (relax(current_path) && cost > current_path.cost) { - optim_path = current_path; - cost = current_path.cost; - } - } - } - - prune_edge(path, edge) { - // check that path + edge meet constraints e.g. - if (current_path.cost + edge.cost > constrained_cost) - return false; - else - return true; - } - - relax_edge(current_path, edge) { - next_node = edge.destination; - if (Visited_Node.get(next_node)) - return false; - next_path = Processed_Path.get(edge.destination); - if (!next_path) { - next_path = new path(edge.destination); - Processed_Path.add(next_path); - } - total_cost = current_path.cost + edge.cost; - if (total_cost < next_path.cost) { - next_path = current_path; - next_path.add_edge(edge); - next_path.cost = total_cost; - Priority_Queue.add(next_path); - } - return (next_path.destination == destination); - } - -``` +.. code-block:: c + + cost = MAX_COST; + Priority_Queue.empty(); + Visited_Node.empty(); + Processed_Path.empty(); + src = new_path(source_address); + src.cost = 0; + dst = new_destinatio(destination_address); + dst.cost = MAX_COST; + Processed_Path.add(src); + Processed_Path.add(dst); + while (Priority_Queue.count != 0) { + current_path = Priority_Queue.pop(); + current_node = next_path.destination; + Visited_Node.add(current_node); + for (current_node.edges: edge) { + if (prune_edge(current_path, edge) + continue; + if (relax(current_path) && cost > current_path.cost) { + optim_path = current_path; + cost = current_path.cost; + } + } + } + + prune_edge(path, edge) { + // check that path + edge meet constraints e.g. + if (current_path.cost + edge.cost > constrained_cost) + return false; + else + return true; + } + + relax_edge(current_path, edge) { + next_node = edge.destination; + if (Visited_Node.get(next_node)) + return false; + next_path = Processed_Path.get(edge.destination); + if (!next_path) { + next_path = new path(edge.destination); + Processed_Path.add(next_path); + } + total_cost = current_path.cost + edge.cost; + if (total_cost < next_path.cost) { + next_path = current_path; + next_path.add_edge(edge); + next_path.cost = total_cost; + Priority_Queue.add(next_path); + } + return (next_path.destination == destination); + } + Definition ---------- @@ -163,34 +163,34 @@ To perform a Path Computation with given constraints, proceed as follow: .. code-block:: c - struct cspf *algo; - struct ls_ted *ted; - struct in_addr src; - struct in_addr dst; - struct constraints csts; - struct c_path *path; - - // Create a new CSPF structure - algo = cspf_new(); - - // Initialize constraints - csts.cost = 100; - csts.ctype = CSPF_TE_METRIC; - csts.family = AF_INET; - csts.type = SR_TE; - csts.bw = 1000000; - csts.cos = 3; - - // Then, initialise th CSPF with source, destination and constraints - cspf_init_v4(algo, ted, src, dst, &csts); - - // Finally, got the Computed Path; - path = compute_p2p_path(ted, algo); - - if (path.status == SUCCESS) - zlog_info("Got a valid constraints path"); - else - zlog_info("Unable to compute constraints path. Got %d status", path->status); + struct cspf *algo; + struct ls_ted *ted; + struct in_addr src; + struct in_addr dst; + struct constraints csts; + struct c_path *path; + + // Create a new CSPF structure + algo = cspf_new(); + + // Initialize constraints + csts.cost = 100; + csts.ctype = CSPF_TE_METRIC; + csts.family = AF_INET; + csts.type = SR_TE; + csts.bw = 1000000; + csts.cos = 3; + + // Then, initialise th CSPF with source, destination and constraints + cspf_init_v4(algo, ted, src, dst, &csts); + + // Finally, got the Computed Path; + path = compute_p2p_path(ted, algo); + + if (path.status == SUCCESS) + zlog_info("Got a valid constraints path"); + else + zlog_info("Unable to compute constraints path. Got %d status", path->status); If you would compute another path, you must call `cspf_init()` prior to diff --git a/doc/developer/frr-release-procedure.rst b/doc/developer/frr-release-procedure.rst index 6088b52da44b..9378637dedb4 100644 --- a/doc/developer/frr-release-procedure.rst +++ b/doc/developer/frr-release-procedure.rst @@ -152,11 +152,11 @@ Stage 2 - Staging 3. Suppose we are releasing 8.5.0, then ``X.Y.Z`` is ``8.5.0``. Run this: .. code-block:: console - + cd /home/builduser/frr TAG=X.Y.Z git fetch --all - git checkout frr- + git checkout frr-$TAG docker buildx build --platform linux/amd64,linux/arm64,linux/ppc64le,linux/s390x,linux/arm/v7,linux/arm/v6 -f docker/alpine/Dockerfile -t quay.io/frrouting/frr:$TAG --push . git tag docker/$TAG git push origin docker/$TAG @@ -165,7 +165,7 @@ Stage 2 - Staging create a git tag corresponding to the commit that the image was built from and upload that to Github. It's important that the git tag point to the exact codebase that was used to build the docker image, so if any - changes need to be made on top of the ``frr-`` release tag, make + changes need to be made on top of the ``frr-$TAG`` release tag, make sure these changes are committed and pointed at by the ``docker/X.Y.Z`` tag. diff --git a/doc/developer/index.rst b/doc/developer/index.rst index 5da7bc416849..bd794b11a8df 100644 --- a/doc/developer/index.rst +++ b/doc/developer/index.rst @@ -5,6 +5,7 @@ FRRouting Developer's Guide :maxdepth: 2 workflow + checkpatch building packaging process-architecture @@ -22,3 +23,4 @@ FRRouting Developer's Guide path pceplib link-state + northbound/northbound diff --git a/doc/developer/northbound/advanced-topics.rst b/doc/developer/northbound/advanced-topics.rst new file mode 100644 index 000000000000..bee29a95a929 --- /dev/null +++ b/doc/developer/northbound/advanced-topics.rst @@ -0,0 +1,294 @@ +Auto-generated CLI commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to have less code to maintain, it should be possible to write a +tool that auto-generates CLI commands based on the FRR YANG models. As a +matter of fact, there are already a number of NETCONF-based CLIs that do +exactly that (e.g. `Clixon `__, +ConfD’s CLI). + +The problem however is that there isn’t an exact one-to-one mapping +between the existing CLI commands and the corresponding YANG nodes from +the native models. As an example, ripd’s +``timers basic (5-2147483647) (5-2147483647) (5-2147483647)`` command +changes three YANG leaves at the same time. In order to auto-generate +CLI commands and retain their original form, it’s necessary to add +annotations in the YANG modules to specify how the commands should look +like. Without YANG annotations, the CLI auto-generator will generate a +command for each YANG leaf, (leaf-)list and presence-container. The +ripd’s ``timers basic`` command, for instance, would become three +different commands, which would be undesirable. + + This Tail-f’s® + `document `__ + shows how to customize ConfD auto-generated CLI commands using YANG + annotations. + +The good news is that *libyang* allows users to create plugins to +implement their own YANG extensions, which can be used to implement CLI +annotations. If done properly, a CLI generator can save FRR developers +from writing and maintaining hundreds if not thousands of DEFPYs! + +CLI on a separate program +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The flexible design of the northbound architecture opens the door to +move the CLI to a separate program in the long-term future. Some +advantages of doing so would be: \* Treat the CLI as just another +northbound client, instead of having CLI commands embedded in the +binaries of all FRR daemons. \* Improved robustness: bugs in CLI +commands (e.g. null-pointer dereferences) or in the CLI code itself +wouldn’t affect the FRR daemons. \* Foster innovation by allowing other +CLI programs to be implemented, possibly using higher level programming +languages. + +The problem, however, is that the northbound retrofitting process will +convert only the CLI configuration commands and EXEC commands in a first +moment. Retrofitting the “show” commands is a completely different story +and shouldn’t happen anytime soon. This should hinder progress towards +moving the CLI to a separate program. + +Proposed feature: confirmed commits +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Confirmed commits allow the user to request an automatic rollback to the +previous configuration if the commit operation is not confirmed within a +number of minutes. This is particularly useful when the user is +accessing the CLI through the network (e.g. using SSH) and any +configuration change might cause an unexpected loss of connectivity +between the user and the router (e.g. misconfiguration of a routing +protocol). By using a confirmed commit, the user can rest assured the +connectivity will be restored after the given timeout expires, avoiding +the need to access the router physically to fix the problem. + +Example of how this feature could be provided in the CLI: +``commit confirmed [minutes <1-60>]``. The ability to do confirmed +commits should also be exposed in the northbound API so that the +northbound plugins can also take advantage of it (in the case of the +Sysrepo and ConfD plugins, confirmed commits are implemented externally +in the *netopeer2-server* and *confd* daemons, respectively). + +Proposed feature: enable/disable configuration commands/sections +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since the ``lyd_node`` data structure from *libyang* can hold private +data, it should be possible to mark configuration commands or sections +as active or inactive. This would allow CLI users to leverage this +feature to disable parts of the running configuration without actually +removing the associated commands, and then re-enable the disabled +configuration commands or sections later when necessary. Example: + +:: + + ripd(config)# show configuration running + Configuration: + [snip] + ! + router rip + default-metric 2 + distance 80 + network eth0 + network eth1 + ! + end + ripd(config)# disable router rip + ripd(config)# commit + % Configuration committed successfully (Transaction ID #7). + + ripd(config)# show configuration running + Configuration: + [snip] + ! + !router rip + !default-metric 2 + !distance 80 + !network eth0 + !network eth1 + ! + end + ripd(config)# enable router rip + ripd(config)# commit + % Configuration committed successfully (Transaction ID #8). + + ripd(config)# show configuration running + [snip] + frr defaults traditional + ! + router rip + default-metric 2 + distance 80 + network eth0 + network eth1 + ! + end + +This capability could be useful in a number of occasions, like disabling +configuration commands that are no longer necessary (e.g. ACLs) but that +might be necessary at a later point in the future. Other example is +allowing users to disable a configuration section for testing purposes, +and then re-enable it easily without needing to copy and paste any +command. + +Configuration reloads +~~~~~~~~~~~~~~~~~~~~~ + +Given the limitations of the previous northbound architecture, the FRR +daemons didn’t have the ability to reload their configuration files by +themselves. The SIGHUP handler of most daemons would only re-read the +configuration file and merge it into the running configuration. In most +cases, however, what is desired is to replace the running configuration +by the updated configuration file. The *frr-reload.py* script was +written to work around this problem and it does it well to a certain +extent. The problem with the *frr-reload.py* script is that it’s full of +special cases here and there, which makes it fragile and unreliable. +Maintaining the script is also an additional burden for FRR developers, +few of whom are familiar with its code or know when it needs to be +updated to account for a new feature. + +In the new northbound architecture, reloading the configuration file can +be easily implemented using a configuration transaction. Once the FRR +northbound retrofitting process is complete, all daemons should have the +ability to reload their configuration files upon receiving the SIGHUP +signal, or when the ``configuration load [...] replace`` command is +used. Once that point is reached, the *frr-reload.py* script will no +longer be necessary and should be removed from the FRR repository. + +Configuration changes coming from the kernel +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This +`post `__ +from the Tail-f’s® forum describes the problem of letting systems +configure themselves behind the users back. Here are some selected +snippets from it: > Traditionally, northbound interface users are the +ones in charge of providing configuration data for systems. > > In some +systems, we see a deviation from this traditional practice; allowing +systems to configure “themselves” behind the scenes (or behind the users +back). > > While there might be a business case for such a practice, +this kind of configuration remains “dangerous” from northbound users +perspective and makes systems hard to predict and even harder to debug. +(…) > > With the advent of transactional Network configuration, this +practice can not work anymore. The fact that systems are given the right +to change configuration is a key here in breaking transactional +configuration in a Network. + +FRR is immune to some of the problems described in the aforementioned +post. Management clients can configure interfaces that don’t yet exist, +and once an interface is deleted from the kernel, its configuration is +retained in FRR. + +There are however some cases where information learned from the kernel +(e.g. using netlink) can affect the running configuration of all FRR +daemons. Examples: interface rename events, VRF rename events, interface +being moved to a different VRF, etc. In these cases, since these events +can’t be ignored, the best we can do is to send YANG notifications to +the management clients to inform about the configuration changes. The +management clients should then be prepared to handle such notifications +and react accordingly. + +Interfaces and VRFs +~~~~~~~~~~~~~~~~~~~ + +As of now zebra doesn’t have the ability to create VRFs or virtual +interfaces in the kernel. The ``vrf`` and ``interface`` commands only +create pre-provisioned VRFs and interfaces that are only activated when +the corresponding information is learned from the kernel. When +configuring FRR using an external management client, like a NETCONF +client, it might be desirable to actually create functional VRFs and +virtual interfaces (e.g. VLAN subinterfaces, bridges, etc) that are +installed in the kernel using OS-specific APIs (e.g. netlink, routing +socket, etc). Work needs to be done in this area to make this possible. + +Shared configuration objects +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One of the existing problems in FRR is that it’s hard to ensure that all +daemons are in sync with respect to the shared configuration objects +(e.g. interfaces, VRFs, route-maps, ACLs, etc). When a route-map is +configured using *vtysh*, the same command is sent to all relevant +daemons (the daemons that implement route-maps), which ensures +synchronization among them. The problem is when a daemon starts after +the route-maps are created. In this case this daemon wouldn’t be aware +of the previously configured route-maps (unlike the other daemons), +which can lead to a lot of confusion and unexpected problems. + +With the new northbound architecture, configuration objects can be +manipulated using higher level abstractions, which opens more +possibilities to solve this decades-long problem. As an example, one +solution would be to make the FRR daemons fetch the shared configuration +objects from zebra using the ZAPI interface during initialization. The +shared configuration objects could be requested using a list of XPaths +expressions in the ``ZEBRA_HELLO`` message, which zebra would respond by +sending the shared configuration objects encoded in the JSON format. +This solution however doesn’t address the case where zebra starts or +restarts after the other FRR daemons. Other solution would be to store +the shared configuration objects in the northbound SQL database and make +all daemons fetch these objects from there. So far no work has been made +on this area as more investigation needs to be done. + +vtysh support +~~~~~~~~~~~~~ + +As explained in the [[Transactional CLI]] page, all commands introduced +by the transactional CLI are not yet available in *vtysh*. This needs to +be addressed in the short term future. Some challenges for doing that +work include: \* How to display configurations (running, candidates and +rollbacks) in a more clever way? The implementation of the +``show running-config`` command in *vtysh* is not something that should +be followed as an example. A better idea would be to fetch the desired +configuration from all daemons (encoded in JSON for example), merge them +all into a single ``lyd_node`` variable and then display the combined +configurations from this variable (the configuration merges would +transparently take care of combining the shared configuration objects). +In order to be able to manipulate the JSON configurations, *vtysh* will +need to load the YANG modules from all daemons at startup (this might +have a minimal impact on startup time). The only issue with this +approach is that the ``cli_show()`` callbacks from all daemons are +embedded in their binaries and thus not accessible externally. It might +be necessary to compile these callbacks on a separate shared library so +that they are accessible to *vtysh* too. Other than that, displaying the +combined configurations in the JSON/XML formats should be +straightforward. \* With the current design, transaction IDs are +per-daemon and not global across all FRR daemons. This means that the +same transaction ID can represent different transactions on different +daemons. Given this observation, how to implement the +``rollback configuration`` command in *vtysh*? The easy solution would +be to add a ``daemon WORD`` argument to specify the context of the +rollback, but per-daemon rollbacks would certainly be confusing and +convoluted to end users. A better idea would be to attack the root of +the problem: change configuration transactions to be global instead of +being per-daemon. This involves a bigger change in the northbound +architecture, and would have implications on how transactions are stored +in the SQL database (daemon-specific and shared configuration objects +would need to have their own tables or columns). \* Loading +configuration files in the JSON or XML formats will be tricky, as +*vtysh* will need to know which sections of the configuration should be +sent to which daemons. *vtysh* will either need to fetch the YANG +modules implemented by all daemons at runtime or obtain this information +at compile-time somehow. + +Detecting type mismatches at compile-time +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As described in the [[Retrofitting Configuration Commands]] page, the +northbound configuration callbacks detect type mismatches at runtime +when fetching data from the the ``dnode`` parameter (which represents +the configuration node being created, modified, deleted or moved). When +a type mismatch is detected, the program aborts and displays a backtrace +showing where the problem happened. It would be desirable to detect such +type mismatches at compile-time, the earlier the problems are detected +the sooner they are fixed. + +One possible solution to this problem would be to auto-generate C +structures from the YANG models and provide a function that converts a +libyang’s ``lyd_node`` variable to a C structure containing the same +information. The northbound callbacks could then fetch configuration +data from this C structure, which would naturally lead to type +mismatches being detected at compile time. One of the challenges of +doing this would be the handling of YANG lists and leaf-lists. It would +be necessary to use dynamic data structures like hashes or rb-trees to +hold all elements of the lists and leaf-lists, and the process of +converting a ``lyd_node`` to an auto-generated C-structure could be +expensive. At this point it’s unclear if it’s worth adding more +complexity in the northbound architecture to solve this specific +problem. diff --git a/doc/developer/northbound/architecture.rst b/doc/developer/northbound/architecture.rst new file mode 100644 index 000000000000..e571971c7f53 --- /dev/null +++ b/doc/developer/northbound/architecture.rst @@ -0,0 +1,275 @@ +Introduction +------------ + +The goal of the new northbound API is to provide a better interface to +configure and monitor FRR programatically. The current design based on +CLI commands is no longer adequate in a world where computer networks +are becoming increasingly bigger, more diverse and more complex. Network +scripting using *expect* and screen scraping techniques is too primitive +and unreliable to be used in large-scale networks. What is proposed is +to modernize FRR to turn it into an API-first routing stack, and +reposition the CLI on top of this API. The most important change, +however, is not the API that will be provided to external users. In +fact, multiple APIs will be supported and users will have the ability to +write custom management APIs if necessary. The biggest change is the +introduction of a model-driven management architecture based on the +`YANG `__ modeling language. +Instead of writing code tied to any particular user interface +(e.g. DEFUNs), YANG allows us to write API-agnostic code (in the form of +callbacks) that can be used by any management interface. As an example, +it shouldn’t matter if a set of configuration changes is coming from a +`NETCONF `__ session or from a CLI +terminal, the same callbacks should be called to process the +configuration changes regardless of where they came from. This +model-driven design ensures feature parity across all management +interfaces supported by FRR. + +Quoting :rfc:`7950`: + + YANG is a language originally designed to model data for the NETCONF + protocol. A YANG module defines hierarchies of data that can be used for + NETCONF-based operations, including configuration, state data, RPCs, and + notifications. This allows a complete description of all data sent between a + NETCONF client and server. Although out of scope for this specification, + YANG can also be used with protocols other than NETCONF. + +While the YANG and NETCONF specifications are tightly coupled with one +another, both are independent to a certain extent and are evolving +separately. Examples of other management protocols that use YANG include +`RESTCONF `__, +`gNMI `__ +and +`CoAP `__. + +In addition to being management-protocol independent, some other +advantages of using YANG in FRR are listed below: \* Have a formal +contract between FRR and application developers (management clients). A +management client that has access to the FRR YANG models knows about all +existing configuration options available for use. This information can +be used to auto-generate user-friendly interfaces like Web-UIs, custom +CLIs and even code bindings for several different programming languages. +Using `PyangBind `__, for +example, it’s possible to generate Python class hierarchies from YANG +models and use these classes to instantiate objects that mirror the +structure of the YANG modules and can be serialized/deserialized using +different encoding formats. \* Support different encoding formats for +instance data. Currently only JSON and XML are supported, but +`GPB `__ and +`CBOR `__ are other viable options in the long term. +Additional encoding formats can be implemented in the *libyang* library +for optimal performance, or externally by translating data to/from one +of the supported formats (with a performance penalty). \* Have a formal +mechanism to introduce backward-incompatible changes based on `semantic +versioning `__ (not part of the +YANG standard, which allows backward-compatible module updates only). \* +Provide seamless support to the industry-standard NETCONF/RESTCONF +protocols as alternative management APIs. If FRR configuration/state +data is modeled using YANG, supporting YANG-based protocols like NETCONF +and RESTCONF is much easier. + +As important as shifting to a model-driven management paradigm, the new +northbound architecture also introduces the concept of configuration +transactions. Configuration transactions allow management clients to +commit multiple configuration changes at the same time and rest assured +that either all changes will be applied or none will (all-or-nothing). +Configuration transactions are implemented as pseudo-atomic operations +and facilitate automation by removing the burden of error recovery from +the management side. Another property of configuration transactions is +that the configuration changes are always processed in a pre-defined +order to ensure consistency. Configuration transactions that encompass +multiple network devices are called network-wide transactions and are +also supported by the new northbound architecture. When FRR is built +using the ``--enable-config-rollbacks`` option, all committed +transactions are recorded in the FRR rollback log, which can reside +either in memory (volatile) or on persistent storage. + + Network-wide Transactions is the most important leap in network + management technology since SNMP. The error recovery and sequencing + tasks are removed from the manager side. This is usually more than + half the cost in a mature system; more than the entire cost of the + managed devices. + `[source] `__. + +Figures 1 and 2 below illustrate the old and new northbound architecture +of FRR, respectively. As it can be seen, in the old architecture the CLI +was the only interface used to configure and monitor FRR (the SNMP +plugin was’t taken into account given the small number of implemented +MIBs). This means that the only way to automate FRR was by writing +scripts that send CLI commands and parse the text output (which usually +doesn’t have any structure) using screen scraping and regular +expressions. + +.. figure:: images/arch-before.png + :alt: diagram of northbound architecture prior to nbapi conversion + + Old northbound architecture + +The new northbound architectures, on the other hand, features a +multitude of different management APIs, all of them connected to the +northbound layer of the FRR daemons. By default, only the CLI interface +is compiled built-in in the FRR daemons. The other management interfaces +are provided as optional plugins and need to be loaded during the daemon +initialization (e.g. *zebra -M confd*). This design makes it possible to +integrate FRR with different NETCONF solutions without introducing +vendor lock-in. The [[Plugins - Writing Your Own]] page explains how to +write custom northbound plugins that can be tailored to all needs +(e.g. support custom transport protocols, different data encoding +formats, fine-grained access control, etc). + +.. figure:: images/arch-after.png + :alt: diagram of northbound architecture after nbapi conversion + + New northbound architecture + +Figure 3 shows the internal view of the FRR northbound architecture. In +this image we can see that northbound layer is an abstract entity +positioned between the northbound callbacks and the northbound clients. +The northbound layer is responsible to process the requests coming from +the northbound clients and call the appropriate callbacks to satisfy +these requests. The northbound plugins communicate with the northbound +layer through a public API, which allow users to write third-party +plugins that can be maintained separately. The northbound plugins, in +turn, have their own APIs to communicate with external management +clients. + +.. figure:: images/nb-layer.png + :alt: diagram of northbound architecture internals + + New northbound architecture - internal view + +Initially the CLI (and all of its commands) will be maintained inside +the FRR daemons. In the long term, however, the goal is to move the CLI +to a separate program just like any other management client. The +[[Advanced Topics]] page describes the motivations and challenges of +doing that. Last but not least, the *libyang* block inside the +northbound layer is the engine that makes everything possible. The +*libyang* library will be described in more detail in the following +sections. + +YANG models +----------- + +The main decision to be made when using YANG is which models to +implement. There’s a general consensus that using standard models is +preferable over using custom (native) models. The reasoning is that +applications based on standard models can be reused for all network +appliances that support those models, whereas the same doesn’t apply for +applications written based on custom models. + +That said, there are multiple standards bodies publishing YANG models +and unfortunately not all of them are converging (or at least not yet). +In the context of FRR, which is a routing stack, the two sets of YANG +models that would make sense to implement are the ones from IETF and +from the OpenConfig working group. The question that arises is: which +one of them should we commit to? Or should we try to support both +somehow, at the cost of extra development efforts? + +Another problem, from an implementation point of view, is that it’s +challenging to adapt the existing code base to match standard models. A +more reasonable solution, at least in a first moment, would be to use +YANG deviations and augmentations to do the opposite: adapt the standard +models to the existing code. In practice however this is not as simple +as it seems. There are cases where the differences are too substantial +to be worked around without restructuring the code by changing its data +structures and their relationships. As an example, the *ietf-rip* model +places per-interface RIP configuration parameters inside the +*control-plane-protocol* list (which is augmented by *ietf-rip*). This +means that it’s impossible to configure RIP interface parameters without +first configuring a RIP routing instance. The *ripd* daemon on the other +hand allows the operator to configure RIP interface parameters even if +``router rip`` is not configured. If we were to implement the *ietf-rip* +module natively, we’d need to change ripd’s CLI commands (and the +associated code) to reflect the new configuration hierarchy. + +Taking into account that FRR has a huge code base and that the +northbound retrofitting process per-se will cause a lot of impact, it +was decided to take a conservative approach and write custom YANG models +for FRR modeled after the existing CLI commands. Having YANG models that +closely mirror the CLI commands will allow the FRR developers to +retrofit the code base much more easily, without introducing +backward-incompatible changes in the CLI and reducing the likelihood of +introducing bugs. The [[Retrofitting Configuration Commands]] page +explains in detail how to convert configuration commands to the new +northbound model. + +Even though having native YANG models is not the ideal solution, it will +be already a big step forward for FRR to migrate to a model-driven +management architecture, with support for configuration transactions and +multiple management interfaces, including NETCONF and RESTCONF (through +the northbound plugins). + +The new northbound also features an experimental YANG module translator +that will allow users to translate to and from standard YANG models by +using translation tables. The [[YANG module translator]] page describes +this mechanism in more detail. At this point it’s unclear what can be +achieved through module translation and if that can be considered as a +definitive solution to support standard models or not. + +Northbound Architecture +----------------------- + +.. figure:: images/lys-node.png + :alt: diagram of libyanbg's lys_node data structure + + ``libyang's`` lys_node data structure + + +.. figure:: images/lyd-node.png + :alt: diagram of libyanbg's lyd_node data structure + + ``libyang's`` lyd_node data structure + + +.. figure:: images/ly-ctx.png + :alt: diagram of libyanbg's ly_ctx data structure + + ``libyang's`` ly_ctx data structure + + +.. figure:: images/transactions.png + :alt: diagram showing how configuration transactions work + + Configuration transactions + + +Testing +------- + +The new northbound adds the libyang library as a new mandatory +dependency for FRR. To obtain and install this library, follow the steps +below: + +.. code-block:: console + + git clone https://github.com/CESNET/libyang + cd libyang + git checkout devel + mkdir build ; cd build + cmake -DENABLE_LYD_PRIV=ON .. + make + sudo make install + + +.. note:: + + first make sure to install the libyang + `requirements `__. + + +FRR needs libyang from version 0.16.7 or newer, which is maintained in +the ``devel`` branch. libyang 0.15.x is maintained in the ``master`` +branch and doesn’t contain one small feature used by FRR (the +``LY_CTX_DISABLE_SEARCHDIR_CWD`` flag). FRR also makes use of the +libyang’s ``ENABLE_LYD_PRIV`` feature, which is disabled by default and +needs to be enabled at compile time. + +It’s advisable (but not required) to install sqlite3 and build FRR with +``--enable-config-rollbacks`` in order to have access to the +configuration rollback feature. + +To test the northbound, the suggested method is to use the +[[Transactional CLI]] with the *ripd* daemon and play with the new +commands. The ``debug northbound`` command can be used to see which +northbound callbacks are called in response to the ``commit`` command. +For reference, the [[Demos]] page shows a small demonstration of the +transactional CLI in action and what it’s capable of. diff --git a/doc/developer/northbound/demos.rst b/doc/developer/northbound/demos.rst new file mode 100644 index 000000000000..21ab43a49b60 --- /dev/null +++ b/doc/developer/northbound/demos.rst @@ -0,0 +1,25 @@ +Transactional CLI +----------------- + +This short demo shows some of the capabilities of the new transactional +CLI: |asciicast| + +ConfD + NETCONF + Cisco YDK +--------------------------- + +This is a very simple demo of *ripd* being configured by a python +script. The script uses NETCONF to communicate with *ripd*, which has +the ConfD plugin loaded. The most interesting part, however, is the fact +that the python script is not using handcrafted XML payloads to +configure *ripd*. Instead, the script is using python bindings generated +using Cisco’s YANG Development Kit (YDK). + +- Script used in the demo: + https://gist.github.com/rwestphal/defa9bd1ccf216ab082d4711ae402f95 + +|asciicast| + +.. |asciicast| image:: https://asciinema.org/a/jL0BS5HfP2kS6N1HfgsZvfZk1.png + :target: https://asciinema.org/a/jL0BS5HfP2kS6N1HfgsZvfZk1 +.. |asciicast| image:: https://asciinema.org/a/VfMElNxsjLcdvV7484E6ChxWv.png + :target: https://asciinema.org/a/VfMElNxsjLcdvV7484E6ChxWv diff --git a/doc/developer/northbound/images/arch-after.png b/doc/developer/northbound/images/arch-after.png new file mode 100644 index 000000000000..01e6ae63646c Binary files /dev/null and b/doc/developer/northbound/images/arch-after.png differ diff --git a/doc/developer/northbound/images/arch-before.png b/doc/developer/northbound/images/arch-before.png new file mode 100644 index 000000000000..ab2bb0deb215 Binary files /dev/null and b/doc/developer/northbound/images/arch-before.png differ diff --git a/doc/developer/northbound/images/ly-ctx.png b/doc/developer/northbound/images/ly-ctx.png new file mode 100644 index 000000000000..4d4e138c73a1 Binary files /dev/null and b/doc/developer/northbound/images/ly-ctx.png differ diff --git a/doc/developer/northbound/images/lyd-node.png b/doc/developer/northbound/images/lyd-node.png new file mode 100644 index 000000000000..4ba2b48b71b9 Binary files /dev/null and b/doc/developer/northbound/images/lyd-node.png differ diff --git a/doc/developer/northbound/images/lys-node.png b/doc/developer/northbound/images/lys-node.png new file mode 100644 index 000000000000..e9e46e7f6483 Binary files /dev/null and b/doc/developer/northbound/images/lys-node.png differ diff --git a/doc/developer/northbound/images/nb-layer.png b/doc/developer/northbound/images/nb-layer.png new file mode 100644 index 000000000000..4aa1fd6bffe0 Binary files /dev/null and b/doc/developer/northbound/images/nb-layer.png differ diff --git a/doc/developer/northbound/images/transactions.png b/doc/developer/northbound/images/transactions.png new file mode 100644 index 000000000000..d18faf44782c Binary files /dev/null and b/doc/developer/northbound/images/transactions.png differ diff --git a/doc/developer/northbound/links.rst b/doc/developer/northbound/links.rst new file mode 100644 index 000000000000..e80374c57b15 --- /dev/null +++ b/doc/developer/northbound/links.rst @@ -0,0 +1,233 @@ +RFCs +~~~~ + +- `RFC 7950 - The YANG 1.1 Data Modeling + Language `__ +- `RFC 7951 - JSON Encoding of Data Modeled with + YANG `__ +- `RFC 8342 - Network Management Datastore Architecture + (NMDA) `__ +- `RFC 6087 - Guidelines for Authors and Reviewers of YANG Data Model + Documents `__ +- `RFC 8340 - YANG Tree + Diagrams `__ +- `RFC 6991 - Common YANG Data + Types `__ +- `RFC 6241 - Network Configuration Protocol + (NETCONF) `__ +- `RFC 8040 - RESTCONF + Protocol `__ + +YANG models +~~~~~~~~~~~ + +- Collection of several YANG models, including models from standards + organizations such as the IETF and vendor specific models: + https://github.com/YangModels/yang +- OpenConfig: https://github.com/openconfig/public + +Presentations +~~~~~~~~~~~~~ + +- FRR Advanced Northbound API (May 2018) + + - Slides: + https://www.dropbox.com/s/zhybthruwocbqaw/netdef-frr-northbound.pdf?dl=1 + +- Ok, We Got Data Models, Now What? + + - Video: https://www.youtube.com/watch?v=2oqkiZ83vAA + - Slides: + https://www.nanog.org/sites/default/files/20161017_Alvarez_Ok_We_Got_v1.pdf + +- Data Model-Driven Management: Latest Industry and Tool Developments + + - Video: https://www.youtube.com/watch?v=n_oKGJ_jgYQ + - Slides: + https://pc.nanog.org/static/published/meetings/NANOG72/1559/20180219_Claise_Data_Modeling-Driven_Management__v1.pdf + +- Network Automation And Programmability: Reality Versus The Vendor + Hype When Considering Legacy And NFV Networks + + - Video: https://www.youtube.com/watch?v=N5wbYncUS9o + - Slides: + https://www.nanog.org/sites/default/files/1_Moore_Network_Automation_And_Programmability.pdf + +- Lightning Talk: The API is the new CLI? + + - Video: https://www.youtube.com/watch?v=ngi0erGNi58 + - Slides: + https://pc.nanog.org/static/published/meetings/NANOG72/1638/20180221_Grundemann_Lightning_Talk_The_v1.pdf + +- Lightning Talk: OpenConfig - progress toward vendor-neutral network + management + + - Video: https://www.youtube.com/watch?v=10rSUbeMmT4 + - Slides: + https://pc.nanog.org/static/published/meetings/NANOG71/1535/20171004_Shaikh_Lightning_Talk_Openconfig_v1.pdf + +- Getting started with OpenConfig + + - Video: https://www.youtube.com/watch?v=L7trUNK8NJI + - Slides: + https://pc.nanog.org/static/published/meetings/NANOG71/1456/20171003_Alvarez_Getting_Started_With_v1.pdf + +- Why NETCONF and YANG + + - Video: https://www.youtube.com/watch?v=mp4h8aSTba8 + +- NETCONF and YANG Concepts + + - Video: https://www.youtube.com/watch?v=UwYYvT7DBvg + +- NETCONF Tutorial + + - Video: https://www.youtube.com/watch?v=N4vov1mI14U + +Whitepapers +~~~~~~~~~~~ + +- Automating Network and Service Configuration Using NETCONF and YANG: + http://www.tail-f.com/wordpress/wp-content/uploads/2013/02/Tail-f-Presentation-Netconf-Yang.pdf +- Creating the Programmable Network: The Business Case for NETCONF/YANG + in Network Devices: + http://www.tail-f.com/wordpress/wp-content/uploads/2013/10/HR-Tail-f-NETCONF-WP-10-08-13.pdf +- NETCONF/YANG: What’s Holding Back Adoption & How to Accelerate It: + https://www.oneaccess-net.com/images/public/wp_heavy_reading.pdf +- Achieving Automation with YANG Modeling Technologies: + https://www.cisco.com/c/dam/en/us/products/collateral/cloud-systems-management/network-services-orchestrator/idc-achieving-automation-wp.pdf + +Blog posts and podcasts +~~~~~~~~~~~~~~~~~~~~~~~ + +- OpenConfig and IETF YANG Models: Can they converge? - + http://rob.sh/post/215/ +- OpenConfig: Standardized Models For Networking - + https://packetpushers.net/openconfig-standardized-models-networking/ +- (Podcast) OpenConfig: From Basics to Implementations - + https://blog.ipspace.net/2017/02/openconfig-from-basics-to.html +- (Podcast) How Did NETCONF Start on Software Gone Wild - + https://blog.ipspace.net/2017/12/how-did-netconf-start-on-software-gone.html +- YANG Data Models in the Industry: Current State of Affairs (March + 2018) - + https://www.claise.be/2018/03/yang-data-models-in-the-industry-current-state-of-affairs-march-2018/ +- Why Data Model-driven Telemetry is the only useful Telemetry? - + https://www.claise.be/2018/02/why-data-model-driven-telemetry-is-the-only-useful-telemetry/ +- NETCONF versus RESTCONF: Capabilitity Comparisons for Data + Model-driven Management - + https://www.claise.be/2017/10/netconf-versus-restconf-capabilitity-comparisons-for-data-model-driven-management-2/ +- An Introduction to NETCONF/YANG - + https://www.fir3net.com/Networking/Protocols/an-introduction-to-netconf-yang.html +- Network Automation and the Rise of NETCONF - + https://medium.com/@k.okasha/network-automation-and-the-rise-of-netconf-e96cc33fe28 +- YANG and the Road to a Model Driven Network - + https://medium.com/@k.okasha/yang-and-road-to-a-model-driven-network-e9e52d47148d + +Software +~~~~~~~~ + +libyang +^^^^^^^ + + libyang is a YANG data modelling language parser and toolkit written + (and providing API) in C. + +- GitHub page: https://github.com/CESNET/libyang +- Documentaion: https://netopeer.liberouter.org/doc/libyang/master/ + +pyang +^^^^^ + + pyang is a YANG validator, transformator and code generator, written + in python. It can be used to validate YANG modules for correctness, + to transform YANG modules into other formats, and to generate code + from the modules. + +- GitHub page: https://github.com/mbj4668/pyang +- Documentaion: https://github.com/mbj4668/pyang/wiki/Documentation + +ncclient +^^^^^^^^ + + ncclient is a Python library that facilitates client-side scripting + and application development around the NETCONF protocol. + +- GitHub page: https://github.com/ncclient/ncclient +- Documentaion: https://ncclient.readthedocs.io/en/latest/ + +YDK +^^^ + + ydk-gen is a developer tool that can generate API’s that are modeled + in YANG. Currently, it generates language binding for Python, Go and + C++ with planned support for other language bindings in the future. + +- GitHub pages: + + - Generator: https://github.com/CiscoDevNet/ydk-gen + - Python: https://github.com/CiscoDevNet/ydk-py + + - Python samples: https://github.com/CiscoDevNet/ydk-py-samples + + - Go: https://github.com/CiscoDevNet/ydk-go + - C++: https://github.com/CiscoDevNet/ydk-cpp + +- Documentation: + + - Python: http://ydk.cisco.com/py/docs/ + - Go: http://ydk.cisco.com/go/docs/ + - C++: http://ydk.cisco.com/cpp/docs/ + +- (Blog post) Simplifying Network Programmability with Model-Driven + APIs: + https://blogs.cisco.com/sp/simplifying-network-programmability-with-model-driven-apis +- (Video introduction) Infrastructure as a Code Using YANG, OpenConfig + and YDK: https://www.youtube.com/watch?v=G1b6vJW1R5w + +pyangbind +^^^^^^^^^ + + A plugin for pyang that creates Python bindings for a YANG model. + +- GitHub page: https://github.com/robshakir/pyangbind +- Documentation: http://pynms.io/pyangbind/ + +ConfD +^^^^^ + +- Official webpage (for ConfD Basic): + http://www.tail-f.com/confd-basic/ +- Training Videos: http://www.tail-f.com/confd-training-videos/ +- Forum: http://discuss.tail-f.com/ + +Sysrepo +^^^^^^^ + + Sysrepo is an YANG-based configuration and operational state data + store for Unix/Linux applications. + +- GitHub page: https://github.com/sysrepo/sysrepo +- Official webpage: http://www.sysrepo.org/ +- Documentation: http://www.sysrepo.org/static/doc/html/ + +Netopeer2 +^^^^^^^^^ + + Netopeer2 is a set of tools implementing network configuration tools + based on the NETCONF Protocol. This is the second generation of the + toolset, originally available as the Netopeer project. Netopeer2 is + based on the new generation of the NETCONF and YANG libraries - + libyang and libnetconf2. The Netopeer server uses sysrepo as a + NETCONF datastore implementation. + +- GitHub page: https://github.com/CESNET/Netopeer2 + +Clixon +^^^^^^ + + Clixon is an automatic configuration manager where you generate + interactive CLI, NETCONF, RESTCONF and embedded databases with + transaction support from a YANG specification. + +- GitHub page: https://github.com/clicon/clixon +- Project page: http://www.clicon.org/ diff --git a/doc/developer/northbound/northbound.rst b/doc/developer/northbound/northbound.rst new file mode 100644 index 000000000000..7dddf0646039 --- /dev/null +++ b/doc/developer/northbound/northbound.rst @@ -0,0 +1,21 @@ +.. _northbound: + +************** +Northbound API +************** + +.. toctree:: + :maxdepth: 2 + + architecture + transactional-cli + retrofitting-configuration-commands + operational-data-rpcs-and-notifications + plugins-sysrepo + advanced-topics + yang-tools + yang-module-translator + demos + links + ppr-basic-test-topology + ppr-mpls-basic-test-topology diff --git a/doc/developer/northbound/operational-data-rpcs-and-notifications.rst b/doc/developer/northbound/operational-data-rpcs-and-notifications.rst new file mode 100644 index 000000000000..554bc17c80e0 --- /dev/null +++ b/doc/developer/northbound/operational-data-rpcs-and-notifications.rst @@ -0,0 +1,565 @@ +Operational data +~~~~~~~~~~~~~~~~ + +Writing API-agnostic code for YANG-modeled operational data is +challenging. ConfD and Sysrepo, for instance, have completely different +APIs to fetch operational data. So how can we write API-agnostic +callbacks that can be used by both the ConfD and Sysrepo plugins, and +any other northbound client that might be written in the future? + +As an additional requirement, the callbacks must be designed in a way +that makes in-place XPath filtering possible. As an example, a +management client might want to retrieve only a subset of a large YANG +list (e.g. a BGP table), and for optimal performance it should be +possible to filter out the unwanted elements locally in the managed +devices instead of returning all elements and performing the filtering +on the management application. + +To meet all these requirements, the four callbacks below were introduced +in the northbound architecture: + +.. code:: c + + /* + * Operational data callback. + * + * The callback function should return the value of a specific leaf or + * inform if a typeless value (presence containers or leafs of type + * empty) exists or not. + * + * xpath + * YANG data path of the data we want to get + * + * list_entry + * pointer to list entry + * + * Returns: + * pointer to newly created yang_data structure, or NULL to indicate + * the absence of data + */ + struct yang_data *(*get_elem)(const char *xpath, void *list_entry); + + /* + * Operational data callback for YANG lists. + * + * The callback function should return the next entry in the list. The + * 'list_entry' parameter will be NULL on the first invocation. + * + * list_entry + * pointer to a list entry + * + * Returns: + * pointer to the next entry in the list, or NULL to signal that the + * end of the list was reached + */ + void *(*get_next)(void *list_entry); + + /* + * Operational data callback for YANG lists. + * + * The callback function should fill the 'keys' parameter based on the + * given list_entry. + * + * list_entry + * pointer to a list entry + * + * keys + * structure to be filled based on the attributes of the provided + * list entry + * + * Returns: + * NB_OK on success, NB_ERR otherwise + */ + int (*get_keys)(void *list_entry, struct yang_list_keys *keys); + + /* + * Operational data callback for YANG lists. + * + * The callback function should return a list entry based on the list + * keys given as a parameter. + * + * keys + * structure containing the keys of the list entry + * + * Returns: + * a pointer to the list entry if found, or NULL if not found + */ + void *(*lookup_entry)(struct yang_list_keys *keys); + +These callbacks were designed to provide maximum flexibility, and borrow +a lot of ideas from the ConfD API. Each callback does one and only one +task, they are indivisible primitives that can be combined in several +different ways to iterate over operational data. The extra flexibility +certainly has a performance cost, but it’s the price to pay if we want +to expose FRR operational data using several different management +interfaces (e.g. NETCONF via either ConfD or Sysrepo+Netopeer2). In the +future it might be possible to introduce optional callbacks that do +things like returning multiple objects at once. They would provide +enhanced performance when iterating over large lists, but their use +would be limited by the northbound plugins that can be integrated with +them. + + NOTE: using the northbound callbacks as a base, the ConfD plugin can + provide up to 100 objects between each round trip between FRR and the + *confd* daemon. Preliminary tests showed FRR taking ~7 seconds + (asynchronously, without blocking the main pthread) to return a RIP + table containing 100k routes to a NETCONF client connected to *confd* + (JSON was used as the encoding format). Work needs to be done to find + the bottlenecks and optimize this operation. + +The [[Plugins - Writing Your Own]] page explains how the northbound +plugins can fetch operational data using the aforementioned northbound +callbacks, and how in-place XPath filtering can be implemented. + +Example +^^^^^^^ + +Now let’s move to an example to show how these callbacks are implemented +in practice. The following YANG container is part of the *ietf-rip* +module and contains operational data about RIP neighbors: + +.. code:: yang + + container neighbors { + description + "Neighbor information."; + list neighbor { + key "address"; + description + "A RIP neighbor."; + leaf address { + type inet:ipv4-address; + description + "IP address that a RIP neighbor is using as its + source address."; + } + leaf last-update { + type yang:date-and-time; + description + "The time when the most recent RIP update was + received from this neighbor."; + } + leaf bad-packets-rcvd { + type yang:counter32; + description + "The number of RIP invalid packets received from + this neighbor which were subsequently discarded + for any reason (e.g. a version 0 packet, or an + unknown command type)."; + } + leaf bad-routes-rcvd { + type yang:counter32; + description + "The number of routes received from this neighbor, + in valid RIP packets, which were ignored for any + reason (e.g. unknown address family, or invalid + metric)."; + } + } + } + +We know that this is operational data because the ``neighbors`` +container is within the ``state`` container, which has the +``config false;`` property (which is applied recursively). + +As expected, the ``gen_northbound_callbacks`` tool also generates +skeleton callbacks for nodes that represent operational data: + +.. code:: c + + { + .xpath = "/frr-ripd:ripd/state/neighbors/neighbor", + .cbs.get_next = ripd_state_neighbors_neighbor_get_next, + .cbs.get_keys = ripd_state_neighbors_neighbor_get_keys, + .cbs.lookup_entry = ripd_state_neighbors_neighbor_lookup_entry, + }, + { + .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/address", + .cbs.get_elem = ripd_state_neighbors_neighbor_address_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/last-update", + .cbs.get_elem = ripd_state_neighbors_neighbor_last_update_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/bad-packets-rcvd", + .cbs.get_elem = ripd_state_neighbors_neighbor_bad_packets_rcvd_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/bad-routes-rcvd", + .cbs.get_elem = ripd_state_neighbors_neighbor_bad_routes_rcvd_get_elem, + }, + +The ``/frr-ripd:ripd/state/neighbors/neighbor`` list within the +``neighbors`` container has three different callbacks that need to be +implemented. Let’s start with the first one, the ``get_next`` callback: + +.. code:: c + + static void *ripd_state_neighbors_neighbor_get_next(void *list_entry) + { + struct listnode *node; + + if (list_entry == NULL) + node = listhead(peer_list); + else + node = listnextnode((struct listnode *)list_entry); + + return node; + } + +Given a list entry, the job of this callback is to find the next element +from the list. When the ``list_entry`` parameter is NULL, then the first +element of the list should be returned. + +*ripd* uses the ``rip_peer`` structure to represent RIP neighbors, and +the ``peer_list`` global variable (linked list) is used to store all RIP +neighbors. + +In order to be able to iterate over the list of RIP neighbors, the +callback returns a ``listnode`` variable instead of a ``rip_peer`` +variable. The ``listnextnode`` macro can then be used to find the next +element from the linked list. + +Now the second callback, ``get_keys``: + +.. code:: c + + static int ripd_state_neighbors_neighbor_get_keys(void *list_entry, + struct yang_list_keys *keys) + { + struct listnode *node = list_entry; + struct rip_peer *peer = listgetdata(node); + + keys->num = 1; + (void)inet_ntop(AF_INET, &peer->addr, keys->key[0].value, + sizeof(keys->key[0].value)); + + return NB_OK; + } + +This one is easy. First, we obtain the RIP neighbor from the +``listnode`` structure. Then, we fill the ``keys`` parameter according +to the attributes of the RIP neighbor. In this case, the ``neighbor`` +YANG list has only one key: the neighbor IP address. We then use the +``inet_ntop()`` function to transform this binary IP address into a +string (the lingua franca of the FRR northbound). + +The last callback for the ``neighbor`` YANG list is the ``lookup_entry`` +callback: + +.. code:: c + + static void * + ripd_state_neighbors_neighbor_lookup_entry(struct yang_list_keys *keys) + { + struct in_addr address; + + yang_str2ipv4(keys->key[0].value, &address); + + return rip_peer_lookup(&address); + } + +This callback is the counterpart of the ``get_keys`` callback: given an +array of list keys, the associated list entry should be returned. The +``yang_str2ipv4()`` function is used to convert the list key (an IP +address) from a string to an ``in_addr`` structure. Then the +``rip_peer_lookup()`` function is used to find the list entry. + +Finally, each YANG leaf inside the ``neighbor`` list has its associated +``get_elem`` callback: + +.. code:: c + + /* + * XPath: /frr-ripd:ripd/state/neighbors/neighbor/address + */ + static struct yang_data * + ripd_state_neighbors_neighbor_address_get_elem(const char *xpath, + void *list_entry) + { + struct rip_peer *peer = list_entry; + + return yang_data_new_ipv4(xpath, &peer->addr); + } + + /* + * XPath: /frr-ripd:ripd/state/neighbors/neighbor/last-update + */ + static struct yang_data * + ripd_state_neighbors_neighbor_last_update_get_elem(const char *xpath, + void *list_entry) + { + /* TODO: yang:date-and-time is tricky */ + return NULL; + } + + /* + * XPath: /frr-ripd:ripd/state/neighbors/neighbor/bad-packets-rcvd + */ + static struct yang_data * + ripd_state_neighbors_neighbor_bad_packets_rcvd_get_elem(const char *xpath, + void *list_entry) + { + struct rip_peer *peer = list_entry; + + return yang_data_new_uint32(xpath, peer->recv_badpackets); + } + + /* + * XPath: /frr-ripd:ripd/state/neighbors/neighbor/bad-routes-rcvd + */ + static struct yang_data * + ripd_state_neighbors_neighbor_bad_routes_rcvd_get_elem(const char *xpath, + void *list_entry) + { + struct rip_peer *peer = list_entry; + + return yang_data_new_uint32(xpath, peer->recv_badroutes); + } + +These callbacks receive the list entry as parameter and return the +corresponding data using the ``yang_data_new_*()`` wrapper functions. +Not much to explain here. + +Iterating over operational data without blocking the main pthread +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +One of the problems we have in FRR is that some “show” commands in the +CLI can take too long, potentially long enough to the point of +triggering some protocol timeouts and bringing sessions down. + +To avoid this kind of problem, northbound clients are encouraged to do +one of the following: \* Create a separate pthread for handling requests +to fetch operational data. \* Iterate over YANG lists and leaf-lists +asynchronously, returning a maximum number of elements per time instead +of returning all elements in one shot. + +In order to handle both cases correctly, the ``get_next`` callbacks need +to use locks to prevent the YANG lists from being modified while they +are being iterated over. If that is not done, the list entry returned by +this callback can become a dangling pointer when used in another +callback. + +Currently the ConfD and Sysrepo plugins run only in the main pthread. +The plan in the short-term is to introduce a separate pthread only for +handling operational data, and use the main pthread only for handling +configuration changes, RPCs and notifications. + +RPCs and Actions +~~~~~~~~~~~~~~~~ + +The FRR northbound supports YANG RPCs and Actions through the ``rpc()`` +callback, which is documented as follows in the *lib/northbound.h* file: + +.. code:: c + + /* + * RPC and action callback. + * + * Both 'input' and 'output' are lists of 'yang_data' structures. The + * callback should fetch all the input parameters from the 'input' list, + * and add output parameters to the 'output' list if necessary. + * + * xpath + * xpath of the YANG RPC or action + * + * input + * read-only list of input parameters + * + * output + * list of output parameters to be populated by the callback + * + * Returns: + * NB_OK on success, NB_ERR otherwise + */ + int (*rpc)(const char *xpath, const struct list *input, + struct list *output); + +Note that the same callback is used for both RPCs and actions, which are +essentially the same thing. In the case of YANG actions, the ``xpath`` +parameter can be consulted to find the data node associated to the +operation. + +As part of the northbound retrofitting process, it’s suggested to model +some EXEC-level commands using YANG so that their functionality is +exposed to other management interfaces other than the CLI. As an +example, if the ``clear bgp`` command is modeled using a YANG RPC, and a +corresponding ``rpc`` callback is written, then it should be possible to +clear BGP neighbors using NETCONF and RESTCONF with that RPC (the ConfD +and Sysrepo plugins have full support for YANG RPCs and actions). + +Here’s an example of a very simple RPC modeled using YANG: + +.. code:: yang + + rpc clear-rip-route { + description + "Clears RIP routes from the IP routing table and routes + redistributed into the RIP protocol."; + } + +This RPC doesn’t have any input or output parameters. Below we can see +the implementation of the corresponding ``rpc`` callback, whose skeleton +was automatically generated by the ``gen_northbound_callbacks`` tool: + +.. code:: c + + /* + * XPath: /frr-ripd:clear-rip-route + */ + static int clear_rip_route_rpc(const char *xpath, const struct list *input, + struct list *output) + { + struct route_node *rp; + struct rip_info *rinfo; + struct list *list; + struct listnode *listnode; + + /* Clear received RIP routes */ + for (rp = route_top(rip->table); rp; rp = route_next(rp)) { + list = rp->info; + if (list == NULL) + continue; + + for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { + if (!rip_route_rte(rinfo)) + continue; + + if (CHECK_FLAG(rinfo->flags, RIP_RTF_FIB)) + rip_zebra_ipv4_delete(rp); + break; + } + + if (rinfo) { + RIP_TIMER_OFF(rinfo->t_timeout); + RIP_TIMER_OFF(rinfo->t_garbage_collect); + listnode_delete(list, rinfo); + rip_info_free(rinfo); + } + + if (list_isempty(list)) { + list_delete_and_null(&list); + rp->info = NULL; + route_unlock_node(rp); + } + } + + return NB_OK; + } + +If the ``clear-rip-route`` RPC had any input parameters, they would be +available in the ``input`` list given as a parameter to the callback. +Similarly, the ``output`` list can be used to append output parameters +generated by the RPC, if any are defined in the YANG model. + +The northbound clients (CLI and northbound plugins) have the +responsibility to create and delete the ``input`` and ``output`` lists. +However, in the cases where the RPC or action doesn’t have any input or +output parameters, the northbound client can pass NULL pointers to the +``rpc`` callback to avoid creating linked lists unnecessarily. We can +see this happening in the example below: + +.. code:: c + + /* + * XPath: /frr-ripd:clear-rip-route + */ + DEFPY (clear_ip_rip, + clear_ip_rip_cmd, + "clear ip rip", + CLEAR_STR + IP_STR + "Clear IP RIP database\n") + { + return nb_cli_rpc("/frr-ripd:clear-rip-route", NULL, NULL); + } + +``nb_cli_rpc()`` is a helper function that merely finds the appropriate +``rpc`` callback based on the XPath provided in the first argument, and +map the northbound error code from the ``rpc`` callback to a vty error +code (e.g. ``CMD_SUCCESS``, ``CMD_WARNING``). The second and third +arguments provided to the function refer to the ``input`` and ``output`` +lists. In this case, both arguments are set to NULL since the YANG RPC +in question doesn’t have any input/output parameters. + +Notifications +~~~~~~~~~~~~~ + +YANG notifations are sent using the ``nb_notification_send()`` function, +documented in the *lib/northbound.h* file as follows: + +.. code:: c + + /* + * Send a YANG notification. This is a no-op unless the 'nb_notification_send' + * hook was registered by a northbound plugin. + * + * xpath + * xpath of the YANG notification + * + * arguments + * linked list containing the arguments that should be sent. This list is + * deleted after being used. + * + * Returns: + * NB_OK on success, NB_ERR otherwise + */ + extern int nb_notification_send(const char *xpath, struct list *arguments); + +The northbound doesn’t use callbacks for notifications because +notifications are generated locally and sent to the northbound clients. +This way, whenever a notification needs to be sent, it’s possible to +call the appropriate function directly instead of finding a callback +based on the XPath of the YANG notification. + +As an example, the *ietf-rip* module contains the following +notification: + +.. code:: yang + + notification authentication-failure { + description + "This notification is sent when the system + receives a PDU with the wrong authentication + information."; + leaf interface-name { + type string; + description + "Describes the name of the RIP interface."; + } + } + +The following convenience function was implemented in *ripd* to send +*authentication-failure* YANG notifications: + +.. code:: c + + /* + * XPath: /frr-ripd:authentication-failure + */ + void ripd_notif_send_auth_failure(const char *ifname) + { + const char *xpath = "/frr-ripd:authentication-failure"; + struct list *arguments; + char xpath_arg[XPATH_MAXLEN]; + struct yang_data *data; + + arguments = yang_data_list_new(); + + snprintf(xpath_arg, sizeof(xpath_arg), "%s/interface-name", xpath); + data = yang_data_new_string(xpath_arg, ifname); + listnode_add(arguments, data); + + nb_notification_send(xpath, arguments); + } + +Now sending the *authentication-failure* YANG notification should be as +simple as calling the above function and provide the appropriate +interface name. The notification will be processed by all northbound +plugins that subscribed a callback to the ``nb_notification_send`` hook. +The ConfD and Sysrepo plugins, for instance, use this hook to relay the +notifications to the *confd*/*sysrepod* daemons, which can generate +NETCONF notifications to subscribed clients. When no northbound plugin +is loaded, ``nb_notification_send()`` doesn’t do anything and the +notifications are ignored. diff --git a/doc/developer/northbound/plugins-sysrepo.rst b/doc/developer/northbound/plugins-sysrepo.rst new file mode 100644 index 000000000000..186c3a0177d1 --- /dev/null +++ b/doc/developer/northbound/plugins-sysrepo.rst @@ -0,0 +1,137 @@ +Installation +------------ + +Required dependencies +^^^^^^^^^^^^^^^^^^^^^ + +:: + + # apt-get install git cmake build-essential bison flex libpcre3-dev libev-dev \ + libavl-dev libprotobuf-c-dev protobuf-c-compiler libcmocka0 \ + libcmocka-dev doxygen libssl-dev libssl-dev libssh-dev + +libyang +^^^^^^^ + +:: + + # apt-get install libyang0.16 libyang-dev + +Sysrepo +^^^^^^^ + +:: + + $ git clone https://github.com/sysrepo/sysrepo.git + $ cd sysrepo/ + $ mkdir build; cd build + $ cmake -DCMAKE_BUILD_TYPE=Release -DGEN_LANGUAGE_BINDINGS=OFF .. && make + # make install + +libnetconf2 +^^^^^^^^^^^ + +:: + + $ git clone https://github.com/CESNET/libnetconf2.git + $ cd libnetconf2/ + $ mkdir build; cd build + $ cmake .. && make + # make install + +netopeer2 +^^^^^^^^^ + +:: + + $ git clone https://github.com/CESNET/Netopeer2.git + $ cd Netopeer2 + $ cd server + $ mkdir build; cd build + $ cmake .. && make + # make install + +**Note:** If ``make install`` fails as it can’t find +``libsysrepo.so.0.7``, then run ``ldconfig`` and try again as it might +not have updated the lib search path + +FRR +^^^ + +Build and install FRR using the ``--enable-sysrepo`` configure-time +option. + +Initialization +-------------- + +Install the FRR YANG modules in the Sysrepo datastore: + +:: + + # sysrepoctl --install /usr/local/share/yang/ietf-interfaces@2018-01-09.yang + # sysrepoctl --install /usr/local/share/yang/frr-vrf.yang + # sysrepoctl --install /usr/local/share/yang/frr-interface.yang + # sysrepoctl --install /usr/local/share/yang/frr-route-types.yang + # sysrepoctl --install /usr/local/share/yang/frr-filter.yang + # sysrepoctl --install /usr/local/share/yang/frr-route-map.yang + # sysrepoctl --install /usr/local/share/yang/frr-isisd.yang + # sysrepoctl --install /usr/local/share/yang/frr-ripd.yang + # sysrepoctl --install /usr/local/share/yang/frr-ripngd.yang + # sysrepoctl -c frr-vrf --owner frr --group frr + # sysrepoctl -c frr-interface --owner frr --group frr + # sysrepoctl -c frr-route-types --owner frr --group frr + # sysrepoctl -c frr-filter --owner frr --group frr + # sysrepoctl -c frr-route-map --owner frr --group frr + # sysrepoctl -c frr-isisd --owner frr --group frr + # sysrepoctl -c frr-ripd --owner frr --group frr + # sysrepoctl -c frr-ripngd --owner frr --group frr + +Start netopeer2-server: + +:: + + # netopeer2-server -d & + +Start the FRR daemons with the sysrepo module: + +:: + + # isisd -M sysrepo --log=stdout + +Managing the configuration +-------------------------- + +The following NETCONF scripts can be used to show and edit the FRR +configuration: +https://github.com/rzalamena/ietf-hackathon-brazil-201907/tree/master/netconf-scripts + +Example: + +:: + + # ./netconf-edit.py 127.0.0.1 + # ./netconf-get-config.py 127.0.0.1 + testnetlevel-1 + +.. + + NOTE: the ncclient library needs to be installed first: + ``apt install -y python3-ncclient`` + +The *sysrepocfg* tool can also be used to show/edit the FRR +configuration. Example: + +:: + + # sysrepocfg --format=json --import=frr-isisd.json --datastore=running frr-isisd + # sysrepocfg --format=json --export --datastore=running frr-isisd + { + "frr-isisd:isis": { + "instance": [ + { + "area-tag": "testnet", + "is-type": "level-1" + } + ] + } + } diff --git a/doc/developer/northbound/ppr-basic-test-topology.rst b/doc/developer/northbound/ppr-basic-test-topology.rst new file mode 100644 index 000000000000..582c76c059dc --- /dev/null +++ b/doc/developer/northbound/ppr-basic-test-topology.rst @@ -0,0 +1,1632 @@ +Table of Contents +~~~~~~~~~~~~~~~~~ + +- `Software <#software>`__ +- `Topology <#topology>`__ +- `Configuration <#configuration>`__ + + - `CLI <#configuration-cli>`__ + - `YANG <#configuration-yang>`__ + +- `Verification - Control Plane <#verification-cplane>`__ +- `Verification - Forwarding Plane <#verification-fplane>`__ + +Software +~~~~~~~~ + +The FRR PPR implementation for IS-IS is available here: +https://github.com/opensourcerouting/frr/tree/isisd-ppr + +Topology +~~~~~~~~ + +In this topology we have an IS-IS network consisting of 12 routers. CE1 +and CE2 are the consumer edges, connected to R11 and R14, respectively. +Three hosts are connected to the CEs using only static routes. + +Router R11 advertises 6 PPR TLVs, which corresponds to three +bi-directional GRE tunnels: \* **6000:1::1 <-> 6000:2::1:** {R11 - R21 - +R22 - R23 - R14} (IPv6 Node Addresses only) \* **6000:1::2 <-> +6000:2::2:** {R11 - R21 - R32 - R41 - R33 - R23 - R14} (IPv6 Node and +Interface Addresses) \* **6000:1::3 <-> 6000:2::3:** {R11 - R21 - R99 - +R23 - R14} (misconfigured path) + +PBR rules are configured on R11 and R14 to route the traffic between +Host 1 and Host 3 using the first PPR tunnel. Traffic between Host 2 and +Host 3 uses the regular IS-IS shortest path. + +Additional information: \* Addresses in the 4000::/16 range refer to +interface addresses, where the last hextet corresponds to the node ID. +\* Addresses in the 5000::/16 range refer to loopback addresses, where +the last hextet corresponds to the node ID. \* Addresses in the +6000::/16 range refer to PPR-ID addresses. + +:: + + +-------+ +-------+ +-------+ + | | | | | | + | HOST1 | | HOST2 | | HOST3 | + | | | | | | + +---+---+ +---+---+ +---+---+ + | | | + |fd00:10:1::/64 | | + +-----+ +------+ fd00:20:1::/64| + | |fd00:10:2::/64 | + | | | + +-+--+--+ +---+---+ + | | | | + | CE1 | | CE2 | + | | | | + +---+---+ +---+---+ + | | + | | + |fd00:10:0::/64 fd00:20:0::/64| + | | + | | + +---+---+ +-------+ +-------+ +---+---+ + | |4000:101::/64| |4000:102::/64| |4000:103::/64| | + | R11 +-------------+ R12 +-------------+ R13 +-------------+ R14 | + | | | | | | | | + +---+---+ +--+-+--+ +--+-+--+ +---+---+ + | | | | | | + |4000:104::/64 | |4000:106::/64 | |4000:108::/64 | + +---------+ +--------+ +--------+ +--------+ +--------+ +---------+ + | |4000:105::/64 | |4000:107::/64 | |4000:109::/64 + | | | | | | + +--+-+--+ +--+-+--+ +--+-+--+ + | |4000:110::/64| |4000:111::/64| | + | R21 +-------------+ R22 +-------------+ R23 | + | | | | | | + +--+-+--+ +--+-+--+ +--+-+--+ + | | | | | | + | |4000:113::/64 | |4000:115::/64 | |4000:117::/64 + +---------+ +--------+ +--------+ +--------+ +--------+ +---------+ + |4000:112::/64 | |4000:114::/64 | |4000:116::/64 | + | | | | | | + +---+---+ +--+-+--+ +--+-+--+ +---+---+ + | |4000:118::/64| |4000:119::/64| |4000:120::/64| | + | R31 +-------------+ R32 +-------------+ R33 +-------------+ R34 | + | | | | | | | | + +-------+ +---+---+ +---+---+ +-------+ + | | + |4000:121::/64 | + +----------+----------+ + | + | + +---+---+ + | | + | R41 | + | | + +-------+ + +Configuration +~~~~~~~~~~~~~ + +PPR TLV processing needs to be enabled on all IS-IS routers using the +``ppr on`` command. The advertisements of all PPR TLVs is done by router +R11. + +CLI configuration +^^^^^^^^^^^^^^^^^ + +.. code:: yaml + + --- + + routers: + + host1: + links: + eth-ce1: + peer: [ce1, eth-host1] + frr: + zebra: + staticd: + config: | + interface eth-ce1 + ipv6 address fd00:10:1::1/64 + ! + ipv6 route ::/0 fd00:10:1::100 + + host2: + links: + eth-ce1: + peer: [ce1, eth-host2] + frr: + zebra: + staticd: + config: | + interface eth-ce1 + ipv6 address fd00:10:2::1/64 + ! + ipv6 route ::/0 fd00:10:2::100 + + host3: + links: + eth-ce2: + peer: [ce2, eth-host3] + frr: + zebra: + staticd: + config: | + interface eth-ce2 + ipv6 address fd00:20:1::1/64 + ! + ipv6 route ::/0 fd00:20:1::100 + + ce1: + links: + eth-host1: + peer: [host1, eth-ce1] + eth-host2: + peer: [host2, eth-ce1] + eth-rt11: + peer: [rt11, eth-ce1] + frr: + zebra: + staticd: + config: | + interface eth-host1 + ipv6 address fd00:10:1::100/64 + ! + interface eth-host2 + ipv6 address fd00:10:2::100/64 + ! + interface eth-rt11 + ipv6 address fd00:10:0::100/64 + ! + ipv6 route ::/0 fd00:10:0::11 + + ce2: + links: + eth-host3: + peer: [host3, eth-ce2] + eth-rt14: + peer: [rt14, eth-ce2] + frr: + zebra: + staticd: + config: | + interface eth-host3 + ipv6 address fd00:20:1::100/64 + ! + interface eth-rt14 + ipv6 address fd00:20:0::100/64 + ! + ipv6 route ::/0 fd00:20:0::14 + + rt11: + links: + lo-ppr: + eth-ce1: + peer: [ce1, eth-rt11] + eth-rt12: + peer: [rt12, eth-rt11] + eth-rt21: + peer: [rt21, eth-rt11] + shell: | + # GRE tunnel for preferred packets (PPR) + ip -6 tunnel add tun-ppr mode ip6gre remote 6000:2::1 local 6000:1::1 ttl 64 + ip link set dev tun-ppr up + # PBR rules + ip -6 rule add from fd00:10:1::/64 to fd00:20:1::/64 iif eth-ce1 lookup 10000 + ip -6 route add default dev tun-ppr table 10000 + frr: + zebra: + staticd: + isisd: + config: | + interface lo-ppr + ipv6 address 6000:1::1/128 + ipv6 address 6000:1::2/128 + ipv6 address 6000:1::3/128 + ! + interface lo + ipv6 address 5000::11/128 + ipv6 router isis 1 + ! + interface eth-ce1 + ipv6 address fd00:10:0::11/64 + ! + interface eth-rt12 + ipv6 address 4000:101::11/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt21 + ipv6 address 4000:104::11/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + ipv6 route fd00:10::/32 fd00:10:0::100 + ! + ppr group VOIP + ppr ipv6 6000:1::1/128 prefix 5000::11/128 metric 50 + pde ipv6-node 5000::14/128 + pde ipv6-node 5000::23/128 + pde ipv6-node 5000::22/128 + pde ipv6-node 5000::21/128 + pde ipv6-node 5000::11/128 + ! + ppr ipv6 6000:2::1/128 prefix 5000::14/128 metric 50 + pde ipv6-node 5000::11/128 + pde ipv6-node 5000::21/128 + pde ipv6-node 5000::22/128 + pde ipv6-node 5000::23/128 + pde ipv6-node 5000::14/128 + ! + ! + ppr group INTERFACE_PDES + ppr ipv6 6000:1::2/128 prefix 5000::11/128 + pde ipv6-node 5000::14/128 + pde ipv6-node 5000::23/128 + pde ipv6-node 5000::33/128 + pde ipv6-interface 4000:121::41/64 + pde ipv6-node 5000::32/128 + pde ipv6-interface 4000:113::21/64 + pde ipv6-node 5000::11/128 + ! + ppr ipv6 6000:2::2/128 prefix 5000::14/128 + pde ipv6-node 5000::11/128 + pde ipv6-node 5000::21/128 + pde ipv6-node 5000::32/128 + pde ipv6-interface 4000:121::41/64 + pde ipv6-node 5000::33/128 + pde ipv6-interface 4000:116::23/64 + pde ipv6-node 5000::14/128 + ! + ! + ppr group BROKEN + ppr ipv6 6000:1::3/128 prefix 5000::11/128 metric 1500 + pde ipv6-node 5000::14/128 + pde ipv6-node 5000::23/128 + ! non-existing node!!! + pde ipv6-node 5000::99/128 + pde ipv6-node 5000::21/128 + pde ipv6-node 5000::11/128 + ! + ppr ipv6 6000:2::3/128 prefix 5000::14/128 metric 1500 + pde ipv6-node 5000::11/128 + pde ipv6-node 5000::21/128 + ! non-existing node!!! + pde ipv6-node 5000::99/128 + pde ipv6-node 5000::23/128 + pde ipv6-node 5000::14/128 + ! + ! + router isis 1 + net 49.0000.0000.0000.0011.00 + is-type level-1 + topology ipv6-unicast + ppr on + ppr advertise VOIP + ppr advertise INTERFACE_PDES + ppr advertise BROKEN + ! + + rt12: + links: + eth-rt11: + peer: [rt11, eth-rt12] + eth-rt13: + peer: [rt13, eth-rt12] + eth-rt21: + peer: [rt21, eth-rt12] + eth-rt22: + peer: [rt22, eth-rt12] + frr: + zebra: + isisd: + config: | + interface lo + ipv6 address 5000::12/128 + ipv6 router isis 1 + ! + interface eth-rt11 + ipv6 address 4000:101::12/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt13 + ipv6 address 4000:102::12/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt21 + ipv6 address 4000:105::12/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt22 + ipv6 address 4000:106::12/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0012.00 + is-type level-1 + topology ipv6-unicast + ppr on + ! + + rt13: + links: + eth-rt12: + peer: [rt12, eth-rt13] + eth-rt14: + peer: [rt14, eth-rt13] + eth-rt22: + peer: [rt22, eth-rt13] + eth-rt23: + peer: [rt23, eth-rt13] + frr: + zebra: + isisd: + config: | + interface lo + ipv6 address 5000::13/128 + ipv6 router isis 1 + ! + interface eth-rt12 + ipv6 address 4000:102::13/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt14 + ipv6 address 4000:103::13/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt22 + ipv6 address 4000:107::13/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt23 + ipv6 address 4000:108::13/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0013.00 + is-type level-1 + topology ipv6-unicast + ppr on + ! + + rt14: + links: + lo-ppr: + eth-ce2: + peer: [ce2, eth-rt14] + eth-rt13: + peer: [rt13, eth-rt14] + eth-rt23: + peer: [rt23, eth-rt14] + shell: | + # GRE tunnel for preferred packets (PPR) + ip -6 tunnel add tun-ppr mode ip6gre remote 6000:1::1 local 6000:2::1 ttl 64 + ip link set dev tun-ppr up + # PBR rules + ip -6 rule add from fd00:20:1::/64 to fd00:10:1::/64 iif eth-ce2 lookup 10000 + ip -6 route add default dev tun-ppr table 10000 + frr: + zebra: + staticd: + isisd: + config: | + interface lo-ppr + ipv6 address 6000:2::1/128 + ipv6 address 6000:2::2/128 + ipv6 address 6000:2::3/128 + ! + interface lo + ipv6 address 5000::14/128 + ipv6 router isis 1 + ! + interface eth-ce2 + ipv6 address fd00:20:0::14/64 + ! + interface eth-rt13 + ipv6 address 4000:103::14/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt23 + ipv6 address 4000:109::14/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + ipv6 route fd00:20::/32 fd00:20:0::100 + ! + router isis 1 + net 49.0000.0000.0000.0014.00 + is-type level-1 + topology ipv6-unicast + ppr on + ! + + rt21: + links: + eth-rt11: + peer: [rt11, eth-rt21] + eth-rt12: + peer: [rt12, eth-rt21] + eth-rt22: + peer: [rt22, eth-rt21] + eth-rt31: + peer: [rt31, eth-rt21] + eth-rt32: + peer: [rt32, eth-rt21] + frr: + zebra: + isisd: + config: | + interface lo + ipv6 address 5000::21/128 + ipv6 router isis 1 + ! + interface eth-rt11 + ipv6 address 4000:104::21/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt12 + ipv6 address 4000:105::21/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt22 + ipv6 address 4000:110::21/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt31 + ipv6 address 4000:112::21/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt32 + ipv6 address 4000:113::21/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0021.00 + is-type level-1 + topology ipv6-unicast + ppr on + ! + + rt22: + links: + eth-rt12: + peer: [rt12, eth-rt22] + eth-rt13: + peer: [rt13, eth-rt22] + eth-rt21: + peer: [rt21, eth-rt22] + eth-rt23: + peer: [rt23, eth-rt22] + eth-rt32: + peer: [rt32, eth-rt22] + eth-rt33: + peer: [rt33, eth-rt22] + frr: + zebra: + isisd: + config: | + interface lo + ipv6 address 5000::22/128 + ipv6 router isis 1 + ! + interface eth-rt12 + ipv6 address 4000:106::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt13 + ipv6 address 4000:107::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt21 + ipv6 address 4000:110::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt23 + ipv6 address 4000:111::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt32 + ipv6 address 4000:114::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt33 + ipv6 address 4000:115::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0022.00 + is-type level-1 + topology ipv6-unicast + ppr on + ! + + rt23: + links: + eth-rt13: + peer: [rt13, eth-rt23] + eth-rt14: + peer: [rt14, eth-rt23] + eth-rt22: + peer: [rt22, eth-rt23] + eth-rt33: + peer: [rt33, eth-rt23] + eth-rt34: + peer: [rt34, eth-rt23] + frr: + zebra: + isisd: + config: | + interface lo + ipv6 address 5000::23/128 + ipv6 router isis 1 + ! + interface eth-rt13 + ipv6 address 4000:108::23/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt14 + ipv6 address 4000:109::23/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt22 + ipv6 address 4000:111::23/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt33 + ipv6 address 4000:116::23/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt34 + ipv6 address 4000:117::23/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0023.00 + is-type level-1 + topology ipv6-unicast + ppr on + ! + + rt31: + links: + eth-rt21: + peer: [rt21, eth-rt31] + eth-rt32: + peer: [rt32, eth-rt31] + frr: + zebra: + isisd: + config: | + interface lo + ipv6 address 5000::31/128 + ipv6 router isis 1 + ! + interface eth-rt21 + ipv6 address 4000:112::31/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt32 + ipv6 address 4000:118::31/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0031.00 + is-type level-1 + topology ipv6-unicast + ppr on + ! + + rt32: + links: + eth-rt21: + peer: [rt21, eth-rt32] + eth-rt22: + peer: [rt22, eth-rt32] + eth-rt31: + peer: [rt31, eth-rt32] + eth-rt33: + peer: [rt33, eth-rt32] + eth-sw1: + peer: [sw1, eth-rt32] + frr: + zebra: + isisd: + config: | + interface lo + ipv6 address 5000::32/128 + ipv6 router isis 1 + ! + interface eth-rt21 + ipv6 address 4000:113::32/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt22 + ipv6 address 4000:114::32/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt31 + ipv6 address 4000:118::32/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt33 + ipv6 address 4000:119::32/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-sw1 + ipv6 address 4000:121::32/64 + ipv6 router isis 1 + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0032.00 + is-type level-1 + topology ipv6-unicast + ppr on + ! + + rt33: + links: + eth-rt22: + peer: [rt22, eth-rt33] + eth-rt23: + peer: [rt23, eth-rt33] + eth-rt32: + peer: [rt32, eth-rt33] + eth-rt34: + peer: [rt34, eth-rt33] + eth-sw1: + peer: [sw1, eth-rt33] + frr: + zebra: + isisd: + config: | + interface lo + ipv6 address 5000::33/128 + ipv6 router isis 1 + ! + interface eth-rt22 + ipv6 address 4000:115::33/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt23 + ipv6 address 4000:116::33/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt32 + ipv6 address 4000:119::33/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt34 + ipv6 address 4000:120::33/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-sw1 + ipv6 address 4000:121::33/64 + ipv6 router isis 1 + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0033.00 + is-type level-1 + topology ipv6-unicast + ppr on + ! + + rt34: + links: + eth-rt23: + peer: [rt23, eth-rt34] + eth-rt33: + peer: [rt33, eth-rt34] + frr: + zebra: + isisd: + config: | + interface lo + ipv6 address 5000::34/128 + ipv6 router isis 1 + ! + interface eth-rt23 + ipv6 address 4000:117::34/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt33 + ipv6 address 4000:120::34/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0034.00 + is-type level-1 + topology ipv6-unicast + ppr on + ! + + rt41: + links: + eth-sw1: + peer: [sw1, eth-rt41] + frr: + zebra: + isisd: + config: | + interface lo + ipv6 address 5000::41/128 + ipv6 router isis 1 + ! + interface eth-sw1 + ipv6 address 4000:121::41/64 + ipv6 router isis 1 + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0041.00 + is-type level-1 + topology ipv6-unicast + ppr on + ! + + switches: + sw1: + links: + eth-rt32: + peer: [rt32, eth-sw1] + eth-rt33: + peer: [rt33, eth-sw1] + eth-rt41: + peer: [rt41, eth-sw1] + + frr: + base-config: | + hostname %(node) + password 1 + log file %(logdir)/%(node).log + log commands + ! + debug zebra rib + debug isis ppr + debug isis events + debug isis route-events + debug isis spf-events + debug isis lsp-gen + ! + +YANG +^^^^ + +PPR can also be configured using NETCONF, RESTCONF and gRPC based on the +following YANG models: \* +`frr-ppr.yang `__ +\* +`frr-isisd.yang `__ + +As an example, here’s R11 configuration in the XML format: + +.. code:: xml + + + + lo-ppr + default + + + lo + default + + 1 + true + + + + eth-ce1 + default + + + eth-rt12 + default + + 1 + true + + + 3 + 3 + + + point-to-point + + + + eth-rt21 + default + + 1 + true + + + 3 + 3 + + + point-to-point + + + + + + VOIP + + 6000:1::1/128 + 5000::11/128 + + 5000::14/128 + ipv6-node + topological + + + 5000::23/128 + ipv6-node + topological + + + 5000::22/128 + ipv6-node + topological + + + 5000::21/128 + ipv6-node + topological + + + 5000::11/128 + ipv6-node + topological + + + 50 + + + + 6000:2::1/128 + 5000::14/128 + + 5000::11/128 + ipv6-node + topological + + + 5000::21/128 + ipv6-node + topological + + + 5000::22/128 + ipv6-node + topological + + + 5000::23/128 + ipv6-node + topological + + + 5000::14/128 + ipv6-node + topological + + + 50 + + + + + INTERFACE_PDES + + 6000:1::2/128 + 5000::11/128 + + 5000::14/128 + ipv6-node + topological + + + 5000::23/128 + ipv6-node + topological + + + 5000::33/128 + ipv6-node + topological + + + 4000:121::41/64 + ipv6-interface + topological + + + 5000::32/128 + ipv6-node + topological + + + 4000:113::21/64 + ipv6-interface + topological + + + 5000::11/128 + ipv6-node + topological + + + + 6000:2::2/128 + 5000::14/128 + + 5000::11/128 + ipv6-node + topological + + + 5000::21/128 + ipv6-node + topological + + + 5000::32/128 + ipv6-node + topological + + + 4000:121::41/64 + ipv6-interface + topological + + + 5000::33/128 + ipv6-node + topological + + + 4000:116::23/64 + ipv6-interface + topological + + + 5000::14/128 + ipv6-node + topological + + + + + BROKEN + + 6000:1::3/128 + 5000::11/128 + + 5000::14/128 + ipv6-node + topological + + + 5000::23/128 + ipv6-node + topological + + + 5000::99/128 + ipv6-node + topological + + + 5000::21/128 + ipv6-node + topological + + + 5000::11/128 + ipv6-node + topological + + + 1500 + + + + 6000:2::3/128 + 5000::14/128 + + 5000::11/128 + ipv6-node + topological + + + 5000::21/128 + ipv6-node + topological + + + 5000::99/128 + ipv6-node + topological + + + 5000::23/128 + ipv6-node + topological + + + 5000::14/128 + ipv6-node + topological + + + 1500 + + + + + + + 1 + 49.0000.0000.0000.0011.00 + + + + + + true + + VOIP + + + INTERFACE_PDES + + + BROKEN + + + + + +Verification - Control Plane +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Verify that R11 has flooded the PPR TLVs correctly to all IS-IS routers: + +:: + + # show isis database detail 0000.0000.0011 + Area 1: + IS-IS Level-1 link-state database: + LSP ID PduLen SeqNumber Chksum Holdtime ATT/P/OL + debian.00-00 1233 0x00000009 0x7bd4 683 0/0/0 + Protocols Supported: IPv4, IPv6 + Area Address: 49.0000 + MT Router Info: ipv4-unicast + MT Router Info: ipv6-unicast + Hostname: debian + MT Reachability: 0000.0000.0012.00 (Metric: 10) ipv6-unicast + MT Reachability: 0000.0000.0021.00 (Metric: 10) ipv6-unicast + MT IPv6 Reachability: 5000::11/128 (Metric: 10) ipv6-unicast + MT IPv6 Reachability: 4000:101::/64 (Metric: 10) ipv6-unicast + MT IPv6 Reachability: 4000:104::/64 (Metric: 10) ipv6-unicast + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::11/128 + ID: 6000:1::3/128 (Native IPv6) + PDE: 5000::14/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::23/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::99/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::21/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::11/128 (IPv6 Node Address), L:0 N:1 E:0 + Metric: 1500 + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::14/128 + ID: 6000:2::3/128 (Native IPv6) + PDE: 5000::11/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::21/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::99/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::23/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::14/128 (IPv6 Node Address), L:0 N:1 E:0 + Metric: 1500 + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::11/128 + ID: 6000:1::2/128 (Native IPv6) + PDE: 5000::14/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::23/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::33/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 4000:121::41 (IPv6 Interface Address), L:0 N:0 E:0 + PDE: 5000::32/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 4000:113::21 (IPv6 Interface Address), L:0 N:0 E:0 + PDE: 5000::11/128 (IPv6 Node Address), L:0 N:1 E:0 + Metric: 0 + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::14/128 + ID: 6000:2::2/128 (Native IPv6) + PDE: 5000::11/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::21/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::32/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 4000:121::41 (IPv6 Interface Address), L:0 N:0 E:0 + PDE: 5000::33/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 4000:116::23 (IPv6 Interface Address), L:0 N:0 E:0 + PDE: 5000::14/128 (IPv6 Node Address), L:0 N:1 E:0 + Metric: 0 + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::11/128 + ID: 6000:1::1/128 (Native IPv6) + PDE: 5000::14/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::23/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::22/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::21/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::11/128 (IPv6 Node Address), L:0 N:1 E:0 + Metric: 50 + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::14/128 + ID: 6000:2::1/128 (Native IPv6) + PDE: 5000::11/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::21/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::22/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::23/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::14/128 (IPv6 Node Address), L:0 N:1 E:0 + Metric: 50 + +The PPR TLVs can also be seen using a modified version of Wireshark as +seen below: + +.. figure:: https://user-images.githubusercontent.com/931662/61582441-9551e500-ab01-11e9-8f6f-400ee3fba927.png + :alt: s2 + + s2 + +Using the ``show isis ppr`` command, verify that all routers installed +the PPR-IDs for the paths they are part of. Example: + +Router RT11 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + -------------------------------------------------------------------------------------------- + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Tail-End - - + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Tail-End - - + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Tail-End - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Head-End Up 00:45:41 + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Head-End Up 00:45:41 + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Head-End Up 00:45:41 + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:2::1/128 [115/50] via fe80::c2a:54ff:fe39:bff7, eth-rt21, 00:01:33 + I>* 6000:2::2/128 [115/0] via fe80::c2a:54ff:fe39:bff7, eth-rt21, 00:01:33 + I>* 6000:2::3/128 [115/1500] via fe80::c2a:54ff:fe39:bff7, eth-rt21, 00:01:33 + +Router RT12 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + ------------------------------------------------------------------------------------------ + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Off-Path - - + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Off-Path - - + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Off-Path - - + + # show ipv6 route 6000::/16 longer-prefixes isis + +Router RT13 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + ------------------------------------------------------------------------------------------ + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Off-Path - - + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Off-Path - - + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Off-Path - - + + # show ipv6 route 6000::/16 longer-prefixes isis + +Router RT14 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + -------------------------------------------------------------------------------------------- + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Head-End Up 00:45:45 + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Head-End Up 00:45:45 + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Head-End Up 00:45:45 + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Tail-End - - + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Tail-End - - + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Tail-End - - + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:1::1/128 [115/50] via fe80::58ea:78ff:fe00:92c1, eth-rt23, 00:01:36 + I>* 6000:1::2/128 [115/0] via fe80::58ea:78ff:fe00:92c1, eth-rt23, 00:01:36 + I>* 6000:1::3/128 [115/1500] via fe80::58ea:78ff:fe00:92c1, eth-rt23, 00:01:36 + +Router RT21 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Mid-Point Up 00:45:46 + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Mid-Point Up 00:45:46 + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Mid-Point Up 00:45:46 + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Mid-Point Up 00:45:46 + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Mid-Point Up 00:45:46 + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Mid-Point Down - + + # show isis ppr id ipv6 6000:2::3/128 detail + Area 1: + PPR-ID: 6000:2::3/128 (Native IPv6) + PPR-Prefix: 5000::14/128 + PDEs: + 5000::11/128 (IPv6 Node Address) + 5000::21/128 (IPv6 Node Address) [LOCAL] + 5000::99/128 (IPv6 Node Address) [NEXT] + 5000::23/128 (IPv6 Node Address) + 5000::14/128 (IPv6 Node Address) + Attributes: + Metric: 1500 + Position: Mid-Point + Originator: 0000.0000.0011 + Level: L1 + Algorithm: 1 + MT-ID: ipv4-unicast + Status: Down: PDE is unreachable + Last change: 00:00:37 + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:1::1/128 [115/50] via fe80::142e:79ff:feeb:cffc, eth-rt11, 00:01:38 + I>* 6000:1::2/128 [115/0] via fe80::142e:79ff:feeb:cffc, eth-rt11, 00:01:38 + I>* 6000:1::3/128 [115/1500] via fe80::142e:79ff:feeb:cffc, eth-rt11, 00:01:38 + I>* 6000:2::1/128 [115/50] via fe80::c88e:7fff:fe5f:a08d, eth-rt22, 00:01:38 + I>* 6000:2::2/128 [115/0] via fe80::8b2:9eff:fe98:f66a, eth-rt32, 00:01:38 + +Router RT22 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Mid-Point Up 00:45:47 + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Off-Path - - + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Mid-Point Up 00:45:47 + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Off-Path - - + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Off-Path - - + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:1::1/128 [115/50] via fe80::2cb5:edff:fe60:29b1, eth-rt21, 00:01:38 + I>* 6000:2::1/128 [115/50] via fe80::e8d9:63ff:fea3:177b, eth-rt23, 00:01:38 + +Router RT23 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Mid-Point Up 00:45:49 + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Mid-Point Up 00:45:49 + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Mid-Point Down - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Mid-Point Up 00:45:49 + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Mid-Point Up 00:45:49 + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Mid-Point Up 00:45:49 + + # show isis ppr id ipv6 6000:1::3/128 detail + Area 1: + PPR-ID: 6000:1::3/128 (Native IPv6) + PPR-Prefix: 5000::11/128 + PDEs: + 5000::14/128 (IPv6 Node Address) + 5000::23/128 (IPv6 Node Address) [LOCAL] + 5000::99/128 (IPv6 Node Address) [NEXT] + 5000::21/128 (IPv6 Node Address) + 5000::11/128 (IPv6 Node Address) + Attributes: + Metric: 1500 + Position: Mid-Point + Originator: 0000.0000.0011 + Level: L1 + Algorithm: 1 + MT-ID: ipv4-unicast + Status: Down: PDE is unreachable + Last change: 00:02:50 + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:1::1/128 [115/50] via fe80::d09f:1bff:fe31:e9c9, eth-rt22, 00:01:40 + I>* 6000:1::2/128 [115/0] via fe80::c0c3:b3ff:fe9f:b5d3, eth-rt33, 00:01:40 + I>* 6000:2::1/128 [115/50] via fe80::f40a:66ff:fefc:5c32, eth-rt14, 00:01:40 + I>* 6000:2::2/128 [115/0] via fe80::f40a:66ff:fefc:5c32, eth-rt14, 00:01:40 + I>* 6000:2::3/128 [115/1500] via fe80::f40a:66ff:fefc:5c32, eth-rt14, 00:01:40 + +Router RT31 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + ------------------------------------------------------------------------------------------ + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Off-Path - - + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Off-Path - - + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Off-Path - - + + # show ipv6 route 6000::/16 longer-prefixes isis + +Router RT32 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Mid-Point Up 00:45:51 + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Mid-Point Up 00:45:51 + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Off-Path - - + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:1::2/128 [115/0] via 4000:113::21, eth-rt21, 00:01:42 + I>* 6000:2::2/128 [115/0] via 4000:121::41, eth-sw1, 00:01:42 + +Router RT33 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Mid-Point Up 00:45:52 + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Mid-Point Up 00:45:52 + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Off-Path - - + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:1::2/128 [115/0] via 4000:121::41, eth-sw1, 00:01:43 + I>* 6000:2::2/128 [115/0] via 4000:116::23, eth-rt23, 00:01:43 + +Router RT34 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + ------------------------------------------------------------------------------------------ + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Off-Path - - + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Off-Path - - + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Off-Path - - + + # show ipv6 route 6000::/16 longer-prefixes isis + +Router RT41 +''''''''''' + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:1::2/128 (Native IPv6) 5000::11/128 0 Mid-Point Up 00:45:55 + 1 L1 6000:1::3/128 (Native IPv6) 5000::11/128 1500 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + 1 L1 6000:2::2/128 (Native IPv6) 5000::14/128 0 Mid-Point Up 00:45:55 + 1 L1 6000:2::3/128 (Native IPv6) 5000::14/128 1500 Off-Path - - + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:1::2/128 [115/0] via fe80::b4b9:60ff:feee:3c73, eth-sw1, 00:01:46 + I>* 6000:2::2/128 [115/0] via fe80::bc2a:d9ff:fe65:97f2, eth-sw1, 00:01:46 + +As it can be seen by the output of ``show isis ppr id ipv6 ... detail``, +routers R21 and R23 couldn’t install the third PPR path because of an +unreachable PDE (configuration error). + +Verification - Forwarding Plane +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On Router R11, use the ``traceroute`` tool to ensure that the PPR paths +were installed correctly in the network: + +:: + + root@rt11:~# traceroute 6000:2::1 + traceroute to 6000:2::1 (6000:2::1), 30 hops max, 80 byte packets + 1 4000:104::21 (4000:104::21) 0.612 ms 0.221 ms 0.241 ms + 2 4000:110::22 (4000:110::22) 0.257 ms 0.113 ms 0.105 ms + 3 4000:111::23 (4000:111::23) 0.257 ms 0.151 ms 0.098 ms + 4 6000:2::1 (6000:2::1) 0.346 ms 0.139 ms 0.100 ms + root@rt11:~# + root@rt11:~# traceroute 6000:2::2 + traceroute to 6000:2::2 (6000:2::2), 30 hops max, 80 byte packets + 1 4000:104::21 (4000:104::21) 4.383 ms 4.148 ms 0.044 ms + 2 4000:113::32 (4000:113::32) 0.272 ms 0.065 ms 0.064 ms + 3 4000:121::41 (4000:121::41) 0.263 ms 0.101 ms 0.086 ms + 4 4000:115::33 (4000:115::33) 0.351 ms 4000:119::33 (4000:119::33) 0.249 ms 4000:115::33 (4000:115::33) 0.153 ms + 5 4000:111::23 (4000:111::23) 0.232 ms 0.293 ms 0.131 ms + 6 6000:2::2 (6000:2::2) 0.184 ms 0.212 ms 0.140 ms + root@rt11:~# + root@rt11:~# traceroute 6000:2::3 + traceroute to 6000:2::3 (6000:2::3), 30 hops max, 80 byte packets + 1 4000:104::21 (4000:104::21) 1.537 ms !N 1.347 ms !N 1.075 ms !N + +The failure on the third traceroute is expected since the 6000:2::3 +PPR-ID is misconfigured. + +Now ping Host 3 from Host 1 and use tcpdump or wireshark to verify that +the ICMP packets are being tunneled using GRE and following the {R11 - +R21 - R22 - R23 - R14} path. Here’s a wireshark capture between R11 and +R21: + +.. figure:: https://user-images.githubusercontent.com/931662/61582398-d4cc0180-ab00-11e9-83a8-d219f98010b9.png + :alt: s1 + + s1 + +Using ``traceroute`` it’s also possible to see that the ICMP packets are +being tunneled through the IS-IS network: + +:: + + root@host1:~# traceroute fd00:20:1::1 -s fd00:10:1::1 + traceroute to fd00:20:1::1 (fd00:20:1::1), 30 hops max, 80 byte packets + 1 fd00:10:1::100 (fd00:10:1::100) 0.354 ms 0.092 ms 0.031 ms + 2 fd00:10::11 (fd00:10::11) 0.125 ms 0.022 ms 0.026 ms + 3 * * * + 4 * * * + 5 fd00:20:1::1 (fd00:20:1::1) 0.235 ms 0.106 ms 0.091 ms diff --git a/doc/developer/northbound/ppr-mpls-basic-test-topology.rst b/doc/developer/northbound/ppr-mpls-basic-test-topology.rst new file mode 100644 index 000000000000..cedb795da997 --- /dev/null +++ b/doc/developer/northbound/ppr-mpls-basic-test-topology.rst @@ -0,0 +1,1991 @@ +Table of Contents +~~~~~~~~~~~~~~~~~ + +- `Software <#software>`__ +- `Topology <#topology>`__ +- `Configuration <#configuration>`__ + + - `CLI <#configuration-cli>`__ + - `YANG <#configuration-yang>`__ + +- `Verification - Control Plane <#verification-cplane>`__ +- `Verification - Forwarding Plane <#verification-fplane>`__ + +Software +~~~~~~~~ + +The FRR PPR implementation for IS-IS is available here: +https://github.com/opensourcerouting/frr/tree/isisd-ppr-sr + +Topology +~~~~~~~~ + +In this topology we have an IS-IS network consisting of 12 routers. CE1 +and CE2 are the consumer edges, connected to R11 and R14, respectively. +Three hosts are connected to the CEs using only static routes. + +Router R11 advertises 6 PPR TLVs: \* **IPv6 prefixes 6000:1::1/128 and +6000:2::1/128:** {R11 - R21 - R22 - R23 - R14} (IPv6 Node Addresses). \* +**MPLS SR Prefix-SIDs 500 and 501:** {R11 - R21 - R22 - R23 - R14} (SR +Prefix-SIDs). \* **MPLS SR Prefix-SIDs 502 and 503:** {R11 - R21 - R31 - +R32 - R41 - R33 - R34 - R23 - R14} (SR Prefix-SIDs) + +PBR rules are configured on R11 and R14 to route the traffic between +Host 1 and Host 3 using the first PPR tunnel, whereas all other traffic +between CE1 and CE2 uses the second PPR tunnel. + +Additional information: \* Addresses in the 4000::/16 range refer to +interface addresses, where the last hextet corresponds to the node ID. +\* Addresses in the 5000::/16 range refer to loopback addresses, where +the last hextet corresponds to the node ID. \* Addresses in the +6000::/16 range refer to PPR-ID addresses. + +:: + + +-------+ +-------+ +-------+ + | | | | | | + | HOST1 | | HOST2 | | HOST3 | + | | | | | | + +---+---+ +---+---+ +---+---+ + | | | + |fd00:10:1::/64 | | + +-----+ +------+ fd00:20:1::/64| + | |fd00:10:2::/64 | + | | | + +-+--+--+ +---+---+ + | | | | + | CE1 | | CE2 | + | | | | + +---+---+ +---+---+ + | | + | | + |fd00:10:0::/64 fd00:20:0::/64| + | | + | | + +---+---+ +-------+ +-------+ +---+---+ + | |4000:101::/64| |4000:102::/64| |4000:103::/64| | + | R11 +-------------+ R12 +-------------+ R13 +-------------+ R14 | + | | | | | | | | + +---+---+ +--+-+--+ +--+-+--+ +---+---+ + | | | | | | + |4000:104::/64 | |4000:106::/64 | |4000:108::/64 | + +---------+ +--------+ +--------+ +--------+ +--------+ +---------+ + | |4000:105::/64 | |4000:107::/64 | |4000:109::/64 + | | | | | | + +--+-+--+ +--+-+--+ +--+-+--+ + | |4000:110::/64| |4000:111::/64| | + | R21 +-------------+ R22 +-------------+ R23 | + | | | | | | + +--+-+--+ +--+-+--+ +--+-+--+ + | | | | | | + | |4000:113::/64 | |4000:115::/64 | |4000:117::/64 + +---------+ +--------+ +--------+ +--------+ +--------+ +---------+ + |4000:112::/64 | |4000:114::/64 | |4000:116::/64 | + | | | | | | + +---+---+ +--+-+--+ +--+-+--+ +---+---+ + | |4000:118::/64| |4000:119::/64| |4000:120::/64| | + | R31 +-------------+ R32 +-------------+ R33 +-------------+ R34 | + | | | | | | | | + +-------+ +---+---+ +---+---+ +-------+ + | | + |4000:121::/64 | + +----------+----------+ + | + | + +---+---+ + | | + | R41 | + | | + +-------+ + +Configuration +~~~~~~~~~~~~~ + +PPR TLV processing needs to be enabled on all IS-IS routers using the +``ppr on`` command. The advertisements of all PPR TLVs is done by router +R11. + +CLI configuration +^^^^^^^^^^^^^^^^^ + +.. code:: yaml + + --- + + routers: + + host1: + links: + eth-ce1: + peer: [ce1, eth-host1] + frr: + zebra: + staticd: + config: | + interface eth-ce1 + ipv6 address fd00:10:1::1/64 + ! + ipv6 route ::/0 fd00:10:1::100 + + host2: + links: + eth-ce1: + peer: [ce1, eth-host2] + frr: + zebra: + staticd: + config: | + interface eth-ce1 + ipv6 address fd00:10:2::1/64 + ! + ipv6 route ::/0 fd00:10:2::100 + + host3: + links: + eth-ce2: + peer: [ce2, eth-host3] + frr: + zebra: + staticd: + config: | + interface eth-ce2 + ipv6 address fd00:20:1::1/64 + ! + ipv6 route ::/0 fd00:20:1::100 + + ce1: + links: + eth-host1: + peer: [host1, eth-ce1] + eth-host2: + peer: [host2, eth-ce1] + eth-rt11: + peer: [rt11, eth-ce1] + frr: + zebra: + staticd: + config: | + interface eth-host1 + ipv6 address fd00:10:1::100/64 + ! + interface eth-host2 + ipv6 address fd00:10:2::100/64 + ! + interface eth-rt11 + ipv6 address fd00:10:0::100/64 + ! + ipv6 route ::/0 fd00:10:0::11 label 16501 + + ce2: + links: + eth-host3: + peer: [host3, eth-ce2] + eth-rt14: + peer: [rt14, eth-ce2] + frr: + zebra: + staticd: + config: | + interface eth-host3 + ipv6 address fd00:20:1::100/64 + ! + interface eth-rt14 + ipv6 address fd00:20:0::100/64 + ! + ipv6 route ::/0 fd00:20:0::14 label 16500 + + rt11: + links: + lo: + mpls: yes + lo-ppr: + eth-ce1: + peer: [ce1, eth-rt11] + mpls: yes + eth-rt12: + peer: [rt12, eth-rt11] + mpls: yes + eth-rt21: + peer: [rt21, eth-rt11] + mpls: yes + shell: | + # GRE tunnel for preferred packets (PPR) + ip -6 tunnel add tun-ppr mode ip6gre remote 6000:2::1 local 6000:1::1 ttl 64 + ip link set dev tun-ppr up + # PBR rules + ip -6 rule add from fd00:10:1::/64 to fd00:20:1::/64 iif eth-ce1 lookup 10000 + ip -6 route add default dev tun-ppr table 10000 + frr: + zebra: + staticd: + isisd: + config: | + interface lo-ppr + ipv6 address 6000:1::1/128 + ! + interface lo + ip address 10.0.0.11/32 + ipv6 address 5000::11/128 + ipv6 router isis 1 + ! + interface eth-ce1 + ipv6 address fd00:10:0::11/64 + ! + interface eth-rt12 + ipv6 address 4000:101::11/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt21 + ipv6 address 4000:104::11/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + ipv6 route fd00:10::/32 fd00:10:0::100 + ! + ppr group PPR_IPV6 + ppr ipv6 6000:1::1/128 prefix 5000::11/128 metric 50 + pde ipv6-node 5000::14/128 + pde ipv6-node 5000::23/128 + pde ipv6-node 5000::22/128 + pde ipv6-node 5000::21/128 + pde ipv6-node 5000::11/128 + ! + ppr ipv6 6000:2::1/128 prefix 5000::14/128 metric 50 + pde ipv6-node 5000::11/128 + pde ipv6-node 5000::21/128 + pde ipv6-node 5000::22/128 + pde ipv6-node 5000::23/128 + pde ipv6-node 5000::14/128 + ! + ! + ppr group PPR_MPLS_1 + ppr mpls 500 prefix 5000::11/128 + pde prefix-sid 14 + pde prefix-sid 23 + pde prefix-sid 22 + pde prefix-sid 21 + pde prefix-sid 11 + ! + ppr mpls 501 prefix 5000::14/128 + pde prefix-sid 11 + pde prefix-sid 21 + pde prefix-sid 22 + pde prefix-sid 23 + pde prefix-sid 14 + ! + ! + ppr group PPR_MPLS_2 + ppr mpls 502 prefix 5000::11/128 + pde prefix-sid 14 + pde prefix-sid 23 + pde prefix-sid 34 + pde prefix-sid 33 + pde prefix-sid 41 + pde prefix-sid 32 + pde prefix-sid 31 + pde prefix-sid 21 + pde prefix-sid 11 + ! + ppr mpls 503 prefix 5000::14/128 + pde prefix-sid 11 + pde prefix-sid 21 + pde prefix-sid 31 + pde prefix-sid 32 + pde prefix-sid 41 + pde prefix-sid 33 + pde prefix-sid 34 + pde prefix-sid 23 + pde prefix-sid 14 + ! + ! + router isis 1 + net 49.0000.0000.0000.0011.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing prefix 5000::11/128 index 11 no-php-flag + ppr on + ppr advertise PPR_IPV6 + ppr advertise PPR_MPLS_1 + ppr advertise PPR_MPLS_2 + ! + + rt12: + links: + lo: + mpls: yes + eth-rt11: + peer: [rt11, eth-rt12] + mpls: yes + eth-rt13: + peer: [rt13, eth-rt12] + mpls: yes + eth-rt21: + peer: [rt21, eth-rt12] + mpls: yes + eth-rt22: + peer: [rt22, eth-rt12] + mpls: yes + frr: + zebra: + isisd: + config: | + interface lo + ip address 10.0.0.12/32 + ipv6 address 5000::12/128 + ipv6 router isis 1 + ! + interface eth-rt11 + ipv6 address 4000:101::12/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt13 + ipv6 address 4000:102::12/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt21 + ipv6 address 4000:105::12/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt22 + ipv6 address 4000:106::12/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0012.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing prefix 5000::12/128 index 12 no-php-flag + ppr on + ! + + rt13: + links: + lo: + mpls: yes + eth-rt12: + peer: [rt12, eth-rt13] + mpls: yes + eth-rt14: + peer: [rt14, eth-rt13] + mpls: yes + eth-rt22: + peer: [rt22, eth-rt13] + mpls: yes + eth-rt23: + peer: [rt23, eth-rt13] + mpls: yes + frr: + zebra: + isisd: + config: | + interface lo + ip address 10.0.0.13/32 + ipv6 address 5000::13/128 + ipv6 router isis 1 + ! + interface eth-rt12 + ipv6 address 4000:102::13/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt14 + ipv6 address 4000:103::13/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt22 + ipv6 address 4000:107::13/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt23 + ipv6 address 4000:108::13/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0013.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing prefix 5000::13/128 index 13 no-php-flag + ppr on + ! + + rt14: + links: + lo: + mpls: yes + lo-ppr: + eth-ce2: + peer: [ce2, eth-rt14] + mpls: yes + eth-rt13: + peer: [rt13, eth-rt14] + mpls: yes + eth-rt23: + peer: [rt23, eth-rt14] + mpls: yes + shell: | + # GRE tunnel for preferred packets (PPR) + ip -6 tunnel add tun-ppr mode ip6gre remote 6000:1::1 local 6000:2::1 ttl 64 + ip link set dev tun-ppr up + # PBR rules + ip -6 rule add from fd00:20:1::/64 to fd00:10:1::/64 iif eth-ce2 lookup 10000 + ip -6 route add default dev tun-ppr table 10000 + frr: + zebra: + staticd: + isisd: + config: | + interface lo-ppr + ipv6 address 6000:2::1/128 + ! + interface lo + ip address 10.0.0.14/32 + ipv6 address 5000::14/128 + ipv6 router isis 1 + ! + interface eth-ce2 + ipv6 address fd00:20:0::14/64 + ! + interface eth-rt13 + ipv6 address 4000:103::14/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt23 + ipv6 address 4000:109::14/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + ipv6 route fd00:20::/32 fd00:20:0::100 + ! + router isis 1 + net 49.0000.0000.0000.0014.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing prefix 5000::14/128 index 14 no-php-flag + ppr on + ! + + rt21: + links: + lo: + mpls: yes + eth-rt11: + peer: [rt11, eth-rt21] + mpls: yes + eth-rt12: + peer: [rt12, eth-rt21] + mpls: yes + eth-rt22: + peer: [rt22, eth-rt21] + mpls: yes + eth-rt31: + peer: [rt31, eth-rt21] + mpls: yes + eth-rt32: + peer: [rt32, eth-rt21] + mpls: yes + frr: + zebra: + isisd: + config: | + interface lo + ip address 10.0.0.21/32 + ipv6 address 5000::21/128 + ipv6 router isis 1 + ! + interface eth-rt11 + ipv6 address 4000:104::21/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt12 + ipv6 address 4000:105::21/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt22 + ipv6 address 4000:110::21/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt31 + ipv6 address 4000:112::21/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt32 + ipv6 address 4000:113::21/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0021.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing prefix 5000::21/128 index 21 no-php-flag + ppr on + ! + + rt22: + links: + lo: + mpls: yes + eth-rt12: + peer: [rt12, eth-rt22] + mpls: yes + eth-rt13: + peer: [rt13, eth-rt22] + mpls: yes + eth-rt21: + peer: [rt21, eth-rt22] + mpls: yes + eth-rt23: + peer: [rt23, eth-rt22] + mpls: yes + eth-rt32: + peer: [rt32, eth-rt22] + mpls: yes + eth-rt33: + mpls: yes + peer: [rt33, eth-rt22] + frr: + zebra: + isisd: + config: | + interface lo + ip address 10.0.0.22/32 + ipv6 address 5000::22/128 + ipv6 router isis 1 + ! + interface eth-rt12 + ipv6 address 4000:106::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt13 + ipv6 address 4000:107::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt21 + ipv6 address 4000:110::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt23 + ipv6 address 4000:111::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt32 + ipv6 address 4000:114::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt33 + ipv6 address 4000:115::22/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0022.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing prefix 5000::22/128 index 22 no-php-flag + ppr on + ! + + rt23: + links: + lo: + mpls: yes + eth-rt13: + peer: [rt13, eth-rt23] + mpls: yes + eth-rt14: + peer: [rt14, eth-rt23] + mpls: yes + eth-rt22: + peer: [rt22, eth-rt23] + mpls: yes + eth-rt33: + peer: [rt33, eth-rt23] + mpls: yes + eth-rt34: + peer: [rt34, eth-rt23] + mpls: yes + frr: + zebra: + isisd: + config: | + interface lo + ip address 10.0.0.23/32 + ipv6 address 5000::23/128 + ipv6 router isis 1 + ! + interface eth-rt13 + ipv6 address 4000:108::23/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt14 + ipv6 address 4000:109::23/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt22 + ipv6 address 4000:111::23/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt33 + ipv6 address 4000:116::23/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt34 + ipv6 address 4000:117::23/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0023.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing global-block 20000 27999 + segment-routing prefix 5000::23/128 index 23 no-php-flag + ppr on + ! + + rt31: + links: + lo: + mpls: yes + eth-rt21: + peer: [rt21, eth-rt31] + mpls: yes + eth-rt32: + peer: [rt32, eth-rt31] + mpls: yes + frr: + zebra: + isisd: + config: | + interface lo + ip address 10.0.0.31/32 + ipv6 address 5000::31/128 + ipv6 router isis 1 + ! + interface eth-rt21 + ipv6 address 4000:112::31/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt32 + ipv6 address 4000:118::31/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0031.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing prefix 5000::31/128 index 31 no-php-flag + ppr on + ! + + rt32: + links: + lo: + mpls: yes + eth-rt21: + peer: [rt21, eth-rt32] + mpls: yes + eth-rt22: + peer: [rt22, eth-rt32] + mpls: yes + eth-rt31: + peer: [rt31, eth-rt32] + mpls: yes + eth-rt33: + peer: [rt33, eth-rt32] + mpls: yes + eth-sw1: + peer: [sw1, eth-rt32] + mpls: yes + frr: + zebra: + isisd: + config: | + interface lo + ip address 10.0.0.32/32 + ipv6 address 5000::32/128 + ipv6 router isis 1 + ! + interface eth-rt21 + ipv6 address 4000:113::32/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt22 + ipv6 address 4000:114::32/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt31 + ipv6 address 4000:118::32/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt33 + ipv6 address 4000:119::32/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-sw1 + ipv6 address 4000:121::32/64 + ipv6 router isis 1 + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0032.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing prefix 5000::32/128 index 32 no-php-flag + ppr on + ! + + rt33: + links: + lo: + mpls: yes + eth-rt22: + peer: [rt22, eth-rt33] + mpls: yes + eth-rt23: + peer: [rt23, eth-rt33] + mpls: yes + eth-rt32: + peer: [rt32, eth-rt33] + mpls: yes + eth-rt34: + peer: [rt34, eth-rt33] + mpls: yes + eth-sw1: + peer: [sw1, eth-rt33] + mpls: yes + frr: + zebra: + isisd: + config: | + interface lo + ip address 10.0.0.33/32 + ipv6 address 5000::33/128 + ipv6 router isis 1 + ! + interface eth-rt22 + ipv6 address 4000:115::33/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt23 + ipv6 address 4000:116::33/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt32 + ipv6 address 4000:119::33/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt34 + ipv6 address 4000:120::33/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-sw1 + ipv6 address 4000:121::33/64 + ipv6 router isis 1 + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0033.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing prefix 5000::33/128 index 33 no-php-flag + ppr on + ! + + rt34: + links: + lo: + mpls: yes + eth-rt23: + peer: [rt23, eth-rt34] + mpls: yes + eth-rt33: + peer: [rt33, eth-rt34] + mpls: yes + frr: + zebra: + isisd: + config: | + interface lo + ip address 10.0.0.34/32 + ipv6 address 5000::34/128 + ipv6 router isis 1 + ! + interface eth-rt23 + ipv6 address 4000:117::34/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + interface eth-rt33 + ipv6 address 4000:120::34/64 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0034.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing prefix 5000::34/128 index 34 no-php-flag + ppr on + ! + + rt41: + links: + lo: + mpls: yes + eth-sw1: + peer: [sw1, eth-rt41] + mpls: yes + frr: + zebra: + isisd: + config: | + interface lo + ip address 10.0.0.41/32 + ipv6 address 5000::41/128 + ipv6 router isis 1 + ! + interface eth-sw1 + ipv6 address 4000:121::41/64 + ipv6 router isis 1 + isis hello-multiplier 3 + ! + router isis 1 + net 49.0000.0000.0000.0041.00 + is-type level-1 + topology ipv6-unicast + segment-routing on + segment-routing prefix 5000::41/128 index 41 no-php-flag + ppr on + ! + + switches: + sw1: + links: + eth-rt32: + peer: [rt32, eth-sw1] + eth-rt33: + peer: [rt33, eth-sw1] + eth-rt41: + peer: [rt41, eth-sw1] + + frr: + #valgrind: yes + base-config: | + hostname %(node) + password 1 + log file %(logdir)/%(node).log + log commands + ! + debug zebra rib + debug isis sr-events + debug isis ppr + debug isis events + debug isis route-events + debug isis spf-events + debug isis lsp-gen + ! + +.. + + NOTE: it’s of fundamental importance to enable MPLS processing on the + loopback interfaces, otherwise the tail-end routers of the PPR-MPLS + tunnels will drop the labeled packets they receive. + +YANG +^^^^ + +PPR can also be configured using NETCONF, RESTCONF and gRPC based on the +following YANG models: \* +`frr-ppr.yang `__ +\* +`frr-isisd.yang `__ + +As an example, here’s R11 configuration in the XML format: + +.. code:: xml + + + + lo-ppr + default + + + lo + default + + 1 + true + + + + eth-ce1 + default + + + eth-rt12 + default + + 1 + true + + + 3 + 3 + + + point-to-point + + + + eth-rt21 + default + + 1 + true + + + 3 + 3 + + + point-to-point + + + + + + PPR_IPV6 + + 6000:1::1/128 + 5000::11/128 + + 5000::14/128 + ipv6-node + topological + + + 5000::23/128 + ipv6-node + topological + + + 5000::22/128 + ipv6-node + topological + + + 5000::21/128 + ipv6-node + topological + + + 5000::11/128 + ipv6-node + topological + + + 50 + + + + 6000:2::1/128 + 5000::14/128 + + 5000::11/128 + ipv6-node + topological + + + 5000::21/128 + ipv6-node + topological + + + 5000::22/128 + ipv6-node + topological + + + 5000::23/128 + ipv6-node + topological + + + 5000::14/128 + ipv6-node + topological + + + 50 + + + + + PPR_MPLS_1 + + 500 + 5000::11/128 + + 14 + prefix-sid + topological + + + 23 + prefix-sid + topological + + + 22 + prefix-sid + topological + + + 21 + prefix-sid + topological + + + 11 + prefix-sid + topological + + + + 501 + 5000::14/128 + + 11 + prefix-sid + topological + + + 21 + prefix-sid + topological + + + 22 + prefix-sid + topological + + + 23 + prefix-sid + topological + + + 14 + prefix-sid + topological + + + + + PPR_MPLS_2 + + 502 + 5000::11/128 + + 14 + prefix-sid + topological + + + 23 + prefix-sid + topological + + + 34 + prefix-sid + topological + + + 33 + prefix-sid + topological + + + 41 + prefix-sid + topological + + + 32 + prefix-sid + topological + + + 31 + prefix-sid + topological + + + 21 + prefix-sid + topological + + + 11 + prefix-sid + topological + + + + 503 + 5000::14/128 + + 11 + prefix-sid + topological + + + 21 + prefix-sid + topological + + + 31 + prefix-sid + topological + + + 32 + prefix-sid + topological + + + 41 + prefix-sid + topological + + + 33 + prefix-sid + topological + + + 34 + prefix-sid + topological + + + 23 + prefix-sid + topological + + + 14 + prefix-sid + topological + + + + + + + 1 + 49.0000.0000.0000.0011.00 + + + + + + true + + + 5000::11/128 + 11 + no-php + + + + + true + + PPR_IPV6 + + + PPR_MPLS_1 + + + PPR_MPLS_2 + + + + + +Verification - Control Plane +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Verify that R11 has flooded the PPR TLVs correctly to all IS-IS routers: + +:: + + # show isis database detail 0000.0000.0011 + Area 1: + IS-IS Level-1 link-state database: + LSP ID PduLen SeqNumber Chksum Holdtime ATT/P/OL + debian.00-00 * 980 0x00000003 0x3b69 894 0/0/0 + Protocols Supported: IPv4, IPv6 + Area Address: 49.0000 + MT Router Info: ipv4-unicast + MT Router Info: ipv6-unicast + Hostname: debian + TE Router ID: 10.0.0.11 + Router Capability: 10.0.0.11 , D:0, S:0 + Segment Routing: I:1 V:1, SRGB Base: 16000 Range: 8000 + Algorithm: 0: SPF 0: Strict SPF + MT Reachability: 0000.0000.0012.00 (Metric: 10) ipv6-unicast + Adjacency-SID: 16, Weight: 0, Flags: F:1 B:0, V:1, L:1, S:0, P:0 + MT Reachability: 0000.0000.0021.00 (Metric: 10) ipv6-unicast + Adjacency-SID: 17, Weight: 0, Flags: F:1 B:0, V:1, L:1, S:0, P:0 + IPv4 Interface Address: 10.0.0.11 + Extended IP Reachability: 10.0.0.11/32 (Metric: 10) + MT IPv6 Reachability: 5000::11/128 (Metric: 10) ipv6-unicast + Subtlvs: + SR Prefix-SID Index: 11, Algorithm: 0, Flags: NO-PHP + MT IPv6 Reachability: 4000:101::/64 (Metric: 10) ipv6-unicast + MT IPv6 Reachability: 4000:104::/64 (Metric: 10) ipv6-unicast + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::11/128 + ID: 6000:1::1/128 (Native IPv6) + PDE: 5000::14/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::23/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::22/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::21/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::11/128 (IPv6 Node Address), L:0 N:1 E:0 + Metric: 50 + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::14/128 + ID: 6000:2::1/128 (Native IPv6) + PDE: 5000::11/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::21/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::22/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::23/128 (IPv6 Node Address), L:0 N:0 E:0 + PDE: 5000::14/128 (IPv6 Node Address), L:0 N:1 E:0 + Metric: 50 + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::11/128 + ID: 500 (MPLS) + PDE: 14 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 23 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 22 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 21 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 11 (SR-MPLS Prefix SID), L:0 N:1 E:0 + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::14/128 + ID: 501 (MPLS) + PDE: 11 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 21 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 22 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 23 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 14 (SR-MPLS Prefix SID), L:0 N:1 E:0 + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::11/128 + ID: 502 (MPLS) + PDE: 14 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 23 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 34 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 33 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 41 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 32 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 31 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 21 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 11 (SR-MPLS Prefix SID), L:0 N:1 E:0 + PPR: Fragment ID: 0, MT-ID: ipv4-unicast, Algorithm: SPF, F:0 D:0 A:0 U:1 + PPR Prefix: 5000::14/128 + ID: 503 (MPLS) + PDE: 11 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 21 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 31 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 32 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 41 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 33 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 34 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 23 (SR-MPLS Prefix SID), L:0 N:0 E:0 + PDE: 14 (SR-MPLS Prefix SID), L:0 N:1 E:0 + +Using the ``show isis ppr`` command, verify that all routers installed +the PPR-IDs for the paths they are part of. Example: + +Router RT11 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + -------------------------------------------------------------------------------------------- + 1 L1 500 (MPLS) 5000::11/128 0 Tail-End Up 00:00:42 + 1 L1 501 (MPLS) 5000::14/128 0 Head-End Up 00:00:41 + 1 L1 502 (MPLS) 5000::11/128 0 Tail-End Up 00:00:42 + 1 L1 503 (MPLS) 5000::14/128 0 Head-End Up 00:00:41 + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Tail-End - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Head-End Up 00:00:41 + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------------------------------- + 16 SR (IS-IS) fe80::2065:5ff:fe72:d6c5 implicit-null + 17 SR (IS-IS) fe80::345f:dfff:fea4:913d implicit-null + 16011 SR (IS-IS) lo - + 16012 SR (IS-IS) fe80::2065:5ff:fe72:d6c5 16012 + 16013 SR (IS-IS) fe80::2065:5ff:fe72:d6c5 16013 + 16014 SR (IS-IS) fe80::2065:5ff:fe72:d6c5 16014 + 16021 SR (IS-IS) fe80::345f:dfff:fea4:913d 16021 + 16022 SR (IS-IS) fe80::345f:dfff:fea4:913d 16022 + 16022 SR (IS-IS) fe80::2065:5ff:fe72:d6c5 16022 + 16023 SR (IS-IS) fe80::345f:dfff:fea4:913d 16023 + 16023 SR (IS-IS) fe80::2065:5ff:fe72:d6c5 16023 + 16031 SR (IS-IS) fe80::345f:dfff:fea4:913d 16031 + 16032 SR (IS-IS) fe80::345f:dfff:fea4:913d 16032 + 16033 SR (IS-IS) fe80::345f:dfff:fea4:913d 16033 + 16033 SR (IS-IS) fe80::2065:5ff:fe72:d6c5 16033 + 16034 SR (IS-IS) fe80::345f:dfff:fea4:913d 16034 + 16034 SR (IS-IS) fe80::2065:5ff:fe72:d6c5 16034 + 16041 SR (IS-IS) fe80::345f:dfff:fea4:913d 16041 + 16500 PPR (IS-IS) lo - + 16501 PPR (IS-IS) fe80::345f:dfff:fea4:913d 16501 + 16502 PPR (IS-IS) lo - + 16503 PPR (IS-IS) fe80::345f:dfff:fea4:913d 16503 + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:2::1/128 [115/50] via fe80::345f:dfff:fea4:913d, eth-rt21, 00:00:41 + +Router RT12 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + ------------------------------------------------------------------------------------------ + 1 L1 500 (MPLS) 5000::11/128 0 Off-Path - - + 1 L1 501 (MPLS) 5000::14/128 0 Off-Path - - + 1 L1 502 (MPLS) 5000::11/128 0 Off-Path - - + 1 L1 503 (MPLS) 5000::14/128 0 Off-Path - - + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ---------------------------------------------------------------------- + 16 SR (IS-IS) fe80::60ad:96ff:fe3f:9989 implicit-null + 17 SR (IS-IS) fe80::9cd2:25ff:febc:84c4 implicit-null + 18 SR (IS-IS) fe80::941c:12ff:fe55:8a12 implicit-null + 19 SR (IS-IS) fe80::78a7:59ff:fedc:48b8 implicit-null + 16011 SR (IS-IS) fe80::60ad:96ff:fe3f:9989 16011 + 16012 SR (IS-IS) lo - + 16013 SR (IS-IS) fe80::9cd2:25ff:febc:84c4 16013 + 16014 SR (IS-IS) fe80::9cd2:25ff:febc:84c4 16014 + 16021 SR (IS-IS) fe80::941c:12ff:fe55:8a12 16021 + 16022 SR (IS-IS) fe80::78a7:59ff:fedc:48b8 16022 + 16023 SR (IS-IS) fe80::78a7:59ff:fedc:48b8 16023 + 16023 SR (IS-IS) fe80::9cd2:25ff:febc:84c4 16023 + 16031 SR (IS-IS) fe80::941c:12ff:fe55:8a12 16031 + 16032 SR (IS-IS) fe80::78a7:59ff:fedc:48b8 16032 + 16032 SR (IS-IS) fe80::941c:12ff:fe55:8a12 16032 + 16033 SR (IS-IS) fe80::78a7:59ff:fedc:48b8 16033 + 16034 SR (IS-IS) fe80::78a7:59ff:fedc:48b8 16034 + 16034 SR (IS-IS) fe80::9cd2:25ff:febc:84c4 16034 + 16041 SR (IS-IS) fe80::78a7:59ff:fedc:48b8 16041 + 16041 SR (IS-IS) fe80::941c:12ff:fe55:8a12 16041 + + # show ipv6 route 6000::/16 longer-prefixes isis + +Router RT13 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + ------------------------------------------------------------------------------------------ + 1 L1 500 (MPLS) 5000::11/128 0 Off-Path - - + 1 L1 501 (MPLS) 5000::14/128 0 Off-Path - - + 1 L1 502 (MPLS) 5000::11/128 0 Off-Path - - + 1 L1 503 (MPLS) 5000::14/128 0 Off-Path - - + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ---------------------------------------------------------------------- + 16 SR (IS-IS) fe80::1c70:63ff:fe40:3a35 implicit-null + 17 SR (IS-IS) fe80::20:56ff:feff:b218 implicit-null + 18 SR (IS-IS) fe80::44c5:3fff:fe1e:f34a implicit-null + 19 SR (IS-IS) fe80::387d:34ff:fe02:87c3 implicit-null + 16011 SR (IS-IS) fe80::20:56ff:feff:b218 16011 + 16012 SR (IS-IS) fe80::20:56ff:feff:b218 16012 + 16013 SR (IS-IS) lo - + 16014 SR (IS-IS) fe80::1c70:63ff:fe40:3a35 16014 + 16021 SR (IS-IS) fe80::387d:34ff:fe02:87c3 16021 + 16021 SR (IS-IS) fe80::20:56ff:feff:b218 16021 + 16022 SR (IS-IS) fe80::387d:34ff:fe02:87c3 16022 + 16023 SR (IS-IS) fe80::44c5:3fff:fe1e:f34a 20023 + 16031 SR (IS-IS) fe80::387d:34ff:fe02:87c3 16031 + 16031 SR (IS-IS) fe80::20:56ff:feff:b218 16031 + 16032 SR (IS-IS) fe80::387d:34ff:fe02:87c3 16032 + 16033 SR (IS-IS) fe80::44c5:3fff:fe1e:f34a 20033 + 16033 SR (IS-IS) fe80::387d:34ff:fe02:87c3 16033 + 16034 SR (IS-IS) fe80::44c5:3fff:fe1e:f34a 20034 + 16041 SR (IS-IS) fe80::44c5:3fff:fe1e:f34a 20041 + 16041 SR (IS-IS) fe80::387d:34ff:fe02:87c3 16041 + + # show ipv6 route 6000::/16 longer-prefixes isis + +Router RT14 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + -------------------------------------------------------------------------------------------- + 1 L1 500 (MPLS) 5000::11/128 0 Head-End Up 00:00:46 + 1 L1 501 (MPLS) 5000::14/128 0 Tail-End Up 00:00:47 + 1 L1 502 (MPLS) 5000::11/128 0 Head-End Up 00:00:46 + 1 L1 503 (MPLS) 5000::14/128 0 Tail-End Up 00:00:47 + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Head-End Up 00:00:46 + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Tail-End - - + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------------------------------- + 16 SR (IS-IS) fe80::bcb5:99ff:fed7:22ad implicit-null + 17 SR (IS-IS) fe80::4c7b:a1ff:fe66:6ca7 implicit-null + 16011 SR (IS-IS) fe80::bcb5:99ff:fed7:22ad 16011 + 16012 SR (IS-IS) fe80::bcb5:99ff:fed7:22ad 16012 + 16013 SR (IS-IS) fe80::bcb5:99ff:fed7:22ad 16013 + 16014 SR (IS-IS) lo - + 16021 SR (IS-IS) fe80::4c7b:a1ff:fe66:6ca7 20021 + 16021 SR (IS-IS) fe80::bcb5:99ff:fed7:22ad 16021 + 16022 SR (IS-IS) fe80::4c7b:a1ff:fe66:6ca7 20022 + 16022 SR (IS-IS) fe80::bcb5:99ff:fed7:22ad 16022 + 16023 SR (IS-IS) fe80::4c7b:a1ff:fe66:6ca7 20023 + 16031 SR (IS-IS) fe80::4c7b:a1ff:fe66:6ca7 20031 + 16031 SR (IS-IS) fe80::bcb5:99ff:fed7:22ad 16031 + 16032 SR (IS-IS) fe80::4c7b:a1ff:fe66:6ca7 20032 + 16032 SR (IS-IS) fe80::bcb5:99ff:fed7:22ad 16032 + 16033 SR (IS-IS) fe80::4c7b:a1ff:fe66:6ca7 20033 + 16034 SR (IS-IS) fe80::4c7b:a1ff:fe66:6ca7 20034 + 16041 SR (IS-IS) fe80::4c7b:a1ff:fe66:6ca7 20041 + 16500 PPR (IS-IS) fe80::4c7b:a1ff:fe66:6ca7 20500 + 16501 PPR (IS-IS) lo - + 16502 PPR (IS-IS) fe80::4c7b:a1ff:fe66:6ca7 20502 + 16503 PPR (IS-IS) lo - + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:1::1/128 [115/50] via fe80::4c7b:a1ff:fe66:6ca7, eth-rt23, 00:00:02 + +Router RT21 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 500 (MPLS) 5000::11/128 0 Mid-Point Up 00:00:49 + 1 L1 501 (MPLS) 5000::14/128 0 Mid-Point Up 00:00:48 + 1 L1 502 (MPLS) 5000::11/128 0 Mid-Point Up 00:00:49 + 1 L1 503 (MPLS) 5000::14/128 0 Mid-Point Up 00:00:48 + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Mid-Point Up 00:00:49 + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Mid-Point Up 00:00:48 + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------------------------------- + 16 SR (IS-IS) fe80::b886:2cff:fe84:a76f implicit-null + 17 SR (IS-IS) fe80::bc7e:bbff:fe7f:ecb0 implicit-null + 18 SR (IS-IS) fe80::e877:a2ff:feb7:4438 implicit-null + 19 SR (IS-IS) fe80::a0c2:82ff:fe39:204c implicit-null + 20 SR (IS-IS) fe80::ac6a:8aff:fe14:4f36 implicit-null + 16011 SR (IS-IS) fe80::e877:a2ff:feb7:4438 16011 + 16012 SR (IS-IS) fe80::a0c2:82ff:fe39:204c 16012 + 16013 SR (IS-IS) fe80::ac6a:8aff:fe14:4f36 16013 + 16013 SR (IS-IS) fe80::a0c2:82ff:fe39:204c 16013 + 16014 SR (IS-IS) fe80::ac6a:8aff:fe14:4f36 16014 + 16014 SR (IS-IS) fe80::a0c2:82ff:fe39:204c 16014 + 16021 SR (IS-IS) lo - + 16022 SR (IS-IS) fe80::ac6a:8aff:fe14:4f36 16022 + 16023 SR (IS-IS) fe80::ac6a:8aff:fe14:4f36 16023 + 16031 SR (IS-IS) fe80::bc7e:bbff:fe7f:ecb0 16031 + 16032 SR (IS-IS) fe80::b886:2cff:fe84:a76f 16032 + 16033 SR (IS-IS) fe80::b886:2cff:fe84:a76f 16033 + 16033 SR (IS-IS) fe80::ac6a:8aff:fe14:4f36 16033 + 16034 SR (IS-IS) fe80::b886:2cff:fe84:a76f 16034 + 16034 SR (IS-IS) fe80::ac6a:8aff:fe14:4f36 16034 + 16041 SR (IS-IS) fe80::b886:2cff:fe84:a76f 16041 + 16500 PPR (IS-IS) fe80::e877:a2ff:feb7:4438 16500 + 16501 PPR (IS-IS) fe80::ac6a:8aff:fe14:4f36 16501 + 16502 PPR (IS-IS) fe80::e877:a2ff:feb7:4438 16502 + 16503 PPR (IS-IS) fe80::bc7e:bbff:fe7f:ecb0 16503 + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:1::1/128 [115/50] via fe80::e877:a2ff:feb7:4438, eth-rt11, 00:00:04 + I>* 6000:2::1/128 [115/50] via fe80::ac6a:8aff:fe14:4f36, eth-rt22, 00:00:04 + +Router RT22 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 500 (MPLS) 5000::11/128 0 Mid-Point Up 00:00:50 + 1 L1 501 (MPLS) 5000::14/128 0 Mid-Point Up 00:00:50 + 1 L1 502 (MPLS) 5000::11/128 0 Off-Path - - + 1 L1 503 (MPLS) 5000::14/128 0 Off-Path - - + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Mid-Point Up 00:00:50 + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Mid-Point Up 00:00:50 + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------------------------------- + 16 SR (IS-IS) fe80::3432:84ff:fe9d:2e41 implicit-null + 17 SR (IS-IS) fe80::c436:63ff:feb3:4f5d implicit-null + 18 SR (IS-IS) fe80::56:41ff:fe53:a6b2 implicit-null + 19 SR (IS-IS) fe80::b423:eaff:fea1:8247 implicit-null + 20 SR (IS-IS) fe80::9c2f:11ff:fe0a:ab34 implicit-null + 21 SR (IS-IS) fe80::7402:b8ff:fee9:682e implicit-null + 16011 SR (IS-IS) fe80::b423:eaff:fea1:8247 16011 + 16011 SR (IS-IS) fe80::3432:84ff:fe9d:2e41 16011 + 16012 SR (IS-IS) fe80::3432:84ff:fe9d:2e41 16012 + 16013 SR (IS-IS) fe80::c436:63ff:feb3:4f5d 16013 + 16014 SR (IS-IS) fe80::56:41ff:fe53:a6b2 20014 + 16014 SR (IS-IS) fe80::c436:63ff:feb3:4f5d 16014 + 16021 SR (IS-IS) fe80::b423:eaff:fea1:8247 16021 + 16022 SR (IS-IS) lo - + 16023 SR (IS-IS) fe80::56:41ff:fe53:a6b2 20023 + 16031 SR (IS-IS) fe80::9c2f:11ff:fe0a:ab34 16031 + 16031 SR (IS-IS) fe80::b423:eaff:fea1:8247 16031 + 16032 SR (IS-IS) fe80::9c2f:11ff:fe0a:ab34 16032 + 16033 SR (IS-IS) fe80::7402:b8ff:fee9:682e 16033 + 16034 SR (IS-IS) fe80::7402:b8ff:fee9:682e 16034 + 16034 SR (IS-IS) fe80::56:41ff:fe53:a6b2 20034 + 16041 SR (IS-IS) fe80::7402:b8ff:fee9:682e 16041 + 16041 SR (IS-IS) fe80::9c2f:11ff:fe0a:ab34 16041 + 16500 PPR (IS-IS) fe80::b423:eaff:fea1:8247 16500 + 16501 PPR (IS-IS) fe80::56:41ff:fe53:a6b2 20501 + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:1::1/128 [115/50] via fe80::b423:eaff:fea1:8247, eth-rt21, 00:00:06 + I>* 6000:2::1/128 [115/50] via fe80::56:41ff:fe53:a6b2, eth-rt23, 00:00:06 + +Router RT23 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 500 (MPLS) 5000::11/128 0 Mid-Point Up 00:00:52 + 1 L1 501 (MPLS) 5000::14/128 0 Mid-Point Up 00:00:52 + 1 L1 502 (MPLS) 5000::11/128 0 Mid-Point Up 00:00:52 + 1 L1 503 (MPLS) 5000::14/128 0 Mid-Point Up 00:00:52 + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Mid-Point Up 00:00:52 + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Mid-Point Up 00:00:52 + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------------------------------- + 16 SR (IS-IS) fe80::c4ca:41ff:fe2d:de8c implicit-null + 17 SR (IS-IS) fe80::a02b:1eff:fed6:97e4 implicit-null + 18 SR (IS-IS) fe80::5c15:8aff:feea:1d07 implicit-null + 19 SR (IS-IS) fe80::a42f:50ff:fe9c:af9f implicit-null + 20 SR (IS-IS) fe80::d0dc:6eff:fe71:9f19 implicit-null + 20011 SR (IS-IS) fe80::5c15:8aff:feea:1d07 16011 + 20011 SR (IS-IS) fe80::a02b:1eff:fed6:97e4 16011 + 20012 SR (IS-IS) fe80::5c15:8aff:feea:1d07 16012 + 20012 SR (IS-IS) fe80::a02b:1eff:fed6:97e4 16012 + 20013 SR (IS-IS) fe80::a02b:1eff:fed6:97e4 16013 + 20014 SR (IS-IS) fe80::c4ca:41ff:fe2d:de8c 16014 + 20021 SR (IS-IS) fe80::5c15:8aff:feea:1d07 16021 + 20022 SR (IS-IS) fe80::5c15:8aff:feea:1d07 16022 + 20023 SR (IS-IS) lo - + 20031 SR (IS-IS) fe80::a42f:50ff:fe9c:af9f 16031 + 20031 SR (IS-IS) fe80::5c15:8aff:feea:1d07 16031 + 20032 SR (IS-IS) fe80::a42f:50ff:fe9c:af9f 16032 + 20032 SR (IS-IS) fe80::5c15:8aff:feea:1d07 16032 + 20033 SR (IS-IS) fe80::a42f:50ff:fe9c:af9f 16033 + 20034 SR (IS-IS) fe80::d0dc:6eff:fe71:9f19 16034 + 20041 SR (IS-IS) fe80::a42f:50ff:fe9c:af9f 16041 + 20500 PPR (IS-IS) fe80::5c15:8aff:feea:1d07 16500 + 20501 PPR (IS-IS) fe80::c4ca:41ff:fe2d:de8c 16501 + 20502 PPR (IS-IS) fe80::d0dc:6eff:fe71:9f19 16502 + 20503 PPR (IS-IS) fe80::c4ca:41ff:fe2d:de8c 16503 + + # show ipv6 route 6000::/16 longer-prefixes isis + Codes: K - kernel route, C - connected, S - static, R - RIPng, + O - OSPFv3, I - IS-IS, B - BGP, N - NHRP, T - Table, + v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, + f - OpenFabric, + > - selected route, * - FIB route, q - queued route, r - rejected route + + I>* 6000:1::1/128 [115/50] via fe80::5c15:8aff:feea:1d07, eth-rt22, 00:00:07 + I>* 6000:2::1/128 [115/50] via fe80::c4ca:41ff:fe2d:de8c, eth-rt14, 00:00:07 + +Router RT31 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 500 (MPLS) 5000::11/128 0 Off-Path - - + 1 L1 501 (MPLS) 5000::14/128 0 Off-Path - - + 1 L1 502 (MPLS) 5000::11/128 0 Mid-Point Up 00:00:54 + 1 L1 503 (MPLS) 5000::14/128 0 Mid-Point Up 00:00:54 + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------------------------------- + 16 SR (IS-IS) fe80::a067:c6ff:fe2c:3385 implicit-null + 17 SR (IS-IS) fe80::f46d:c8ff:fe8a:a341 implicit-null + 16011 SR (IS-IS) fe80::a067:c6ff:fe2c:3385 16011 + 16012 SR (IS-IS) fe80::a067:c6ff:fe2c:3385 16012 + 16013 SR (IS-IS) fe80::f46d:c8ff:fe8a:a341 16013 + 16013 SR (IS-IS) fe80::a067:c6ff:fe2c:3385 16013 + 16014 SR (IS-IS) fe80::f46d:c8ff:fe8a:a341 16014 + 16014 SR (IS-IS) fe80::a067:c6ff:fe2c:3385 16014 + 16021 SR (IS-IS) fe80::a067:c6ff:fe2c:3385 16021 + 16022 SR (IS-IS) fe80::f46d:c8ff:fe8a:a341 16022 + 16022 SR (IS-IS) fe80::a067:c6ff:fe2c:3385 16022 + 16023 SR (IS-IS) fe80::f46d:c8ff:fe8a:a341 16023 + 16023 SR (IS-IS) fe80::a067:c6ff:fe2c:3385 16023 + 16031 SR (IS-IS) lo - + 16032 SR (IS-IS) fe80::f46d:c8ff:fe8a:a341 16032 + 16033 SR (IS-IS) fe80::f46d:c8ff:fe8a:a341 16033 + 16034 SR (IS-IS) fe80::f46d:c8ff:fe8a:a341 16034 + 16041 SR (IS-IS) fe80::f46d:c8ff:fe8a:a341 16041 + 16502 PPR (IS-IS) fe80::a067:c6ff:fe2c:3385 16502 + 16503 PPR (IS-IS) fe80::f46d:c8ff:fe8a:a341 16503 + + # show ipv6 route 6000::/16 longer-prefixes isis + +Router RT32 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 500 (MPLS) 5000::11/128 0 Off-Path - - + 1 L1 501 (MPLS) 5000::14/128 0 Off-Path - - + 1 L1 502 (MPLS) 5000::11/128 0 Mid-Point Up 00:00:55 + 1 L1 503 (MPLS) 5000::14/128 0 Mid-Point Up 00:00:55 + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------------------------------- + 16 SR (IS-IS) fe80::881f:d3ff:febd:9e8c implicit-null + 17 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 implicit-null + 18 SR (IS-IS) fe80::9863:abff:fed0:d7e implicit-null + 19 SR (IS-IS) fe80::ec65:d1ff:fe32:b508 implicit-null + 20 SR (IS-IS) fe80::a4e9:77ff:feaa:f690 implicit-null + 21 SR (IS-IS) fe80::40c4:e6ff:fe26:767f implicit-null + 16011 SR (IS-IS) fe80::881f:d3ff:febd:9e8c 16011 + 16012 SR (IS-IS) fe80::40c4:e6ff:fe26:767f 16012 + 16012 SR (IS-IS) fe80::881f:d3ff:febd:9e8c 16012 + 16013 SR (IS-IS) fe80::40c4:e6ff:fe26:767f 16013 + 16014 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16014 + 16014 SR (IS-IS) fe80::ec65:d1ff:fe32:b508 16014 + 16014 SR (IS-IS) fe80::40c4:e6ff:fe26:767f 16014 + 16021 SR (IS-IS) fe80::881f:d3ff:febd:9e8c 16021 + 16022 SR (IS-IS) fe80::40c4:e6ff:fe26:767f 16022 + 16023 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16023 + 16023 SR (IS-IS) fe80::ec65:d1ff:fe32:b508 16023 + 16023 SR (IS-IS) fe80::40c4:e6ff:fe26:767f 16023 + 16031 SR (IS-IS) fe80::9863:abff:fed0:d7e 16031 + 16032 SR (IS-IS) lo - + 16033 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16033 + 16033 SR (IS-IS) fe80::ec65:d1ff:fe32:b508 16033 + 16034 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16034 + 16034 SR (IS-IS) fe80::ec65:d1ff:fe32:b508 16034 + 16041 SR (IS-IS) fe80::a4e9:77ff:feaa:f690 16041 + 16502 PPR (IS-IS) fe80::9863:abff:fed0:d7e 16502 + 16503 PPR (IS-IS) fe80::a4e9:77ff:feaa:f690 16503 + + # show ipv6 route 6000::/16 longer-prefixes isis + +Router RT33 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 500 (MPLS) 5000::11/128 0 Off-Path - - + 1 L1 501 (MPLS) 5000::14/128 0 Off-Path - - + 1 L1 502 (MPLS) 5000::11/128 0 Mid-Point Up 00:00:57 + 1 L1 503 (MPLS) 5000::14/128 0 Mid-Point Up 00:00:57 + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------------------------------- + 16 SR (IS-IS) fe80::2832:a9ff:fec3:7078 implicit-null + 17 SR (IS-IS) fe80::7806:e1ff:fe72:9b1f implicit-null + 18 SR (IS-IS) fe80::5476:31ff:fe94:c39 implicit-null + 19 SR (IS-IS) fe80::a4e9:77ff:feaa:f690 implicit-null + 20 SR (IS-IS) fe80::68c9:2ff:fe04:5eba implicit-null + 21 SR (IS-IS) fe80::d053:97ff:fee2:1711 implicit-null + 16011 SR (IS-IS) fe80::2832:a9ff:fec3:7078 16011 + 16011 SR (IS-IS) fe80::5476:31ff:fe94:c39 16011 + 16011 SR (IS-IS) fe80::d053:97ff:fee2:1711 16011 + 16012 SR (IS-IS) fe80::d053:97ff:fee2:1711 16012 + 16013 SR (IS-IS) fe80::68c9:2ff:fe04:5eba 20013 + 16013 SR (IS-IS) fe80::d053:97ff:fee2:1711 16013 + 16014 SR (IS-IS) fe80::68c9:2ff:fe04:5eba 20014 + 16021 SR (IS-IS) fe80::2832:a9ff:fec3:7078 16021 + 16021 SR (IS-IS) fe80::5476:31ff:fe94:c39 16021 + 16021 SR (IS-IS) fe80::d053:97ff:fee2:1711 16021 + 16022 SR (IS-IS) fe80::d053:97ff:fee2:1711 16022 + 16023 SR (IS-IS) fe80::68c9:2ff:fe04:5eba 20023 + 16031 SR (IS-IS) fe80::2832:a9ff:fec3:7078 16031 + 16031 SR (IS-IS) fe80::5476:31ff:fe94:c39 16031 + 16032 SR (IS-IS) fe80::2832:a9ff:fec3:7078 16032 + 16032 SR (IS-IS) fe80::5476:31ff:fe94:c39 16032 + 16033 SR (IS-IS) lo - + 16034 SR (IS-IS) fe80::7806:e1ff:fe72:9b1f 16034 + 16041 SR (IS-IS) fe80::a4e9:77ff:feaa:f690 16041 + 16502 PPR (IS-IS) fe80::a4e9:77ff:feaa:f690 16502 + 16503 PPR (IS-IS) fe80::7806:e1ff:fe72:9b1f 16503 + + # show ipv6 route 6000::/16 longer-prefixes isis + +Router RT34 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 500 (MPLS) 5000::11/128 0 Off-Path - - + 1 L1 501 (MPLS) 5000::14/128 0 Off-Path - - + 1 L1 502 (MPLS) 5000::11/128 0 Mid-Point Up 00:00:59 + 1 L1 503 (MPLS) 5000::14/128 0 Mid-Point Up 00:00:59 + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------------------------------- + 16 SR (IS-IS) fe80::ac33:5dff:fe99:81ec implicit-null + 17 SR (IS-IS) fe80::f009:b9ff:fe05:e540 implicit-null + 16011 SR (IS-IS) fe80::ac33:5dff:fe99:81ec 16011 + 16011 SR (IS-IS) fe80::f009:b9ff:fe05:e540 20011 + 16012 SR (IS-IS) fe80::ac33:5dff:fe99:81ec 16012 + 16012 SR (IS-IS) fe80::f009:b9ff:fe05:e540 20012 + 16013 SR (IS-IS) fe80::f009:b9ff:fe05:e540 20013 + 16014 SR (IS-IS) fe80::f009:b9ff:fe05:e540 20014 + 16021 SR (IS-IS) fe80::ac33:5dff:fe99:81ec 16021 + 16021 SR (IS-IS) fe80::f009:b9ff:fe05:e540 20021 + 16022 SR (IS-IS) fe80::ac33:5dff:fe99:81ec 16022 + 16022 SR (IS-IS) fe80::f009:b9ff:fe05:e540 20022 + 16023 SR (IS-IS) fe80::f009:b9ff:fe05:e540 20023 + 16031 SR (IS-IS) fe80::ac33:5dff:fe99:81ec 16031 + 16032 SR (IS-IS) fe80::ac33:5dff:fe99:81ec 16032 + 16033 SR (IS-IS) fe80::ac33:5dff:fe99:81ec 16033 + 16034 SR (IS-IS) lo - + 16041 SR (IS-IS) fe80::ac33:5dff:fe99:81ec 16041 + 16502 PPR (IS-IS) fe80::ac33:5dff:fe99:81ec 16502 + 16503 PPR (IS-IS) fe80::f009:b9ff:fe05:e540 20503 + + # show ipv6 route 6000::/16 longer-prefixes isis + +Router RT41 +^^^^^^^^^^^ + +:: + + # show isis ppr + Area Level ID Prefix Metric Position Status Uptime + --------------------------------------------------------------------------------------------- + 1 L1 500 (MPLS) 5000::11/128 0 Off-Path - - + 1 L1 501 (MPLS) 5000::14/128 0 Off-Path - - + 1 L1 502 (MPLS) 5000::11/128 0 Mid-Point Up 00:01:01 + 1 L1 503 (MPLS) 5000::14/128 0 Mid-Point Up 00:01:01 + 1 L1 6000:1::1/128 (Native IPv6) 5000::11/128 50 Off-Path - - + 1 L1 6000:2::1/128 (Native IPv6) 5000::14/128 50 Off-Path - - + + # show mpls table + Inbound Label Type Nexthop Outbound Label + ----------------------------------------------------------------------- + 16 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 implicit-null + 17 SR (IS-IS) fe80::2832:a9ff:fec3:7078 implicit-null + 16011 SR (IS-IS) fe80::2832:a9ff:fec3:7078 16011 + 16012 SR (IS-IS) fe80::2832:a9ff:fec3:7078 16012 + 16012 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16012 + 16013 SR (IS-IS) fe80::2832:a9ff:fec3:7078 16013 + 16013 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16013 + 16014 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16014 + 16021 SR (IS-IS) fe80::2832:a9ff:fec3:7078 16021 + 16022 SR (IS-IS) fe80::2832:a9ff:fec3:7078 16022 + 16022 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16022 + 16023 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16023 + 16031 SR (IS-IS) fe80::2832:a9ff:fec3:7078 16031 + 16032 SR (IS-IS) fe80::2832:a9ff:fec3:7078 16032 + 16033 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16033 + 16034 SR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16034 + 16041 SR (IS-IS) lo - + 16502 PPR (IS-IS) fe80::2832:a9ff:fec3:7078 16502 + 16503 PPR (IS-IS) fe80::1c7e:c3ff:fe5e:7a54 16503 + + # show ipv6 route 6000::/16 longer-prefixes isis + +Notice how R23 uses a different SRGB compared to the other routers in +the network. As such, this router install different labels for PPR-IDs +500 and 501 (e.g. 20500 instead of 16500 using the default SRGB). + +Verification - Forwarding Plane +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Ping Host 3 from Host2 and use tcpdump or wireshark to verify that the +ICMP packets are being tunneled using MPLS LSPs and following the {R11 - +R21 - R22 - R23 - R14} path. Here’s a wireshark capture between R11 and +R21: + +.. figure:: https://user-images.githubusercontent.com/931662/64057179-2e980080-cb70-11e9-89c3-ff43e6d66cae.png + :alt: wireshark + + wireshark + +Using ``traceroute`` it’s also possible to see that the ICMP packets are +being tunneled through the IS-IS network: + +:: + + root@host2:~# traceroute -n fd00:20:1::1 -s fd00:10:2::1 + traceroute to fd00:20:1::1 (fd00:20:1::1), 30 hops max, 80 byte packets + 1 fd00:10:2::100 1.996 ms 1.832 ms 1.725 ms + 2 * * * + 3 * * * + 4 * * * + 5 * * * + 6 * * * + 7 * * * + 8 fd00:20::100 0.154 ms 0.191 ms 0.116 ms + 9 fd00:20:1::1 0.125 ms 0.105 ms 0.104 ms diff --git a/doc/developer/northbound/retrofitting-configuration-commands.rst b/doc/developer/northbound/retrofitting-configuration-commands.rst new file mode 100644 index 000000000000..c13332bf1fb5 --- /dev/null +++ b/doc/developer/northbound/retrofitting-configuration-commands.rst @@ -0,0 +1,1916 @@ +Table of Contents +----------------- + +- `Introduction <#introduction>`__ +- `Retrofitting process <#retrofitting-process>`__ + + - `Step 1: writing a YANG module <#step1>`__ + - `Step 2: generate skeleton northbound callbacks <#step2>`__ + - `Step 3: update the frr_yang_module_info array of all relevant + daemons <#step3>`__ + - `Step 4: implement the northbound configuration + callbacks <#step4>`__ + - `Step 5: rewrite the CLI commands as dumb wrappers around the + northbound callbacks <#step5>`__ + - `Step 6: implement the ``cli_show`` callbacks <#step6>`__ + - `Step 7: consolidation <#step7>`__ + +- `Final Considerations <#final-considerations>`__ + +Introduction +------------ + +This page explains how to convert existing CLI configuration commands to +the new northbound model. This documentation is meant to be the primary +reference for developers working on the northbound retrofitting process. +We’ll show several examples taken from the ripd northbound conversion to +illustrate some concepts described herein. + +Retrofitting process +-------------------- + +Step 1: writing a YANG module +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The first step is to write a YANG module that models faithfully the +commands that are going to be converted. As explained in the +[[Architecture]] page, the goal is to introduce the new YANG-based +Northbound API without introducing backward incompatible changes in the +CLI. The northbound retrofitting process should be completely +transparent to FRR users. + +The developer is free to choose whether to write a full YANG module or a +partial YANG module and increment it gradually. For developers who lack +experience with YANG it’s probably a better idea to model one command at +time. + +It’s recommended to reuse definitions from standard YANG models whenever +possible to facilitate the process of writing module translators using +the [[YANG module translator]]. As an example, the frr-ripd YANG module +incorporated several parts of the IETF RIP YANG module. The repositories +below contain big collections of YANG models that might be used as a +reference: \* https://github.com/YangModels/yang \* +https://github.com/openconfig/public + +When writing a YANG module, it’s highly recommended to follow the +guidelines from `RFC 6087 `__. In +general, most commands should be modeled fairly easy. Here are a few +guidelines specific to authors of FRR YANG models: \* Use +presence-containers or lists to model commands that change the CLI node +(e.g. ``router rip``, ``interface eth0``). This way, if the +presence-container or list entry is removed, all configuration options +below them are removed automatically (exactly like the CLI behaves when +a configuration object is removed using a *no* command). This +recommendation is orthogonal to the `YANG authoring guidelines for +OpenConfig +models `__ +where the use of presence containers is discouraged. OpenConfig YANG +models however were not designed to replicate the behavior of legacy CLI +commands. \* When using YANG lists, be careful to identify what should +be the key leaves. In the ``offset-list WORD (0-16) IFNAME`` +command, for example, both the direction (````) and the +interface name should be the keys of the list. This can be only known by +analyzing the data structures used to store the commands. \* For +clarity, use non-presence containers to group leaves that are associated +to the same configuration command (as we’ll see later, this also +facilitate the process of writing ``cli_show`` callbacks). \* YANG +leaves of type *enumeration* should define explicitly the value of each +*enum* option based on the value used in the FRR source code. \* Default +values should be taken from the source code whenever they exist. + +Some commands are more difficult to model and demand the use of more +advanced YANG constructs like *choice*, *when* and *must* statements. +**One key requirement is that it should be impossible to load an invalid +JSON/XML configuration to FRR**. The YANG modules should model exactly +what the CLI accepts in the form of commands, and all restrictions +imposed by the CLI should be defined in the YANG models whenever +possible. As we’ll see later, not all constraints can be expressed using +the YANG language and sometimes we’ll need to resort to code-level +validation in the northbound callbacks. + + Tip: the [[YANG tools]] page details several tools and commands that + might be useful when writing a YANG module, like validating YANG + files, indenting YANG files, validating instance data, etc. + +In the example YANG snippet below, we can see the use of the *must* +statement that prevents ripd from redistributing RIP routes into itself. +Although ripd CLI doesn’t allow the operator to enter *redistribute rip* +under *router rip*, we don’t have the same protection when configuring +ripd using other northbound interfaces (e.g. NETCONF). So without this +constraint it would be possible to feed an invalid configuration to ripd +(i.e. a bug). + +.. code:: yang + + list redistribute { + key "protocol"; + description + "Redistributes routes learned from other routing protocols."; + leaf protocol { + type frr-route-types:frr-route-types-v4; + description + "Routing protocol."; + must '. != "rip"'; + } + [snip] + } + +In the example below, we use the YANG *choice* statement to ensure that +either the ``password`` leaf or the ``key-chain`` leaf is configured, +but not both. This is in accordance to the sanity checks performed by +the *ip rip authentication* commands. + +.. code:: yang + + choice authentication-data { + description + "Choose whether to use a simple password or a key-chain."; + leaf authentication-password { + type string { + length "1..16"; + } + description + "Authentication string."; + } + leaf authentication-key-chain { + type string; + description + "Key-chain name."; + } + } + +Once finished, the new YANG model should be put into the FRR *yang/* top +level directory. This will ensure it will be installed automatically by +``make install``. It’s also encouraged (but not required) to put sample +configurations under *yang/examples/* using either JSON or XML files. + +Step 2: generate skeleton northbound callbacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use the *gen_northbound_callbacks* tool to generate skeleton callbacks +for the YANG module. Example: + +.. code:: sh + + $ tools/gen_northbound_callbacks frr-ripd > ripd/rip_northbound.c + +The tool will look for the given module in the ``YANG_MODELS_PATH`` +directory defined during the installation. For each schema node of the +YANG module, the tool will generate skeleton callbacks based on the +properties of the node. Example: + +.. code:: c + + /* + * XPath: /frr-ripd:ripd/instance + */ + static int ripd_instance_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) + { + /* TODO: implement me. */ + return NB_OK; + } + + static int ripd_instance_delete(enum nb_event event, + const struct lyd_node *dnode) + { + /* TODO: implement me. */ + return NB_OK; + } + + /* + * XPath: /frr-ripd:ripd/instance/allow-ecmp + */ + static int ripd_instance_allow_ecmp_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) + { + /* TODO: implement me. */ + return NB_OK; + } + + [snip] + + const struct frr_yang_module_info frr_ripd_info = { + .name = "frr-ripd", + .nodes = { + { + .xpath = "/frr-ripd:ripd/instance", + .cbs.create = ripd_instance_create, + .cbs.delete = ripd_instance_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/allow-ecmp", + .cbs.modify = ripd_instance_allow_ecmp_modify, + }, + [snip] + { + .xpath = "/frr-ripd:ripd/state/routes/route", + .cbs.get_next = ripd_state_routes_route_get_next, + .cbs.get_keys = ripd_state_routes_route_get_keys, + .cbs.lookup_entry = ripd_state_routes_route_lookup_entry, + }, + { + .xpath = "/frr-ripd:ripd/state/routes/route/prefix", + .cbs.get_elem = ripd_state_routes_route_prefix_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/routes/route/next-hop", + .cbs.get_elem = ripd_state_routes_route_next_hop_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/routes/route/interface", + .cbs.get_elem = ripd_state_routes_route_interface_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/routes/route/metric", + .cbs.get_elem = ripd_state_routes_route_metric_get_elem, + }, + { + .xpath = "/frr-ripd:clear-rip-route", + .cbs.rpc = clear_rip_route_rpc, + }, + [snip] + +After the C source file is generated, it’s necessary to add a copyright +header on it and indent the code using ``clang-format``. + +Step 3: update the *frr_yang_module_info* array of all relevant daemons +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We must inform the northbound about which daemons will implement the new +YANG module. This is done by updating the ``frr_daemon_info`` structure +of these daemons, with help of the ``FRR_DAEMON_INFO`` macro. + +When a YANG module is specific to a single daemon, like the frr-ripd +module, then only the corresponding daemon should be updated. When the +YANG module is related to a subset of libfrr (e.g. route-maps), then all +FRR daemons that make use of that subset must be updated. + +Example: + +.. code:: c + + static const struct frr_yang_module_info *ripd_yang_modules[] = { + &frr_interface_info, + &frr_ripd_info, + }; + + FRR_DAEMON_INFO(ripd, RIP, .vty_port = RIP_VTY_PORT, + [snip] + .yang_modules = ripd_yang_modules, + .n_yang_modules = array_size(ripd_yang_modules), ) + +Step 4: implement the northbound configuration callbacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Implementing the northbound configuration callbacks consists mostly of +copying code from the corresponding CLI commands and make the required +adaptations. + +It’s recommended to convert one command or a small group of related +commands per commit. Small commits are preferred to facilitate the +review process. Both “old” and “new” command can coexist without +problems, so the retrofitting process can happen gradually over time. + +The configuration callbacks +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +These are the four main northbound configuration callbacks, as defined +in the ``lib/northbound.h`` file: + +.. code:: c + + /* + * Configuration callback. + * + * A presence container, list entry, leaf-list entry or leaf of type + * empty has been created. + * + * For presence-containers and list entries, the callback is supposed to + * initialize the default values of its children (if any) from the YANG + * models. + * + * event + * The transaction phase. Refer to the documentation comments of + * nb_event for more details. + * + * dnode + * libyang data node that is being created. + * + * resource + * Pointer to store resource(s) allocated during the NB_EV_PREPARE + * phase. The same pointer can be used during the NB_EV_ABORT and + * NB_EV_APPLY phases to either release or make use of the allocated + * resource(s). It's set to NULL when the event is NB_EV_VALIDATE. + * + * Returns: + * - NB_OK on success. + * - NB_ERR_VALIDATION when a validation error occurred. + * - NB_ERR_RESOURCE when the callback failed to allocate a resource. + * - NB_ERR_INCONSISTENCY when an inconsistency was detected. + * - NB_ERR for other errors. + */ + int (*create)(enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource); + + /* + * Configuration callback. + * + * The value of a leaf has been modified. + * + * List keys don't need to implement this callback. When a list key is + * modified, the northbound treats this as if the list was deleted and a + * new one created with the updated key value. + * + * event + * The transaction phase. Refer to the documentation comments of + * nb_event for more details. + * + * dnode + * libyang data node that is being modified + * + * resource + * Pointer to store resource(s) allocated during the NB_EV_PREPARE + * phase. The same pointer can be used during the NB_EV_ABORT and + * NB_EV_APPLY phases to either release or make use of the allocated + * resource(s). It's set to NULL when the event is NB_EV_VALIDATE. + * + * Returns: + * - NB_OK on success. + * - NB_ERR_VALIDATION when a validation error occurred. + * - NB_ERR_RESOURCE when the callback failed to allocate a resource. + * - NB_ERR_INCONSISTENCY when an inconsistency was detected. + * - NB_ERR for other errors. + */ + int (*modify)(enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource); + + /* + * Configuration callback. + * + * A presence container, list entry, leaf-list entry or optional leaf + * has been deleted. + * + * The callback is supposed to delete the entire configuration object, + * including its children when they exist. + * + * event + * The transaction phase. Refer to the documentation comments of + * nb_event for more details. + * + * dnode + * libyang data node that is being deleted. + * + * Returns: + * - NB_OK on success. + * - NB_ERR_VALIDATION when a validation error occurred. + * - NB_ERR_INCONSISTENCY when an inconsistency was detected. + * - NB_ERR for other errors. + */ + int (*delete)(enum nb_event event, const struct lyd_node *dnode); + + /* + * Configuration callback. + * + * A list entry or leaf-list entry has been moved. Only applicable when + * the "ordered-by user" statement is present. + * + * event + * The transaction phase. Refer to the documentation comments of + * nb_event for more details. + * + * dnode + * libyang data node that is being moved. + * + * Returns: + * - NB_OK on success. + * - NB_ERR_VALIDATION when a validation error occurred. + * - NB_ERR_INCONSISTENCY when an inconsistency was detected. + * - NB_ERR for other errors. + */ + int (*move)(enum nb_event event, const struct lyd_node *dnode); + +Since skeleton northbound callbacks are generated automatically by the +*gen_northbound_callbacks* tool, the developer doesn’t need to worry +about which callbacks need to be implemented. + + NOTE: once a daemon starts, it reads its YANG modules and validates + that all required northbound callbacks were implemented. If any + northbound callback is missing, an error is logged and the program + exists. + +Transaction phases +^^^^^^^^^^^^^^^^^^ + +Configuration transactions and their phases were described in detail in +the [[Architecture]] page. Here’s the definition of the ``nb_event`` +enumeration as defined in the *lib/northbound.h* file: + +.. code:: c + + /* Northbound events. */ + enum nb_event { + /* + * The configuration callback is supposed to verify that the changes are + * valid and can be applied. + */ + NB_EV_VALIDATE, + + /* + * The configuration callback is supposed to prepare all resources + * required to apply the changes. + */ + NB_EV_PREPARE, + + /* + * Transaction has failed, the configuration callback needs to release + * all resources previously allocated. + */ + NB_EV_ABORT, + + /* + * The configuration changes need to be applied. The changes can't be + * rejected at this point (errors are logged and ignored). + */ + NB_EV_APPLY, + }; + +When converting a CLI command, we must identify all error-prone +operations and perform them in the ``NB_EV_PREPARE`` phase of the +northbound callbacks. When the operation in question involves the +allocation of a specific resource (e.g. file descriptors), we can store +the allocated resource in the ``resource`` variable given to the +callback. This way the allocated resource can be obtained in the other +phases of the transaction using the same parameter. + +Here’s the ``create`` northbound callback associated to the +``router rip`` command: + +.. code:: c + + /* + * XPath: /frr-ripd:ripd/instance + */ + static int ripd_instance_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) + { + int socket; + + switch (event) { + case NB_EV_VALIDATE: + break; + case NB_EV_PREPARE: + socket = rip_create_socket(); + if (socket < 0) + return NB_ERR_RESOURCE; + resource->fd = socket; + break; + case NB_EV_ABORT: + socket = resource->fd; + close(socket); + break; + case NB_EV_APPLY: + socket = resource->fd; + rip_create(socket); + break; + } + + return NB_OK; + } + +Note that the socket creation is an error-prone operation since it +depends on the underlying operating system, so the socket must be +created during the ``NB_EV_PREPARE`` phase and stored in +``resource->fd``. This socket is then either closed or used depending on +the outcome of the preparation phase of the whole transaction. + +During the ``NB_EV_VALIDATE`` phase, the northbound callbacks must +validate if the intended changes are valid. As an example, FRR doesn’t +allow the operator to deconfigure active interfaces: + +.. code:: c + + static int lib_interface_delete(enum nb_event event, + const struct lyd_node *dnode) + { + struct interface *ifp; + + ifp = yang_dnode_get_entry(dnode); + + switch (event) { + case NB_EV_VALIDATE: + if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { + zlog_warn("%s: only inactive interfaces can be deleted", + __func__); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + if_delete(ifp); + break; + } + + return NB_OK; + } + +Note however that it’s preferred to use YANG to model the validation +constraints whenever possible. Code-level validations should be used +only to validate constraints that can’t be modeled using the YANG +language. + +Most callbacks don’t need to perform any validations nor perform any +error-prone operations, so in these cases we can use the following +pattern to return early if ``event`` is different than ``NB_EV_APPLY``: + +.. code:: c + + /* + * XPath: /frr-ripd:ripd/instance/distance/default + */ + static int ripd_instance_distance_default_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) + { + if (event != NB_EV_APPLY) + return NB_OK; + + rip->distance = yang_dnode_get_uint8(dnode, NULL); + + return NB_OK; + } + +During development it’s recommend to use the *debug northbound* command +to debug configuration transactions and see what callbacks are being +called. Example: + +:: + + ripd# conf t + ripd(config)# debug northbound + ripd(config)# router rip + ripd(config-router)# allow-ecmp + ripd(config-router)# network eth0 + ripd(config-router)# redistribute ospf metric 2 + ripd(config-router)# commit + % Configuration committed successfully. + + ripd(config-router)# + +Now the ripd log: + +:: + + 2018/09/23 12:43:59 RIP: northbound callback: event [validate] op [create] xpath [/frr-ripd:ripd/instance] value [(none)] + 2018/09/23 12:43:59 RIP: northbound callback: event [validate] op [modify] xpath [/frr-ripd:ripd/instance/allow-ecmp] value [true] + 2018/09/23 12:43:59 RIP: northbound callback: event [validate] op [create] xpath [/frr-ripd:ripd/instance/interface[.='eth0']] value [eth0] + 2018/09/23 12:43:59 RIP: northbound callback: event [validate] op [create] xpath [/frr-ripd:ripd/instance/redistribute[protocol='ospf']] value [(none)] + 2018/09/23 12:43:59 RIP: northbound callback: event [validate] op [modify] xpath [/frr-ripd:ripd/instance/redistribute[protocol='ospf']/metric] value [2] + 2018/09/23 12:43:59 RIP: northbound callback: event [prepare] op [create] xpath [/frr-ripd:ripd/instance] value [(none)] + 2018/09/23 12:43:59 RIP: northbound callback: event [prepare] op [modify] xpath [/frr-ripd:ripd/instance/allow-ecmp] value [true] + 2018/09/23 12:43:59 RIP: northbound callback: event [prepare] op [create] xpath [/frr-ripd:ripd/instance/interface[.='eth0']] value [eth0] + 2018/09/23 12:43:59 RIP: northbound callback: event [prepare] op [create] xpath [/frr-ripd:ripd/instance/redistribute[protocol='ospf']] value [(none)] + 2018/09/23 12:43:59 RIP: northbound callback: event [prepare] op [modify] xpath [/frr-ripd:ripd/instance/redistribute[protocol='ospf']/metric] value [2] + 2018/09/23 12:43:59 RIP: northbound callback: event [apply] op [create] xpath [/frr-ripd:ripd/instance] value [(none)] + 2018/09/23 12:43:59 RIP: northbound callback: event [apply] op [modify] xpath [/frr-ripd:ripd/instance/allow-ecmp] value [true] + 2018/09/23 12:43:59 RIP: northbound callback: event [apply] op [create] xpath [/frr-ripd:ripd/instance/interface[.='eth0']] value [eth0] + 2018/09/23 12:43:59 RIP: northbound callback: event [apply] op [create] xpath [/frr-ripd:ripd/instance/redistribute[protocol='ospf']] value [(none)] + 2018/09/23 12:43:59 RIP: northbound callback: event [apply] op [modify] xpath [/frr-ripd:ripd/instance/redistribute[protocol='ospf']/metric] value [2] + 2018/09/23 12:43:59 RIP: northbound callback: event [apply] op [apply_finish] xpath [/frr-ripd:ripd/instance/redistribute[protocol='ospf']] value [(null)] + +Getting the data +^^^^^^^^^^^^^^^^ + +One parameter that is common to all northbound configuration callbacks +is the ``dnode`` parameter. This is a libyang data node structure that +contains information relative to the configuration change that is being +performed. For ``create`` callbacks, it contains the configuration node +that is being added. For ``delete`` callbacks, it contains the +configuration node that is being deleted. For ``modify`` callbacks, it +contains the configuration node that is being modified. + +In order to get the actual data value out of the ``dnode`` variable, we +need to use the ``yang_dnode_get_*()`` wrappers documented in +*lib/yang_wrappers.h*. + +The advantage of passing a ``dnode`` structure to the northbound +callbacks is that the whole candidate being committed is made available, +so the callbacks can obtain values from other portions of the +configuration if necessary. This can be done by providing an xpath +expression to the second parameter of the ``yang_dnode_get_*()`` +wrappers to specify the element we want to get. The example below shows +a callback that gets the values of two leaves that are part of the same +list entry: + +.. code:: c + + static int + ripd_instance_redistribute_metric_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) + { + int type; + uint8_t metric; + + if (event != NB_EV_APPLY) + return NB_OK; + + type = yang_dnode_get_enum(dnode, "../protocol"); + metric = yang_dnode_get_uint8(dnode, NULL); + + rip->route_map[type].metric_config = true; + rip->route_map[type].metric = metric; + rip_redistribute_conf_update(type); + + return NB_OK; + } + +.. + + NOTE: if the wrong ``yang_dnode_get_*()`` wrapper is used, the code + will log an error and abort. An example would be using + ``yang_dnode_get_enum()`` to get the value of a boolean data node. + +No need to check if the configuration value has changed +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A common pattern in CLI commands is this: + +.. code:: c + + DEFUN (...) + { + [snip] + if (new_value == old_value) + return CMD_SUCCESS; + [snip] + } + +Several commands need to check if the new value entered by the user is +the same as the one currently configured. Then, if yes, ignore the +command since nothing was changed. + +The northbound callbacks on the other hand don’t need to perform this +check since they act on effective configuration changes. Using the CLI +as an example, if the operator enters the same command multiple times, +the northbound layer will detect that nothing has changed in the +configuration and will avoid calling the northbound callbacks +unnecessarily. + +In some cases, however, it might be desirable to check for +inconsistencies and notify the northbound when that happens: + +.. code:: c + + /* + * XPath: /frr-ripd:ripd/instance/interface + */ + static int ripd_instance_interface_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) + { + const char *ifname; + + if (event != NB_EV_APPLY) + return NB_OK; + + ifname = yang_dnode_get_string(dnode, NULL); + + return rip_enable_if_add(ifname); + } + +.. code:: c + + /* Add interface to rip_enable_if. */ + int rip_enable_if_add(const char *ifname) + { + int ret; + + ret = rip_enable_if_lookup(ifname); + if (ret >= 0) + return NB_ERR_INCONSISTENCY; + + vector_set(rip_enable_interface, + XSTRDUP(MTYPE_RIP_INTERFACE_STRING, ifname)); + + rip_enable_apply_all(); /* TODOVJ */ + + return NB_OK; + } + +In the example above, the ``rip_enable_if_add()`` function should never +return ``NB_ERR_INCONSISTENCY`` in normal conditions. This is because +the northbound layer guarantees that the same interface will never be +added more than once (except when it’s removed and re-added again). But +to be on the safe side it’s probably wise to check for internal +inconsistencies to ensure everything is working as expected. + +Default values +^^^^^^^^^^^^^^ + +Whenever creating a new presence-container or list entry, it’s usually +necessary to initialize certain variables to their default values. FRR +most of the time uses special constants for that purpose +(e.g. ``RIP_DEFAULT_METRIC_DEFAULT``, ``DFLT_BGP_HOLDTIME``, etc). Now +that we have YANG models, we want to fetch the default values from these +models instead. This will allow us to changes default values smoothly +without needing to touch the code. Better yet, it will allow users to +create YANG deviations to define custom default values easily. + +To fetch default values from the loaded YANG models, use the +``yang_get_default_*()`` wrapper functions +(e.g. ``yang_get_default_bool()``) documented in *lib/yang_wrappers.h*. + +Example: + +.. code:: c + + int rip_create(int socket) + { + rip = XCALLOC(MTYPE_RIP, sizeof(struct rip)); + + /* Set initial values. */ + rip->ecmp = yang_get_default_bool("%s/allow-ecmp", RIP_INSTANCE); + rip->default_metric = + yang_get_default_uint8("%s/default-metric", RIP_INSTANCE); + [snip] + } + +Configuration options are edited individually +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Several CLI commands edit multiple configuration options at the same +time. Some examples taken from ripd: \* +``timers basic (5-2147483647) (5-2147483647) (5-2147483647)`` - +*/frr-ripd:ripd/instance/timers/flush-interval* - +*/frr-ripd:ripd/instance/timers/holddown-interval* - +*/frr-ripd:ripd/instance/timers/update-interval* \* +``distance (1-255) A.B.C.D/M [WORD]`` - +*/frr-ripd:ripd/instance/distance/source/prefix* - +*/frr-ripd:ripd/instance/distance/source/distance* - +*/frr-ripd:ripd/instance/distance/source/access-list* + +In the new northbound model, there’s one or more separate callbacks for +each configuration option. This usually has implications when converting +code from CLI commands to the northbound commands. An example of this is +the following commit from ripd: +`7cf2f2eaf `__. +The ``rip_distance_set()`` and ``rip_distance_unset()`` functions were +torn apart and their code split into a few different callbacks. + +For lists and presence-containers, it’s possible to use the +``yang_dnode_set_entry()`` function to attach user data to a libyang +data node, and then retrieve this value in the other callbacks (for the +same node or any of its children) using the ``yang_dnode_get_entry()`` +function. Example: + +.. code:: c + + static int ripd_instance_distance_source_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) + { + struct prefix_ipv4 prefix; + struct route_node *rn; + + if (event != NB_EV_APPLY) + return NB_OK; + + yang_dnode_get_ipv4p(&prefix, dnode, "./prefix"); + + /* Get RIP distance node. */ + rn = route_node_get(rip_distance_table, (struct prefix *)&prefix); + rn->info = rip_distance_new(); + yang_dnode_set_entry(dnode, rn); + + return NB_OK; + } + +.. code:: c + + static int + ripd_instance_distance_source_distance_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) + { + struct route_node *rn; + uint8_t distance; + struct rip_distance *rdistance; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Set distance value. */ + rn = yang_dnode_get_entry(dnode); + distance = yang_dnode_get_uint8(dnode, NULL); + rdistance = rn->info; + rdistance->distance = distance; + + return NB_OK; + } + +Commands that edit multiple configuration options at the same time can +also use the ``apply_finish`` optional callback, documented as follows +in the *lib/northbound.h* file: + +.. code:: c + + /* + * Optional configuration callback for YANG lists and containers. + * + * The 'apply_finish' callbacks are called after all other callbacks + * during the apply phase (NB_EV_APPLY). These callbacks are called only + * under one of the following two cases: + * * The container or a list entry has been created; + * * Any change is made within the descendants of the list entry or + * container (e.g. a child leaf was modified, created or deleted). + * + * This callback is useful in the cases where a single event should be + * triggered regardless if the container or list entry was changed once + * or multiple times. + * + * dnode + * libyang data node from the YANG list or container. + */ + void (*apply_finish)(const struct lyd_node *dnode); + +Here’s an example of how this callback can be used: + +.. code:: c + + /* + * XPath: /frr-ripd:ripd/instance/timers/ + */ + static void ripd_instance_timers_apply_finish(const struct lyd_node *dnode) + { + /* Reset update timer thread. */ + rip_event(RIP_UPDATE_EVENT, 0); + } + +.. code:: c + + { + .xpath = "/frr-ripd:ripd/instance/timers", + .cbs.apply_finish = ripd_instance_timers_apply_finish, + .cbs.cli_show = cli_show_rip_timers, + }, + { + .xpath = "/frr-ripd:ripd/instance/timers/flush-interval", + .cbs.modify = ripd_instance_timers_flush_interval_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/timers/holddown-interval", + .cbs.modify = ripd_instance_timers_holddown_interval_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/timers/update-interval", + .cbs.modify = ripd_instance_timers_update_interval_modify, + }, + +In this example, we want to call the ``rip_event()`` function only once +regardless if all RIP timers were modified or only one of them. Without +the ``apply_finish`` callback we’d need to call ``rip_event()`` in the +``modify`` callback of each timer (a YANG leaf), resulting in redundant +call to the ``rip_event()`` function if multiple timers are changed at +once. + +Bonus: libyang user types +^^^^^^^^^^^^^^^^^^^^^^^^^ + +When writing YANG modules, it’s advisable to create derived types for +data types that are used on multiple places (e.g. MAC addresses, IS-IS +networks, etc). Here’s how `RFC +7950 `__ defines derived +types: > YANG can define derived types from base types using the +“typedef” > statement. A base type can be either a built-in type or a +derived > type, allowing a hierarchy of derived types. > > A derived +type can be used as the argument for the “type” statement. > > YANG +Example: > > typedef percent { > type uint8 { > range “0 .. 100”; > } > +} > > leaf completed { > type percent; > } + +Derived types are essentially built-in types with imposed restrictions. +As an example, the ``ipv4-address`` derived type from IETF is defined +using the ``string`` built-in type with a ``pattern`` constraint (a +regular expression): + +:: + + typedef ipv4-address { + type string { + pattern + '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}' + + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])' + + '(%[\p{N}\p{L}]+)?'; + } + description + "The ipv4-address type represents an IPv4 address in + dotted-quad notation. The IPv4 address may include a zone + index, separated by a % sign. + + The zone index is used to disambiguate identical address + values. For link-local addresses, the zone index will + typically be the interface index number or the name of an + interface. If the zone index is not present, the default + zone of the device will be used. + + The canonical format for the zone index is the numerical + format"; + } + +Sometimes, however, it’s desirable to have a binary representation of +the derived type that is different from the associated built-in type. +Taking the ``ipv4-address`` example above, it would be more convenient +to manipulate this YANG type using ``in_addr`` structures instead of +strings. libyang allow us to do that using the user types plugin: +https://netopeer.liberouter.org/doc/libyang/master/howtoschemaplugins.html#usertypes + +Here’s how the the ``ipv4-address`` derived type is implemented in FRR +(*yang/libyang_plugins/frr_user_types.c*): + +.. code:: c + + static int ipv4_address_store_clb(const char *type_name, const char *value_str, + lyd_val *value, char **err_msg) + { + value->ptr = malloc(sizeof(struct in_addr)); + if (!value->ptr) + return 1; + + if (inet_pton(AF_INET, value_str, value->ptr) != 1) { + free(value->ptr); + return 1; + } + + return 0; + } + +.. code:: c + + struct lytype_plugin_list frr_user_types[] = { + {"ietf-inet-types", "2013-07-15", "ipv4-address", + ipv4_address_store_clb, free}, + {"ietf-inet-types", "2013-07-15", "ipv4-address-no-zone", + ipv4_address_store_clb, free}, + [snip] + {NULL, NULL, NULL, NULL, NULL} /* terminating item */ + }; + +Now, in addition to the string representation of the data value, libyang +will also store the data in the binary format we specified (an +``in_addr`` structure). + +Whenever a new derived type is implemented in FRR, it’s also recommended +to write new wrappers in the *lib/yang_wrappers.c* file +(e.g. ``yang_dnode_get_ipv4()``, ``yang_get_default_ipv4()``, etc). + +Step 5: rewrite the CLI commands as dumb wrappers around the northbound callbacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once the northbound callbacks are implemented, we need to rewrite the +associated CLI commands on top of the northbound layer. This is the +easiest part of the retrofitting process. + +For protocol daemons, it’s recommended to put all CLI commands on a +separate C file (e.g. *ripd/rip_cli.c*). This helps to keep the code +more clean by separating the main protocol code from the user interface. +It should also help when moving the CLI to a separate program in the +future. + +For libfrr commands, it’s not possible to centralize all commands in a +single file because the *extract.pl* script from *vtysh* treats commands +differently depending on the file in which they are defined (e.g. DEFUNs +from *lib/routemap.c* are installed using the ``VTYSH_RMAP`` constant, +which identifies the daemons that support route-maps). In this case, the +CLI commands should be rewritten but maintained in the same file. + +Since all CLI configuration commands from FRR will need to be rewritten, +this is an excellent opportunity to rework this part of the code to make +the commands easier to maintain and extend. These are the three main +recommendations: 1. Always use DEFPY instead of DEFUN to improve code +readability. 2. Always try to join multiple DEFUNs into a single DEFPY +whenever possible. As an example, there’s no need to have both +``distance (1-255) A.B.C.D/M`` and ``distance (1-255) A.B.C.D/M WORD`` +when a single ``distance (1-255) A.B.C.D/M [WORD]`` would suffice. 3. +When necessary, create a separate DEFPY for ``no`` commands so that part +of the configuration command can be made optional for convenience. +Example: +``no timers basic [(5-2147483647) (5-2147483647) (5-2147483647)]``. In +this example, everything after ``no timers basic`` is ignored by FRR, so +it makes sense to accept ``no timers basic`` as a valid command. But it +also makes sense to accept all parameters +(``no timers basic (5-2147483647) (5-2147483647) (5-2147483647)``) to +make it easier to remove the command just by prefixing a “no” to it. + +To rewrite a CLI command as a dumb wrapper around the northbound +callbacks, use the ``nb_cli_cfg_change()`` function. This function +accepts as a parameter an array of ``cli_config_change`` structures that +specify the changes that need to performed on the candidate +configuration. Here’s the declaration of this structure (taken from the +*lib/northbound_cli.h* file): + +.. code:: c + + struct cli_config_change { + /* + * XPath (absolute or relative) of the configuration option being + * edited. + */ + char xpath[XPATH_MAXLEN]; + + /* + * Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or + * NB_OP_DELETE). + */ + enum nb_operation operation; + + /* + * New value of the configuration option. Should be NULL for typeless + * YANG data (e.g. presence-containers). For convenience, NULL can also + * be used to restore a leaf to its default value. + */ + const char *value; + }; + +The ``nb_cli_cfg_change()`` function positions the CLI command on top on +top of the northbound layer. Instead of changing the running +configuration directly, this function changes the candidate +configuration instead, as described in the [[Transactional CLI]] page. +When the transactional CLI is not in use (i.e. the default mode), then +``nb_cli_cfg_change()`` performs an implicit ``commit`` operation after +changing the candidate configuration. + + NOTE: the ``nb_cli_cfg_change()`` function clones the candidate + configuration before actually editing it. This way, if any error + happens during the editing, the original candidate is restored to + avoid inconsistencies. Either all changes from the configuration + command are performed successfully or none are. It’s like a + mini-transaction but happening on the candidate configuration (thus + the northbound callbacks are not involved). + +Other important details to keep in mind while rewriting the CLI +commands: \* ``nb_cli_cfg_change()`` returns CLI errors codes +(e.g. ``CMD_SUCCESS``, ``CMD_WARNING``), so the return value of this +function can be used as the return value of CLI commands. \* Calls to +``VTY_PUSH_CONTEXT`` and ``VTY_PUSH_CONTEXT_SUB`` should be converted to +calls to ``VTY_PUSH_XPATH``. Similarly, the following macros aren’t +necessary anymore and can be removed: ``VTY_DECLVAR_CONTEXT``, +``VTY_DECLVAR_CONTEXT_SUB``, ``VTY_GET_CONTEXT`` and +``VTY_CHECK_CONTEXT``. The ``nb_cli_cfg_change()`` functions uses the +``VTY_CHECK_XPATH`` macro to check if the data node being edited still +exists before doing anything else. + +The examples below provide additional details about how the conversion +should be done. + +Example 1 +^^^^^^^^^ + +In this first example, the *router rip* command becomes a dumb wrapper +around the ``ripd_instance_create()`` callback. Note that we don’t need +to check if the ``/frr-ripd:ripd/instance`` data path already exists +before trying to create it. The northbound will detect when this +presence-container already exists and do nothing. The +``VTY_PUSH_XPATH()`` macro is used to change the vty node and set the +context for other commands under *router rip*. + +.. code:: c + + DEFPY_NOSH (router_rip, + router_rip_cmd, + "router rip", + "Enable a routing process\n" + "Routing Information Protocol (RIP)\n") + { + int ret; + + struct cli_config_change changes[] = { + { + .xpath = "/frr-ripd:ripd/instance", + .operation = NB_OP_CREATE, + .value = NULL, + }, + }; + + ret = nb_cli_cfg_change(vty, NULL, changes, array_size(changes)); + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(RIP_NODE, changes[0].xpath); + + return ret; + } + +Example 2 +^^^^^^^^^ + +Here we can see the use of relative xpaths (starting with ``./``), which +are more convenient that absolute xpaths (which would be +``/frr-ripd:ripd/instance/default-metric`` in this example). This is +possible because the use of ``VTY_PUSH_XPATH()`` in the *router rip* +command set the vty base xpath to ``/frr-ripd:ripd/instance``. + +.. code:: c + + DEFPY (rip_default_metric, + rip_default_metric_cmd, + "default-metric (1-16)", + "Set a metric of redistribute routes\n" + "Default metric\n") + { + struct cli_config_change changes[] = { + { + .xpath = "./default-metric", + .operation = NB_OP_MODIFY, + .value = default_metric_str, + }, + }; + + return nb_cli_cfg_change(vty, NULL, changes, array_size(changes)); + } + +In the command below we the ``value`` to NULL to indicate that we want +to set this leaf to its default value. This is better than hardcoding +the default value because the default might change in the future. Also, +users might define custom defaults by using YANG deviations, so it’s +better to write code that works correctly regardless of the default +values defined in the YANG models. + +.. code:: c + + DEFPY (no_rip_default_metric, + no_rip_default_metric_cmd, + "no default-metric [(1-16)]", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n") + { + struct cli_config_change changes[] = { + { + .xpath = "./default-metric", + .operation = NB_OP_MODIFY, + .value = NULL, + }, + }; + + return nb_cli_cfg_change(vty, NULL, changes, array_size(changes)); + } + +Example 3 +^^^^^^^^^ + +This example shows how one command can change multiple leaves at the +same time. + +.. code:: c + + DEFPY (rip_timers, + rip_timers_cmd, + "timers basic (5-2147483647)$update (5-2147483647)$timeout (5-2147483647)$garbage", + "Adjust routing timers\n" + "Basic routing protocol update timers\n" + "Routing table update timer value in second. Default is 30.\n" + "Routing information timeout timer. Default is 180.\n" + "Garbage collection timer. Default is 120.\n") + { + struct cli_config_change changes[] = { + { + .xpath = "./timers/update-interval", + .operation = NB_OP_MODIFY, + .value = update_str, + }, + { + .xpath = "./timers/holddown-interval", + .operation = NB_OP_MODIFY, + .value = timeout_str, + }, + { + .xpath = "./timers/flush-interval", + .operation = NB_OP_MODIFY, + .value = garbage_str, + }, + }; + + return nb_cli_cfg_change(vty, NULL, changes, array_size(changes)); + } + +Example 4 +^^^^^^^^^ + +This example shows how to create a list entry: + +.. code:: c + + DEFPY (rip_distance_source, + rip_distance_source_cmd, + "distance (1-255) A.B.C.D/M$prefix [WORD$acl]", + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") + { + char xpath_list[XPATH_MAXLEN]; + struct cli_config_change changes[] = { + { + .xpath = ".", + .operation = NB_OP_CREATE, + }, + { + .xpath = "./distance", + .operation = NB_OP_MODIFY, + .value = distance_str, + }, + { + .xpath = "./access-list", + .operation = acl ? NB_OP_MODIFY : NB_OP_DELETE, + .value = acl, + }, + }; + + snprintf(xpath_list, sizeof(xpath_list), "./distance/source[prefix='%s']", + prefix_str); + + return nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes)); + } + +The ``xpath_list`` variable is used to hold the xpath that identifies +the list entry. The keys of the list entry should be embedded in this +xpath and don’t need to be part of the array of configuration changes. +All entries from the ``changes`` array use relative xpaths which are +based on the xpath of the list entry. + +The ``access-list`` optional leaf can be either modified or deleted +depending whether the optional *WORD* parameter is present or not. + +When deleting a list entry, all non-key leaves can be ignored: + +.. code:: c + + DEFPY (no_rip_distance_source, + no_rip_distance_source_cmd, + "no distance (1-255) A.B.C.D/M$prefix [WORD$acl]", + NO_STR + "Administrative distance\n" + "Distance value\n" + "IP source prefix\n" + "Access list name\n") + { + char xpath_list[XPATH_MAXLEN]; + struct cli_config_change changes[] = { + { + .xpath = ".", + .operation = NB_OP_DELETE, + }, + }; + + snprintf(xpath_list, sizeof(xpath_list), "./distance/source[prefix='%s']", + prefix_str); + + return nb_cli_cfg_change(vty, xpath_list, changes, 1); + } + +Example 5 +^^^^^^^^^ + +This example shows a DEFPY statement that performs two validations +before calling ``nb_cli_cfg_change()``: + +.. code:: c + + DEFPY (ip_rip_authentication_string, + ip_rip_authentication_string_cmd, + "ip rip authentication string LINE$password", + IP_STR + "Routing Information Protocol\n" + "Authentication control\n" + "Authentication string\n" + "Authentication string\n") + { + struct cli_config_change changes[] = { + { + .xpath = "./frr-ripd:rip/authentication/password", + .operation = NB_OP_MODIFY, + .value = password, + }, + }; + + if (strlen(password) > 16) { + vty_out(vty, + "%% RIPv2 authentication string must be shorter than 16\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (yang_dnode_exists(vty->candidate_config->dnode, "%s%s", + VTY_GET_XPATH, + "/frr-ripd:rip/authentication/key-chain")) { + vty_out(vty, "%% key-chain configuration exists\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return nb_cli_cfg_change(vty, NULL, changes, array_size(changes)); + } + +These two validations are not strictly necessary since the configuration +change is validated using libyang afterwards. The issue with the libyang +validation is that the error messages from libyang are too verbose: + +:: + + ripd# conf t + ripd(config)# interface eth0 + ripd(config-if)# ip rip authentication string XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + % Failed to edit candidate configuration. + + Value "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" does not satisfy the constraint "1..16" (range, length, or pattern). + Failed to create node "authentication-password" as a child of "rip". + YANG path: /frr-interface:lib/interface[name='eth0'][vrf='Default-IP-Routing-Table']/frr-ripd:rip/authentication-password + +On the other hand, the original error message from ripd is much cleaner: + +:: + + ripd# conf t + ripd(config)# interface eth0 + ripd(config-if)# ip rip authentication string XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + % RIPv2 authentication string must be shorter than 16 + +The second validation is a bit more complex. If we try to create the +``authentication/password`` leaf when the ``authentication/key-chain`` +leaf already exists (both are under a YANG *choice* statement), libyang +will automatically delete the ``authentication/key-chain`` and create +``authentication/password`` on its place. This is different from the +original ripd behavior where the *ip rip authentication key-chain* +command must be removed before configuring the *ip rip authentication +string* command. + +In the spirit of not introducing any backward-incompatible changes in +the CLI, converted commands should retain some of their validation +checks to preserve their original behavior. + +Step 6: implement the ``cli_show`` callbacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The traditional method used by FRR to display the running configuration +consists of looping through all CLI nodes all call their ``func`` +callbacks one by one, which in turn read the configuration from internal +variables and dump them to the terminal in the form of CLI commands. + +The problem with this approach is twofold. First, since the callbacks +read the configuration from internal variables, they can’t display +anything other than the running configuration. Second, they don’t have +the ability to display default values when requested by the user +(e.g. *show configuration candidate with-defaults*). + +The new northbound architecture solves these problems by introducing a +new callback: ``cli_show``. Here’s the signature of this function (taken +from the *lib/northbound.h* file): + +.. code:: c + + /* + * Optional callback to show the CLI command associated to the given + * YANG data node. + * + * vty + * the vty terminal to dump the configuration to + * + * dnode + * libyang data node that should be shown in the form of a CLI + * command + * + * show_defaults + * specify whether to display default configuration values or not. + * This parameter can be ignored most of the time since the + * northbound doesn't call this callback for default leaves or + * non-presence containers that contain only default child nodes. + * The exception are commands associated to multiple configuration + * options, in which case it might be desirable to hide one or more + * parts of the command when this parameter is set to false. + */ + void (*cli_show)(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); + +One of the main differences to the old CLI ``func`` callbacks is that +the ``cli_show`` callbacks are associated to YANG data paths and not to +CLI nodes. This means we can define one separate callback for each CLI +command, making the code more modular and easier to maintain (among +other advantages that will be more clear later). For enhanced code +readability, it’s recommended to position the ``cli_show`` callbacks +immediately after their associated command definitions (DEFPYs). + +The ``cli_show`` callbacks are used by the ``nb_cli_show_config_cmds()`` +function to display configurations stored inside ``nb_config`` +structures. The configuration being displayed can be anything from the +running configuration (*show configuration running*), a candidate +configuration (*show configuration candidate*) or a rollback +configuration (*show configuration transaction (1-4294967296)*). The +``nb_cli_show_config_cmds()`` function works by iterating over all data +nodes from the given configuration and calling the ``cli_show`` callback +for the nodes where it’s defined. If a list has dozens of entries, the +``cli_show`` callback associated to this list will be called multiple +times with the ``dnode`` parameter pointing to different list entries on +each iteration. + +For backward compatibility with the *show running-config* command, we +can’t get rid of the CLI ``func`` callbacks at this point in time. +However, we can make the CLI ``func`` callbacks call the corresponding +``cli_show`` callbacks to avoid code duplication. The +``nb_cli_show_dnode_cmds()`` function can be used for that purpose. Once +the CLI retrofitting process finishes for all FRR daemons, we can remove +the legacy CLI ``func`` callbacks and turn *show running-config* into a +shorthand for *show configuration running*. + +Regarding displaying configuration with default values, this is +something that is taken care of by the ``nb_cli_show_config_cmds()`` +function itself. When the *show configuration* command is used without +the *with-defaults* option, ``nb_cli_show_config_cmds()`` will skip +calling ``cli_show`` callbacks for data nodes that contain only default +values (e.g. default leaves or non-presence containers that contain only +default child nodes). There are however some exceptional cases where the +implementer of the ``cli_show`` callback should take into consideration +if default values should be displayed or not. This and other concepts +will be explained in more detail in the examples below. + +.. _example-1-1: + +Example 1 +^^^^^^^^^ + +Command: ``default-metric (1-16)`` + +YANG representation: + +.. code:: yang + + leaf default-metric { + type uint8 { + range "1..16"; + } + default "1"; + description + "Default metric of redistributed routes."; + } + +Placement of the ``cli_show`` callback: + +.. code:: diff + + { + .xpath = "/frr-ripd:ripd/instance/default-metric", + .cbs.modify = ripd_instance_default_metric_modify, + + .cbs.cli_show = cli_show_rip_default_metric, + }, + +Implementation of the ``cli_show`` callback: + +.. code:: c + + void cli_show_rip_default_metric(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) + { + vty_out(vty, " default-metric %s\n", + yang_dnode_get_string(dnode, NULL)); + } + +In this first example, the *default-metric* command was modeled using a +YANG leaf, and we added a new ``cli_show`` callback attached to the YANG +path of this leaf. + +The callback makes use of the ``yang_dnode_get_string()`` function to +obtain the string value of the configuration option. The following would +also be possible: + +.. code:: c + + vty_out(vty, " default-metric %u\n", + yang_dnode_get_uint8(dnode, NULL)); + +Both options are possible because libyang stores both a binary +representation and a textual representation of all values stored in a +data node (``lyd_node``). For simplicity, it’s recommended to always use +``yang_dnode_get_string()`` in the ``cli_show`` callbacks. + +.. _example-2-1: + +Example 2 +^^^^^^^^^ + +Command: ``router rip`` + +YANG representation: + +.. code:: yang + + container instance { + presence "Present if the RIP protocol is enabled."; + description + "RIP routing instance."; + [snip] + } + +Placement of the ``cli_show`` callback: + +.. code:: diff + + { + .xpath = "/frr-ripd:ripd/instance", + .cbs.create = ripd_instance_create, + .cbs.delete = ripd_instance_delete, + + .cbs.cli_show = cli_show_router_rip, + }, + +Implementation of the ``cli_show`` callback: + +.. code:: c + + void cli_show_router_rip(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) + { + vty_out(vty, "!\n"); + vty_out(vty, "router rip\n"); + } + +In this example, the ``cli_show`` callback doesn’t need to obtain any +value from the ``dnode`` parameter since presence-containers don’t hold +any data (apart from their child nodes, but they have their own +``cli_show`` callbacks). + +.. _example-3-1: + +Example 3 +^^^^^^^^^ + +Command: ``timers basic (5-2147483647) (5-2147483647) (5-2147483647)`` + +YANG representation: + +.. code:: yang + + container timers { + description + "Settings of basic timers"; + leaf flush-interval { + type uint32 { + range "5..2147483647"; + } + units "seconds"; + default "120"; + description + "Interval before a route is flushed from the routing + table."; + } + leaf holddown-interval { + type uint32 { + range "5..2147483647"; + } + units "seconds"; + default "180"; + description + "Interval before better routes are released."; + } + leaf update-interval { + type uint32 { + range "5..2147483647"; + } + units "seconds"; + default "30"; + description + "Interval at which RIP updates are sent."; + } + } + +Placement of the ``cli_show`` callback: + +.. code:: diff + + { + + .xpath = "/frr-ripd:ripd/instance/timers", + + .cbs.cli_show = cli_show_rip_timers, + + }, + + { + .xpath = "/frr-ripd:ripd/instance/timers/flush-interval", + .cbs.modify = ripd_instance_timers_flush_interval_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/timers/holddown-interval", + .cbs.modify = ripd_instance_timers_holddown_interval_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/timers/update-interval", + .cbs.modify = ripd_instance_timers_update_interval_modify, + }, + +Implementation of the ``cli_show`` callback: + +.. code:: c + + void cli_show_rip_timers(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) + { + vty_out(vty, " timers basic %s %s %s\n", + yang_dnode_get_string(dnode, "./update-interval"), + yang_dnode_get_string(dnode, "./holddown-interval"), + yang_dnode_get_string(dnode, "./flush-interval")); + } + +This command is a bit different since it changes three leaves at the +same time. This means we need to have a single ``cli_show`` callback in +order to display the three leaves together in the same line. + +The new ``cli_show_rip_timers()`` callback was added attached to the +*timers* non-presence container that groups the three leaves. Without +the *timers* non-presence container we’d need to display the *timers +basic* command inside the ``cli_show_router_rip()`` callback, which +would break our requirement of having a separate ``cli_show`` callback +for each configuration command. + +.. _example-4-1: + +Example 4 +^^^^^^^^^ + +Command: +``redistribute [{metric (0-16)|route-map WORD}]`` + +YANG representation: + +.. code:: yang + + list redistribute { + key "protocol"; + description + "Redistributes routes learned from other routing protocols."; + leaf protocol { + type frr-route-types:frr-route-types-v4; + description + "Routing protocol."; + must '. != "rip"'; + } + leaf route-map { + type string { + length "1..max"; + } + description + "Applies the conditions of the specified route-map to + routes that are redistributed into the RIP routing + instance."; + } + leaf metric { + type uint8 { + range "0..16"; + } + description + "Metric used for the redistributed route. If a metric is + not specified, the metric configured with the + default-metric attribute in RIP router configuration is + used. If the default-metric attribute has not been + configured, the default metric for redistributed routes + is 0."; + } + } + +Placement of the ``cli_show`` callback: + +.. code:: diff + + { + .xpath = "/frr-ripd:ripd/instance/redistribute", + .cbs.create = ripd_instance_redistribute_create, + .cbs.delete = ripd_instance_redistribute_delete, + + .cbs.cli_show = cli_show_rip_redistribute, + }, + { + .xpath = "/frr-ripd:ripd/instance/redistribute/route-map", + .cbs.modify = ripd_instance_redistribute_route_map_modify, + .cbs.delete = ripd_instance_redistribute_route_map_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/redistribute/metric", + .cbs.modify = ripd_instance_redistribute_metric_modify, + .cbs.delete = ripd_instance_redistribute_metric_delete, + }, + +Implementation of the ``cli_show`` callback: + +.. code:: c + + void cli_show_rip_redistribute(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) + { + vty_out(vty, " redistribute %s", + yang_dnode_get_string(dnode, "./protocol")); + if (yang_dnode_exists(dnode, "./metric")) + vty_out(vty, " metric %s", + yang_dnode_get_string(dnode, "./metric")); + if (yang_dnode_exists(dnode, "./route-map")) + vty_out(vty, " route-map %s", + yang_dnode_get_string(dnode, "./route-map")); + vty_out(vty, "\n"); + } + +Similar to the previous example, the *redistribute* command changes +several leaves at the same time, and we need a single callback to +display all leaves in a single line in accordance to the CLI command. In +this case, the leaves are already grouped by a YANG list so there’s no +need to add a non-presence container. The new ``cli_show`` callback was +attached to the YANG path of the list. + +It’s also worth noting the use of the ``yang_dnode_exists()`` function +to check if optional leaves exist in the configuration before displaying +them. + +.. _example-5-1: + +Example 5 +^^^^^^^^^ + +Command: +``ip rip authentication mode ]|text>`` + +YANG representation: + +.. code:: yang + + container authentication-scheme { + description + "Specify the authentication scheme for the RIP interface"; + leaf mode { + type enumeration { + [snip] + } + default "none"; + description + "Specify the authentication mode."; + } + leaf md5-auth-length { + when "../mode = 'md5'"; + type enumeration { + [snip] + } + default "20"; + description + "MD5 authentication data length."; + } + } + +Placement of the ``cli_show`` callback: + +.. code:: diff + + + { + + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme", + + .cbs.cli_show = cli_show_ip_rip_authentication_scheme, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/mode", + .cbs.modify = lib_interface_rip_authentication_scheme_mode_modify, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length", + .cbs.modify = lib_interface_rip_authentication_scheme_md5_auth_length_modify, + .cbs.delete = lib_interface_rip_authentication_scheme_md5_auth_length_delete, + }, + +Implementation of the ``cli_show`` callback: + +.. code:: c + + void cli_show_ip_rip_authentication_scheme(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults) + { + switch (yang_dnode_get_enum(dnode, "./mode")) { + case RIP_NO_AUTH: + vty_out(vty, " no ip rip authentication mode\n"); + break; + case RIP_AUTH_SIMPLE_PASSWORD: + vty_out(vty, " ip rip authentication mode text\n"); + break; + case RIP_AUTH_MD5: + vty_out(vty, " ip rip authentication mode md5"); + if (show_defaults + || !yang_dnode_is_default(dnode, "./md5-auth-length")) { + if (yang_dnode_get_enum(dnode, "./md5-auth-length") + == RIP_AUTH_MD5_SIZE) + vty_out(vty, " auth-length rfc"); + else + vty_out(vty, " auth-length old-ripd"); + } + vty_out(vty, "\n"); + break; + } + } + +This is the most complex ``cli_show`` callback we have in ripd. Its +complexity comes from the following: \* The +``ip rip authentication mode ...`` command changes two YANG leaves at +the same time. \* Part of the command should be hidden when the +``show_defaults`` parameter is set to false. + +This is the behavior we want to implement: + +:: + + ripd(config)# interface eth0 + ripd(config-if)# ip rip authentication mode md5 + ripd(config-if)# + ripd(config-if)# show configuration candidate + Configuration: + ! + [snip] + ! + interface eth0 + ip rip authentication mode md5 + ! + end + ripd(config-if)# + ripd(config-if)# show configuration candidate with-defaults + Configuration: + ! + [snip] + ! + interface eth0 + [snip] + ip rip authentication mode md5 auth-length old-ripd + ! + end + +Note that ``auth-length old-ripd`` should be hidden unless the +configuration is shown using the *with-defaults* option. This is why the +``cli_show_ip_rip_authentication_scheme()`` callback needs to consult +the value of the *show_defaults* parameter. It’s expected that only a +very small minority of all ``cli_show`` callbacks will need to consult +the *show_defaults* parameter (there’s a chance this might be the only +case!) + +In the case of the *timers basic* command seen before, we need to +display the value of all leaves even if only one of them has a value +different from the default. Hence the ``cli_show_rip_timers()`` callback +was able to completely ignore the *show_defaults* parameter. + +Step 7: consolidation +~~~~~~~~~~~~~~~~~~~~~ + +As mentioned in the fourth step, the northbound retrofitting process can +happen gradually over time, since both “old” and “new” commands can +coexist without problems. Once all commands from a given daemon were +converted, we can proceed to the consolidation step, which consists of +the following: \* Remove the vty configuration lock, which is enabled by +default in all daemons. Now multiple users should be able to edit the +configuration concurrently, using either shared or private candidate +configurations. \* Reference commit: +`57dccdb1 `__. +\* Stop using the qobj infrastructure to keep track of configuration +objects. This is not necessary anymore, the northbound uses a similar +mechanism to keep track of YANG data nodes in the candidate +configuration. \* Reference commit: +`4e6d63ce `__. +\* Make the daemon SIGHUP handler re-read the configuration file (and +ensure it’s not doing anything other than that). \* Reference commit: +`5e57edb4 `__. + +Final Considerations +-------------------- + +Testing +^^^^^^^ + +Converting CLI commands to the new northbound model can be a complicated +task for beginners, but the more commands one converts, the easier it +gets. It’s highly recommended to perform as much testing as possible on +the converted commands to reduce the likelihood of introducing +regressions. Tools like topotests, ANVL and the `CLI +fuzzer `__ can be used to +catch hidden bugs that might be present. As usual, it’s also recommended +to use valgrind and static code analyzers to catch other types of +problems like memory leaks. + +Amount of work +^^^^^^^^^^^^^^ + +The output below gives a rough estimate of the total number of +configuration commands that need to be converted per daemon: + +.. code:: sh + + $ for dir in lib zebra bgpd ospfd ospf6d isisd ripd ripngd eigrpd pimd pbrd ldpd nhrpd babeld ; do echo -n "$dir: " && cd $dir && grep -ERn "DEFUN|DEFPY" * | grep -Ev "clippy|show|clear" | wc -l && cd ..; done + lib: 302 + zebra: 181 + bgpd: 569 + ospfd: 198 + ospf6d: 99 + isisd: 126 + ripd: 64 + ripngd: 44 + eigrpd: 58 + pimd: 113 + pbrd: 9 + ldpd: 46 + nhrpd: 24 + babeld: 28 + +As it can be seen, the northbound retrofitting process will demand a lot +of work from FRR developers and should take months to complete. Everyone +is welcome to collaborate! diff --git a/doc/developer/northbound/transactional-cli.rst b/doc/developer/northbound/transactional-cli.rst new file mode 100644 index 000000000000..439bb6afceb1 --- /dev/null +++ b/doc/developer/northbound/transactional-cli.rst @@ -0,0 +1,244 @@ +Table of Contents +----------------- + +- `Introduction <#introduction>`__ +- `Configuration modes <#config-modes>`__ +- `New commands <#retrofitting-process>`__ + + - `commit check <#cmd1>`__ + - `commit <#cmd2>`__ + - `discard <#cmd3>`__ + - `configuration database max-transactions <#cmd4>`__ + - `configuration load <#cmd5>`__ + - `rollback configuration <#cmd6>`__ + - `show configuration candidate <#cmd7>`__ + - `show configuration compare <#cmd8>`__ + - `show configuration running <#cmd9>`__ + - `show configuration transaction <#cmd10>`__ + - `show yang module <#cmd11>`__ + - `show yang module-translator <#cmd12>`__ + - `update <#cmd13>`__ + - `yang module-translator load <#cmd14>`__ + - `yang module-translator unload <#cmd15>`__ + +Introduction +~~~~~~~~~~~~ + +All FRR daemons have built-in support for the CLI, which can be accessed +either through local telnet or via the vty socket (e.g. by using +*vtysh*). This will not change with the introduction of the Northbound +API. However, a new command-line option will be available for all FRR +daemons: ``--tcli``. When given, this option makes the daemon start with +a transactional CLI and configuration commands behave a bit different. +Instead of editing the running configuration, they will edit the +candidate configuration. In other words, the configuration commands +won’t be applied immediately, that has to be done on a separate step +using the new ``commit`` command. + +The transactional CLI simply leverages the new capabilities provided by +the Northbound API and exposes the concept of candidate configurations +to CLI users too. When the transactional mode is not used, the +configuration commands also edit the candidate configuration, but +there’s an implicit ``commit`` after each command. + +In order for the transactional CLI to work, all configuration commands +need to be converted to the new northbound model. Commands not converted +to the new northbound model will change the running configuration +directly since they bypass the FRR northbound layer. For this reason, +starting a daemon with the transactional CLI is not advisable unless all +of its commands have already been converted. When that’s not the case, +we can run into a situation like this: + +:: + + ospfd(config)# router ospf + ospfd(config-router)# ospf router-id 1.1.1.1 + [segfault in ospfd] + +The segfault above can happen if ``router ospf`` edits the candidate +configuration but ``ospf router-id 1.1.1.1`` edits the running +configuration. The second command tries to set +``ospf->router_id_static`` but, since the previous ``router ospf`` +command hasn’t been commited yet, the ``ospf`` global variable is set to +NULL, which leads to the crash. Besides this problem, having a set of +commands that edit the candidate configuration and others that edit the +running configuration is confusing at best. The ``--tcli`` option should +be used only by developers until the northbound retrofitting process is +complete. + +Configuration modes +~~~~~~~~~~~~~~~~~~~ + +When using the transactional CLI (``--tcli``), FRR supports three +different forms of the ``configure`` command: \* ``configure terminal``: +in this mode, a single candidate configuration is shared by all users. +This means that one user might delete a configuration object that’s +being edited by another user, in which case the CLI will detect and +report the problem. If one user issues the ``commit`` command, all +changes done by all users are committed. \* ``configure private``: users +have a private candidate configuration that is edited separately from +the other users. The ``commit`` command commits only the changes done by +the user. \* ``configure exclusive``: similar to ``configure private``, +but also locks the running configuration to prevent other users from +changing it. The configuration lock is released when the user exits the +configuration mode. + +When using ``configure terminal`` or ``configure private``, the +candidate configuration being edited might become outdated if another +user commits a different candidate configuration on another session. +TODO: show image to illustrate the problem. + +New commands +~~~~~~~~~~~~ + +The list below contains the new CLI commands introduced by Northbound +API. The commands are available when a daemon is started using the +transactional CLI (``--tcli``). Currently ``vtysh`` doesn’t support any +of these new commands. + +Please refer to the [[Demos]] page to see a demo of the transactional +CLI in action. + +-------------- + +``commit check`` +'''''''''''''''' + +Check if the candidate configuration is valid or not. + +``commit [force] [comment LINE...]`` +'''''''''''''''''''''''''''''''''''' + +Commit the changes done in the candidate configuration into the running +configuration. + +Options: \* ``force``: commit even if the candidate configuration is +outdated. It’s usually a better option to use the ``update`` command +instead. \* ``comment LINE...``: assign a comment to the configuration +transaction. This comment is displayed when viewing the recorded +transactions in the output of the ``show configuration transaction`` +command. + +``discard`` +''''''''''' + +Discard the changes done in the candidate configuration. + +``configuration database max-transactions (1-100)`` +''''''''''''''''''''''''''''''''''''''''''''''''''' + +Set the maximum number of transactions to store in the rollback log. + +``configuration load [translate WORD]] FILENAME|transaction (1-4294967296)> [replace]`` +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Load a new configuration into the candidate configuration. When loading +the configuration from a file, it’s assumed that the configuration will +be in the form of CLI commands by default. The ``json`` and ``xml`` +options can be used to load configurations in the JSON and XML formats, +respectively. It’s also possible to load a configuration from a previous +transaction by specifying the desired transaction ID +(``(1-4294967296)``). + +Options: \* ``translate WORD``: translate the JSON/XML configuration +file using the YANG module translator. \* ``replace``: replace the +candidate by the loaded configuration. The default is to merge the +loaded configuration into the candidate configuration. + +``rollback configuration (1-4294967296)`` +''''''''''''''''''''''''''''''''''''''''' + +Roll back the running configuration to a previous configuration +identified by its transaction ID (``(1-4294967296)``). + +``show configuration candidate [ [translate WORD]] []`` +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Show the candidate configuration. + +Options: \* ``json``: show the configuration in the JSON format. \* +``xml``: show the configuration in the XML format. \* +``translate WORD``: translate the JSON/XML output using the YANG module +translator. \* ``with-defaults``: show default values that are hidden by +default. \* ``changes``: show only the changes done in the candidate +configuration. + +``show configuration compare [ [translate WORD]]`` +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Show the difference between two different configurations. + +Options: \* ``json``: show the configuration differences in the JSON +format. \* ``xml``: show the configuration differences in the XML +format. \* ``translate WORD``: translate the JSON/XML output using the +YANG module translator. + +``show configuration running [ [translate WORD]] [with-defaults]`` +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Show the running configuration. + +Options: \* ``json``: show the configuration in the JSON format. \* +``xml``: show the configuration in the XML format. \* +``translate WORD``: translate the JSON/XML output using the YANG module +translator. \* ``with-defaults``: show default values that are hidden by +default. + + NOTE: ``show configuration running`` shows only the running + configuration as known by the northbound layer. Configuration + commands not converted to the new northbound model will not be + displayed. To show the full running configuration, the legacy + ``show running-config`` command must be used. + +``show configuration transaction [(1-4294967296) [ [translate WORD]] [changes]]`` +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +When a transaction ID (``(1-4294967296)``) is given, show the +configuration associated to the previously committed transaction. + +When a transaction ID is not given, show all recorded transactions in +the rollback log. + +Options: \* ``json``: show the configuration in the JSON format. \* +``xml``: show the configuration in the XML format. \* +``translate WORD``: translate the JSON/XML output using the YANG module +translator. \* ``with-defaults``: show default values that are hidden by +default. \* ``changes``: show changes compared to the previous +transaction. + +``show yang module [module-translator WORD] [WORD ]`` +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +When a YANG module is not given, show all loaded YANG modules. +Otherwise, show detailed information about the given module. + +Options: \* ``module-translator WORD``: change the context to modules +loaded by the specified YANG module translator. \* ``summary``: display +summary information about the module. \* ``tree``: display module in the +tree (RFC 8340) format. \* ``yang``: display module in the YANG format. +\* ``yin``: display module in the YIN format. + +``show yang module-translator`` +''''''''''''''''''''''''''''''' + +Show all loaded YANG module translators. + +``update`` +'''''''''' + +Rebase the candidate configuration on top of the latest running +configuration. Conflicts are resolved automatically by giving preference +to the changes done in the candidate configuration. + +The candidate configuration might be outdated if the running +configuration was updated after the candidate was created. + +``yang module-translator load FILENAME`` +'''''''''''''''''''''''''''''''''''''''' + +Load a YANG module translator from the filesystem. + +``yang module-translator unload WORD`` +'''''''''''''''''''''''''''''''''''''' + +Unload a YANG module translator identified by its name. diff --git a/doc/developer/northbound/yang-module-translator.rst b/doc/developer/northbound/yang-module-translator.rst new file mode 100644 index 000000000000..aa527ce6b272 --- /dev/null +++ b/doc/developer/northbound/yang-module-translator.rst @@ -0,0 +1,629 @@ +Table of Contents +----------------- + +- `Introduction <#introduction>`__ +- `Deviation Modules <#deviation-modules>`__ +- `Translation Tables <#translation-tables>`__ +- `CLI Demonstration <#cli-demonstration>`__ +- `Implementation Details <#implementation-details>`__ + +Introduction +------------ + +One key requirement for the FRR northbound architecture is that it +should be possible to configure/monitor FRR using different sets of YANG +models. This is especially important considering that the industry +hasn’t reached a consensus to provide a single source of standard models +for network management. At this moment both the IETF and OpenConfig +models are widely implemented and are unlikely to converge, at least not +in the short term. In the ideal scenario, management applications should +be able to use either IETF or OpenConfig models to configure and monitor +FRR programatically (or even both at the same time!). + +But how can FRR support multiple sets of YANG models at the same time? +There must be only a single source of truth that models the existing +implementation accurately (the native models). Writing different code +paths or callbacks for different models would be inviable, it would lead +to a lot of duplicated code and extra maintenance overhead. + +In order to support different sets of YANG modules without introducing +the overhead of writing additional code, the solution is to create a +mechanism that dynamically translates YANG instance data between +non-native models to native models and vice-versa. Based on this idea, +an experimental YANG module translator was implemented within the FRR +northbound layer. The translator works by translating XPaths at runtime +using translation tables provided by the user. The translator itself is +modeled using YANG and users can create translators using simple JSON +files. + +A YANG module translator consists of two components: deviation modules +and translation tables. + +Deviation Modules +----------------- + +The first step when writing a YANG module translator is to create a +`deviations `__ module for +each module that is going be translated. This is necessary because in +most cases it won’t be possible to create a perfect translator that +covers the non-native models on their entirety. Some non-native modules +might contain nodes that can’t be mapped to a corresponding node in the +FRR native models. This is either because the corresponding +functionality is not implemented in FRR or because it’s modeled in a +different way that is incompatible. + +An an example, *ripd* doesn’t have BFD support yet, so we need to create +a YANG deviation to modify the *ietf-rip* module and remove the ``bfd`` +container from it: + +.. code:: yang + + deviation "/ietf-routing:routing/ietf-routing:control-plane-protocols/ietf-routing:control-plane-protocol/ietf-rip:rip/ietf-rip:interfaces/ietf-rip:interface/ietf-rip:bfd" { + deviate not-supported; + } + +In the example below, while both the *frr-ripd* and *ietf-rip* modules +support RIP authentication, they model the authentication data in +different ways, making translation not possible given the constraints of +the current module translator. A new deviation is necessary to remove +the ``authentication`` container from the *ietf-rip* module: + +.. code:: yang + + deviation "/ietf-routing:routing/ietf-routing:control-plane-protocols/ietf-routing:control-plane-protocol/ietf-rip:rip/ietf-rip:interfaces/ietf-rip:interface/ietf-rip:authentication" { + deviate not-supported; + } + +.. + + NOTE: it should be possible to translate the + ``ietf-rip:authentication`` container if the *frr-ripd* module is + modified to model the corresponding data in a compatible way. Another + option is to improve the module translator to make more complex + translations possible, instead of requiring one-to-one XPath + mappings. + +Sometimes creating a mapping between nodes from the native and +non-native models is possible, but the nodes have different properties +that need to be normalized to allow the translation. In the example +below, a YANG deviation is used to change the type and the default value +from a node from the ``ietf-rip`` module. + +.. code:: yang + + deviation "/ietf-routing:routing/ietf-routing:control-plane-protocols/ietf-routing:control-plane-protocol/ietf-rip:rip/ietf-rip:timers/ietf-rip:flush-interval" { + deviate replace { + default "120"; + } + deviate replace { + type uint32; + } + } + +The deviation modules allow the management applications to know which +parts of the custom modules (e.g. IETF/OC) can be used to configure and +monitor FRR. + +In order to facilitate the process of creating YANG deviation modules, +the *gen_yang_deviations* tool was created to automate part of the +process. This tool creates a “not-supported” deviation for all nodes +from the given non-native module. Example: + +:: + + $ tools/gen_yang_deviations ietf-rip > yang/ietf/frr-deviations-ietf-rip.yang + $ head -n 40 yang/ietf/frr-deviations-ietf-rip.yang + deviation "/ietf-rip:clear-rip-route" { + deviate not-supported; + } + + deviation "/ietf-rip:clear-rip-route/ietf-rip:input" { + deviate not-supported; + } + + deviation "/ietf-rip:clear-rip-route/ietf-rip:input/ietf-rip:rip-instance" { + deviate not-supported; + } + + deviation "/ietf-routing:routing/ietf-routing:control-plane-protocols/ietf-routing:control-plane-protocol/ietf-rip:rip" { + deviate not-supported; + } + + deviation "/ietf-routing:routing/ietf-routing:control-plane-protocols/ietf-routing:control-plane-protocol/ietf-rip:rip/ietf-rip:originate-default-route" { + deviate not-supported; + } + + deviation "/ietf-routing:routing/ietf-routing:control-plane-protocols/ietf-routing:control-plane-protocol/ietf-rip:rip/ietf-rip:originate-default-route/ietf-rip:enabled" { + deviate not-supported; + } + + deviation "/ietf-routing:routing/ietf-routing:control-plane-protocols/ietf-routing:control-plane-protocol/ietf-rip:rip/ietf-rip:originate-default-route/ietf-rip:route-policy" { + deviate not-supported; + } + + deviation "/ietf-routing:routing/ietf-routing:control-plane-protocols/ietf-routing:control-plane-protocol/ietf-rip:rip/ietf-rip:default-metric" { + deviate not-supported; + } + + deviation "/ietf-routing:routing/ietf-routing:control-plane-protocols/ietf-routing:control-plane-protocol/ietf-rip:rip/ietf-rip:distance" { + deviate not-supported; + } + + deviation "/ietf-routing:routing/ietf-routing:control-plane-protocols/ietf-routing:control-plane-protocol/ietf-rip:rip/ietf-rip:triggered-update-threshold" { + deviate not-supported; + } + +Once all existing nodes are listed in the deviation module, it’s easy to +check the deviations that need to be removed or modified. This is more +convenient than starting with a blank deviations module and listing +manually all nodes that need to be deviated. + +After removing and/or modifying the auto-generated deviations, the next +step is to write the module XPath translation table as we’ll see in the +next section. Before that, it’s possible to use the *yanglint* tool to +check how the non-native module looks like after applying the +deviations. Example: + +:: + + $ yanglint -f tree yang/ietf/ietf-rip@2018-02-03.yang yang/ietf/frr-deviations-ietf-rip.yang + module: ietf-rip + + augment /ietf-routing:routing/ietf-routing:control-plane-protocols/ietf-routing:control-plane-protocol: + +--rw rip + +--rw originate-default-route + | +--rw enabled? boolean + +--rw default-metric? uint8 <1> + +--rw distance? uint8 <0> + +--rw timers + | +--rw update-interval? uint32 <30> + | +--rw holddown-interval? uint32 <180> + | +--rw flush-interval? uint32 <120> + +--rw interfaces + | +--rw interface* [interface] + | +--rw interface ietf-interfaces:interface-ref + | +--rw split-horizon? enumeration + +--ro ipv4 + +--ro neighbors + | +--ro neighbor* [ipv4-address] + | +--ro ipv4-address ietf-inet-types:ipv4-address + | +--ro last-update? ietf-yang-types:date-and-time + | +--ro bad-packets-rcvd? ietf-yang-types:counter32 + | +--ro bad-routes-rcvd? ietf-yang-types:counter32 + +--ro routes + +--ro route* [ipv4-prefix] + +--ro ipv4-prefix ietf-inet-types:ipv4-prefix + +--ro next-hop? ietf-inet-types:ipv4-address + +--ro interface? ietf-interfaces:interface-ref + +--ro metric? uint8 + + rpcs: + +---x clear-rip-route + +.. + + NOTE: the same output can be obtained using the + ``show yang module module-translator ietf ietf-rip tree`` command in + FRR once the *ietf* module translator is loaded. + +In the example above, it can be seen that the vast majority of the +*ietf-rip* nodes were removed because of the “not-supported” deviations. +When a module translator is loaded, FRR calculates the coverage of the +translator by dividing the number of YANG nodes before applying the +deviations by the number of YANG nodes after applying the deviations. +The calculated coverage is displayed in the output of the +``show yang module-translator`` command: + +:: + + ripd# show yang module-translator + Family Module Deviations Coverage (%) + ----------------------------------------------------------------------- + ietf ietf-interfaces frr-deviations-ietf-interfaces 3.92 + ietf ietf-routing frr-deviations-ietf-routing 1.56 + ietf ietf-rip frr-deviations-ietf-rip 13.60 + +As it can be seen in the output above, the *ietf* module translator +covers only ~13% of the original *ietf-rip* module. This is in part +because the *ietf-rip* module models both RIPv2 and RIPng. Also, +*ietf-rip.yang* contains several knobs that aren’t implemented in *ripd* +yet (e.g. BFD support, per-interface timers, statistics, etc). Work can +be done over time to increase the coverage to a more reasonable number. + +Translation Tables +------------------ + +Below is an example of a translator for the IETF family of models: + +.. code:: json + + { + "frr-module-translator:frr-module-translator": { + "family": "ietf", + "module": [ + { + "name": "ietf-interfaces@2018-01-09", + "deviations": "frr-deviations-ietf-interfaces", + "mappings": [ + { + "custom": "/ietf-interfaces:interfaces/interface[name='KEY1']", + "native": "/frr-interface:lib/interface[name='KEY1'][vrf='default']" + }, + { + "custom": "/ietf-interfaces:interfaces/interface[name='KEY1']/description", + "native": "/frr-interface:lib/interface[name='KEY1'][vrf='default']/description" + } + ] + }, + { + "name": "ietf-routing@2018-01-25", + "deviations": "frr-deviations-ietf-routing", + "mappings": [ + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']", + "native": "/frr-ripd:ripd/instance" + } + ] + }, + { + "name": "ietf-rip@2018-02-03", + "deviations": "frr-deviations-ietf-rip", + "mappings": [ + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/default-metric", + "native": "/frr-ripd:ripd/instance/default-metric" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/distance", + "native": "/frr-ripd:ripd/instance/distance/default" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/originate-default-route/enabled", + "native": "/frr-ripd:ripd/instance/default-information-originate" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/update-interval", + "native": "/frr-ripd:ripd/instance/timers/update-interval" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/holddown-interval", + "native": "/frr-ripd:ripd/instance/timers/holddown-interval" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/flush-interval", + "native": "/frr-ripd:ripd/instance/timers/flush-interval" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/interfaces/interface[interface='KEY1']", + "native": "/frr-ripd:ripd/instance/interface[.='KEY1']" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/interfaces/interface[interface='KEY1']/split-horizon", + "native": "/frr-interface:lib/interface[name='KEY1'][vrf='default']/frr-ripd:rip/split-horizon" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']", + "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/last-update", + "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/last-update" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/bad-packets-rcvd", + "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/bad-packets-rcvd" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/bad-routes-rcvd", + "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/bad-routes-rcvd" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']", + "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/next-hop", + "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/next-hop" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/interface", + "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/interface" + }, + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/metric", + "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/metric" + }, + { + "custom": "/ietf-rip:clear-rip-route", + "native": "/frr-ripd:clear-rip-route" + } + ] + } + ] + } + } + +The main motivation to use YANG itself to model YANG module translators +was a practical one: leverage *libyang* to validate the structure of the +user input (JSON files) instead of doing that manually in the +*lib/yang_translator.c* file (tedious and error-prone work). + +Module translators can be loaded using the following CLI command: + +:: + + ripd(config)# yang module-translator load /usr/local/share/yang/ietf/frr-ietf-translator.json + % Module translator "ietf" loaded successfully. + +Module translators can also be loaded/unloaded programatically using the +``yang_translator_load()/yang_translator_unload()`` functions within the +northbound plugins. These functions are documented in the +*lib/yang_translator.h* file. + +Each module translator must be assigned a “family” identifier +(e.g. IETF, OpenConfig), and can contain mappings for multiple +interrelated YANG modules. The mappings consist of pairs of +custom/native XPath expressions that should be equivalent, despite +belonging to different YANG modules. + +Example: + +.. code:: json + + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/default-metric", + "native": "/frr-ripd:ripd/instance/default-metric" + }, + +The nodes pointed by the custom and native XPaths must have compatible +types. In the case of the example above, both nodes point to a YANG leaf +of type ``uint8``, so the mapping is valid. + +In the example below, the “custom” XPath points to a YANG list +(typeless), and the “native” XPath points to a YANG leaf-list of +strings. In this exceptional case, the types are also considered to be +compatible. + +.. code:: json + + { + "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/interfaces/interface[interface='KEY1']", + "native": "/frr-ripd:ripd/instance/interface[.='KEY1']" + }, + +The ``KEY1..KEY4`` values have a special meaning and are used to +preserve the list keys while performing the XPath translation. + +Once a YANG module translator is loaded and validated at a syntactic +level using *libyang*, further validations are performed to check for +missing mappings (after loading the deviation modules) and incompatible +YANG types. Example: + +:: + + ripd(config)# yang module-translator load /usr/local/share/yang/ietf/frr-ietf-translator.json + % Failed to load "/usr/local/share/yang/ietf/frr-ietf-translator.json" + + Please check the logs for more details. + +:: + + 2018/09/03 15:18:45 RIP: yang_translator_validate_cb: YANG types are incompatible (xpath: "/ietf-routing:routing/control-plane-protocols/control-plane-protocol/ietf-rip:rip/default-metric") + 2018/09/03 15:18:45 RIP: yang_translator_validate_cb: missing mapping for "/ietf-routing:routing/control-plane-protocols/control-plane-protocol/ietf-rip:rip/distance" + 2018/09/03 15:18:45 RIP: yang_translator_validate: failed to validate "ietf" module translator: 2 error(s) + +Overall, this translation mechanism based on XPath mappings is simple +and functional, but only to a certain extent. The native models need to +be reasonably similar to the models that are going be translated, +otherwise the translation is compromised and a good coverage can’t be +achieved. Other translation techniques must be investigated to address +this shortcoming and make it possible to create more powerful YANG +module translators. + +YANG module translators can be evaluated based on the following metrics: +\* Translation potential: is it possible to make complex translations, +taking several variables into account? \* Complexity: measure of how +easy or hard it is to write a module translator. \* Speed: measure of +how fast the translation can be achieved. Translation speed is of +fundamental importance, especially for operational data. \* Robustness: +can the translator be checked for inconsistencies at load time? A module +translator based on scripts wouldn’t fare well on this metric. \* +Round-trip conversions: can the translated data be translated back to +the original format without information loss? + +CLI Demonstration +----------------- + +As of now the only northbound client that supports the YANG module +translator is the FRR embedded CLI. The confd and sysrepo plugins need +to be extended to support the module translator, which might be used not +only for configuration data, but also for operational data, RPCs and +notifications. + +In this demonstration, we’ll use the CLI ``configuration load`` command +to load the following JSON configuration file specified using the IETF +data hierarchy: + +.. code:: json + + { + "ietf-interfaces:interfaces": { + "interface": [ + { + "description": "Engineering", + "name": "eth0" + } + ] + }, + "ietf-routing:routing": { + "control-plane-protocols": { + "control-plane-protocol": [ + { + "name": "main", + "type": "ietf-rip:ripv2", + "ietf-rip:rip": { + "default-metric": "2", + "distance": "80", + "interfaces": { + "interface": [ + { + "interface": "eth0", + "split-horizon": "poison-reverse" + } + ] + }, + "originate-default-route": { + "enabled": "true" + }, + "timers": { + "flush-interval": "241", + "holddown-interval": "181", + "update-interval": "31" + } + } + } + ] + } + } + } + +In order to load this configuration file, it’s necessary to load the +IETF module translator first. Then, when entering the +``configuration load`` command, the ``translate ietf`` parameters must +be given to specify that the input needs to be translated using the +previously loaded ``ietf`` module translator. Example: + +:: + + ripd(config)# configuration load file json /mnt/renato/git/frr/yang/example/ietf-rip.json + % Failed to load configuration: + + Unknown element "interfaces". + ripd(config)# + ripd(config)# yang module-translator load /usr/local/share/yang/ietf/frr-ietf-translator.json + % Module translator "ietf" loaded successfully. + + ripd(config)# + ripd(config)# configuration load file json translate ietf /mnt/renato/git/frr/yang/example/ietf-rip.json + +Now let’s check the candidate configuration to see if the configuration +file was loaded successfully: + +:: + + ripd(config)# show configuration candidate + Configuration: + ! + frr version 5.1-dev + frr defaults traditional + ! + interface eth0 + description Engineering + ip rip split-horizon poisoned-reverse + ! + router rip + default-metric 2 + distance 80 + network eth0 + default-information originate + timers basic 31 181 241 + ! + end + ripd(config)# show configuration candidate json + { + "frr-interface:lib": { + "interface": [ + { + "name": "eth0", + "vrf": "default", + "description": "Engineering", + "frr-ripd:rip": { + "split-horizon": "poison-reverse" + } + } + ] + }, + "frr-ripd:ripd": { + "instance": { + "default-metric": 2, + "distance": { + "default": 80 + }, + "interface": [ + "eth0" + ], + "default-information-originate": true, + "timers": { + "flush-interval": 241, + "holddown-interval": 181, + "update-interval": 31 + } + } + } + } + +As it can be seen, the candidate configuration is identical to the one +defined in the *ietf-rip.json* file, only the structure is different. +This means that the *ietf-rip.json* file was translated successfully. + +The ``ietf`` module translator can also be used to do the translation in +other direction: transform data from the native format to the IETF +format. This is shown below by altering the output of the +``show configuration candidate json`` command using the +``translate ietf`` parameter: + +:: + + ripd(config)# show configuration candidate json translate ietf + { + "ietf-interfaces:interfaces": { + "interface": [ + { + "name": "eth0", + "description": "Engineering" + } + ] + }, + "ietf-routing:routing": { + "control-plane-protocols": { + "control-plane-protocol": [ + { + "type": "ietf-rip:ripv2", + "name": "main", + "ietf-rip:rip": { + "interfaces": { + "interface": [ + { + "interface": "eth0", + "split-horizon": "poison-reverse" + } + ] + }, + "default-metric": 2, + "distance": 80, + "originate-default-route": { + "enabled": true + }, + "timers": { + "flush-interval": 241, + "holddown-interval": 181, + "update-interval": 31 + } + } + } + ] + } + } + } + +As expected, this output is exactly identical to the configuration +defined in the *ietf-rip.json* file. The module translator was able to +do a round-trip conversion without information loss. + +Implementation Details +---------------------- + +A different libyang context is allocated for each YANG module +translator. This is important to avoid collisions and ensure that +non-native data can’t be instantiated in the running and candidate +configurations. diff --git a/doc/developer/northbound/yang-tools.rst b/doc/developer/northbound/yang-tools.rst new file mode 100644 index 000000000000..4eb1a2fb2cb4 --- /dev/null +++ b/doc/developer/northbound/yang-tools.rst @@ -0,0 +1,106 @@ +yanglint cheat sheet +~~~~~~~~~~~~~~~~~~~~ + + libyang project includes a feature-rich tool called yanglint(1) for + validation and conversion of the schemas and YANG modeled data. The + source codes are located at /tools/lint and can be used to explore + how an application is supposed to use the libyang library. + yanglint(1) binary as well as its man page are installed together + with the library itself. + +Validate a YANG module: + +.. code:: sh + + $ yanglint -p module.yang + +Generate tree representation of a YANG module: + +.. code:: sh + + $ yanglint -p -f tree module.yang + +Validate JSON/XML instance data: + +.. code:: sh + + $ yanglint -p module.yang data.{json,xml} + +Convert JSON/XML instance data to another format: + +.. code:: sh + + $ yanglint -p -f xml module.yang data.json + $ yanglint -p -f json module.yang data.xml + +*yanglint* also features an interactive mode which is very useful when +needing to validate data from multiple modules at the same time. The +*yanglint* README provides several examples: +https://github.com/CESNET/libyang/blob/master/tools/lint/examples/README.md + +Man page (groff): +https://github.com/CESNET/libyang/blob/master/tools/lint/yanglint.1 + +pyang cheat sheet +~~~~~~~~~~~~~~~~~ + + pyang is a YANG validator, transformator and code generator, written + in python. It can be used to validate YANG modules for correctness, + to transform YANG modules into other formats, and to generate code + from the modules. + +Obtaining and installing pyang: + +.. code:: sh + + $ git clone https://github.com/mbj4668/pyang.git + $ cd pyang/ + $ sudo python setup.py install + +Validate a YANG module: + +.. code:: sh + + $ pyang --ietf -p module.yang + +Generate tree representation of a YANG module: + +.. code:: sh + + $ pyang -f tree -p module.yang + +Indent a YANG file: + +.. code:: sh + + $ pyang -p \ + --keep-comments -f yang --yang-canonical \ + module.yang -o module.yang + +Generate skeleton instance data: \* XML: + +.. code:: sh + + $ pyang -p \ + -f sample-xml-skeleton --sample-xml-skeleton-defaults \ + module.yang [augmented-module1.yang ...] -o module.xml + +- JSON: + +.. code:: sh + + $ pyang -p \ + -f jsonxsl module.yang -o module.xsl + $ xsltproc -o module.json module.xsl module.xml + +Validate XML instance data (works only with YANG 1.0): + +.. code:: sh + + $ yang2dsdl -v module.xml module.yang + +vim +~~~ + +YANG syntax highlighting for vim: +https://github.com/nathanalderson/yang.vim diff --git a/doc/developer/ospf.rst b/doc/developer/ospf.rst index a5164d552a18..837a0bd18598 100644 --- a/doc/developer/ospf.rst +++ b/doc/developer/ospf.rst @@ -9,4 +9,5 @@ OSPFD ospf-api ospf-sr + cspf diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index 840afa9f74fc..0deb0f5da089 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -11,6 +11,7 @@ dev_RSTFILES = \ doc/developer/building-frr-for-centos7.rst \ doc/developer/building-frr-for-debian8.rst \ doc/developer/building-frr-for-debian9.rst \ + doc/developer/building-frr-for-debian12.rst \ doc/developer/building-frr-for-fedora.rst \ doc/developer/building-frr-for-freebsd10.rst \ doc/developer/building-frr-for-freebsd11.rst \ @@ -67,6 +68,19 @@ dev_RSTFILES = \ doc/developer/workflow.rst \ doc/developer/xrefs.rst \ doc/developer/zebra.rst \ + doc/developer/northbound/advanced-topics.rst \ + doc/developer/northbound/architecture.rst \ + doc/developer/northbound/demos.rst \ + doc/developer/northbound/links.rst \ + doc/developer/northbound/northbound.rst \ + doc/developer/northbound/operational-data-rpcs-and-notifications.rst \ + doc/developer/northbound/plugins-sysrepo.rst \ + doc/developer/northbound/ppr-basic-test-topology.rst \ + doc/developer/northbound/ppr-mpls-basic-test-topology.rst \ + doc/developer/northbound/retrofitting-configuration-commands.rst \ + doc/developer/northbound/transactional-cli.rst \ + doc/developer/northbound/yang-module-translator.rst \ + doc/developer/northbound/yang-tools.rst \ # end EXTRA_DIST += \ diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index 87edad40bb58..0e4f05ed0041 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -472,8 +472,8 @@ For each capture a window is opened displaying a live summary of the captured packets. Additionally, the entire packet stream is captured in a pcap file in the tests log directory e.g.,:: -When using a unified log file `frr.log` one substitutes `frr` for the daemon -name in the ``--logd`` CLI option, e.g., +When using a unified log file ``frr.log`` one substitutes ``frr`` for the +daemon name in the ``--logd`` CLI option, e.g., .. code:: shell @@ -617,6 +617,8 @@ allocations upon exit. To enable also reporting of memory leaks to a specific location, define an environment variable ``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.: +:: + export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" For tests that support the TOPOTESTS_CHECK_MEMLEAK environment variable, this diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 5199d42db312..68834ed71096 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -167,28 +167,26 @@ as early as possible, i.e. the first 2-week window. For reference, the expected release schedule according to the above is: +---------+------------+------------+------------+ -| Release | 2023-07-04 | 2023-10-31 | 2024-02-27 | +| Release | 2023-11-07 | 2024-03-05 | 2024-07-02 | +---------+------------+------------+------------+ -| RC | 2023-06-20 | 2023-10-17 | 2024-02-13 | +| RC | 2023-10-24 | 2024-02-20 | 2024-06-18 | +---------+------------+------------+------------+ -| dev/X.Y | 2023-06-06 | 2023-10-03 | 2024-01-30 | +| dev/X.Y | 2023-10-10 | 2024-02-06 | 2024-06-04 | +---------+------------+------------+------------+ -| freeze | 2023-05-23 | 2023-09-19 | 2024-01-16 | +| freeze | 2023-09-26 | 2024-01-23 | 2024-05-21 | +---------+------------+------------+------------+ Here is the hint on how to get the dates easily: .. code-block:: console - ~$ # Last freeze date was 2023-09-19 - ~$ date +%F --date='2023-09-19 +119 days' # Next freeze date - 2024-01-16 - ~$ date +%F --date='2024-01-16 +14 days' # Next dev/X.Y date - 2024-01-30 - ~$ date +%F --date='2024-01-30 +14 days' # Next RC date - 2024-02-13 - ~$ date +%F --date='2024-02-13 +14 days' # Next Release date - 2024-02-27 + ~$ # Release date is 2023-11-07 (First Tuesday each March/July/November) + ~$ date +%F --date='2023-11-07 -42 days' # Next freeze date + 2023-09-26 + ~$ date +%F --date='2023-11-07 -28 days' # Next dev/X.Y date + 2023-10-10 + ~$ date +%F --date='2023-11-07 -14 days' # Next RC date + 2023-10-24 Each release is managed by one or more volunteer release managers from the FRR community. These release managers are expected to handle the branch for a period @@ -819,6 +817,7 @@ The project provides multiple tools to allow you to correctly style your code as painlessly as possible, primarily built around ``clang-format``. clang-format + In the project root there is a :file:`.clang-format` configuration file which can be used with the ``clang-format`` source formatter tool from the LLVM project. Most of the time, this is the easiest and smartest tool to @@ -877,6 +876,8 @@ clang-format checkpatch.sh checkpatch.pl + .. seealso:: :ref:`checkpatch` + In the Linux kernel source tree there is a Perl script used to check incoming patches for style errors. FRR uses a shell script front end and an adapted version of the perl script for the same purpose. These scripts can @@ -1353,12 +1354,12 @@ Coverity static analysis errors prior to submission using the be installed. For example, this can be accomplished on Ubuntu with the ``sudo apt-get install clang-tools`` command. Then, touch the files you want scanned and invoke the ``scan-build`` command. For example:: - + cd ~/GitHub/frr touch ospfd/ospf_flood.c ospfd/ospf_vty.c ospfd/ospf_opaque.c cd build scan-build make -j32 - + The results of the scan including any static analysis errors will appear inline. Additionally, there will a directory in the /tmp containing the Coverity reports (e.g., scan-build-2023-06-09-120100-473730-1). diff --git a/doc/developer/zebra.rst b/doc/developer/zebra.rst index 5f039758a5ee..be2952e71a5a 100644 --- a/doc/developer/zebra.rst +++ b/doc/developer/zebra.rst @@ -159,229 +159,7 @@ Past Versions Zebra Protocol Commands ----------------------- -+------------------------------------+-------+ -| Command | Value | -+====================================+=======+ -| ZEBRA_INTERFACE_ADD | 0 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_DELETE | 1 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_ADDRESS_ADD | 2 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_ADDRESS_DELETE | 3 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_UP | 4 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_DOWN | 5 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_SET_MASTER | 6 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_SET_PROTODOWN | 7 | -+------------------------------------+-------+ -| ZEBRA_ROUTE_ADD | 8 | -+------------------------------------+-------+ -| ZEBRA_ROUTE_DELETE | 9 | -+------------------------------------+-------+ -| ZEBRA_ROUTE_NOTIFY_OWNER | 10 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_ADD | 11 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_DELETE | 12 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_DEFAULT_ADD | 13 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_DEFAULT_DELETE | 14 | -+------------------------------------+-------+ -| ZEBRA_ROUTER_ID_ADD | 15 | -+------------------------------------+-------+ -| ZEBRA_ROUTER_ID_DELETE | 16 | -+------------------------------------+-------+ -| ZEBRA_ROUTER_ID_UPDATE | 17 | -+------------------------------------+-------+ -| ZEBRA_HELLO | 18 | -+------------------------------------+-------+ -| ZEBRA_CAPABILITIES | 19 | -+------------------------------------+-------+ -| ZEBRA_NEXTHOP_REGISTER | 20 | -+------------------------------------+-------+ -| ZEBRA_NEXTHOP_UNREGISTER | 21 | -+------------------------------------+-------+ -| ZEBRA_NEXTHOP_UPDATE | 22 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_NBR_ADDRESS_ADD | 23 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_NBR_ADDRESS_DELETE | 24 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_BFD_DEST_UPDATE | 25 | -+------------------------------------+-------+ -| ZEBRA_IMPORT_ROUTE_REGISTER | 26 | -+------------------------------------+-------+ -| ZEBRA_IMPORT_ROUTE_UNREGISTER | 27 | -+------------------------------------+-------+ -| ZEBRA_BFD_DEST_REGISTER | 29 | -+------------------------------------+-------+ -| ZEBRA_BFD_DEST_DEREGISTER | 30 | -+------------------------------------+-------+ -| ZEBRA_BFD_DEST_UPDATE | 31 | -+------------------------------------+-------+ -| ZEBRA_BFD_DEST_REPLAY | 32 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_ROUTE_ADD | 33 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_ROUTE_DEL | 34 | -+------------------------------------+-------+ -| ZEBRA_VRF_UNREGISTER | 35 | -+------------------------------------+-------+ -| ZEBRA_VRF_ADD | 36 | -+------------------------------------+-------+ -| ZEBRA_VRF_DELETE | 37 | -+------------------------------------+-------+ -| ZEBRA_VRF_LABEL | 38 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_VRF_UPDATE | 39 | -+------------------------------------+-------+ -| ZEBRA_BFD_CLIENT_REGISTER | 40 | -+------------------------------------+-------+ -| ZEBRA_BFD_CLIENT_DEREGISTER | 41 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_ENABLE_RADV | 42 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_DISABLE_RADV | 43 | -+------------------------------------+-------+ -| ZEBRA_NEXTHOP_LOOKUP_MRIB | 44 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_LINK_PARAMS | 45 | -+------------------------------------+-------+ -| ZEBRA_MPLS_LABELS_ADD | 46 | -+------------------------------------+-------+ -| ZEBRA_MPLS_LABELS_DELETE | 47 | -+------------------------------------+-------+ -| ZEBRA_MPLS_LABELS_REPLACE | 48 | -+------------------------------------+-------+ -| ZEBRA_IPMR_ROUTE_STATS | 49 | -+------------------------------------+-------+ -| ZEBRA_LABEL_MANAGER_CONNECT | 50 | -+------------------------------------+-------+ -| ZEBRA_LABEL_MANAGER_CONNECT_ASYNC | 51 | -+------------------------------------+-------+ -| ZEBRA_GET_LABEL_CHUNK | 52 | -+------------------------------------+-------+ -| ZEBRA_RELEASE_LABEL_CHUNK | 53 | -+------------------------------------+-------+ -| ZEBRA_FEC_REGISTER | 54 | -+------------------------------------+-------+ -| ZEBRA_FEC_UNREGISTER | 55 | -+------------------------------------+-------+ -| ZEBRA_FEC_UPDATE | 56 | -+------------------------------------+-------+ -| ZEBRA_ADVERTISE_DEFAULT_GW | 57 | -+------------------------------------+-------+ -| ZEBRA_ADVERTISE_SVI_MACIP | 58 | -+------------------------------------+-------+ -| ZEBRA_ADVERTISE_SUBNET | 59 | -+------------------------------------+-------+ -| ZEBRA_ADVERTISE_ALL_VNI | 60 | -+------------------------------------+-------+ -| ZEBRA_LOCAL_ES_ADD | 61 | -+------------------------------------+-------+ -| ZEBRA_LOCAL_ES_DEL | 62 | -+------------------------------------+-------+ -| ZEBRA_VNI_ADD | 63 | -+------------------------------------+-------+ -| ZEBRA_VNI_DEL | 64 | -+------------------------------------+-------+ -| ZEBRA_L3VNI_ADD | 65 | -+------------------------------------+-------+ -| ZEBRA_L3VNI_DEL | 66 | -+------------------------------------+-------+ -| ZEBRA_REMOTE_VTEP_ADD | 67 | -+------------------------------------+-------+ -| ZEBRA_REMOTE_VTEP_DEL | 68 | -+------------------------------------+-------+ -| ZEBRA_MACIP_ADD | 69 | -+------------------------------------+-------+ -| ZEBRA_MACIP_DEL | 70 | -+------------------------------------+-------+ -| ZEBRA_IP_PREFIX_ROUTE_ADD | 71 | -+------------------------------------+-------+ -| ZEBRA_IP_PREFIX_ROUTE_DEL | 72 | -+------------------------------------+-------+ -| ZEBRA_REMOTE_MACIP_ADD | 73 | -+------------------------------------+-------+ -| ZEBRA_REMOTE_MACIP_DEL | 74 | -+------------------------------------+-------+ -| ZEBRA_DUPLICATE_ADDR_DETECTION | 75 | -+------------------------------------+-------+ -| ZEBRA_PW_ADD | 76 | -+------------------------------------+-------+ -| ZEBRA_PW_DELETE | 77 | -+------------------------------------+-------+ -| ZEBRA_PW_SET | 78 | -+------------------------------------+-------+ -| ZEBRA_PW_UNSET | 79 | -+------------------------------------+-------+ -| ZEBRA_PW_STATUS_UPDATE | 80 | -+------------------------------------+-------+ -| ZEBRA_RULE_ADD | 81 | -+------------------------------------+-------+ -| ZEBRA_RULE_DELETE | 82 | -+------------------------------------+-------+ -| ZEBRA_RULE_NOTIFY_OWNER | 83 | -+------------------------------------+-------+ -| ZEBRA_TABLE_MANAGER_CONNECT | 84 | -+------------------------------------+-------+ -| ZEBRA_GET_TABLE_CHUNK | 85 | -+------------------------------------+-------+ -| ZEBRA_RELEASE_TABLE_CHUNK | 86 | -+------------------------------------+-------+ -| ZEBRA_IPSET_CREATE | 87 | -+------------------------------------+-------+ -| ZEBRA_IPSET_DESTROY | 88 | -+------------------------------------+-------+ -| ZEBRA_IPSET_ENTRY_ADD | 89 | -+------------------------------------+-------+ -| ZEBRA_IPSET_ENTRY_DELETE | 90 | -+------------------------------------+-------+ -| ZEBRA_IPSET_NOTIFY_OWNER | 91 | -+------------------------------------+-------+ -| ZEBRA_IPSET_ENTRY_NOTIFY_OWNER | 92 | -+------------------------------------+-------+ -| ZEBRA_IPTABLE_ADD | 93 | -+------------------------------------+-------+ -| ZEBRA_IPTABLE_DELETE | 94 | -+------------------------------------+-------+ -| ZEBRA_IPTABLE_NOTIFY_OWNER | 95 | -+------------------------------------+-------+ -| ZEBRA_VXLAN_FLOOD_CONTROL | 96 | -+------------------------------------+-------+ -| ZEBRA_VXLAN_SG_ADD | 97 | -+------------------------------------+-------+ -| ZEBRA_VXLAN_SG_DEL | 98 | -+------------------------------------+-------+ -| ZEBRA_VXLAN_SG_REPLAY | 99 | -+------------------------------------+-------+ -| ZEBRA_MLAG_PROCESS_UP | 100 | -+------------------------------------+-------+ -| ZEBRA_MLAG_PROCESS_DOWN | 101 | -+------------------------------------+-------+ -| ZEBRA_MLAG_CLIENT_REGISTER | 102 | -+------------------------------------+-------+ -| ZEBRA_MLAG_CLIENT_UNREGISTER | 103 | -+------------------------------------+-------+ -| ZEBRA_MLAG_FORWARD_MSG | 104 | -+------------------------------------+-------+ -| ZEBRA_ERROR | 105 | -+------------------------------------+-------+ -| ZEBRA_CLIENT_CAPABILITIES | 106 | -+------------------------------------+-------+ -| ZEBRA_OPAQUE_MESSAGE | 107 | -+------------------------------------+-------+ -| ZEBRA_OPAQUE_REGISTER | 108 | -+------------------------------------+-------+ -| ZEBRA_OPAQUE_UNREGISTER | 109 | -+------------------------------------+-------+ -| ZEBRA_NEIGH_DISCOVER | 110 | -+------------------------------------+-------+ +The definitions of zebra protocol commands can be found at ``lib/zclient.h``. Dataplane batching ================== diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index debc7f188909..000000000000 --- a/doc/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -sphinx==4.0.2 diff --git a/doc/user/.readthedocs.yaml b/doc/user/.readthedocs.yaml new file mode 100644 index 000000000000..c5a11dab17ce --- /dev/null +++ b/doc/user/.readthedocs.yaml @@ -0,0 +1,12 @@ +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: doc/user/conf.py diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 337cfff9378f..bbf24c5eed94 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -92,9 +92,6 @@ Basic Config Commands of some routine in FRR mistakenly blocking/hogging the processing loop and should be reported as a FRR bug. - The default limit is 5 seconds (i.e. 5000), but this can be changed by the - deprecated ``--enable-time-check=...`` compile-time option. - This command has no effect if :clicmd:`service cputime-stats` is disabled. .. clicmd:: service walltime-warning (1-4294967295) @@ -106,9 +103,6 @@ Basic Config Commands provide an immediate sign that FRR is not operating correctly due to externally caused starvation.) - The default limit is 5 seconds as above, including the same deprecated - ``--enable-time-check=...`` compile-time option. - .. clicmd:: log trap LEVEL These commands are deprecated and are present only for historical @@ -684,8 +678,7 @@ Terminal Mode Commands This command displays system run statistics for all the different event types. If no options is specified all different run types are displayed together. Additionally you can ask to look at (r)ead, (w)rite, (t)imer, - (e)vent and e(x)ecute thread event types. If you have compiled with - disable-cpu-time then this command will not show up. + (e)vent and e(x)ecute thread event types. .. clicmd:: show thread poll diff --git a/doc/user/bgp-linkstate.rst b/doc/user/bgp-linkstate.rst new file mode 100644 index 000000000000..59e37b19f70c --- /dev/null +++ b/doc/user/bgp-linkstate.rst @@ -0,0 +1,146 @@ +.. _bgp-link-state: + +BGP Link-State +============== + +Overview +-------- + +BGP Link-State (BGP-LS) is an extension of the BGP protocol designed to +redistribute information from an IGP database to a remote controller (most +likely a Path Computation Element - PCE). BGP-LS does nothing more than +transport IGP information. Therefore, it cannot be used to replace a Link State +routing protocol like OSPF and IS-IS. + +Historically, the only way to get a network controller to collect an IGP +database was to have it participate in the IGP itself as if it were a standard +router. Since the controllers were usually located far from the IGP area, +tunnels such as GRE were used to connect the controllers to the IGP area. This +method was so impractical that an alternative solution was imagined: using the +already deployed inter-domain BGP protocol to redistribute the various IGP +databases. + +BGP Link-State as defined in `RFC7752 +`_ uses the AFI 16388 and SAFI 71. +The BGP Link-State pseudo-prefixes distributed by the `NLRI (Network Layer +Reachability Information)` uniquely define the following +IGP information: + +- Nodes +- Link +- IPv4 Prefix +- IPv6 Prefix + +They are called descriptors. In addition, a new type of BGP Attributes called +"BGP-LS attributes" carries the other information related to a descriptor. + +NLRI and attribute information for BGP-LS is organized using the TLV format +already used by IS-IS LSPs and OSPF opaque LSAs. The `list of TLV code points +`_ +is maintained by IANA. + +Current implementation +---------------------- + +The current version can participate in BGP Link-State AFI / SAFI with +third-party routers and forward the BGP Link-State descriptors and attributes to +other routers. However, it can not generate BGP Link-State data from OSPF and +IS-IS. + +IANA maintains a `registry of BGP-LS NRLI descriptor types +`_. +Only the following RFC7752 NRLI types are supported by the current version: + +- Nodes +- Link +- IPv4 Prefix +- IPv6 Prefix + +The BGP-LS attribute TLVs for these NLRI types are transmitted as is to other +routers which means that all the current and future version are already +supported. + +Show commands +------------- + +The following configuration enables the negotiation of the link-state AFI / SAFI +with the 192.0.2.2 eBGP peer. + +.. code-block:: frr + + router bgp 65003 + neighbor 192.0.2.2 remote-as 65002 + neighbor 192.0.2.2 update-source 192.0.2.3 + ! + address-family link-state link-state + neighbor 192.0.2.2 activate + neighbor 192.0.2.2 route-map PERMIT-ALL in + neighbor 192.0.2.2 route-map PERMIT-ALL out + exit-address-family + exit + ! + route-map PERMIT-ALL permit 1 + +The BGP-LS table can be displayed. + +.. code-block:: frr + + frr# show bgp link-state link-state + BGP table version is 8, local router ID is 192.0.2.3, vrf id 0 + Default local pref 100, local AS 65003 + Network Next Hop Metric LocPrf Weight Path + *> Node OSPFv2 ID:0x20 Local{AS:65001 ID:0 Area:0 Rtr:10.10.10.10:1.1.1.1}/48 + 0 65002 65001 i + *> IPv4-Prefix OSPFv2 ID:0x20 Local{AS:65001 ID:0 Area:0 Rtr:10.10.10.10:1.1.1.1} Prefix{IPv4:89.10.11.0/24}/64 + 0 65002 65001 i + *> IPv6-Prefix ISIS-L2 ID:0x20 Local{AS:65001 ID:0 Rtr:0000.0000.1003.00} Prefix{IPv6:12:12::12:12/128 MT:2}/74 + 0 65002 65001 i + *> IPv6-Prefix OSPFv3 ID:0x20 Local{AS:65001 ID:0 Area:0 Rtr:10.10.10.10} Prefix{OSPF-Route-Type:1 IPv6:12:12::12:12/128 MT:2}/74 + 0 65002 65001 i + *> Node OSPFv2 ID:0x20 Local{AS:65001 ID:0 Area:0 Rtr:10.10.10.10}/48 + 0 65002 65001 i + *> Node ISIS-L1 ID:0x20 Local{AS:65001 ID:0 Rtr:0000.0000.1003.00}/48 + 0 65002 65001 i + *> Link ISIS-L1 ID:0x20 Local{AS:65001 ID:0 Rtr:0000.0000.1001} Remote{AS:65001 ID:0 Rtr:0000.0000.1000} Link{IPv4:10.1.0.1 Neigh-IPv4:10.1.0.2 IPv6:2001::1 Neigh-IPv6:2001::2 MT:0,2}/132 + 0 65002 65001 i + +The "detail-routes" allows displaying the BGP-LS attributes as well. + +.. code-block:: frr + + frr# show bgp link-state link-state detail-routes + (...) + BGP routing table entry for Link ISIS-L1 ID:0x20 Local{AS:65001 ID:0 Rtr:0000.0000.1001} Remote{AS:65001 ID:0 Rtr:0000.0000.1000} Link{IPv4:10.1.0.1 Neigh-IPv4:10.1.0.2 IPv6:2001::1 Neigh-IPv6:2001::2 MT:0,2}/116, version 1 + Paths: (1 available, best #1) + Advertised to non peer-group peers: + 192.0.2.1 192.0.2.3 + 65001 + :: from 192.0.2.1 (192.0.2.1) + Origin IGP, valid, external, best (First path received) + Last update: Mon Apr 17 15:45:42 2023 + BGP-LS attributes: + IPv4 Router-ID of Local Node: 1.1.1.1 + IPv4 Router-ID of Remote Node: 10.10.10.10 + Maximum link bandwidth: 1410.07 Mbps + Max. reservable link bandwidth: 1410.07 Mbps + Unreserved bandwidth: + [0]: 1410.07 Mbps [1]: 1410.07 Mbps + [2]: 1410.07 Mbps [3]: 1410.07 Mbps + [4]: 1410.07 Mbps [5]: 1410.07 Mbps + [6]: 1410.07 Mbps [7]: 1410.07 Mbps + TE Default Metric: 100 + IGP Metric: 10 + Adjacency SID: + Flags: 0b00110000 + Weight: 0 + SID: 15000 + Unidirectional Link Delay: 8500 microseconds + Min/Max Unidirectional Link Delay: 8000/9000 microseconds + Application-Specific Link Attributes: + SABM Flags : 0b00010000 00000000 00000000 00000000 + UDABM Flags: 0b00000000 00000000 00000000 00000000 + Administrative group: 0x00000001 + TE Default Metric: 100 + Min/Max Unidirectional Link Delay: 8000/9000 microseconds + Extended Administrative Group: 0x00000001 + diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 651aa36d0eea..36eb8315f70d 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -461,6 +461,15 @@ Administrative Distance Metrics Sets the administrative distance for a particular route. + If the system has a static route configured from the kernel, it has a + distance of 0. In some cases, it might be useful to override the route + from the FRR. E.g.: Kernel has a statically configured default route, + and you received another default route from the BGP and want to install + it to be preferred over the static route. In such a case, you MUST set + a higher distance from the kernel. + + .. seealso:: :ref:`administrative-distance` + .. _bgp-requires-policy: Require policy on EBGP @@ -818,6 +827,10 @@ from eBGP peers, :ref:`bgp-route-selection`. MED as an intra-AS metric to steer equal-length AS_PATH routes to, e.g., desired exit points. +.. [#med-transitivity-rant] For some set of objects to have an order, there *must* be some binary ordering relation that is defined for *every* combination of those objects, and that relation *must* be transitive. I.e.:, if the relation operator is <, and if a < b and b < c then that relation must carry over and it *must* be that a < c for the objects to have an order. The ordering relation may allow for equality, i.e. a < b and b < a may both be true and imply that a and b are equal in the order and not distinguished by it, in which case the set has a partial order. Otherwise, if there is an order, all the objects have a distinct place in the order and the set has a total order) +.. [bgp-route-osci-cond] McPherson, D. and Gill, V. and Walton, D., "Border Gateway Protocol (BGP) Persistent Route Oscillation Condition", IETF RFC3345 +.. [stable-flexible-ibgp] Flavel, A. and M. Roughan, "Stable and flexible iBGP", ACM SIGCOMM 2009 +.. [ibgp-correctness] Griffin, T. and G. Wilfong, "On the correctness of IBGP configuration", ACM SIGCOMM 2002 .. _bgp-graceful-restart: @@ -840,7 +853,10 @@ The following functionality is provided by graceful restart: 1. The feature allows the restarting router to indicate to the helping peer the routes it can preserve in its forwarding plane during control plane restart by sending graceful restart capability in the OPEN message sent during - session establishment. + session establishment. Graceful restart notification flag and/or restart + time can also be changed during the dynamic BGP capabilities. If using + dynamic capabilities, no session reset is required, thus it's very useful + to increase restart time before doing a software upgrade or so. 2. The feature allows helping router to advertise to all other peers the routes received from the restarting router which are preserved in the forwarding plane of the restarting router during control plane restart. @@ -1701,6 +1717,16 @@ Configuring Peers turning on this command will allow BGP to install v4 routes with v6 nexthops if you do not have v4 configured on interfaces. +.. clicmd:: neighbor PEER capability dynamic + + Allow BGP to negotiate the Dynamic Capability with its peers. + + Dynamic Capability defines a new BGP message (CAPABILITY) that can be used + to set/unset BGP capabilities without bringing down a BGP session. + + This includes changing graceful-restart (LLGR also) timers, + enabling/disabling add-path, and other supported capabilities. + .. clicmd:: neighbor accept-own Enable handling of self-originated VPN routes containing ``accept-own`` community. @@ -1811,6 +1837,13 @@ Configuring Peers and is not displayed. The `bgp default l2vpn-evpn` form of the command is displayed. +.. clicmd:: bgp default link-state + + This command allows the user to specify that the link-state link-state + address family is turned on by default or not. This command defaults to off + and is not displayed. + The `bgp default link-state` form of the command is displayed. + .. clicmd:: bgp default show-hostname This command shows the hostname of the peer in certain BGP commands @@ -2160,8 +2193,8 @@ Using AS Path in Route Map Remove some AS numbers from the AS_PATH of the BGP path's NLRI. Removed AS numbers are conformant with the regex defined in as-path access-list WORD. The no form of this command removes this set operation from the route-map. - - + + .. _bgp-communities-attribute: Communities Attribute @@ -5210,10 +5243,7 @@ Show command json output: .. include:: flowspec.rst -.. [#med-transitivity-rant] For some set of objects to have an order, there *must* be some binary ordering relation that is defined for *every* combination of those objects, and that relation *must* be transitive. I.e.:, if the relation operator is <, and if a < b and b < c then that relation must carry over and it *must* be that a < c for the objects to have an order. The ordering relation may allow for equality, i.e. a < b and b < a may both be true and imply that a and b are equal in the order and not distinguished by it, in which case the set has a partial order. Otherwise, if there is an order, all the objects have a distinct place in the order and the set has a total order) -.. [bgp-route-osci-cond] McPherson, D. and Gill, V. and Walton, D., "Border Gateway Protocol (BGP) Persistent Route Oscillation Condition", IETF RFC3345 -.. [stable-flexible-ibgp] Flavel, A. and M. Roughan, "Stable and flexible iBGP", ACM SIGCOMM 2009 -.. [ibgp-correctness] Griffin, T. and G. Wilfong, "On the correctness of IBGP configuration", ACM SIGCOMM 2002 +.. include:: bgp-linkstate.rst .. _bgp-fast-convergence: diff --git a/doc/user/conf.py b/doc/user/conf.py index 728f9c936486..40accc1bd28d 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -130,6 +130,7 @@ "rpki.rst", "routeserver.rst", "ospf_fundamentals.rst", + "bgp-linkstate.rst", "flowspec.rst", "snmptrap.rst", "wecmp_linkbw.rst", diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 8e8fb246086b..24c6c223e3e1 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -351,20 +351,6 @@ options from the list below. Use libpam for PAM support in vtysh. -.. option:: --enable-time-check XXX - - This option is deprecated as it was replaced by the - :clicmd:`service cputime-stats` CLI command, which may be adjusted at - runtime rather than being a compile-time setting. See there for further - detail. - -.. option:: --disable-cpu-time - - This option is deprecated as it was replaced by the - :clicmd:`service cputime-warning NNN` CLI command, which may be adjusted at - runtime rather than being a compile-time setting. See there for further - detail. - .. option:: --enable-pcreposix Turn on the usage of PCRE Posix libs for regex functionality. diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 83fc2e0281ea..63c921330bbc 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -594,6 +594,40 @@ The following command show Flex-Algo information: includes an 'algorithm (128-255)' optional argument. See :ref:`showing-isis-information` and :ref:`isis-segment-routing`. +.. _isis-srv6: + +Segment Routing over IPv6 (SRv6) +================================ + +This feature enables extensions in IS-IS to support Segment Routing over IPv6 +data plane (SRv6) as per RFC 9352. + +.. clicmd:: segment-routing srv6 + + Enable Segment Routing over IPv6 data plane (SRv6). + +.. clicmd:: locator NAME + + Specify the SRv6 locator to use for SRv6. The locator must be configured in + Zebra. Once the locator is configured, IS-IS automatically allocates prefix + SID and adjacency SIDs, creates local SID entries in the data plane, and + advertises them in the IGP domain. + +.. clicmd:: interface NAME + + Specify the dummy interface used to install SRv6 SIDs in the Linux data plane. + The interface must be created manually. By default, the interface is 'sr0'. + The interface can be created using the iproute2 utility: + + .. code-block:: bash + + ip link add sr0 type dummy + ip link set sr0 up + +.. clicmd:: show isis segment-routing srv6 node + + Show detailed information about all learned SRv6 Nodes. + Debugging ISIS ============== @@ -774,6 +808,33 @@ A Segment Routing configuration, with IPv4, IPv6, SRGB and MSD configuration. segment-routing prefix 2001:db8:1000::1/128 index 101 explicit-null ! +An SRv6 configuration: + +.. code-block:: frr + + hostname HOSTNAME + password PASSWORD + log file /var/log/isisd.log + ! + ! + interface eth0 + ipv6 router isis FOO + ip router isis FOO + isis hello-interval 5 + ! + interface eth1 + ip router isis FOO + ! + ! + router isis FOO + net 49.0001.1111.1111.1111.00 + is-type level-2-only + metric-style wide + segment-routing srv6 + locator loc1 + ! + line vty + .. _isis-vrf-config-examples: diff --git a/doc/user/mgmtd.rst b/doc/user/mgmtd.rst index 737eb57c85bc..42bc860b7271 100644 --- a/doc/user/mgmtd.rst +++ b/doc/user/mgmtd.rst @@ -356,7 +356,7 @@ MGMT Show commands Currenlty supported values for 'candidate' and 'running' only ('operational' shall be supported in future soon). -.. clicmd:: show mgmt database-contents [candidate|operation|running] [xpath WORD] [file WORD] json|xml +.. clicmd:: show mgmt datastore-contents [candidate|operation|running] [xpath WORD] [file WORD] json|xml This command dumps the subtree pointed by the xpath in JSON or XML format. If filepath is not present then the tree will be printed on the shell. diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index b61c9448db87..d61522b051f2 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -314,7 +314,7 @@ To start OSPF process you have to specify the OSPF router. This command controls the ospf instance's socket buffer sizes. The 'no' form resets one or both values to the default. - + .. clicmd:: no socket-per-interface Ordinarily, ospfd uses a socket per interface for sending @@ -599,6 +599,38 @@ Interfaces KEY is the actual message digest key, of up to 16 chars (larger strings will be truncated), and is associated with the given KEYID. +.. clicmd:: ip ospf authentication key-chain KEYCHAIN + + Specify that HMAC cryptographic authentication must be used on this interface + using a key chain. Overrides any authentication enabled on a per-area basis + (:clicmd:`area A.B.C.D authentication message-digest`). + + ``KEYCHAIN``: Specifies the name of the key chain that contains the authentication + key(s) and cryptographic algorithms to be used for OSPF authentication. The key chain + is a logical container that holds one or more authentication keys, + allowing for key rotation and management. + + Note that OSPF HMAC cryptographic authentication requires that time never go backwards + (correct time is NOT important, only that it never goes backwards), even + across resets, if ospfd is to be able to promptly reestablish adjacencies + with its neighbours after restarts/reboots. The host should have system time + be set at boot from an external or non-volatile source (e.g. battery backed + clock, NTP, etc.) or else the system clock should be periodically saved to + non-volatile storage and restored at boot if HMAC cryptographic authentication is to be + expected to work reliably. + + Example: + + .. code:: sh + + r1(config)#key chain temp + r1(config-keychain)#key 13 + r1(config-keychain-key)#key-string ospf + r1(config-keychain-key)#cryptographic-algorithm hmac-sha-256 + r1(config)#int eth0 + r1(config-if)#ip ospf authentication key-chain temp + r1(config-if)#ip ospf area 0 + .. clicmd:: ip ospf cost (1-65535) diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index d0513018e33c..83abfa220eee 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -28,8 +28,8 @@ documented elsewhere. .. _nexthop-groups: -Nexthop Groups -============== +PBR Nexthop Groups +================== A nexthop group is a list of ECMP nexthops used to forward packets when a pbr-map is matched. diff --git a/doc/user/static.rst b/doc/user/static.rst index 6d8aca97bbab..d405276573df 100644 --- a/doc/user/static.rst +++ b/doc/user/static.rst @@ -164,3 +164,23 @@ network 9.9.9.9/24: .. code-block:: frr ip route 9.9.9.9/24 6.6.6.6 color 123 + +SRv6 Route Commands +==================== + +It is possible to specify a static route for ipv6 prefixes using an SRv6 +`segments` instruction. The `/` separator can be used to specify +multiple segments instructions. + +.. code-block:: frr + + ipv6 route X:X::X:X segments U:U::U:U/Y:Y::Y:Y/Z:Z::Z:Z + + +:: + + router(config)# ipv6 route 2005::1/64 ens3 segments 2001:db8:aaaa::7/2002::4/2002::3/2002::2 + + router# show ipv6 route + [..] + S>* 2005::/64 [1/0] is directly connected, ens3, seg6 2001:db8:aaaa::7,2002::4,2002::3,2002::2, weight 1, 00:00:06 diff --git a/doc/user/vtysh.rst b/doc/user/vtysh.rst index 1ab54f09ab9c..adbdf3451a3a 100644 --- a/doc/user/vtysh.rst +++ b/doc/user/vtysh.rst @@ -18,8 +18,9 @@ administrator with an external editor. .. warning:: - This also means the ``hostname`` and ``banner motd`` commands (which both do - have effect for vtysh) need to be manually updated in :file:`vtysh.conf`. + This also means the ``hostname``, ``domainname``, and ``banner motd`` commands + (which do have effect for vtysh) need to be manually updated + in :file:`vtysh.conf`. .. clicmd:: copy FILENAME running-config diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index e3c99983544b..ba6e3bf37fa9 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -334,11 +334,15 @@ the default route. Allow IPv4 nexthop tracking to resolve via the default route. This parameter is configured per-VRF, so the command is also available in the VRF subnode. + This is enabled by default for a traditional profile. + .. clicmd:: ipv6 nht resolve-via-default Allow IPv6 nexthop tracking to resolve via the default route. This parameter is configured per-VRF, so the command is also available in the VRF subnode. + This is enabled by default for a traditional profile. + .. clicmd:: show ip nht [vrf NAME] [A.B.C.D|X:X::X:X] [mrib] [json] Show nexthop tracking status for address resolution. If vrf is not specified @@ -370,6 +374,8 @@ outgoing interface Resolve PBR nexthop via ip neigh tracking +.. _administrative-distance: + Administrative Distance ======================= @@ -416,16 +422,34 @@ the same distances that other routing suites have chosen. +------------+-----------+ An admin distance of 255 indicates to Zebra that the route should not be -installed into the Data Plane. Additionally routes with an admin distance +installed into the Data Plane. Additionally routes with an admin distance of 255 will not be redistributed. Zebra does treat Kernel routes as special case for the purposes of Admin -Distance. Upon learning about a route that is not originated by FRR -we read the metric value as a uint32_t. The top byte of the value +Distance. Upon learning about a route that is not originated by FRR +we read the metric value as a uint32_t. The top byte of the value is interpreted as the Administrative Distance and the low three bytes -are read in as the metric. This special case is to facilitate VRF +are read in as the metric. This special case is to facilitate VRF default routes. +.. code-block:: shell + + $ # Set administrative distance to 255 for Zebra + $ ip route add 192.0.2.0/24 metric $(( 2**32 - 2**24 )) dev lo + $ vtysh -c 'show ip route 192.0.2.0/24 json' | jq '."192.0.2.0/24"[] | (.distance, .metric)' + 255 + 0 + $ # Set administrative distance to 192 for Zebra + $ ip route add 192.0.2.0/24 metric $(( 2**31 + 2**30 )) dev lo + $ vtysh -c 'show ip route 192.0.2.0/24 json' | jq '."192.0.2.0/24"[] | (.distance, .metric)' + 192 + 0 + $ # Set administrative distance to 128, and metric 100 for Zebra + $ ip route add 192.0.2.0/24 metric $(( 2**31 + 100 )) dev lo + $ vtysh -c 'show ip route 192.0.2.0/24 json' | jq '."192.0.2.0/24"[] | (.distance, .metric)' + 128 + 100 + Route Replace Semantics ======================= @@ -759,6 +783,19 @@ presence of the entry. 21 Static 10.125.0.2 IPv4 Explicit Null +Allocated label chunks table can be dumped using the command + +.. clicmd:: show debugging label-table + +:: + + zebra# show debugging label-table + Proto ospf: [300/350] + Proto srte: [500/500] + Proto isis: [1200/1300] + Proto ospf: [20000/21000] + Proto isis: [22000/23000] + .. _zebra-srv6: Segment-Routing IPv6 @@ -1234,6 +1271,12 @@ FPM Commands The ``no`` form uses the old known FPM behavior of including next hop information in the route (e.g. ``RTM_NEWROUTE``) messages. +.. clicmd:: fpm use-route-replace + + Use the netlink ``NLM_F_REPLACE`` flag for updating routes instead of + two different messages to update a route + (``RTM_DELROUTE`` + ``RTM_NEWROUTE``). + .. clicmd:: show fpm counters [json] Show the FPM statistics (plain text or JSON formatted). diff --git a/include/linux/seg6.h b/include/linux/seg6.h index 329163e4a08d..5b572ba3dbf8 100644 --- a/include/linux/seg6.h +++ b/include/linux/seg6.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +// SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note /* * SR-IPv6 implementation * @@ -30,7 +30,7 @@ struct ipv6_sr_hdr { __u8 flags; __u16 tag; - struct in6_addr segments[0]; + struct in6_addr segments[]; }; #define SR6_FLAG1_PROTECTED (1 << 6) diff --git a/include/linux/seg6_local.h b/include/linux/seg6_local.h index 6788b58799e3..401c8b0c6e94 100644 --- a/include/linux/seg6_local.h +++ b/include/linux/seg6_local.h @@ -23,6 +23,7 @@ enum { SEG6_LOCAL_BPF, SEG6_LOCAL_VRFTABLE, SEG6_LOCAL_COUNTERS, + SEG6_LOCAL_FLAVORS, __SEG6_LOCAL_MAX, }; #define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1) @@ -105,4 +106,27 @@ enum { #define SEG6_LOCAL_CNT_MAX (__SEG6_LOCAL_CNT_MAX - 1) +/* SRv6 End* Flavor attributes */ +enum { + SEG6_LOCAL_FLV_UNSPEC, + SEG6_LOCAL_FLV_OPERATION, + SEG6_LOCAL_FLV_LCBLOCK_BITS, + SEG6_LOCAL_FLV_LCNODE_FN_BITS, + __SEG6_LOCAL_FLV_MAX, +}; + +#define SEG6_LOCAL_FLV_MAX (__SEG6_LOCAL_FLV_MAX - 1) + +/* Designed flavor operations for SRv6 End* Behavior */ +enum { + SEG6_LOCAL_FLV_OP_UNSPEC, + SEG6_LOCAL_FLV_OP_PSP, + SEG6_LOCAL_FLV_OP_USP, + SEG6_LOCAL_FLV_OP_USD, + SEG6_LOCAL_FLV_OP_NEXT_CSID, + __SEG6_LOCAL_FLV_OP_MAX +}; + +#define SEG6_LOCAL_FLV_OP_MAX (__SEG6_LOCAL_FLV_OP_MAX - 1) + #endif diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 30b71537e0e5..cba1b91faef1 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -90,6 +90,7 @@ struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa, } } adj->adj_sids = list_new(); + adj->srv6_endx_sids = list_new(); listnode_add(circuit->area->adjacency_list, adj); return adj; @@ -160,6 +161,7 @@ void isis_delete_adj(void *arg) XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->global_ipv6_addrs); adj_mt_finish(adj); list_delete(&adj->adj_sids); + list_delete(&adj->srv6_endx_sids); listnode_delete(adj->circuit->area->adjacency_list, adj); XFREE(MTYPE_ISIS_ADJACENCY, adj); diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index c0c8e68145d2..dc181055fa98 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -98,6 +98,8 @@ struct isis_adjacency { struct list *adj_sids; /* Segment Routing Adj-SIDs. */ uint32_t snmp_idx; struct listnode *snmp_list_node; + + struct list *srv6_endx_sids; /* SRv6 End.X SIDs. */ }; struct isis_threeway_adj; diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index feab45123383..ffa6ad3e402d 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -41,6 +41,7 @@ #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" +#include "isisd/isis_srv6.h" #include "isisd/isis_te.h" #include "isisd/isis_mt.h" #include "isisd/isis_errors.h" @@ -1631,6 +1632,9 @@ static int isis_ifp_up(struct interface *ifp) isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp); } + /* Notify SRv6 that the interface went up */ + isis_srv6_ifp_up_notify(ifp); + return 0; } diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 6f53ab479fe0..9718a457ede5 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -2037,6 +2037,234 @@ void cli_show_isis_prefix_sid_algorithm(struct vty *vty, vty_out(vty, "\n"); } +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/locator + */ +DEFPY (isis_srv6_locator, + isis_srv6_locator_cmd, + "[no] locator NAME$loc_name", + NO_STR + "Specify SRv6 locator\n" + "Specify SRv6 locator\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./locator", NB_OP_DESTROY, loc_name); + else + nb_cli_enqueue_change(vty, "./locator", NB_OP_MODIFY, loc_name); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_isis_srv6_locator(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " locator %s\n", yang_dnode_get_string(dnode, NULL)); +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/enabled + */ +DEFPY_YANG_NOSH (isis_srv6_enable, + isis_srv6_enable_cmd, + "segment-routing srv6", + SR_STR + "Enable Segment Routing over IPv6 (SRv6)\n") +{ + int ret; + char xpath[XPATH_MAXLEN + 37]; + + snprintf(xpath, sizeof(xpath), "%s/segment-routing-srv6", + VTY_CURR_XPATH); + + nb_cli_enqueue_change(vty, "./segment-routing-srv6/enabled", + NB_OP_MODIFY, "true"); + + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(ISIS_SRV6_NODE, xpath); + + return ret; +} + +DEFPY_YANG (no_isis_srv6_enable, + no_isis_srv6_enable_cmd, + "no segment-routing srv6", + NO_STR + SR_STR + "Disable Segment Routing over IPv6 (SRv6)\n") +{ + nb_cli_enqueue_change(vty, "./segment-routing-srv6", NB_OP_DESTROY, + NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_isis_srv6_enabled(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + if (!yang_dnode_get_bool(dnode, NULL)) + vty_out(vty, " no"); + + vty_out(vty, " segment-routing srv6\n"); +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd + */ +DEFPY_YANG_NOSH (isis_srv6_node_msd, + isis_srv6_node_msd_cmd, + "[no] node-msd", + NO_STR + "Segment Routing over IPv6 (SRv6) Maximum SRv6 SID Depths\n") +{ + int ret = CMD_SUCCESS; + char xpath[XPATH_MAXLEN + 37]; + + snprintf(xpath, sizeof(xpath), "%s/msd/node-msd", VTY_CURR_XPATH); + + if (no) { + nb_cli_enqueue_change(vty, "./msd/node_msd/max-segs-left", + NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msd/node_msd/end-pop", + NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msd/node_msd/h-encaps", + NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msd/node_msd/end-d", + NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + } else + VTY_PUSH_XPATH(ISIS_SRV6_NODE_MSD_NODE, xpath); + + return ret; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-segs-left + */ +DEFPY (isis_srv6_node_msd_max_segs_left, + isis_srv6_node_msd_max_segs_left_cmd, + "[no] max-segs-left (0-255)$max_segs_left", + NO_STR + "Specify Maximum Segments Left MSD\n" + "Specify Maximum Segments Left MSD\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./max-segs-left", NB_OP_DESTROY, + NULL); + else + nb_cli_enqueue_change(vty, "./max-segs-left", NB_OP_MODIFY, + max_segs_left_str); + + return nb_cli_apply_changes(vty, NULL); +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-pop + */ +DEFPY (isis_srv6_node_msd_max_end_pop, + isis_srv6_node_msd_max_end_pop_cmd, + "[no] max-end-pop (0-255)$max_end_pop", + NO_STR + "Specify Maximum End Pop MSD\n" + "Specify Maximum End Pop MSD\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./max-end-pop", NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, "./max-end-pop", NB_OP_MODIFY, + max_end_pop_str); + + return nb_cli_apply_changes(vty, NULL); +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-h-encaps + */ +DEFPY (isis_srv6_node_msd_max_h_encaps, + isis_srv6_node_msd_max_h_encaps_cmd, + "[no] max-h-encaps (0-255)$max_h_encaps", + NO_STR + "Specify Maximum H.Encaps MSD\n" + "Specify Maximum H.Encaps MSD\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./max-h-encaps", NB_OP_DESTROY, + NULL); + else + nb_cli_enqueue_change(vty, "./max-h-encaps", NB_OP_MODIFY, + max_h_encaps_str); + + return nb_cli_apply_changes(vty, NULL); +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-d + */ +DEFPY (isis_srv6_node_msd_max_end_d, + isis_srv6_node_msd_max_end_d_cmd, + "[no] max-end-d (0-255)$max_end_d", + NO_STR + "Specify Maximum End D MSD\n" + "Specify Maximum End D MSD\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./max-end-d", NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, "./max-end-d", NB_OP_MODIFY, + max_end_d_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_isis_srv6_node_msd(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " node-msd\n"); + if (yang_dnode_get_uint8(dnode, "./max-segs-left") != + yang_get_default_uint8("%s/msd/node-msd/max-segs-left", ISIS_SRV6)) + vty_out(vty, " max-segs-left %u\n", + yang_dnode_get_uint8(dnode, "./max-segs-left")); + if (yang_dnode_get_uint8(dnode, "./max-end-pop") != + yang_get_default_uint8("%s/msd/node-msd/max-end-pop", ISIS_SRV6)) + vty_out(vty, " max-end-pop %u\n", + yang_dnode_get_uint8(dnode, "./max-end-pop")); + if (yang_dnode_get_uint8(dnode, "./max-h-encaps") != + yang_get_default_uint8("%s/msd/node-msd/max-h-encaps", ISIS_SRV6)) + vty_out(vty, " max-h-encaps %u\n", + yang_dnode_get_uint8(dnode, "./max-h-encaps")); + if (yang_dnode_get_uint8(dnode, "./max-end-d") != + yang_get_default_uint8("%s/msd/node-msd/max-end-d", ISIS_SRV6)) + vty_out(vty, " max-end-d %u\n", + yang_dnode_get_uint8(dnode, "./max-end-d")); +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/interface + */ +DEFPY (isis_srv6_interface, + isis_srv6_interface_cmd, + "[no] interface WORD$interface", + NO_STR + "Interface for Segment Routing over IPv6 (SRv6)\n" + "Interface for Segment Routing over IPv6 (SRv6)\n") +{ + if (no) { + nb_cli_enqueue_change(vty, "./interface", + NB_OP_MODIFY, NULL); + } else { + nb_cli_enqueue_change(vty, "./interface", + NB_OP_MODIFY, interface); + } + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_isis_srv6_interface(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " interface %s\n", yang_dnode_get_string(dnode, NULL)); +} + /* * XPath: /frr-isisd:isis/instance/fast-reroute/level-{1,2}/lfa/priority-limit */ @@ -3806,6 +4034,20 @@ void isis_cli_init(void) install_element(ISIS_NODE, &isis_frr_remote_lfa_plist_cmd); install_element(ISIS_NODE, &no_isis_frr_remote_lfa_plist_cmd); + install_element(ISIS_NODE, &isis_srv6_enable_cmd); + install_element(ISIS_NODE, &no_isis_srv6_enable_cmd); + install_element(ISIS_SRV6_NODE, &isis_srv6_locator_cmd); + install_element(ISIS_SRV6_NODE, &isis_srv6_node_msd_cmd); + install_element(ISIS_SRV6_NODE, &isis_srv6_interface_cmd); + install_element(ISIS_SRV6_NODE_MSD_NODE, + &isis_srv6_node_msd_max_segs_left_cmd); + install_element(ISIS_SRV6_NODE_MSD_NODE, + &isis_srv6_node_msd_max_end_pop_cmd); + install_element(ISIS_SRV6_NODE_MSD_NODE, + &isis_srv6_node_msd_max_h_encaps_cmd); + install_element(ISIS_SRV6_NODE_MSD_NODE, + &isis_srv6_node_msd_max_end_d_cmd); + install_element(INTERFACE_NODE, &isis_passive_cmd); install_element(INTERFACE_NODE, &isis_passwd_cmd); diff --git a/isisd/isis_flex_algo.c b/isisd/isis_flex_algo.c index ef30987b8e7c..fbe249ab5abd 100644 --- a/isisd/isis_flex_algo.c +++ b/isisd/isis_flex_algo.c @@ -127,10 +127,7 @@ _isis_flex_algo_elected(int algorithm, const struct isis_area *area, * Perform FAD comparison. First, compare the priority, and if they are * the same, compare the sys-id. */ - /* clang-format off */ - frr_each_const(lspdb, &area->lspdb[ISIS_LEVEL1 - 1], lsp) { - /* clang-format on */ - + frr_each (lspdb_const, &area->lspdb[ISIS_LEVEL1 - 1], lsp) { if (!lsp->tlvs || !lsp->tlvs->router_cap) continue; diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 950d5f359c08..1b3491f5d38e 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1210,6 +1210,62 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) /* And finally MSD */ rcap->msd = srdb->config.msd; } + + /* Add SRv6 Sub-TLVs if SRv6 is enabled */ + if (area->srv6db.config.enabled) { + struct isis_srv6_db *srv6db = &area->srv6db; + + rcap->srv6_cap.is_srv6_capable = true; + + /* SRv6 flags */ + rcap->srv6_cap.flags = 0; + + /* And finally MSDs */ + rcap->srv6_msd.max_seg_left_msd = + srv6db->config.max_seg_left_msd; + rcap->srv6_msd.max_end_pop_msd = + srv6db->config.max_end_pop_msd; + rcap->srv6_msd.max_h_encaps_msd = + srv6db->config.max_h_encaps_msd; + rcap->srv6_msd.max_end_d_msd = + srv6db->config.max_end_d_msd; + } else { + rcap->srv6_cap.is_srv6_capable = false; + } + } + + /* Add SRv6 Locator TLV. */ + if (area->srv6db.config.enabled && + !list_isempty(area->srv6db.srv6_locator_chunks)) { + struct isis_srv6_locator locator = {}; + struct srv6_locator_chunk *chunk; + + /* TODO: support more than one locator */ + chunk = (struct srv6_locator_chunk *)listgetdata( + listhead(area->srv6db.srv6_locator_chunks)); + + locator.metric = 0; + locator.prefix = chunk->prefix; + locator.flags = 0; + locator.algorithm = 0; + + struct listnode *sid_node; + struct isis_srv6_sid *sid; + locator.srv6_sid = list_new(); + for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_sids, sid_node, + sid)) { + listnode_add(locator.srv6_sid, sid); + } + + isis_tlvs_add_srv6_locator(lsp->tlvs, 0, &locator); + lsp_debug("ISIS (%s): Adding SRv6 Locator information", + area->area_tag); + + list_delete(&locator.srv6_sid); + + isis_tlvs_add_ipv6_reach(lsp->tlvs, + isis_area_ipv6_topology(area), + &chunk->prefix, 0, false, NULL); } /* IPv4 address and TE router ID TLVs. diff --git a/isisd/isis_main.c b/isisd/isis_main.c index b495d3a9ddee..da4c7bc00a42 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -93,6 +93,7 @@ static __attribute__((__noreturn__)) void terminate(int i) { isis_terminate(); isis_sr_term(); + isis_srv6_term(); isis_zebra_stop(); exit(i); } @@ -296,6 +297,7 @@ int main(int argc, char **argv, char **envp) isis_route_map_init(); isis_mpls_te_init(); isis_sr_init(); + isis_srv6_init(); lsp_init(); mt_init(); diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index c81412d24ab2..16cafa2ff034 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -860,6 +860,58 @@ const struct frr_yang_module_info frr_isisd_info = { .destroy = isis_instance_flex_algo_priority_destroy, }, }, + { + .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/enabled", + .cbs = { + .modify = isis_instance_segment_routing_srv6_enabled_modify, + .cli_show = cli_show_isis_srv6_enabled, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/locator", + .cbs = { + .modify = isis_instance_segment_routing_srv6_locator_modify, + .destroy = isis_instance_segment_routing_srv6_locator_destroy, + .cli_show = cli_show_isis_srv6_locator, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-segs-left", + .cbs = { + .modify = isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_modify, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-pop", + .cbs = { + .modify = isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_modify, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-h-encaps", + .cbs = { + .modify = isis_instance_segment_routing_srv6_msd_node_msd_max_h_encaps_modify, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-d", + .cbs = { + .modify = isis_instance_segment_routing_srv6_msd_node_msd_max_end_d_modify, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd", + .cbs = { + .cli_show = cli_show_isis_srv6_node_msd, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/interface", + .cbs = { + .modify = isis_instance_segment_routing_srv6_interface_modify, + .cli_show = cli_show_isis_srv6_interface, + }, + }, { .xpath = "/frr-isisd:isis/instance/mpls/ldp-sync", .cbs = { diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index 3b8ddca4f840..c04a006a2e3c 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -322,6 +322,30 @@ int isis_instance_flex_algo_affinity_mapping_value_modify( struct nb_cb_modify_args *args); int isis_instance_flex_algo_affinity_mapping_value_destroy( struct nb_cb_destroy_args *args); +int isis_instance_segment_routing_srv6_enabled_modify( + struct nb_cb_modify_args *args); +void cli_show_isis_srv6_enabled(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults); +int isis_instance_segment_routing_srv6_locator_modify( + struct nb_cb_modify_args *args); +int isis_instance_segment_routing_srv6_locator_destroy( + struct nb_cb_destroy_args *args); +void cli_show_isis_srv6_locator(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults); +int isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_modify( + struct nb_cb_modify_args *args); +int isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_modify( + struct nb_cb_modify_args *args); +int isis_instance_segment_routing_srv6_msd_node_msd_max_h_encaps_modify( + struct nb_cb_modify_args *args); +int isis_instance_segment_routing_srv6_msd_node_msd_max_end_d_modify( + struct nb_cb_modify_args *args); +void cli_show_isis_srv6_node_msd(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults); +int isis_instance_segment_routing_srv6_interface_modify( + struct nb_cb_modify_args *args); +void cli_show_isis_srv6_interface(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults); int isis_instance_mpls_ldp_sync_destroy(struct nb_cb_destroy_args *args); int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args); int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args); diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index a3d8896e4f10..b6ee073fd5da 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -35,6 +35,7 @@ #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" #include "isisd/isis_spf_private.h" +#include "isisd/isis_srv6.h" #include "isisd/isis_te.h" #include "isisd/isis_mt.h" #include "isisd/isis_redist.h" @@ -3446,6 +3447,230 @@ int isis_instance_flex_algo_priority_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/enabled + */ +int isis_instance_segment_routing_srv6_enabled_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srv6db.config.enabled = yang_dnode_get_bool(args->dnode, NULL); + + if (area->srv6db.config.enabled) { + if (IS_DEBUG_EVENTS) + zlog_debug( + "Segment Routing over IPv6 (SRv6): OFF -> ON"); + } else { + if (IS_DEBUG_EVENTS) + zlog_debug( + "Segment Routing over IPv6 (SRv6): ON -> OFF"); + } + + /* Regenerate LSPs to advertise SRv6 capabilities or signal that the + * node is no longer SRv6-capable. */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/locator + */ +int isis_instance_segment_routing_srv6_locator_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *loc_name; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(lyd_parent(lyd_parent(args->dnode)), NULL, + true); + + loc_name = yang_dnode_get_string(args->dnode, NULL); + + if (strncmp(loc_name, area->srv6db.config.srv6_locator_name, + sizeof(area->srv6db.config.srv6_locator_name)) == 0) { + snprintf(args->errmsg, args->errmsg_len, + "SRv6 locator %s is already configured", loc_name); + return NB_ERR_NO_CHANGES; + } + + /* Remove previously configured locator */ + if (strncmp(area->srv6db.config.srv6_locator_name, "", + sizeof(area->srv6db.config.srv6_locator_name)) != 0) { + sr_debug("Unsetting previously configured SRv6 locator"); + if (!isis_srv6_locator_unset(area)) { + zlog_warn("Failed to unset SRv6 locator"); + return NB_ERR; + } + } + + strlcpy(area->srv6db.config.srv6_locator_name, loc_name, + sizeof(area->srv6db.config.srv6_locator_name)); + + sr_debug("Configured SRv6 locator %s for IS-IS area %s", loc_name, + area->area_tag); + + sr_debug("Trying to get a chunk from locator %s for IS-IS area %s", + loc_name, area->area_tag); + + if (isis_zebra_srv6_manager_get_locator_chunk(loc_name) < 0) + return NB_ERR; + + return NB_OK; +} + +int isis_instance_segment_routing_srv6_locator_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + const char *loc_name; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(lyd_parent(lyd_parent(args->dnode)), NULL, + true); + + loc_name = yang_dnode_get_string(args->dnode, NULL); + + sr_debug("Trying to unset SRv6 locator %s", loc_name); + + if (strncmp(loc_name, area->srv6db.config.srv6_locator_name, + sizeof(area->srv6db.config.srv6_locator_name)) != 0) { + sr_debug("SRv6 locator %s is not configured", loc_name); + snprintf(args->errmsg, args->errmsg_len, + "SRv6 locator %s is not configured", loc_name); + return NB_ERR_NO_CHANGES; + } + + if (!isis_srv6_locator_unset(area)) { + zlog_warn("Failed to unset SRv6 locator"); + return NB_ERR; + } + + sr_debug("Deleted SRv6 locator %s for IS-IS area %s", loc_name, + area->area_tag); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-segs-left + */ +int isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srv6db.config.max_seg_left_msd = yang_dnode_get_uint8(args->dnode, + NULL); + + /* Update and regenerate LSP */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-pop + */ +int isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srv6db.config.max_end_pop_msd = yang_dnode_get_uint8(args->dnode, + NULL); + + /* Update and regenerate LSP */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-h-encaps + */ +int isis_instance_segment_routing_srv6_msd_node_msd_max_h_encaps_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srv6db.config.max_h_encaps_msd = yang_dnode_get_uint8(args->dnode, + NULL); + + /* Update and regenerate LSP */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-d + */ +int isis_instance_segment_routing_srv6_msd_node_msd_max_end_d_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->srv6db.config.max_end_d_msd = yang_dnode_get_uint8(args->dnode, + NULL); + + /* Update and regenerate LSP */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/segment-routing-srv6/interface + */ +int isis_instance_segment_routing_srv6_interface_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *ifname; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(lyd_parent(lyd_parent(args->dnode)), NULL, + true); + + ifname = yang_dnode_get_string(args->dnode, NULL); + + sr_debug("Changing SRv6 interface for IS-IS area %s to %s", + area->area_tag, ifname); + + isis_srv6_interface_set(area, ifname); + + return NB_OK; +} + /* * XPath: /frr-isisd:isis/instance/mpls/ldp-sync */ diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index e114467e07cc..a2230cd00995 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -837,6 +837,7 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree, struct isis_mt_router_info *mt_router_info = NULL; struct prefix_pair ip_info; bool has_valid_psid; + bool loc_is_in_ipv6_reach = false; if (isis_lfa_excise_node_check(spftree, lsp->hdr.lsp_id)) { if (IS_DEBUG_LFA) @@ -1128,6 +1129,50 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree, process_N(spftree, vtype, &ip_info, dist, depth + 1, NULL, parent); } + + /* Process SRv6 Locator TLVs */ + + struct isis_item_list *srv6_locators = isis_lookup_mt_items( + &lsp->tlvs->srv6_locator, spftree->mtid); + + struct isis_srv6_locator_tlv *loc; + for (loc = srv6_locators ? (struct isis_srv6_locator_tlv *) + srv6_locators->head + : NULL; + loc; loc = loc->next) { + + if (loc->algorithm != SR_ALGORITHM_SPF) + continue; + + dist = cost + loc->metric; + vtype = VTYPE_IP6REACH_INTERNAL; + memset(&ip_info, 0, sizeof(ip_info)); + ip_info.dest.family = AF_INET6; + ip_info.dest.u.prefix6 = loc->prefix.prefix; + ip_info.dest.prefixlen = loc->prefix.prefixlen; + + /* An SRv6 Locator can be received in both a Prefix + Reachability TLV and an SRv6 Locator TLV (as per RFC + 9352 section #5). We go through the Prefix Reachability + TLVs and check if the SRv6 Locator is present in some of + them. If we find the SRv6 Locator in some Prefix + Reachbility TLV then it means that we have already + processed it before and we can skip it. */ + for (r = ipv6_reachs ? (struct isis_ipv6_reach *) + ipv6_reachs->head + : NULL; + r; r = r->next) { + if (prefix_same((struct prefix *)&r->prefix, + (struct prefix *)&loc->prefix)) + loc_is_in_ipv6_reach = true; + } + + /* SRv6 locator not present in Prefix Reachability TLV, + * let's process it */ + if (!loc_is_in_ipv6_reach) + process_N(spftree, vtype, &ip_info, dist, + depth + 1, NULL, parent); + } } end: diff --git a/isisd/isis_srv6.c b/isisd/isis_srv6.c new file mode 100644 index 000000000000..0eb8ac3fb75f --- /dev/null +++ b/isisd/isis_srv6.c @@ -0,0 +1,853 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * This is an implementation of Segment Routing over IPv6 (SRv6) for IS-IS + * as per RFC 9352 + * https://datatracker.ietf.org/doc/html/rfc9352 + * + * Copyright (C) 2023 Carmine Scarpitta - University of Rome Tor Vergata + */ + +#include + +#include "srv6.h" +#include "termtable.h" +#include "lib/lib_errors.h" + +#include "isisd/isisd.h" +#include "isisd/isis_adjacency.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_route.h" +#include "isisd/isis_srv6.h" +#include "isisd/isis_zebra.h" + +/* Local variables and functions */ +DEFINE_MTYPE_STATIC(ISISD, ISIS_SRV6_SID, "ISIS SRv6 Segment ID"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_SRV6_INFO, "ISIS SRv6 information"); + +/** + * Fill in SRv6 SID Structure Sub-Sub-TLV with information from an SRv6 SID. + * + * @param sid SRv6 SID configuration + * @param structure_subsubtlv SRv6 SID Structure Sub-Sub-TLV to be updated + */ +void isis_srv6_sid_structure2subsubtlv( + const struct isis_srv6_sid *sid, + struct isis_srv6_sid_structure_subsubtlv *structure_subsubtlv) +{ + /* Set Locator Block length */ + structure_subsubtlv->loc_block_len = sid->structure.loc_block_len; + + /* Set Locator Node length */ + structure_subsubtlv->loc_node_len = sid->structure.loc_node_len; + + /* Set Function length */ + structure_subsubtlv->func_len = sid->structure.func_len; + + /* Set Argument length */ + structure_subsubtlv->arg_len = sid->structure.arg_len; +} + +/** + * Fill in SRv6 End SID Sub-TLV with information from an SRv6 SID. + * + * @param sid SRv6 SID configuration + * @param sid_subtlv SRv6 End SID Sub-TLV to be updated + */ +void isis_srv6_end_sid2subtlv(const struct isis_srv6_sid *sid, + struct isis_srv6_end_sid_subtlv *sid_subtlv) +{ + /* Set SRv6 SID flags */ + sid_subtlv->flags = sid->flags; + + /* Set SRv6 SID behavior */ + sid_subtlv->behavior = sid->behavior; + + /* Set SRv6 SID value */ + sid_subtlv->sid = sid->sid; +} + +/** + * Fill in SRv6 Locator TLV with information from an SRv6 locator. + * + * @param loc SRv6 Locator configuration + * @param loc_tlv SRv6 Locator TLV to be updated + */ +void isis_srv6_locator2tlv(const struct isis_srv6_locator *loc, + struct isis_srv6_locator_tlv *loc_tlv) +{ + /* Set SRv6 Locator metric */ + loc_tlv->metric = loc->metric; + + /* Set SRv6 Locator flags */ + loc_tlv->flags = loc->flags; + + /* Set SRv6 Locator algorithm */ + loc_tlv->algorithm = loc->algorithm; + + /* Set SRv6 Locator prefix */ + loc_tlv->prefix = loc->prefix; +} + +/** + * Unset the SRv6 locator for a given IS-IS area. + * + * @param area IS-IS area + * + * @result True on success, False otherwise + */ +bool isis_srv6_locator_unset(struct isis_area *area) +{ + int ret; + struct listnode *node, *nnode; + struct srv6_locator_chunk *chunk; + struct isis_srv6_sid *sid; + struct srv6_adjacency *sra; + + if (strncmp(area->srv6db.config.srv6_locator_name, "", + sizeof(area->srv6db.config.srv6_locator_name)) == 0) { + sr_debug("SRv6 locator not set"); + return true; + } + + /* Delete SRv6 SIDs */ + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_sids, node, nnode, sid)) { + sr_debug( + "Deleting SRv6 SID (locator %s, sid %pI6) from IS-IS area %s", + area->srv6db.config.srv6_locator_name, &sid->sid, + area->area_tag); + + /* Uninstall the SRv6 SID from the forwarding plane through + * Zebra */ + isis_zebra_srv6_sid_uninstall(area, sid); + + listnode_delete(area->srv6db.srv6_sids, sid); + isis_srv6_sid_free(sid); + } + + /* Uninstall all local Adjacency-SIDs. */ + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) + srv6_endx_sid_del(sra); + + /* Inform Zebra that we are releasing the SRv6 locator */ + ret = isis_zebra_srv6_manager_release_locator_chunk( + area->srv6db.config.srv6_locator_name); + if (ret < 0) + return false; + + /* Delete chunks */ + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_locator_chunks, node, nnode, + chunk)) { + sr_debug( + "Releasing chunk of locator %s (prefix %pFX) for IS-IS area %s", + area->srv6db.config.srv6_locator_name, &chunk->prefix, + area->area_tag); + + listnode_delete(area->srv6db.srv6_locator_chunks, chunk); + srv6_locator_chunk_free(&chunk); + } + + /* Clear locator name */ + memset(area->srv6db.config.srv6_locator_name, 0, + sizeof(area->srv6db.config.srv6_locator_name)); + + /* Regenerate LSPs to advertise that the SRv6 locator no longer exists + */ + lsp_regenerate_schedule(area, area->is_type, 0); + + return true; +} + +/** + * Set the interface used to install SRv6 SIDs into the data plane. + * + * @param area IS-IS area + */ +void isis_srv6_interface_set(struct isis_area *area, const char *ifname) +{ + struct listnode *node; + struct isis_srv6_sid *sid; + + if (!ifname) + return; + + if (!strncmp(ifname, area->srv6db.config.srv6_ifname, IF_NAMESIZE)) { + /* The interface has not changed, nothing to do */ + return; + } + + sr_debug("SRv6 interface for IS-IS area %s changed (old interface: %s, new interface: %s)", area->area_tag, area->srv6db.config.srv6_ifname, ifname); + + /* Walk through all SIDs and uninstall them from the data plane */ + for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_sids, node, sid)) { + sr_debug("Uninstalling SID %pI6 from the data plane", &sid->sid); + isis_zebra_srv6_sid_uninstall(area, sid); + } + + strncpy(area->srv6db.config.srv6_ifname, ifname, IF_NAMESIZE - 1); + + if (!if_lookup_by_name(area->srv6db.config.srv6_ifname, VRF_DEFAULT)) { + sr_debug("Interface %s not yet exist in data plane, deferring SIDs installation until it's created", area->srv6db.config.srv6_ifname); + return; + } + + /* Walk through all SIDs and re-install them into the data plane with the newly configured interface */ + for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_sids, node, sid)) { + sr_debug("Installing SID %pI6 from the data plane", &sid->sid); + isis_zebra_srv6_sid_install(area, sid); + } +} + +/** + * Encode SID function in the SRv6 SID. + * + * @param sid + * @param func + * @param offset + * @param len + */ +static void encode_sid_func(struct in6_addr *sid, uint32_t func, uint8_t offset, + uint8_t len) +{ + for (uint8_t idx = 0; idx < len; idx++) { + uint8_t tidx = offset + idx; + sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); + if (func >> (len - 1 - idx) & 0x1) + sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); + } +} + +static bool sid_exist(struct isis_area *area, const struct in6_addr *sid) +{ + struct listnode *node; + struct isis_srv6_sid *s; + struct srv6_adjacency *sra; + + for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_sids, node, s)) + if (sid_same(&s->sid, sid)) + return true; + for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_endx_sids, node, sra)) + if (sid_same(&sra->sid, sid)) + return true; + return false; +} + +/** + * Request a SID from the SRv6 locator. + * + * @param area IS-IS area + * @param chunk SRv6 locator chunk + * @param sid_func The FUNCTION part of the SID to be allocated (a negative + * number will allocate the first available SID) + * + * @return First available SID on success or in6addr_any if the SRv6 + * locator chunk is full + */ +static struct in6_addr +srv6_locator_request_sid(struct isis_area *area, + struct srv6_locator_chunk *chunk, int sid_func) +{ + struct in6_addr sid; + uint8_t offset = 0; + uint8_t func_len = 0; + uint32_t func_max; + bool allocated = false; + + if (!area || !chunk) + return in6addr_any; + + sr_debug("ISIS-SRv6 (%s): requested new SID from locator %s", + area->area_tag, chunk->locator_name); + + /* Let's build the SID, step by step. A SID has the following structure + (defined in RFC 8986): LOCATOR:FUNCTION:ARGUMENT.*/ + + /* First, we encode the LOCATOR in the L most significant bits. */ + sid = chunk->prefix.prefix; + + /* The next part of the SID is the FUNCTION. Let's compute the length + * and the offset of the FUNCTION in the SID */ + func_len = chunk->function_bits_length; + offset = chunk->block_bits_length + chunk->node_bits_length; + + /* Then, encode the FUNCTION */ + if (sid_func >= 0) { + /* SID FUNCTION has been specified. We need to allocate a SID + * with the requested FUNCTION. */ + encode_sid_func(&sid, sid_func, offset, func_len); + if (sid_exist(area, &sid)) { + zlog_warn( + "ISIS-SRv6 (%s): the requested SID %pI6 is already used", + area->area_tag, &sid); + return sid; + } + allocated = true; + } else { + /* SID FUNCTION not specified. We need to choose a FUNCTION that + * is not already used. So let's iterate through all possible + * functions and get the first available one. */ + func_max = (1 << func_len) - 1; + for (uint32_t func = 1; func < func_max; func++) { + encode_sid_func(&sid, func, offset, func_len); + if (sid_exist(area, &sid)) + continue; + allocated = true; + break; + } + } + + if (!allocated) { + /* We ran out of available SIDs */ + zlog_warn("ISIS-SRv6 (%s): no SIDs available in locator %s", + area->area_tag, chunk->locator_name); + return in6addr_any; + } + + sr_debug("ISIS-SRv6 (%s): allocating new SID %pI6", area->area_tag, + &sid); + + return sid; +} + +/** + * Allocate an SRv6 SID from an SRv6 locator. + * + * @param area IS-IS area + * @param chunk SRv6 locator chunk + * @param behavior SRv6 Endpoint Behavior bound to the SID + * + * @result the allocated SID on success, NULL otherwise + */ +struct isis_srv6_sid * +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, + enum srv6_endpoint_behavior_codepoint behavior, + int sid_func) +{ + struct isis_srv6_sid *sid = NULL; + + if (!area || !chunk) + return NULL; + + sid = XCALLOC(MTYPE_ISIS_SRV6_SID, sizeof(struct isis_srv6_sid)); + + sid->sid = srv6_locator_request_sid(area, chunk, sid_func); + if (IPV6_ADDR_SAME(&sid->sid, &in6addr_any)) { + isis_srv6_sid_free(sid); + return NULL; + } + + sid->behavior = behavior; + sid->structure.loc_block_len = chunk->block_bits_length; + sid->structure.loc_node_len = chunk->node_bits_length; + sid->structure.func_len = chunk->function_bits_length; + sid->structure.arg_len = chunk->argument_bits_length; + sid->locator = chunk; + sid->area = area; + + return sid; +} + +void isis_srv6_sid_free(struct isis_srv6_sid *sid) +{ + XFREE(MTYPE_ISIS_SRV6_SID, sid); +} + +/** + * Delete all backup SRv6 End.X SIDs. + * + * @param area IS-IS area + * @param level IS-IS level + */ +void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level) +{ + struct srv6_adjacency *sra; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) + if (sra->type == ISIS_SRV6_LAN_BACKUP && + (sra->adj->level & level)) + srv6_endx_sid_del(sra); +} + +/* --- SRv6 End.X SID management functions ------------------- */ + +/** + * Add new local End.X SID. + * + * @param adj IS-IS Adjacency + * @param backup True to initialize backup Adjacency SID + * @param nexthops List of backup nexthops (for backup End.X SIDs only) + */ +void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, + struct list *nexthops) +{ + struct isis_circuit *circuit = adj->circuit; + struct isis_area *area = circuit->area; + struct srv6_adjacency *sra; + struct isis_srv6_endx_sid_subtlv *adj_sid; + struct isis_srv6_lan_endx_sid_subtlv *ladj_sid; + struct in6_addr nexthop; + uint8_t flags = 0; + struct srv6_locator_chunk *chunk; + uint32_t behavior; + + if (!area || !area->srv6db.srv6_locator_chunks || + list_isempty(area->srv6db.srv6_locator_chunks)) + return; + + sr_debug("ISIS-SRv6 (%s): Add %s End.X SID", area->area_tag, + backup ? "Backup" : "Primary"); + + /* Determine nexthop IP address */ + if (!circuit->ipv6_router || !adj->ll_ipv6_count) + return; + + chunk = (struct srv6_locator_chunk *)listgetdata( + listhead(area->srv6db.srv6_locator_chunks)); + if (!chunk) + return; + + nexthop = adj->ll_ipv6_addrs[0]; + + /* Prepare SRv6 End.X as per RFC9352 section #8.1 */ + if (backup) + SET_FLAG(flags, EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG); + + if (circuit->ext == NULL) + circuit->ext = isis_alloc_ext_subtlvs(); + + behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) + ? SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID + : SRV6_ENDPOINT_BEHAVIOR_END_X; + + sra = XCALLOC(MTYPE_ISIS_SRV6_INFO, sizeof(*sra)); + sra->type = backup ? ISIS_SRV6_LAN_BACKUP : ISIS_SRV6_ADJ_NORMAL; + sra->behavior = behavior; + sra->locator = chunk; + sra->structure.loc_block_len = chunk->block_bits_length; + sra->structure.loc_node_len = chunk->node_bits_length; + sra->structure.func_len = chunk->function_bits_length; + sra->structure.arg_len = chunk->argument_bits_length; + sra->nexthop = nexthop; + + sra->sid = srv6_locator_request_sid(area, chunk, -1); + if (IPV6_ADDR_SAME(&sra->sid, &in6addr_any)) { + XFREE(MTYPE_ISIS_SRV6_INFO, sra); + return; + } + + switch (circuit->circ_type) { + /* SRv6 LAN End.X SID for Broadcast interface section #8.2 */ + case CIRCUIT_T_BROADCAST: + ladj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*ladj_sid)); + memcpy(ladj_sid->neighbor_id, adj->sysid, + sizeof(ladj_sid->neighbor_id)); + ladj_sid->flags = flags; + ladj_sid->algorithm = SR_ALGORITHM_SPF; + ladj_sid->weight = 0; + ladj_sid->behavior = sra->behavior; + ladj_sid->sid = sra->sid; + ladj_sid->subsubtlvs = isis_alloc_subsubtlvs( + ISIS_CONTEXT_SUBSUBTLV_SRV6_ENDX_SID); + ladj_sid->subsubtlvs->srv6_sid_structure = XCALLOC( + MTYPE_ISIS_SUBSUBTLV, + sizeof(*ladj_sid->subsubtlvs->srv6_sid_structure)); + ladj_sid->subsubtlvs->srv6_sid_structure->loc_block_len = + sra->structure.loc_block_len; + ladj_sid->subsubtlvs->srv6_sid_structure->loc_node_len = + sra->structure.loc_node_len; + ladj_sid->subsubtlvs->srv6_sid_structure->func_len = + sra->structure.func_len; + ladj_sid->subsubtlvs->srv6_sid_structure->arg_len = + sra->structure.arg_len; + isis_tlvs_add_srv6_lan_endx_sid(circuit->ext, ladj_sid); + sra->u.lendx_sid = ladj_sid; + break; + /* SRv6 End.X SID for Point to Point interface section #8.1 */ + case CIRCUIT_T_P2P: + adj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*adj_sid)); + adj_sid->flags = flags; + adj_sid->algorithm = SR_ALGORITHM_SPF; + adj_sid->weight = 0; + adj_sid->behavior = sra->behavior; + adj_sid->sid = sra->sid; + adj_sid->subsubtlvs = isis_alloc_subsubtlvs( + ISIS_CONTEXT_SUBSUBTLV_SRV6_ENDX_SID); + adj_sid->subsubtlvs->srv6_sid_structure = XCALLOC( + MTYPE_ISIS_SUBSUBTLV, + sizeof(*adj_sid->subsubtlvs->srv6_sid_structure)); + adj_sid->subsubtlvs->srv6_sid_structure->loc_block_len = + sra->structure.loc_block_len; + adj_sid->subsubtlvs->srv6_sid_structure->loc_node_len = + sra->structure.loc_node_len; + adj_sid->subsubtlvs->srv6_sid_structure->func_len = + sra->structure.func_len; + adj_sid->subsubtlvs->srv6_sid_structure->arg_len = + sra->structure.arg_len; + isis_tlvs_add_srv6_endx_sid(circuit->ext, adj_sid); + sra->u.endx_sid = adj_sid; + break; + default: + flog_err(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u", + __func__, circuit->circ_type); + exit(1); + } + + /* Add Adjacency-SID in SRDB */ + sra->adj = adj; + listnode_add(area->srv6db.srv6_endx_sids, sra); + listnode_add(adj->srv6_endx_sids, sra); + + isis_zebra_srv6_adj_sid_install(sra); +} + +/** + * Add Primary and Backup local SRv6 End.X SID. + * + * @param adj IS-IS Adjacency + */ +void srv6_endx_sid_add(struct isis_adjacency *adj) +{ + srv6_endx_sid_add_single(adj, false, NULL); +} + +/** + * Delete local SRv6 End.X SID. + * + * @param sra SRv6 Adjacency + */ +void srv6_endx_sid_del(struct srv6_adjacency *sra) +{ + struct isis_circuit *circuit = sra->adj->circuit; + struct isis_area *area = circuit->area; + + sr_debug("ISIS-SRv6 (%s): Delete SRv6 End.X SID", area->area_tag); + + isis_zebra_srv6_adj_sid_uninstall(sra); + + /* Release dynamic SRv6 SID and remove subTLVs */ + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + isis_tlvs_del_srv6_lan_endx_sid(circuit->ext, sra->u.lendx_sid); + break; + case CIRCUIT_T_P2P: + isis_tlvs_del_srv6_endx_sid(circuit->ext, sra->u.endx_sid); + break; + default: + flog_err(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u", + __func__, circuit->circ_type); + exit(1); + } + + if (sra->type == ISIS_SRV6_LAN_BACKUP && sra->backup_nexthops) { + sra->backup_nexthops->del = + (void (*)(void *))isis_nexthop_delete; + list_delete(&sra->backup_nexthops); + } + + /* Remove Adjacency-SID from the SRDB */ + listnode_delete(area->srv6db.srv6_endx_sids, sra); + listnode_delete(sra->adj->srv6_endx_sids, sra); + XFREE(MTYPE_ISIS_SRV6_INFO, sra); +} + +/** + * Lookup SRv6 End.X SID by type. + * + * @param adj IS-IS Adjacency + * @param type SRv6 End.X SID type + */ +struct srv6_adjacency *isis_srv6_endx_sid_find(struct isis_adjacency *adj, + enum srv6_adj_type type) +{ + struct srv6_adjacency *sra; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(adj->srv6_endx_sids, node, sra)) + if (sra->type == type) + return sra; + + return NULL; +} + +/** + * Remove all SRv6 End.X SIDs associated to an adjacency that is going down. + * + * @param adj IS-IS Adjacency + * + * @return 0 + */ +static int srv6_adj_state_change(struct isis_adjacency *adj) +{ + struct srv6_adjacency *sra; + struct listnode *node, *nnode; + + if (!adj->circuit->area->srv6db.config.enabled) + return 0; + + if (adj->adj_state == ISIS_ADJ_UP) + return 0; + + for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids, node, nnode, sra)) + srv6_endx_sid_del(sra); + + return 0; +} + +/** + * When IS-IS Adjacency got one or more IPv6 addresses, add new + * IPv6 address to corresponding SRv6 End.X SID accordingly. + * + * @param adj IS-IS Adjacency + * @param family Inet Family (IPv4 or IPv6) + * @param global Indicate if it concerns the Local or Global IPv6 addresses + * + * @return 0 + */ +static int srv6_adj_ip_enabled(struct isis_adjacency *adj, int family, + bool global) +{ + if (!adj->circuit->area->srv6db.config.enabled || global || + family != AF_INET6) + return 0; + + srv6_endx_sid_add(adj); + + return 0; +} + +/** + * When IS-IS Adjacency doesn't have any IPv6 addresses anymore, + * delete the corresponding SRv6 End.X SID(s) accordingly. + * + * @param adj IS-IS Adjacency + * @param family Inet Family (IPv4 or IPv6) + * @param global Indicate if it concerns the Local or Global IPv6 addresses + * + * @return 0 + */ +static int srv6_adj_ip_disabled(struct isis_adjacency *adj, int family, + bool global) +{ + struct srv6_adjacency *sra; + struct listnode *node, *nnode; + + if (!adj->circuit->area->srv6db.config.enabled || global || + family != AF_INET6) + return 0; + + for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids, node, nnode, sra)) + srv6_endx_sid_del(sra); + + return 0; +} + +/** + * Show Segment Routing over IPv6 (SRv6) Node. + * + * @param vty VTY output + * @param area IS-IS area + * @param level IS-IS level + */ +static void show_node(struct vty *vty, struct isis_area *area, int level) +{ + struct isis_lsp *lsp; + struct ttable *tt; + + vty_out(vty, " IS-IS %s SRv6-Nodes:\n\n", circuit_t2string(level)); + + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row( + tt, + "System ID|Algorithm|SRH Max SL|SRH Max End Pop|SRH Max H.encaps|SRH Max End D"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); + + frr_each (lspdb, &area->lspdb[level - 1], lsp) { + struct isis_router_cap *cap; + + if (!lsp->tlvs) + continue; + cap = lsp->tlvs->router_cap; + if (!cap) + continue; + + ttable_add_row(tt, "%pSY|%s|%u|%u|%u|%u", lsp->hdr.lsp_id, + cap->algo[0] == SR_ALGORITHM_SPF ? "SPF" + : "S-SPF", + cap->srv6_msd.max_seg_left_msd, + cap->srv6_msd.max_end_pop_msd, + cap->srv6_msd.max_h_encaps_msd, + cap->srv6_msd.max_end_d_msd); + } + + /* Dump the generated table. */ + if (tt->nrows > 1) { + char *table; + + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + } + ttable_del(tt); +} + +DEFUN(show_srv6_node, show_srv6_node_cmd, + "show " PROTO_NAME " segment-routing srv6 node", + SHOW_STR + PROTO_HELP + "Segment-Routing\n" + "Segment-Routing over IPv6 (SRv6)\n" + "SRv6 node\n") +{ + struct listnode *node, *inode; + struct isis_area *area; + struct isis *isis; + + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + vty_out(vty, "Area %s:\n", + area->area_tag ? area->area_tag : "null"); + if (!area->srv6db.config.enabled) { + vty_out(vty, " SRv6 is disabled\n"); + continue; + } + for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; + level++) + show_node(vty, area, level); + } + } + + return CMD_SUCCESS; +} + +int isis_srv6_ifp_up_notify(struct interface *ifp) +{ + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + struct listnode *node, *node2; + struct isis_area *area; + struct isis_srv6_sid *sid; + + if (!isis) + return 0; + + /* Walk through all areas of the ISIS instance */ + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + /* Skip area, if SRv6 is not enabled */ + if (!area->srv6db.config.enabled) + continue; + + /* Skip area if the interface is not the one configured for SRv6 */ + if (strncmp(area->srv6db.config.srv6_ifname, ifp->name, IF_NAMESIZE)) + continue; + + sr_debug("Interface %s went up. Installing SIDs for area %s in data plane", ifp->name, area->area_tag); + + /* Walk through all SIDs and re-install them into the data plane with the newly configured interface */ + for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_sids, node2, sid)) { + sr_debug("Installing SID %pI6 from the data plane", &sid->sid); + isis_zebra_srv6_sid_install(area, sid); + } + } + + return 0; +} + +/** + * IS-IS SRv6 initialization for given area. + * + * @param area IS-IS area + */ +void isis_srv6_area_init(struct isis_area *area) +{ + struct isis_srv6_db *srv6db; + + if (!area) + return; + + srv6db = &area->srv6db; + + sr_debug("ISIS-SRv6 (%s): Initialize Segment Routing SRv6 DB", + area->area_tag); + + /* Initialize SRv6 Data Base */ + memset(srv6db, 0, sizeof(*srv6db)); + srv6db->srv6_endx_sids = list_new(); + + /* Pull defaults from the YANG module */ + srv6db->config.enabled = yang_get_default_bool("%s/enabled", ISIS_SRV6); + srv6db->config.max_seg_left_msd = + yang_get_default_uint8("%s/msd/node-msd/max-segs-left", + ISIS_SRV6); + srv6db->config.max_end_pop_msd = + yang_get_default_uint8("%s/msd/node-msd/max-end-pop", ISIS_SRV6); + srv6db->config.max_h_encaps_msd = + yang_get_default_uint8("%s/msd/node-msd/max-h-encaps", + ISIS_SRV6); + srv6db->config.max_end_d_msd = + yang_get_default_uint8("%s/msd/node-msd/max-end-d", ISIS_SRV6); + strncpy(srv6db->config.srv6_ifname, yang_get_default_string("%s/interface", ISIS_SRV6), IF_NAMESIZE - 1); + + /* Initialize SRv6 Locator chunks list */ + srv6db->srv6_locator_chunks = list_new(); + + /* Initialize SRv6 SIDs list */ + srv6db->srv6_sids = list_new(); + srv6db->srv6_sids->del = (void (*)(void *))isis_srv6_sid_free; +} + +/** + * Terminate IS-IS SRv6 for the given area. + * + * @param area IS-IS area + */ +void isis_srv6_area_term(struct isis_area *area) +{ + struct isis_srv6_db *srv6db = &area->srv6db; + struct srv6_adjacency *sra; + struct listnode *node, *nnode; + struct srv6_locator_chunk *chunk; + + sr_debug("ISIS-SRv6 (%s): Terminate SRv6", area->area_tag); + + /* Uninstall all local SRv6 End.X SIDs */ + if (area->srv6db.config.enabled) + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, + sra)) + srv6_endx_sid_del(sra); + + /* Free SRv6 Locator chunks list */ + for (ALL_LIST_ELEMENTS(srv6db->srv6_locator_chunks, node, nnode, chunk)) + srv6_locator_chunk_free(&chunk); + list_delete(&srv6db->srv6_locator_chunks); + + /* Free SRv6 SIDs list */ + list_delete(&srv6db->srv6_sids); + list_delete(&srv6db->srv6_endx_sids); +} + +/** + * IS-IS SRv6 global initialization. + */ +void isis_srv6_init(void) +{ + install_element(VIEW_NODE, &show_srv6_node_cmd); + + /* Register hooks. */ + hook_register(isis_adj_state_change_hook, srv6_adj_state_change); + hook_register(isis_adj_ip_enabled_hook, srv6_adj_ip_enabled); + hook_register(isis_adj_ip_disabled_hook, srv6_adj_ip_disabled); +} + +/** + * IS-IS SRv6 global terminate. + */ +void isis_srv6_term(void) +{ + /* Unregister hooks. */ + hook_unregister(isis_adj_state_change_hook, srv6_adj_state_change); + hook_unregister(isis_adj_ip_enabled_hook, srv6_adj_ip_enabled); + hook_unregister(isis_adj_ip_disabled_hook, srv6_adj_ip_disabled); +} diff --git a/isisd/isis_srv6.h b/isisd/isis_srv6.h new file mode 100644 index 000000000000..65c0978bc55a --- /dev/null +++ b/isisd/isis_srv6.h @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * This is an implementation of Segment Routing over IPv6 (SRv6) for IS-IS + * as per RFC 9352 + * https://datatracker.ietf.org/doc/html/rfc9352 + * + * Copyright (C) 2023 Carmine Scarpitta - University of Rome Tor Vergata + */ + +#ifndef _FRR_ISIS_SRV6_H +#define _FRR_ISIS_SRV6_H + +#include "lib/srv6.h" +#include "isisd/isis_tlvs.h" + +/* SRv6 SID structure */ +struct isis_srv6_sid_structure { + uint8_t loc_block_len; + uint8_t loc_node_len; + uint8_t func_len; + uint8_t arg_len; +}; + +/* SRv6 SID not bound to any adjacency */ +struct isis_srv6_sid { + struct isis_srv6_sid *next; + + /* SID flags */ + uint8_t flags; + + /* SID value */ + struct in6_addr sid; + + /* Endpoint behavior bound to the SID */ + enum srv6_endpoint_behavior_codepoint behavior; + + /* SRv6 SID structure */ + struct isis_srv6_sid_structure structure; + + /* Parent SRv6 locator */ + struct srv6_locator_chunk *locator; + + /* Backpointer to IS-IS area */ + struct isis_area *area; +}; + +/* SRv6 Locator */ +struct isis_srv6_locator { + struct isis_srv6_locator *next; + + uint32_t metric; + + uint8_t flags; +#define ISIS_SRV6_LOCATOR_FLAG_D 1 << 7 + + uint8_t algorithm; + struct prefix_ipv6 prefix; + + struct list *srv6_sid; +}; + +/* SRv6 Adjacency-SID type */ +enum srv6_adj_type { + ISIS_SRV6_ADJ_NORMAL = 0, + ISIS_SRV6_LAN_BACKUP, +}; + +/* SRv6 Adjacency. */ +struct srv6_adjacency { + /* Adjacency type */ + enum srv6_adj_type type; + + /* SID flags */ + uint8_t flags; + + /* SID value */ + struct in6_addr sid; + + /* Endpoint behavior bound to the SID */ + enum srv6_endpoint_behavior_codepoint behavior; + + /* SRv6 SID structure */ + struct isis_srv6_sid_structure structure; + + /* Parent SRv6 locator */ + struct srv6_locator_chunk *locator; + + /* Adjacency-SID nexthop information */ + struct in6_addr nexthop; + + /* End.X SID TI-LFA backup nexthops */ + struct list *backup_nexthops; + + /* SRv6 (LAN) End.X SID Sub-TLV */ + union { + struct isis_srv6_endx_sid_subtlv *endx_sid; + struct isis_srv6_lan_endx_sid_subtlv *lendx_sid; + } u; + + /* Back pointer to IS-IS adjacency. */ + struct isis_adjacency *adj; +}; + +/* Per-area IS-IS SRv6 Data Base (SRv6 DB) */ +struct isis_srv6_db { + + /* List of SRv6 Locator chunks */ + struct list *srv6_locator_chunks; + + /* List of SRv6 SIDs allocated by the IS-IS instance */ + struct list *srv6_sids; + + /* List of SRv6 End.X SIDs allocated by the IS-IS instance */ + struct list *srv6_endx_sids; + + /* Area SRv6 configuration. */ + struct { + /* Administrative status of SRv6 */ + bool enabled; + + /* Name of the SRv6 Locator */ + char srv6_locator_name[SRV6_LOCNAME_SIZE]; + + /* Maximum Segments Left Depth supported by the router */ + uint8_t max_seg_left_msd; + + /* Maximum Maximum End Pop Depth supported by the router */ + uint8_t max_end_pop_msd; + + /* Maximum H.Encaps supported by the router */ + uint8_t max_h_encaps_msd; + + /* Maximum End D MSD supported by the router */ + uint8_t max_end_d_msd; + + /* Interface used for installing SRv6 SIDs into the data plane */ + char srv6_ifname[IF_NAMESIZE]; + } config; +}; + +bool isis_srv6_locator_unset(struct isis_area *area); + +void isis_srv6_interface_set(struct isis_area *area, const char *ifname); + +struct isis_srv6_sid * +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, + enum srv6_endpoint_behavior_codepoint behavior, + int sid_func); +extern void isis_srv6_sid_free(struct isis_srv6_sid *sid); + +extern void isis_srv6_area_init(struct isis_area *area); +extern void isis_srv6_area_term(struct isis_area *area); + +void isis_srv6_init(void); +void isis_srv6_term(void); + +void isis_srv6_sid_structure2subsubtlv( + const struct isis_srv6_sid *sid, + struct isis_srv6_sid_structure_subsubtlv *structure_subsubtlv); +void isis_srv6_end_sid2subtlv(const struct isis_srv6_sid *sid, + struct isis_srv6_end_sid_subtlv *sid_subtlv); +void isis_srv6_locator2tlv(const struct isis_srv6_locator *loc, + struct isis_srv6_locator_tlv *loc_tlv); + +void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, + struct list *nexthops); +void srv6_endx_sid_add(struct isis_adjacency *adj); +void srv6_endx_sid_del(struct srv6_adjacency *sra); +struct srv6_adjacency *isis_srv6_endx_sid_find(struct isis_adjacency *adj, + enum srv6_adj_type type); +void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level); + +int isis_srv6_ifp_up_notify(struct interface *ifp); + +#endif /* _FRR_ISIS_SRV6_H */ diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index e871ae8c4f99..ecf43faa7060 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -5,6 +5,9 @@ * Copyright (C) 2015,2017 Christian Franke * * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR) + * + * Copyright (C) 2023 Carmine Scarpitta - University of Rome Tor Vergata + * (for IS-IS Extensions to Support SRv6 as per RFC 9352) */ #include @@ -37,7 +40,7 @@ DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs"); DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs"); -DEFINE_MTYPE_STATIC(ISISD, ISIS_SUBSUBTLV, "ISIS Sub-Sub-TLVs"); +DEFINE_MTYPE(ISISD, ISIS_SUBSUBTLV, "ISIS Sub-Sub-TLVs"); DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists"); typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type, @@ -96,7 +99,8 @@ static const struct pack_order_entry pack_order[] = { PACK_ENTRY(EXTENDED_IP_REACH, ISIS_ITEMS, extended_ip_reach), PACK_ENTRY(MT_IP_REACH, ISIS_MT_ITEMS, mt_ip_reach), PACK_ENTRY(IPV6_REACH, ISIS_ITEMS, ipv6_reach), - PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach) + PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach), + PACK_ENTRY(SRV6_LOCATOR, ISIS_MT_ITEMS, srv6_locator) }; /* This is a forward definition. The table is actually initialized @@ -109,6 +113,18 @@ static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX]; static void append_item(struct isis_item_list *dest, struct isis_item *item); static void init_item_list(struct isis_item_list *items); +static struct isis_subsubtlvs * +isis_copy_subsubtlvs(struct isis_subsubtlvs *subsubtlvs); +static void isis_format_subsubtlvs(struct isis_subsubtlvs *subsubtlvs, + struct sbuf *buf, struct json_object *json, + int indent); +static int isis_pack_subsubtlvs(struct isis_subsubtlvs *subsubtlvs, + struct stream *s); +static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len, + struct stream *stream, struct sbuf *log, void *dest, + int indent, bool *unpacked_known_tlvs); +static void isis_free_subsubtlvs(struct isis_subsubtlvs *subsubtlvs); + /* For tests/isisd, TLV text requires ipv4-unicast instead of standard */ static const char *isis_mtid2str_fake(uint16_t mtid) { @@ -127,6 +143,9 @@ struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void) init_item_list(&ext->lan_sid); ext->aslas = list_new(); + init_item_list(&ext->srv6_endx_sid); + init_item_list(&ext->srv6_lan_endx_sid); + admin_group_init(&ext->ext_admin_group); return ext; @@ -158,6 +177,18 @@ void isis_del_ext_subtlvs(struct isis_ext_subtlvs *ext) admin_group_term(&ext->ext_admin_group); + /* First, free SRv6 End.X SID and SRv6 LAN End.X SID list if needed */ + for (item = ext->srv6_endx_sid.head; item; item = next_item) { + next_item = item->next; + isis_free_subsubtlvs(((struct isis_srv6_endx_sid_subtlv *)item)->subsubtlvs); + XFREE(MTYPE_ISIS_SUBTLV, item); + } + for (item = ext->srv6_lan_endx_sid.head; item; item = next_item) { + next_item = item->next; + isis_free_subsubtlvs(((struct isis_srv6_lan_endx_sid_subtlv *)item)->subsubtlvs); + XFREE(MTYPE_ISIS_SUBTLV, item); + } + XFREE(MTYPE_ISIS_SUBTLV, ext); } @@ -174,6 +205,8 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid) struct isis_lan_adj_sid *lan; struct listnode *node, *nnode; struct isis_asla_subtlvs *new_asla, *asla; + struct isis_srv6_endx_sid_subtlv *srv6_adj; + struct isis_srv6_lan_endx_sid_subtlv *srv6_lan; /* Copy the Extended IS main part */ memcpy(rv, exts, sizeof(struct isis_ext_subtlvs)); @@ -192,9 +225,16 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid) init_item_list(&rv->adj_sid); init_item_list(&rv->lan_sid); + /* Prepare SRv6 (LAN) End.X SID */ + init_item_list(&rv->srv6_endx_sid); + init_item_list(&rv->srv6_lan_endx_sid); + UNSET_SUBTLV(rv, EXT_ADJ_SID); UNSET_SUBTLV(rv, EXT_LAN_ADJ_SID); + UNSET_SUBTLV(rv, EXT_SRV6_ENDX_SID); + UNSET_SUBTLV(rv, EXT_SRV6_LAN_ENDX_SID); + /* Copy Adj SID list for IPv4 & IPv6 in function of MT ID */ for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj != NULL; adj = adj->next) { @@ -238,6 +278,50 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid) SET_SUBTLV(rv, EXT_LAN_ADJ_SID); } + /* Copy SRv6 End.X SID list for IPv4 & IPv6 in function of MT ID */ + for (srv6_adj = (struct isis_srv6_endx_sid_subtlv *) + exts->srv6_endx_sid.head; + srv6_adj != NULL; srv6_adj = srv6_adj->next) { + if ((mtid != 65535) && (mtid != ISIS_MT_DISABLE) && + ((mtid != ISIS_MT_IPV6_UNICAST))) + continue; + + struct isis_srv6_endx_sid_subtlv *new; + + new = XCALLOC(MTYPE_ISIS_SUBTLV, + sizeof(struct isis_srv6_endx_sid_subtlv)); + new->flags = srv6_adj->flags; + new->algorithm = srv6_adj->algorithm; + new->weight = srv6_adj->weight; + new->behavior = srv6_adj->behavior; + new->sid = srv6_adj->sid; + new->subsubtlvs = isis_copy_subsubtlvs(srv6_adj->subsubtlvs); + append_item(&rv->srv6_endx_sid, (struct isis_item *)new); + SET_SUBTLV(rv, EXT_SRV6_ENDX_SID); + } + /* Same for SRv6 LAN End.X SID */ + for (srv6_lan = (struct isis_srv6_lan_endx_sid_subtlv *) + exts->srv6_lan_endx_sid.head; + srv6_lan != NULL; srv6_lan = srv6_lan->next) { + if ((mtid != 65535) && (mtid != ISIS_MT_DISABLE) && + ((mtid != ISIS_MT_IPV6_UNICAST))) + continue; + + struct isis_srv6_lan_endx_sid_subtlv *new; + + new = XCALLOC(MTYPE_ISIS_SUBTLV, + sizeof(struct isis_srv6_lan_endx_sid_subtlv)); + memcpy(new->neighbor_id, srv6_lan->neighbor_id, 6); + new->flags = srv6_lan->flags; + new->algorithm = srv6_lan->algorithm; + new->weight = srv6_lan->weight; + new->behavior = srv6_lan->behavior; + new->sid = srv6_lan->sid; + new->subsubtlvs = isis_copy_subsubtlvs(srv6_lan->subsubtlvs); + append_item(&rv->srv6_lan_endx_sid, (struct isis_item *)new); + SET_SUBTLV(rv, EXT_SRV6_LAN_ENDX_SID); + } + rv->aslas = list_new(); for (ALL_LIST_ELEMENTS(exts->aslas, node, nnode, asla)) { @@ -823,6 +907,156 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, lan->neighbor_id); } } + /* SRv6 End.X SID as per RFC9352 section #8.1 */ + if (IS_SUBTLV(exts, EXT_SRV6_ENDX_SID)) { + struct isis_srv6_endx_sid_subtlv *adj; + + if (json) { + struct json_object *arr_adj_json, *flags_json; + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "srv6-endx-sid", + 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_string_add( + flags_json, "flag-b", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-s", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-p", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, flags_json); + if (adj->subsubtlvs) + isis_format_subsubtlvs(adj->subsubtlvs, + NULL, json, + indent + 4); + } + } else + for (adj = (struct isis_srv6_endx_sid_subtlv *) + exts->srv6_endx_sid.head; + adj; adj = adj->next) { + sbuf_push( + buf, indent, + "SRv6 End.X SID: %pI6, Algorithm: %s, Weight: %hhu, Endpoint Behavior: %s, Flags: B:%c, S:%c, P:%c\n", + &adj->sid, + sr_algorithm_string(adj->algorithm), + adj->weight, + seg6local_action2str(adj->behavior), + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? '1' + : '0'); + if (adj->subsubtlvs) + isis_format_subsubtlvs(adj->subsubtlvs, + buf, NULL, + indent + 4); + } + } + /* SRv6 LAN End.X SID as per RFC9352 section #8.2 */ + if (IS_SUBTLV(exts, EXT_SRV6_LAN_ENDX_SID)) { + struct isis_srv6_lan_endx_sid_subtlv *lan; + if (json) { + struct json_object *arr_adj_json, *flags_json; + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "srv6-lan-endx-sid", + 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_string_add( + flags_json, "flag-b", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-s", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-p", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? "1" + : "0"); + 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, json, + indent + 4); + } + } else + for (lan = (struct isis_srv6_lan_endx_sid_subtlv *) + exts->srv6_lan_endx_sid.head; + lan; lan = lan->next) { + sbuf_push( + buf, indent, + "SRv6 Lan End.X SID: %pI6, Algorithm: %s, Weight: %hhu, Endpoint Behavior: %s, Flags: B:%c, S:%c, P:%c " + "Neighbor-ID: %pSY\n", + &lan->sid, + sr_algorithm_string(lan->algorithm), + lan->weight, + seg6local_action2str(lan->behavior), + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? '1' + : '0', + lan->neighbor_id); + if (lan->subsubtlvs) + isis_format_subsubtlvs(lan->subsubtlvs, + buf, NULL, + indent + 4); + } + } for (ALL_LIST_ELEMENTS_RO(exts->aslas, node, asla)) format_item_asla_subtlvs(asla, buf, indent); } @@ -1112,6 +1346,89 @@ static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts, stream_putl(s, lan->sid); } } + /* SRv6 End.X SID as per RFC9352 section #8.1 */ + if (IS_SUBTLV(exts, EXT_SRV6_ENDX_SID)) { + struct isis_srv6_endx_sid_subtlv *adj; + size_t subtlv_len; + size_t subtlv_len_pos; + + for (adj = (struct isis_srv6_endx_sid_subtlv *) + exts->srv6_endx_sid.head; + adj; adj = adj->next) { + stream_putc(s, ISIS_SUBTLV_SRV6_ENDX_SID); + + subtlv_len_pos = stream_get_endp(s); + stream_putc(s, 0); /* length will be filled later */ + + stream_putc(s, adj->flags); + stream_putc(s, adj->algorithm); + stream_putc(s, adj->weight); + stream_putw(s, adj->behavior); + stream_put(s, &adj->sid, IPV6_MAX_BYTELEN); + + if (adj->subsubtlvs) { + /* Pack Sub-Sub-TLVs */ + if (isis_pack_subsubtlvs(adj->subsubtlvs, s)) + return 1; + } else { + /* No Sub-Sub-TLVs */ + if (STREAM_WRITEABLE(s) < 1) { + *min_len = + ISIS_SUBTLV_SRV6_ENDX_SID_SIZE; + return 1; + } + + /* Put 0 as Sub-Sub-TLV length, because we have + * no Sub-Sub-TLVs */ + stream_putc(s, 0); + } + + subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1; + stream_putc_at(s, subtlv_len_pos, subtlv_len); + } + } + /* SRv6 LAN End.X SID as per RFC9352 section #8.2 */ + if (IS_SUBTLV(exts, EXT_SRV6_LAN_ENDX_SID)) { + struct isis_srv6_lan_endx_sid_subtlv *lan; + size_t subtlv_len; + size_t subtlv_len_pos; + + for (lan = (struct isis_srv6_lan_endx_sid_subtlv *) + exts->srv6_lan_endx_sid.head; + lan; lan = lan->next) { + stream_putc(s, ISIS_SUBTLV_SRV6_LAN_ENDX_SID); + + subtlv_len_pos = stream_get_endp(s); + stream_putc(s, 0); /* length will be filled later */ + + stream_put(s, lan->neighbor_id, 6); + stream_putc(s, lan->flags); + stream_putc(s, lan->algorithm); + stream_putc(s, lan->weight); + stream_putw(s, lan->behavior); + stream_put(s, &lan->sid, IPV6_MAX_BYTELEN); + + if (lan->subsubtlvs) { + /* Pack Sub-Sub-TLVs */ + if (isis_pack_subsubtlvs(lan->subsubtlvs, s)) + return 1; + } else { + /* No Sub-Sub-TLVs */ + if (STREAM_WRITEABLE(s) < 1) { + *min_len = + ISIS_SUBTLV_SRV6_LAN_ENDX_SID_SIZE; + return 1; + } + + /* Put 0 as Sub-Sub-TLV length, because we have + * no Sub-Sub-TLVs */ + stream_putc(s, 0); + } + + subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1; + stream_putc_at(s, subtlv_len_pos, subtlv_len); + } + } for (ALL_LIST_ELEMENTS_RO(exts->aslas, node, asla)) { ret = pack_item_ext_subtlv_asla(asla, s, min_len); @@ -1343,6 +1660,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, uint8_t sum = 0; uint8_t subtlv_type; uint8_t subtlv_len; + uint8_t subsubtlv_len; size_t nb_groups; uint32_t val; @@ -1681,6 +1999,92 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, SET_SUBTLV(exts, EXT_LAN_ADJ_SID); } break; + /* SRv6 End.X SID as per RFC9352 section #8.1 */ + case ISIS_SUBTLV_SRV6_ENDX_SID: + if (subtlv_len < ISIS_SUBTLV_SRV6_ENDX_SID_SIZE) { + TLV_SIZE_MISMATCH(log, indent, + "SRv6 End.X SID"); + stream_forward_getp(s, subtlv_len); + } else { + struct isis_srv6_endx_sid_subtlv *adj; + + adj = XCALLOC( + MTYPE_ISIS_SUBTLV, + sizeof(struct + isis_srv6_endx_sid_subtlv)); + adj->flags = stream_getc(s); + adj->algorithm = stream_getc(s); + adj->weight = stream_getc(s); + adj->behavior = stream_getw(s); + stream_get(&adj->sid, s, IPV6_MAX_BYTELEN); + subsubtlv_len = stream_getc(s); + + adj->subsubtlvs = isis_alloc_subsubtlvs( + ISIS_CONTEXT_SUBSUBTLV_SRV6_ENDX_SID); + + bool unpacked_known_tlvs = false; + if (unpack_tlvs( + ISIS_CONTEXT_SUBSUBTLV_SRV6_ENDX_SID, + subsubtlv_len, s, log, + adj->subsubtlvs, indent + 4, + &unpacked_known_tlvs)) { + XFREE(MTYPE_ISIS_SUBTLV, adj); + break; + } + if (!unpacked_known_tlvs) { + isis_free_subsubtlvs(adj->subsubtlvs); + adj->subsubtlvs = NULL; + } + + append_item(&exts->srv6_endx_sid, + (struct isis_item *)adj); + SET_SUBTLV(exts, EXT_SRV6_ENDX_SID); + } + break; + /* SRv6 LAN End.X SID as per RFC9352 section #8.2 */ + case ISIS_SUBTLV_SRV6_LAN_ENDX_SID: + if (subtlv_len < ISIS_SUBTLV_SRV6_LAN_ENDX_SID_SIZE) { + TLV_SIZE_MISMATCH(log, indent, + "SRv6 LAN End.X SID"); + stream_forward_getp(s, subtlv_len); + } else { + struct isis_srv6_lan_endx_sid_subtlv *lan; + + lan = XCALLOC( + MTYPE_ISIS_SUBTLV, + sizeof(struct + isis_srv6_lan_endx_sid_subtlv)); + stream_get(&(lan->neighbor_id), s, + ISIS_SYS_ID_LEN); + lan->flags = stream_getc(s); + lan->algorithm = stream_getc(s); + lan->weight = stream_getc(s); + lan->behavior = stream_getw(s); + stream_get(&lan->sid, s, IPV6_MAX_BYTELEN); + subsubtlv_len = stream_getc(s); + + lan->subsubtlvs = isis_alloc_subsubtlvs( + ISIS_CONTEXT_SUBSUBTLV_SRV6_ENDX_SID); + + bool unpacked_known_tlvs = false; + if (unpack_tlvs( + ISIS_CONTEXT_SUBSUBTLV_SRV6_ENDX_SID, + subsubtlv_len, s, log, + lan->subsubtlvs, indent + 4, + &unpacked_known_tlvs)) { + XFREE(MTYPE_ISIS_SUBTLV, lan); + break; + } + if (!unpacked_known_tlvs) { + isis_free_subsubtlvs(lan->subsubtlvs); + lan->subsubtlvs = NULL; + } + + append_item(&exts->srv6_lan_endx_sid, + (struct isis_item *)lan); + SET_SUBTLV(exts, EXT_SRV6_LAN_ENDX_SID); + } + break; case ISIS_SUBTLV_ASLA: if (unpack_item_ext_subtlv_asla(mtid, subtlv_len, s, log, indent, @@ -1950,6 +2354,113 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context, return 0; } +/* Functions related to Sub-Sub-TLV 1 SRv6 SID Structure + * as per RFC 9352 section #9 */ +static struct isis_srv6_sid_structure_subsubtlv * +copy_subsubtlv_srv6_sid_structure( + struct isis_srv6_sid_structure_subsubtlv *sid_struct) +{ + if (!sid_struct) + return NULL; + + struct isis_srv6_sid_structure_subsubtlv *rv = + XCALLOC(MTYPE_ISIS_SUBSUBTLV, sizeof(*rv)); + + rv->loc_block_len = sid_struct->loc_block_len; + rv->loc_node_len = sid_struct->loc_node_len; + rv->func_len = sid_struct->func_len; + rv->arg_len = sid_struct->arg_len; + + return rv; +} + +static void format_subsubtlv_srv6_sid_structure( + struct isis_srv6_sid_structure_subsubtlv *sid_struct, struct sbuf *buf, + struct json_object *json, int indent) +{ + if (!sid_struct) + return; + + if (json) { + struct json_object *sid_struct_json; + sid_struct_json = json_object_new_object(); + json_object_object_add(json, "srv6-sid-structure", + sid_struct_json); + json_object_int_add(sid_struct_json, "loc-block-len", + sid_struct->loc_block_len); + json_object_int_add(sid_struct_json, "loc-node-len", + sid_struct->loc_node_len); + json_object_int_add(sid_struct_json, "func-len", + sid_struct->func_len); + json_object_int_add(sid_struct_json, "arg-len", + sid_struct->arg_len); + } else { + sbuf_push(buf, indent, "SRv6 SID Structure "); + sbuf_push(buf, 0, "Locator Block length: %hhu, ", + sid_struct->loc_block_len); + sbuf_push(buf, 0, "Locator Node length: %hhu, ", + sid_struct->loc_node_len); + sbuf_push(buf, 0, "Function length: %hhu, ", + sid_struct->func_len); + sbuf_push(buf, 0, "Argument length: %hhu, ", + sid_struct->arg_len); + sbuf_push(buf, 0, "\n"); + } +} + +static void free_subsubtlv_srv6_sid_structure( + struct isis_srv6_sid_structure_subsubtlv *sid_struct) +{ + XFREE(MTYPE_ISIS_SUBSUBTLV, sid_struct); +} + +static int pack_subsubtlv_srv6_sid_structure( + struct isis_srv6_sid_structure_subsubtlv *sid_struct, struct stream *s) +{ + if (!sid_struct) + return 0; + + if (STREAM_WRITEABLE(s) < 6) { + return 1; + } + + stream_putc(s, ISIS_SUBSUBTLV_SRV6_SID_STRUCTURE); + stream_putc(s, 4); + stream_putc(s, sid_struct->loc_block_len); + stream_putc(s, sid_struct->loc_node_len); + stream_putc(s, sid_struct->func_len); + stream_putc(s, sid_struct->arg_len); + + return 0; +} + +static int unpack_subsubtlv_srv6_sid_structure( + enum isis_tlv_context context, uint8_t tlv_type, uint8_t tlv_len, + struct stream *s, struct sbuf *log, void *dest, int indent) +{ + struct isis_subsubtlvs *subsubtlvs = dest; + struct isis_srv6_sid_structure_subsubtlv sid_struct = {}; + + sbuf_push(log, indent, "Unpacking SRv6 SID Structure...\n"); + if (tlv_len != 4) { + sbuf_push( + log, indent, + "Invalid SRv6 SID Structure Sub-Sub-TLV size. (Expected 4 bytes, got %hhu)\n", + tlv_len); + return 1; + } + + sid_struct.loc_block_len = stream_getc(s); + sid_struct.loc_node_len = stream_getc(s); + sid_struct.func_len = stream_getc(s); + sid_struct.arg_len = stream_getc(s); + + subsubtlvs->srv6_sid_structure = + copy_subsubtlv_srv6_sid_structure(&sid_struct); + + return 0; +} + static struct isis_item *copy_item(enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item *item); @@ -1970,6 +2481,76 @@ static int pack_items_(uint16_t mtid, enum isis_tlv_context context, struct list *new_fragment_arg); #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__) +/* Functions related to Sub-Sub-TLVs in general */ + +struct isis_subsubtlvs *isis_alloc_subsubtlvs(enum isis_tlv_context context) +{ + struct isis_subsubtlvs *result; + + result = XCALLOC(MTYPE_ISIS_SUBSUBTLV, sizeof(*result)); + result->context = context; + + return result; +} + +static struct isis_subsubtlvs * +isis_copy_subsubtlvs(struct isis_subsubtlvs *subsubtlvs) +{ + if (!subsubtlvs) + return NULL; + + struct isis_subsubtlvs *rv = XCALLOC(MTYPE_ISIS_SUBSUBTLV, sizeof(*rv)); + + rv->context = subsubtlvs->context; + + rv->srv6_sid_structure = copy_subsubtlv_srv6_sid_structure( + subsubtlvs->srv6_sid_structure); + + return rv; +} + +static void isis_format_subsubtlvs(struct isis_subsubtlvs *subsubtlvs, + struct sbuf *buf, struct json_object *json, + int indent) +{ + format_subsubtlv_srv6_sid_structure(subsubtlvs->srv6_sid_structure, buf, + json, indent); +} + +static void isis_free_subsubtlvs(struct isis_subsubtlvs *subsubtlvs) +{ + if (!subsubtlvs) + return; + + free_subsubtlv_srv6_sid_structure(subsubtlvs->srv6_sid_structure); + + XFREE(MTYPE_ISIS_SUBSUBTLV, subsubtlvs); +} + +static int isis_pack_subsubtlvs(struct isis_subsubtlvs *subsubtlvs, + struct stream *s) +{ + int rv; + size_t subsubtlv_len_pos = stream_get_endp(s); + + if (STREAM_WRITEABLE(s) < 1) + return 1; + + stream_putc(s, 0); /* Put 0 as Sub-Sub-TLVs length, filled in later */ + + rv = pack_subsubtlv_srv6_sid_structure(subsubtlvs->srv6_sid_structure, + s); + if (rv) + return rv; + + size_t subsubtlv_len = stream_get_endp(s) - subsubtlv_len_pos - 1; + if (subsubtlv_len > 255) + return 1; + + stream_putc_at(s, subsubtlv_len_pos, subsubtlv_len); + return 0; +} + /* Functions related to subtlvs */ static struct isis_subtlvs *isis_alloc_subtlvs(enum isis_tlv_context context) @@ -1980,6 +2561,7 @@ static struct isis_subtlvs *isis_alloc_subtlvs(enum isis_tlv_context context) result->context = context; init_item_list(&result->prefix_sids); + init_item_list(&result->srv6_end_sids); return result; } @@ -1998,6 +2580,10 @@ static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs) rv->source_prefix = copy_subtlv_ipv6_source_prefix(subtlvs->source_prefix); + + copy_items(subtlvs->context, ISIS_SUBTLV_SRV6_END_SID, + &subtlvs->srv6_end_sids, &rv->srv6_end_sids); + return rv; } @@ -2008,6 +2594,9 @@ static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf, &subtlvs->prefix_sids, buf, json, indent); format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, json, indent); + + format_items(subtlvs->context, ISIS_SUBTLV_SRV6_END_SID, + &subtlvs->srv6_end_sids, buf, json, indent); } static void isis_free_subtlvs(struct isis_subtlvs *subtlvs) @@ -2020,6 +2609,9 @@ static void isis_free_subtlvs(struct isis_subtlvs *subtlvs) XFREE(MTYPE_ISIS_SUBTLV, subtlvs->source_prefix); + free_items(subtlvs->context, ISIS_SUBTLV_SRV6_END_SID, + &subtlvs->srv6_end_sids); + XFREE(MTYPE_ISIS_SUBTLV, subtlvs); } @@ -2038,22 +2630,191 @@ static int pack_subtlvs(struct isis_subtlvs *subtlvs, struct stream *s) if (rv) return rv; - rv = pack_subtlv_ipv6_source_prefix(subtlvs->source_prefix, s); - if (rv) - return rv; + rv = pack_subtlv_ipv6_source_prefix(subtlvs->source_prefix, s); + if (rv) + return rv; + + rv = pack_items(subtlvs->context, ISIS_SUBTLV_SRV6_END_SID, + &subtlvs->srv6_end_sids, s, NULL, NULL, NULL, NULL); + if (rv) + return rv; + + size_t subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1; + if (subtlv_len > 255) + return 1; + + stream_putc_at(s, subtlv_len_pos, subtlv_len); + return 0; +} + +static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len, + struct stream *stream, struct sbuf *log, void *dest, + int indent, bool *unpacked_known_tlvs); + +/* Functions for Sub-TLV 5 SRv6 End SID as per RFC 9352 section #7.2 */ +static struct isis_item *copy_item_srv6_end_sid(struct isis_item *i) +{ + struct isis_srv6_end_sid_subtlv *sid = + (struct isis_srv6_end_sid_subtlv *)i; + struct isis_srv6_end_sid_subtlv *rv = + XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv)); + + rv->behavior = sid->behavior; + rv->sid = sid->sid; + rv->subsubtlvs = isis_copy_subsubtlvs(sid->subsubtlvs); + + return (struct isis_item *)rv; +} + +static void format_item_srv6_end_sid(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, struct json_object *json, + int indent) +{ + struct isis_srv6_end_sid_subtlv *sid = + (struct isis_srv6_end_sid_subtlv *)i; + + if (json) { + struct json_object *sid_json; + sid_json = json_object_new_object(); + json_object_object_add(json, "srv6-end-sid", sid_json); + json_object_string_add(sid_json, "endpoint-behavior", + seg6local_action2str(sid->behavior)); + json_object_string_addf(sid_json, "sid-value", "%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, ", + seg6local_action2str(sid->behavior)); + sbuf_push(buf, 0, "SID value: %pI6\n", &sid->sid); + + if (sid->subsubtlvs) { + sbuf_push(buf, indent, " Sub-Sub-TLVs:\n"); + isis_format_subsubtlvs(sid->subsubtlvs, buf, NULL, + indent + 4); + } + } +} + +static void free_item_srv6_end_sid(struct isis_item *i) +{ + struct isis_srv6_end_sid_subtlv *item = + (struct isis_srv6_end_sid_subtlv *)i; + + isis_free_subsubtlvs(item->subsubtlvs); + XFREE(MTYPE_ISIS_SUBTLV, i); +} + +static int pack_item_srv6_end_sid(struct isis_item *i, struct stream *s, + size_t *min_len) +{ + struct isis_srv6_end_sid_subtlv *sid = + (struct isis_srv6_end_sid_subtlv *)i; + + if (STREAM_WRITEABLE(s) < 19) { + *min_len = 19; + return 1; + } + + stream_putc(s, sid->flags); + stream_putw(s, sid->behavior); + stream_put(s, &sid->sid, IPV6_MAX_BYTELEN); + + if (sid->subsubtlvs) { + /* Pack Sub-Sub-TLVs */ + if (isis_pack_subsubtlvs(sid->subsubtlvs, s)) + return 1; + } else { + /* No Sub-Sub-TLVs */ + if (STREAM_WRITEABLE(s) < 1) { + *min_len = 20; + return 1; + } + + /* Put 0 as Sub-Sub-TLV length, because we have no Sub-Sub-TLVs + */ + stream_putc(s, 0); + } + + return 0; +} + +static int unpack_item_srv6_end_sid(uint16_t mtid, uint8_t len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_subtlvs *subtlvs = dest; + struct isis_srv6_end_sid_subtlv *sid = NULL; + size_t consume; + uint8_t subsubtlv_len; + + sbuf_push(log, indent, "Unpacking SRv6 End SID...\n"); + + consume = 19; + if (len < consume) { + sbuf_push( + log, indent, + "Not enough data left. (expected 19 or more bytes, got %hhu)\n", + len); + goto out; + } + + sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*sid)); + + sid->flags = stream_getc(s); + sid->behavior = stream_getw(s); + stream_get(&sid->sid, s, IPV6_MAX_BYTELEN); + + format_item_srv6_end_sid(mtid, (struct isis_item *)sid, log, NULL, + indent + 2); + + /* Process Sub-Sub-TLVs */ + consume += 1; + if (len < consume) { + sbuf_push( + log, indent, + "Expected 1 byte of Sub-Sub-TLV len, but no more data persent.\n"); + goto out; + } + subsubtlv_len = stream_getc(s); + + consume += subsubtlv_len; + if (len < consume) { + sbuf_push(log, indent, + "Expected %hhu bytes of Sub-Sub-TLVs, but only %u bytes available.\n", + subsubtlv_len, len - ((uint8_t)consume - subsubtlv_len)); + goto out; + } - size_t subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1; - if (subtlv_len > 255) - return 1; + sid->subsubtlvs = + isis_alloc_subsubtlvs(ISIS_CONTEXT_SUBSUBTLV_SRV6_END_SID); - stream_putc_at(s, subtlv_len_pos, subtlv_len); + bool unpacked_known_tlvs = false; + if (unpack_tlvs(ISIS_CONTEXT_SUBSUBTLV_SRV6_END_SID, subsubtlv_len, s, + log, sid->subsubtlvs, indent + 4, + &unpacked_known_tlvs)) { + goto out; + } + if (!unpacked_known_tlvs) { + isis_free_subsubtlvs(sid->subsubtlvs); + sid->subsubtlvs = NULL; + } + + append_item(&subtlvs->srv6_end_sids, (struct isis_item *)sid); return 0; +out: + if (sid) + free_item_srv6_end_sid((struct isis_item *)sid); + return 1; } -static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len, - struct stream *stream, struct sbuf *log, void *dest, - int indent, bool *unpacked_known_tlvs); - /* Functions related to TLVs 1 Area Addresses */ static struct isis_item *copy_item_area_address(struct isis_item *i) @@ -4132,6 +4893,11 @@ static void format_tlv_router_cap(const struct isis_router_cap *router_cap, " Got an unsupported sub-TLV: Yes\n"); } #endif /* ifndef FABRICD */ + + /* SRv6 Flags as per RFC 9352 section #2 */ + if (router_cap->srv6_cap.is_srv6_capable) + sbuf_push(buf, indent, " SRv6: O:%s\n", + SUPPORTS_SRV6_OAM(&router_cap->srv6_cap) ? "1" : "0"); } static void free_tlv_router_cap(struct isis_router_cap *router_cap) @@ -4193,7 +4959,7 @@ static size_t isis_router_cap_tlv_size(const struct isis_router_cap *router_cap) #ifndef FABRICD size_t fad_sz; #endif /* ifndef FABRICD */ - int nb_algo; + int nb_algo, nb_msd; if ((router_cap->srgb.range_size != 0) && (router_cap->srgb.lower_bound != 0)) { @@ -4227,6 +4993,28 @@ static size_t isis_router_cap_tlv_size(const struct isis_router_cap *router_cap) } #endif /* ifndef FABRICD */ + if (router_cap->srv6_cap.is_srv6_capable) { + sz += ISIS_SUBTLV_TYPE_FIELD_SIZE + + ISIS_SUBTLV_LENGTH_FIELD_SIZE + + ISIS_SUBTLV_SRV6_CAPABILITIES_SIZE; + + nb_algo = isis_tlvs_sr_algo_count(router_cap); + if (nb_algo != 0) + sz += ISIS_SUBTLV_TYPE_FIELD_SIZE + + ISIS_SUBTLV_LENGTH_FIELD_SIZE + nb_algo; + + nb_msd = router_cap->srv6_msd.max_seg_left_msd + + router_cap->srv6_msd.max_end_pop_msd + + router_cap->srv6_msd.max_h_encaps_msd + + router_cap->srv6_msd.max_end_d_msd; + if (nb_msd != 0) + sz += ISIS_SUBTLV_TYPE_FIELD_SIZE + + ISIS_SUBTLV_LENGTH_FIELD_SIZE + + (ISIS_SUBTLV_NODE_MSD_TYPE_SIZE + + ISIS_SUBTLV_NODE_MSD_VALUE_SIZE) * + nb_msd; + } + return sz; } @@ -4235,6 +5023,8 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap, { size_t tlv_len, len_pos; uint8_t nb_algo; + size_t subtlv_len, subtlv_len_pos; + bool sr_algo_subtlv_present = false; if (!router_cap) return 0; @@ -4268,6 +5058,7 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap, for (int i = 0; i < SR_ALGORITHM_COUNT; i++) if (router_cap->algo[i] != SR_ALGORITHM_UNSET) stream_putc(s, router_cap->algo[i]); + sr_algo_subtlv_present = true; } /* Local Block if defined as per RFC8667 section #3.3 */ @@ -4366,6 +5157,83 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap, } #endif /* ifndef FABRICD */ + /* Add SRv6 capabilities if set as per RFC 9352 section #2 */ + if (router_cap->srv6_cap.is_srv6_capable) { + stream_putc(s, ISIS_SUBTLV_SRV6_CAPABILITIES); + stream_putc(s, ISIS_SUBTLV_SRV6_CAPABILITIES_SIZE); + stream_putw(s, router_cap->srv6_cap.flags); + + /* + * Then add SR Algorithm if set and if we haven't already + * added it when we processed SR-MPLS related Sub-TLVs as + * per RFC 9352 section #3 + */ + if (!sr_algo_subtlv_present) { + nb_algo = isis_tlvs_sr_algo_count(router_cap); + if (nb_algo > 0) { + stream_putc(s, ISIS_SUBTLV_ALGORITHM); + stream_putc(s, nb_algo); + for (int i = 0; i < SR_ALGORITHM_COUNT; i++) + if (router_cap->algo[i] != + SR_ALGORITHM_UNSET) + stream_putc(s, + router_cap->algo[i]); + } + } + + /* And finish with MSDs if set as per RFC 9352 section #4 */ + if (router_cap->srv6_msd.max_seg_left_msd + + router_cap->srv6_msd.max_end_pop_msd + + router_cap->srv6_msd.max_h_encaps_msd + + router_cap->srv6_msd.max_end_d_msd != + 0) { + stream_putc(s, ISIS_SUBTLV_NODE_MSD); + + subtlv_len_pos = stream_get_endp(s); + /* Put 0 as Sub-TLV length for now, real length will be + * adjusted later */ + stream_putc(s, 0); + + /* RFC 9352 section #4.1 */ + if (router_cap->srv6_msd.max_seg_left_msd != 0) { + stream_putc(s, ISIS_SUBTLV_SRV6_MAX_SL_MSD); + stream_putc( + s, + router_cap->srv6_msd.max_seg_left_msd); + } + + /* RFC 9352 section #4.2 */ + if (router_cap->srv6_msd.max_end_pop_msd != 0) { + stream_putc(s, + ISIS_SUBTLV_SRV6_MAX_END_POP_MSD); + stream_putc( + s, + router_cap->srv6_msd.max_end_pop_msd); + } + + /* RFC 9352 section #4.3 */ + if (router_cap->srv6_msd.max_h_encaps_msd != 0) { + stream_putc(s, + ISIS_SUBTLV_SRV6_MAX_H_ENCAPS_MSD); + stream_putc( + s, + router_cap->srv6_msd.max_h_encaps_msd); + } + + /* RFC 9352 section #4.4 */ + if (router_cap->srv6_msd.max_end_d_msd != 0) { + stream_putc(s, ISIS_SUBTLV_SRV6_MAX_END_D_MSD); + stream_putc(s, + router_cap->srv6_msd.max_end_d_msd); + } + + /* Adjust Node MSD Sub-TLV length which depends on MSDs + * presence */ + subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1; + stream_putc_at(s, subtlv_len_pos, subtlv_len); + } + } + /* Adjust TLV length which depends on subTLVs presence */ tlv_len = stream_get_endp(s) - len_pos - 1; stream_putc_at(s, len_pos, tlv_len); @@ -4384,6 +5252,7 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, uint8_t length; uint8_t subtlv_len; uint8_t size; + int num_msd; sbuf_push(log, indent, "Unpacking Router Capability TLV...\n"); if (tlv_len < ISIS_ROUTER_CAP_SIZE) { @@ -4552,19 +5421,66 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, break; case ISIS_SUBTLV_NODE_MSD: + sbuf_push(log, indent, + "Unpacking Node MSD sub-TLV...\n"); + /* Check that MSD is correctly formated */ - if (length < MSD_TLV_SIZE) { + if (length % 2) { + sbuf_push( + log, indent, + "WARNING: Unexpected MSD sub-TLV length\n"); stream_forward_getp(s, length); break; } - msd_type = stream_getc(s); - rcap->msd = stream_getc(s); - /* Only BMI-MSD type has been defined in RFC 8491 */ - if (msd_type != MSD_TYPE_BASE_MPLS_IMPOSITION) - rcap->msd = 0; - /* Only one MSD is standardized. Skip others */ - if (length > MSD_TLV_SIZE) - stream_forward_getp(s, length - MSD_TLV_SIZE); + + /* Get the number of MSDs carried in the value field of + * the Node MSD sub-TLV. The value field consists of one + * or more pairs of a 1-octet MSD-Type and 1-octet + * MSD-Value */ + num_msd = length / 2; + + /* Unpack MSDs */ + for (int i = 0; i < num_msd; i++) { + msd_type = stream_getc(s); + + switch (msd_type) { + case MSD_TYPE_BASE_MPLS_IMPOSITION: + /* BMI-MSD type as per RFC 8491 */ + rcap->msd = stream_getc(s); + break; + case ISIS_SUBTLV_SRV6_MAX_SL_MSD: + /* SRv6 Maximum Segments Left MSD Type + * as per RFC 9352 section #4.1 */ + rcap->srv6_msd.max_seg_left_msd = + stream_getc(s); + break; + case ISIS_SUBTLV_SRV6_MAX_END_POP_MSD: + /* SRv6 Maximum End Pop MSD Type as per + * RFC 9352 section #4.2 */ + rcap->srv6_msd.max_end_pop_msd = + stream_getc(s); + break; + case ISIS_SUBTLV_SRV6_MAX_H_ENCAPS_MSD: + /* SRv6 Maximum H.Encaps MSD Type as per + * RFC 9352 section #4.3 */ + rcap->srv6_msd.max_h_encaps_msd = + stream_getc(s); + break; + case ISIS_SUBTLV_SRV6_MAX_END_D_MSD: + /* SRv6 Maximum End D MSD Type as per + * RFC 9352 section #4.4 */ + rcap->srv6_msd.max_end_d_msd = + stream_getc(s); + break; + default: + /* Unknown MSD, let's skip it */ + sbuf_push( + log, indent, + "WARNING: Skipping unknown MSD Type %hhu (1 byte)\n", + msd_type); + stream_forward_getp(s, 1); + } + } break; #ifndef FABRICD case ISIS_SUBTLV_FAD: @@ -4640,6 +5556,47 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, } break; #endif /* ifndef FABRICD */ + case ISIS_SUBTLV_SRV6_CAPABILITIES: + sbuf_push(log, indent, + "Unpacking SRv6 Capabilities sub-TLV...\n"); + /* Check that SRv6 capabilities sub-TLV is correctly + * formated */ + if (length < ISIS_SUBTLV_SRV6_CAPABILITIES_SIZE) { + sbuf_push( + log, indent, + "WARNING: Unexpected SRv6 Capabilities sub-TLV size (expected %d or more bytes, got %hhu)\n", + ISIS_SUBTLV_SRV6_CAPABILITIES_SIZE, + length); + stream_forward_getp(s, length); + break; + } + /* Only one SRv6 capabilities is supported. Skip + * subsequent one */ + if (rcap->srv6_cap.is_srv6_capable) { + sbuf_push( + log, indent, + "WARNING: SRv6 Capabilities sub-TLV present multiple times, ignoring.\n"); + stream_forward_getp(s, length); + break; + } + rcap->srv6_cap.is_srv6_capable = true; + rcap->srv6_cap.flags = stream_getw(s); + + /* The SRv6 Capabilities Sub-TLV may contain optional + * Sub-Sub-TLVs, as per RFC 9352 section #2. + * Skip any Sub-Sub-TLV contained in the SRv6 + * Capabilities Sub-TLV that is not currently supported + * by IS-IS. + */ + if (length > ISIS_SUBTLV_SRV6_CAPABILITIES_SIZE) + sbuf_push( + log, indent, + "Skipping unknown sub-TLV (%hhu bytes)\n", + length); + stream_forward_getp( + s, length - ISIS_SUBTLV_SRV6_CAPABILITIES_SIZE); + + break; default: stream_forward_getp(s, length); break; @@ -5041,6 +5998,14 @@ static int pack_items_(uint16_t mtid, enum isis_tlv_context context, stream_putw(s, mtid); } + /* The SRv6 Locator TLV (RFC 9352 section #7.1) starts with the MTID + * field */ + if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_SRV6_LOCATOR) { + if (STREAM_WRITEABLE(s) < 2) + goto too_long; + stream_putw(s, mtid); + } + if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_OLDSTYLE_REACH) { if (STREAM_WRITEABLE(s) < 1) goto too_long; @@ -5173,7 +6138,8 @@ static int unpack_tlv_with_items(enum isis_tlv_context context, tlv_start = stream_get_getp(s); tlv_pos = 0; - if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(tlv_type)) { + if (context == ISIS_CONTEXT_LSP && + (IS_COMPAT_MT_TLV(tlv_type) || tlv_type == ISIS_TLV_SRV6_LOCATOR)) { if (tlv_len < 2) { sbuf_push(log, indent, "TLV is too short to contain MTID\n"); @@ -5325,6 +6291,207 @@ static void copy_mt_items(enum isis_tlv_context context, } } +/* Functions related to TLV 27 SRv6 Locator as per RFC 9352 section #7.1*/ +static struct isis_item *copy_item_srv6_locator(struct isis_item *i) +{ + struct isis_srv6_locator_tlv *loc = (struct isis_srv6_locator_tlv *)i; + struct isis_srv6_locator_tlv *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->metric = loc->metric; + rv->flags = loc->flags; + rv->algorithm = loc->algorithm; + rv->prefix = loc->prefix; + rv->subtlvs = copy_subtlvs(loc->subtlvs); + + return (struct isis_item *)rv; +} + +static void format_item_srv6_locator(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, struct json_object *json, + int indent) +{ + struct isis_srv6_locator_tlv *loc = (struct isis_srv6_locator_tlv *)i; + + if (json) { + struct json_object *loc_json; + loc_json = json_object_new_object(); + json_object_object_add(json, "srv6-locator", loc_json); + json_object_int_add(loc_json, "mt-id", mtid); + json_object_string_addf(loc_json, "prefix", "%pFX", + &loc->prefix); + json_object_int_add(loc_json, "metric", loc->metric); + json_object_string_add( + loc_json, "d-flag", + CHECK_FLAG(loc->flags, ISIS_TLV_SRV6_LOCATOR_FLAG_D) + ? "yes" + : ""); + json_object_int_add(loc_json, "algorithm", loc->algorithm); + json_object_string_add(loc_json, "mt-name", + 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, + CHECK_FLAG(loc->flags, ISIS_TLV_SRV6_LOCATOR_FLAG_D) + ? " D-flag" + : ""); + sbuf_push(buf, 0, " %s\n", isis_mtid2str(mtid)); + + if (loc->subtlvs) { + sbuf_push(buf, indent, " Sub-TLVs:\n"); + format_subtlvs(loc->subtlvs, buf, NULL, indent + 4); + } + } +} + +static void free_item_srv6_locator(struct isis_item *i) +{ + struct isis_srv6_locator_tlv *item = (struct isis_srv6_locator_tlv *)i; + + isis_free_subtlvs(item->subtlvs); + XFREE(MTYPE_ISIS_TLV, item); +} + +static int pack_item_srv6_locator(struct isis_item *i, struct stream *s, + size_t *min_len) +{ + struct isis_srv6_locator_tlv *loc = (struct isis_srv6_locator_tlv *)i; + + if (STREAM_WRITEABLE(s) < 7 + (unsigned)PSIZE(loc->prefix.prefixlen)) { + *min_len = 7 + (unsigned)PSIZE(loc->prefix.prefixlen); + return 1; + } + + stream_putl(s, loc->metric); + stream_putc(s, loc->flags); + stream_putc(s, loc->algorithm); + /* Locator size */ + stream_putc(s, loc->prefix.prefixlen); + /* Locator prefix */ + stream_put(s, &loc->prefix.prefix.s6_addr, + PSIZE(loc->prefix.prefixlen)); + + if (loc->subtlvs) { + /* Pack Sub-TLVs */ + if (pack_subtlvs(loc->subtlvs, s)) + return 1; + } else { + /* No Sub-TLVs */ + if (STREAM_WRITEABLE(s) < 1) { + *min_len = 8 + (unsigned)PSIZE(loc->prefix.prefixlen); + return 1; + } + + /* Put 0 as Sub-TLV length, because we have no Sub-TLVs */ + stream_putc(s, 0); + } + + return 0; +} + +static int unpack_item_srv6_locator(uint16_t mtid, uint8_t len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + struct isis_srv6_locator_tlv *rv = NULL; + size_t consume; + uint8_t subtlv_len; + struct isis_item_list *items; + + items = isis_get_mt_items(&tlvs->srv6_locator, mtid); + + sbuf_push(log, indent, "Unpacking SRv6 Locator...\n"); + consume = 7; + if (len < consume) { + sbuf_push( + log, indent, + "Not enough data left. (expected 7 or more bytes, got %hhu)\n", + len); + goto out; + } + + rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->metric = stream_getl(s); + rv->flags = stream_getc(s); + rv->algorithm = stream_getc(s); + + rv->prefix.family = AF_INET6; + rv->prefix.prefixlen = stream_getc(s); + if (rv->prefix.prefixlen > IPV6_MAX_BITLEN) { + sbuf_push(log, indent, "Loc Size %u is implausible for SRv6\n", + rv->prefix.prefixlen); + goto out; + } + + consume += PSIZE(rv->prefix.prefixlen); + if (len < consume) { + sbuf_push( + log, indent, + "Expected %u bytes of prefix, but only %u bytes available.\n", + PSIZE(rv->prefix.prefixlen), len - 7); + goto out; + } + stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen)); + + struct in6_addr orig_locator = rv->prefix.prefix; + apply_mask_ipv6(&rv->prefix); + if (memcmp(&orig_locator, &rv->prefix.prefix, sizeof(orig_locator))) + sbuf_push(log, indent + 2, + "WARNING: SRv6 Locator had hostbits set.\n"); + format_item_srv6_locator(mtid, (struct isis_item *)rv, log, NULL, + indent + 2); + + consume += 1; + if (len < consume) { + sbuf_push( + log, indent, + "Expected 1 byte of subtlv len, but no more data persent.\n"); + goto out; + } + subtlv_len = stream_getc(s); + + if (subtlv_len) { + consume += subtlv_len; + if (len < consume) { + sbuf_push( + log, indent, + "Expected %hhu bytes of subtlvs, but only %u bytes available.\n", + subtlv_len, + len - 7 - PSIZE(rv->prefix.prefixlen)); + goto out; + } + + rv->subtlvs = + isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_SRV6_LOCATOR); + + bool unpacked_known_tlvs = false; + if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_SRV6_LOCATOR, subtlv_len, s, + log, rv->subtlvs, indent + 4, + &unpacked_known_tlvs)) { + goto out; + } + if (!unpacked_known_tlvs) { + isis_free_subtlvs(rv->subtlvs); + rv->subtlvs = NULL; + } + } + + append_item(items, (struct isis_item *)rv); + return 0; +out: + if (rv) + free_item_srv6_locator((struct isis_item *)rv); + return 1; +} + /* Functions related to tlvs in general */ struct isis_tlvs *isis_alloc_tlvs(void) @@ -5350,6 +6517,7 @@ struct isis_tlvs *isis_alloc_tlvs(void) RB_INIT(isis_mt_item_list, &result->mt_ip_reach); init_item_list(&result->ipv6_reach); RB_INIT(isis_mt_item_list, &result->mt_ipv6_reach); + RB_INIT(isis_mt_item_list, &result->srv6_locator); return result; } @@ -5430,6 +6598,9 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs) rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf); + copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_SRV6_LOCATOR, + &tlvs->srv6_locator, &rv->srv6_locator); + return rv; } @@ -5510,6 +6681,9 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, struct json_ob format_tlv_threeway_adj(tlvs->threeway_adj, buf, json, indent); format_tlv_spine_leaf(tlvs->spine_leaf, buf, json, indent); + + format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_SRV6_LOCATOR, + &tlvs->srv6_locator, buf, json, indent); } const char *isis_format_tlvs(struct isis_tlvs *tlvs, struct json_object *json) @@ -5572,6 +6746,8 @@ void isis_free_tlvs(struct isis_tlvs *tlvs) free_tlv_threeway_adj(tlvs->threeway_adj); free_tlv_router_cap(tlvs->router_cap); free_tlv_spine_leaf(tlvs->spine_leaf); + free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_SRV6_LOCATOR, + &tlvs->srv6_locator); XFREE(MTYPE_ISIS_TLV, tlvs); } @@ -5982,6 +7158,15 @@ int isis_unpack_tlvs(size_t avail_len, struct stream *stream, #define ITEM_SUBTLV_OPS(_name_, _desc_) \ ITEM_TLV_OPS(_name_, _desc_) +#define SUBSUBTLV_OPS(_name_, _desc_) \ + static const struct tlv_ops subsubtlv_##_name_##_ops = { \ + .name = _desc_, \ + .unpack = unpack_subsubtlv_##_name_, \ + } + +#define ITEM_SUBSUBTLV_OPS(_name_, _desc_) \ + ITEM_TLV_OPS(_name_, _desc_) + ITEM_TLV_OPS(area_address, "TLV 1 Area Addresses"); ITEM_TLV_OPS(oldstyle_reach, "TLV 2 IS Reachability"); ITEM_TLV_OPS(lan_neighbor, "TLV 6 LAN Neighbors"); @@ -6007,6 +7192,10 @@ TLV_OPS(router_cap, "TLV 242 Router Capability"); ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID"); SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix"); +ITEM_TLV_OPS(srv6_locator, "TLV 27 SRv6 Locator"); +ITEM_SUBTLV_OPS(srv6_end_sid, "Sub-TLV 5 SRv6 End SID"); +SUBSUBTLV_OPS(srv6_sid_structure, "Sub-Sub-TLV 1 SRv6 SID Structure"); + static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = { [ISIS_CONTEXT_LSP] = { [ISIS_TLV_AREA_ADDRESSES] = &tlv_area_address_ops, @@ -6034,6 +7223,7 @@ static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = { [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops, [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops, [ISIS_TLV_ROUTER_CAPABILITY] = &tlv_router_cap_ops, + [ISIS_TLV_SRV6_LOCATOR] = &tlv_srv6_locator_ops, }, [ISIS_CONTEXT_SUBTLV_NE_REACH] = {}, [ISIS_CONTEXT_SUBTLV_IP_REACH] = { @@ -6042,6 +7232,18 @@ static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = { [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = { [ISIS_SUBTLV_PREFIX_SID] = &tlv_prefix_sid_ops, [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops, + }, + [ISIS_CONTEXT_SUBTLV_SRV6_LOCATOR] = { + [ISIS_SUBTLV_SRV6_END_SID] = &tlv_srv6_end_sid_ops, + }, + [ISIS_CONTEXT_SUBSUBTLV_SRV6_END_SID] = { + [ISIS_SUBSUBTLV_SRV6_SID_STRUCTURE] = &subsubtlv_srv6_sid_structure_ops, + }, + [ISIS_CONTEXT_SUBSUBTLV_SRV6_ENDX_SID] = { + [ISIS_SUBSUBTLV_SRV6_SID_STRUCTURE] = &subsubtlv_srv6_sid_structure_ops, + }, + [ISIS_CONTEXT_SUBSUBTLV_SRV6_LAN_ENDX_SID] = { + [ISIS_SUBSUBTLV_SRV6_SID_STRUCTURE] = &subsubtlv_srv6_sid_structure_ops, } }; @@ -6711,6 +7913,44 @@ void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts, UNSET_SUBTLV(exts, EXT_LAN_ADJ_SID); } +/* Add IS-IS SRv6 End.X SID subTLVs */ +void isis_tlvs_add_srv6_endx_sid(struct isis_ext_subtlvs *exts, + struct isis_srv6_endx_sid_subtlv *adj) +{ + append_item(&exts->srv6_endx_sid, (struct isis_item *)adj); + SET_SUBTLV(exts, EXT_SRV6_ENDX_SID); +} + +/* Delete IS-IS SRv6 End.X SID subTLVs */ +void isis_tlvs_del_srv6_endx_sid(struct isis_ext_subtlvs *exts, + struct isis_srv6_endx_sid_subtlv *adj) +{ + isis_free_subsubtlvs(adj->subsubtlvs); + delete_item(&exts->srv6_endx_sid, (struct isis_item *)adj); + XFREE(MTYPE_ISIS_SUBTLV, adj); + if (exts->srv6_endx_sid.count == 0) + UNSET_SUBTLV(exts, EXT_SRV6_ENDX_SID); +} + +/* Add IS-IS SRv6 LAN End.X SID subTLVs */ +void isis_tlvs_add_srv6_lan_endx_sid(struct isis_ext_subtlvs *exts, + struct isis_srv6_lan_endx_sid_subtlv *lan) +{ + append_item(&exts->srv6_lan_endx_sid, (struct isis_item *)lan); + SET_SUBTLV(exts, EXT_SRV6_LAN_ENDX_SID); +} + +/* Delete IS-IS SRv6 LAN End.X SID subTLVs */ +void isis_tlvs_del_srv6_lan_endx_sid(struct isis_ext_subtlvs *exts, + struct isis_srv6_lan_endx_sid_subtlv *lan) +{ + isis_free_subsubtlvs(lan->subsubtlvs); + delete_item(&exts->srv6_lan_endx_sid, (struct isis_item *)lan); + XFREE(MTYPE_ISIS_SUBTLV, lan); + if (exts->srv6_lan_endx_sid.count == 0) + UNSET_SUBTLV(exts, EXT_SRV6_LAN_ENDX_SID); +} + void isis_tlvs_del_asla_flex_algo(struct isis_ext_subtlvs *ext, struct isis_asla_subtlvs *asla) { @@ -6934,3 +8174,95 @@ void isis_tlvs_set_purge_originator(struct isis_tlvs *tlvs, sizeof(tlvs->purge_originator->sender)); } } + +/* Set SRv6 SID Structure Sub-Sub-TLV parameters */ +void isis_subsubtlvs_set_srv6_sid_structure(struct isis_subsubtlvs *subsubtlvs, + struct isis_srv6_sid *sid) +{ + assert(!subsubtlvs->srv6_sid_structure); + + subsubtlvs->srv6_sid_structure = XCALLOC( + MTYPE_ISIS_SUBSUBTLV, sizeof(*subsubtlvs->srv6_sid_structure)); + + isis_srv6_sid_structure2subsubtlv(sid, subsubtlvs->srv6_sid_structure); +} + +/* Add an SRv6 End SID to the SRv6 End SID Sub-TLV */ +void isis_subtlvs_add_srv6_end_sid(struct isis_subtlvs *subtlvs, + struct isis_srv6_sid *sid) +{ + struct isis_srv6_end_sid_subtlv *sid_subtlv; + + if (!sid) + return; + + /* The SRv6 End SID Sub-TLV advertises SRv6 SIDs with Endpoint behaviors + * that do not require a particular neighbor in order to be correctly + * applied (e.g. End, End.DT6, ...). Before proceeding, let's make sure + * we are encoding one of the supported behaviors. */ + if (sid->behavior != SRV6_ENDPOINT_BEHAVIOR_END && + sid->behavior != SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID && + sid->behavior != SRV6_ENDPOINT_BEHAVIOR_END_DT6 && + sid->behavior != SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID && + sid->behavior != SRV6_ENDPOINT_BEHAVIOR_END_DT4 && + sid->behavior != SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID && + sid->behavior != SRV6_ENDPOINT_BEHAVIOR_END_DT46 && + sid->behavior != SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID) + return; + + /* Allocate memory for the Sub-TLV */ + sid_subtlv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*sid_subtlv)); + + /* Fill in the SRv6 End SID Sub-TLV according to the SRv6 SID + * configuration */ + isis_srv6_end_sid2subtlv(sid, sid_subtlv); + + /* Add the SRv6 SID Structure Sub-Sub-TLV */ + sid_subtlv->subsubtlvs = + isis_alloc_subsubtlvs(ISIS_CONTEXT_SUBSUBTLV_SRV6_END_SID); + isis_subsubtlvs_set_srv6_sid_structure(sid_subtlv->subsubtlvs, sid); + + /* Append the SRv6 End SID Sub-TLV to the Sub-TLVs list */ + append_item(&subtlvs->srv6_end_sids, (struct isis_item *)sid_subtlv); +} + +/* Add an SRv6 Locator to the SRv6 Locator TLV */ +void isis_tlvs_add_srv6_locator(struct isis_tlvs *tlvs, uint16_t mtid, + struct isis_srv6_locator *loc) +{ + bool subtlvs_present = false; + struct listnode *node; + struct isis_srv6_sid *sid; + struct isis_srv6_locator_tlv *loc_tlv = + XCALLOC(MTYPE_ISIS_TLV, sizeof(*loc_tlv)); + + /* Fill in the SRv6 Locator TLV according to the SRv6 Locator + * configuration */ + isis_srv6_locator2tlv(loc, loc_tlv); + + /* Add the SRv6 End SID Sub-TLVs */ + loc_tlv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_SRV6_LOCATOR); + for (ALL_LIST_ELEMENTS_RO(loc->srv6_sid, node, sid)) { + if (sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END || + sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID || + sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT6 || + sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID || + sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT4 || + sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID || + sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT46 || + sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID) { + isis_subtlvs_add_srv6_end_sid(loc_tlv->subtlvs, sid); + subtlvs_present = true; + } + } + + if (!subtlvs_present) { + isis_free_subtlvs(loc_tlv->subtlvs); + loc_tlv->subtlvs = NULL; + } + + /* Append the SRv6 Locator TLV to the TLVs list */ + struct isis_item_list *l; + l = isis_get_mt_items(&tlvs->srv6_locator, mtid); + append_item(l, (struct isis_item *)loc_tlv); +} diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 03e2b2edccca..6ecd4c5f6ad8 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -5,6 +5,9 @@ * Copyright (C) 2015,2017 Christian Franke * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR) + * + * Copyright (C) 2023 Carmine Scarpitta - University of Rome Tor Vergata + * (for IS-IS Extensions to Support SRv6 as per RFC 9352) */ #ifndef ISIS_TLVS_H #define ISIS_TLVS_H @@ -16,10 +19,15 @@ #include "affinitymap.h" +#include "lib/srv6.h" + DECLARE_MTYPE(ISIS_SUBTLV); +DECLARE_MTYPE(ISIS_SUBSUBTLV); struct lspdb_head; struct sr_prefix_cfg; +struct isis_srv6_sid; +struct isis_srv6_locator; struct isis_area_address { struct isis_area_address *next; @@ -193,6 +201,96 @@ struct isis_router_cap_fad { }; #endif /* ifndef FABRICD */ +/* SRv6 SID Structure Sub-Sub-TLV as per RFC 9352 section #9 */ +struct isis_srv6_sid_structure_subsubtlv { + uint8_t loc_block_len; + uint8_t loc_node_len; + uint8_t func_len; + uint8_t arg_len; +}; + +/* SRv6 End SID Sub-TLV as per RFC 9352 section #7.2 */ +struct isis_srv6_end_sid_subtlv { + struct isis_srv6_end_sid_subtlv *next; + + uint8_t flags; + enum srv6_endpoint_behavior_codepoint behavior; + struct in6_addr sid; + + struct isis_subsubtlvs *subsubtlvs; +}; + +/* SRv6 End.X SID and SRv6 LAN End.X SID sub-TLVs flags */ +#define EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG 0x20 +#define EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG 0x40 +#define EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG 0x80 + +/* SRv6 End.X SID Sub-TLV as per RFC 9352 section #8.1 */ +struct isis_srv6_endx_sid_subtlv { + struct isis_srv6_endx_sid_subtlv *next; + + uint8_t flags; + uint8_t algorithm; + uint8_t weight; + enum srv6_endpoint_behavior_codepoint behavior; + struct in6_addr sid; + + struct isis_subsubtlvs *subsubtlvs; +}; + +/* SRv6 End.X SID Sub-TLV as per RFC 9352 section #8.2 */ +struct isis_srv6_lan_endx_sid_subtlv { + struct isis_srv6_lan_endx_sid_subtlv *next; + + uint8_t neighbor_id[ISIS_SYS_ID_LEN]; + uint8_t flags; + uint8_t algorithm; + uint8_t weight; + enum srv6_endpoint_behavior_codepoint behavior; + struct in6_addr sid; + + struct isis_subsubtlvs *subsubtlvs; +}; + +/* RFC 9352 section 7.1 */ +struct isis_srv6_locator_tlv { + struct isis_srv6_locator_tlv *next; + + uint32_t metric; + + uint8_t flags; +#define ISIS_TLV_SRV6_LOCATOR_FLAG_D 1 << 7 + + uint8_t algorithm; + struct prefix_ipv6 prefix; + + struct isis_subtlvs *subtlvs; +}; + +#define ISIS_SRV6_LOCATOR_HDR_SIZE 22 + +/* Maximum SRv6 SID Depths (MSD) as per RFC 9352 section #4 */ +struct isis_srv6_msd { + /* RFC 9352 section #4.1 */ + uint8_t max_seg_left_msd; + /* RFC 9352 section #4.2 */ + uint8_t max_end_pop_msd; + /* RFC 9352 section #4.3 */ + uint8_t max_h_encaps_msd; + /* RFC 9352 section #4.4 */ + uint8_t max_end_d_msd; +}; + +/* SRv6 Capabilities as per RFC 9352 section #2 */ +struct isis_srv6_cap { + bool is_srv6_capable; + + uint16_t flags; +#define ISIS_SUBTLV_SRV6_FLAG_O 0x4000 +#define SUPPORTS_SRV6_OAM(srv6) \ + (CHECK_FLAG((srv6)->flags, ISIS_SUBTLV_SRV6_FLAG_O)) +}; + struct isis_router_cap { struct in_addr router_id; uint8_t flags; @@ -208,6 +306,12 @@ struct isis_router_cap { /* RFC9350 Flex-Algorithm */ struct isis_router_cap_fad *fads[SR_ALGORITHM_COUNT]; #endif /* ifndef FABRICD */ + + /* RFC 9352 section #2 */ + struct isis_srv6_cap srv6_cap; + + /* RFC 9352 section #4 */ + struct isis_srv6_msd srv6_msd; }; struct isis_item { @@ -310,6 +414,7 @@ struct isis_tlvs { struct isis_threeway_adj *threeway_adj; struct isis_router_cap *router_cap; struct isis_spine_leaf *spine_leaf; + struct isis_mt_item_list srv6_locator; }; enum isis_tlv_context { @@ -317,6 +422,10 @@ enum isis_tlv_context { ISIS_CONTEXT_SUBTLV_NE_REACH, ISIS_CONTEXT_SUBTLV_IP_REACH, ISIS_CONTEXT_SUBTLV_IPV6_REACH, + ISIS_CONTEXT_SUBTLV_SRV6_LOCATOR, + ISIS_CONTEXT_SUBSUBTLV_SRV6_END_SID, + ISIS_CONTEXT_SUBSUBTLV_SRV6_ENDX_SID, + ISIS_CONTEXT_SUBSUBTLV_SRV6_LAN_ENDX_SID, ISIS_CONTEXT_MAX, }; @@ -327,6 +436,16 @@ struct isis_subtlvs { struct prefix_ipv6 *source_prefix; /* RFC 8667 section #2.4 */ struct isis_item_list prefix_sids; + + /* RFC 9352 section #7.2 */ + struct isis_item_list srv6_end_sids; +}; + +struct isis_subsubtlvs { + enum isis_tlv_context context; + + /* RFC 9352 section #9 */ + struct isis_srv6_sid_structure_subsubtlv *srv6_sid_structure; }; enum isis_tlv_type { @@ -340,6 +459,8 @@ enum isis_tlv_type { ISIS_TLV_PURGE_ORIGINATOR = 13, ISIS_TLV_EXTENDED_REACH = 22, + ISIS_TLV_SRV6_LOCATOR = 27, + ISIS_TLV_OLDSTYLE_IP_REACH = 128, ISIS_TLV_PROTOCOLS_SUPPORTED = 129, ISIS_TLV_OLDSTYLE_IP_REACH_EXT = 130, @@ -414,6 +535,23 @@ enum isis_tlv_type { ISIS_SUBTLV_MAX = 40, + /* RFC 9352 section #2 */ + ISIS_SUBTLV_SRV6_CAPABILITIES = 25, + /* RFC 9352 section #4.1 */ + ISIS_SUBTLV_SRV6_MAX_SL_MSD = 41, + /* RFC 9352 section #4.2 */ + ISIS_SUBTLV_SRV6_MAX_END_POP_MSD = 42, + /* RFC 9352 section #4.3 */ + ISIS_SUBTLV_SRV6_MAX_H_ENCAPS_MSD = 44, + /* RFC 9352 section #4.4 */ + ISIS_SUBTLV_SRV6_MAX_END_D_MSD = 45, + + ISIS_SUBTLV_SRV6_END_SID = 5, + ISIS_SUBTLV_SRV6_ENDX_SID = 43, + ISIS_SUBTLV_SRV6_LAN_ENDX_SID = 44, + + ISIS_SUBSUBTLV_SRV6_SID_STRUCTURE = 1, + /* draft-ietf-lsr-isis-srv6-extensions */ ISIS_SUBSUBTLV_SID_STRUCTURE = 1, @@ -422,6 +560,10 @@ enum isis_tlv_type { /* subTLVs size for TE and SR */ enum ext_subtlv_size { + /* Sub-TLV Type and Length fields */ + ISIS_SUBTLV_TYPE_FIELD_SIZE = 1, + ISIS_SUBTLV_LENGTH_FIELD_SIZE = 1, + /* RFC 5307 */ ISIS_SUBTLV_LLRI_SIZE = 8, @@ -432,6 +574,8 @@ enum ext_subtlv_size { /* RFC 8491 */ ISIS_SUBTLV_NODE_MSD_SIZE = 2, + ISIS_SUBTLV_NODE_MSD_TYPE_SIZE = 1, + ISIS_SUBTLV_NODE_MSD_VALUE_SIZE = 1, /* RFC 8667 sections #2 & #3 */ ISIS_SUBTLV_SID_LABEL_SIZE = 3, @@ -454,6 +598,10 @@ enum ext_subtlv_size { ISIS_SUBTLV_MAX_SIZE = 180, + /* RFC 9352 sections #8.1 & #8.2 */ + ISIS_SUBTLV_SRV6_ENDX_SID_SIZE = 21, + ISIS_SUBTLV_SRV6_LAN_ENDX_SID_SIZE = 27, + /* draft-ietf-lsr-isis-srv6-extensions */ ISIS_SUBSUBTLV_SID_STRUCTURE_SIZE = 4, @@ -462,6 +610,9 @@ enum ext_subtlv_size { /* RFC9350 - Flex-Algorithm */ ISIS_SUBTLV_FAD_SUBSUBTLV_FLAGS_SIZE = 1, + + /* RFC 9352 section #2 */ + ISIS_SUBTLV_SRV6_CAPABILITIES_SIZE = 2, }; enum ext_subsubtlv_types { @@ -502,6 +653,8 @@ enum ext_subsubtlv_types { #define EXT_AVA_BW 0x080000 #define EXT_USE_BW 0x100000 #define EXT_EXTEND_ADM_GRP 0x200000 +#define EXT_SRV6_ENDX_SID 0x400000 +#define EXT_SRV6_LAN_ENDX_SID 0x800000 /* * This structure groups all Extended IS Reachability subTLVs. @@ -551,6 +704,10 @@ struct isis_ext_subtlvs { struct isis_item_list lan_sid; struct list *aslas; + + /* SRv6 End.X & LAN End.X SID */ + struct isis_item_list srv6_endx_sid; + struct isis_item_list srv6_lan_endx_sid; }; /* RFC 8919 */ @@ -599,6 +756,7 @@ int isis_pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream, size_t len_pointer, bool pad, bool is_lsp); void isis_free_tlvs(struct isis_tlvs *tlvs); struct isis_tlvs *isis_alloc_tlvs(void); +struct isis_subsubtlvs *isis_alloc_subsubtlvs(enum isis_tlv_context context); int isis_unpack_tlvs(size_t avail_len, struct stream *stream, struct isis_tlvs **dest, const char **error_log); const char *isis_format_tlvs(struct isis_tlvs *tlvs, struct json_object *json); @@ -726,4 +884,20 @@ isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid); void isis_tlvs_set_purge_originator(struct isis_tlvs *tlvs, const uint8_t *generator, const uint8_t *sender); + +void isis_subsubtlvs_set_srv6_sid_structure(struct isis_subsubtlvs *subsubtlvs, + struct isis_srv6_sid *sid); +void isis_subtlvs_add_srv6_end_sid(struct isis_subtlvs *subtlvs, + struct isis_srv6_sid *sid); +void isis_tlvs_add_srv6_locator(struct isis_tlvs *tlvs, uint16_t mtid, + struct isis_srv6_locator *loc); + +void isis_tlvs_add_srv6_endx_sid(struct isis_ext_subtlvs *exts, + struct isis_srv6_endx_sid_subtlv *adj); +void isis_tlvs_del_srv6_endx_sid(struct isis_ext_subtlvs *exts, + struct isis_srv6_endx_sid_subtlv *adj); +void isis_tlvs_add_srv6_lan_endx_sid(struct isis_ext_subtlvs *exts, + struct isis_srv6_lan_endx_sid_subtlv *lan); +void isis_tlvs_del_srv6_lan_endx_sid(struct isis_ext_subtlvs *exts, + struct isis_srv6_lan_endx_sid_subtlv *lan); #endif diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 4f3198a9fe01..8252c1ac25a6 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -308,6 +308,9 @@ void isis_zebra_route_del_route(struct isis *isis, if (zclient->sock < 0) return; + if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) + return; + memset(&api, 0, sizeof(api)); api.vrf_id = isis->vrf_id; api.type = PROTO_TYPE; @@ -820,6 +823,551 @@ static int isis_zebra_client_close_notify(ZAPI_CALLBACK_ARGS) return ret; } +/** + * Send SRv6 SID to ZEBRA for installation or deletion. + * + * @param cmd ZEBRA_ROUTE_ADD or ZEBRA_ROUTE_DELETE + * @param sid SRv6 SID to install or delete + * @param prefixlen Prefix length + * @param oif Outgoing interface + * @param action SID action + * @param context SID context + */ +static void isis_zebra_send_localsid(int cmd, const struct in6_addr *sid, + uint16_t prefixlen, ifindex_t oif, + enum seg6local_action_t action, + const struct seg6local_context *context) +{ + struct prefix_ipv6 p = {}; + struct zapi_route api = {}; + struct zapi_nexthop *znh; + + if (cmd != ZEBRA_ROUTE_ADD && cmd != ZEBRA_ROUTE_DELETE) { + flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command", + __func__); + return; + } + + if (prefixlen > IPV6_MAX_BITLEN) { + flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong prefixlen %u", + __func__, prefixlen); + return; + } + + sr_debug(" |- %s SRv6 SID %pI6 behavior %s", + cmd == ZEBRA_ROUTE_ADD ? "Add" : "Delete", sid, + seg6local_action2str(action)); + + p.family = AF_INET6; + p.prefixlen = prefixlen; + p.prefix = *sid; + + api.vrf_id = VRF_DEFAULT; + api.type = PROTO_TYPE; + api.instance = 0; + api.safi = SAFI_UNICAST; + memcpy(&api.prefix, &p, sizeof(p)); + + if (cmd == ZEBRA_ROUTE_DELETE) + return (void)zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, + &api); + + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + + znh = &api.nexthops[0]; + + memset(znh, 0, sizeof(*znh)); + + znh->type = NEXTHOP_TYPE_IFINDEX; + znh->ifindex = oif; + SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL); + znh->seg6local_action = action; + memcpy(&znh->seg6local_ctx, context, sizeof(struct seg6local_context)); + + api.nexthop_num = 1; + + zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); +} + +/** + * Install SRv6 SID in the forwarding plane through Zebra. + * + * @param area IS-IS area + * @param sid SRv6 SID + */ +void isis_zebra_srv6_sid_install(struct isis_area *area, + struct isis_srv6_sid *sid) +{ + enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; + uint16_t prefixlen = IPV6_MAX_BITLEN; + struct seg6local_context ctx = {}; + struct interface *ifp; + + if (!area || !sid) + return; + + sr_debug("ISIS-SRv6 (%s): setting SRv6 SID %pI6", area->area_tag, + &sid->sid); + + switch (sid->behavior) { + case SRV6_ENDPOINT_BEHAVIOR_END: + action = ZEBRA_SEG6_LOCAL_ACTION_END; + prefixlen = IPV6_MAX_BITLEN; + break; + case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID: + action = ZEBRA_SEG6_LOCAL_ACTION_END; + prefixlen = sid->locator->block_bits_length + + sid->locator->node_bits_length; + SET_SRV6_FLV_OP(ctx.flv.flv_ops, + ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); + ctx.flv.lcblock_len = sid->locator->block_bits_length; + ctx.flv.lcnode_func_len = sid->locator->node_bits_length; + break; + case SRV6_ENDPOINT_BEHAVIOR_END_X: + case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID: + case SRV6_ENDPOINT_BEHAVIOR_RESERVED: + case SRV6_ENDPOINT_BEHAVIOR_END_DT6: + case SRV6_ENDPOINT_BEHAVIOR_END_DT4: + case SRV6_ENDPOINT_BEHAVIOR_END_DT46: + case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID: + case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID: + case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID: + case SRV6_ENDPOINT_BEHAVIOR_OPAQUE: + default: + zlog_err( + "ISIS-SRv6 (%s): unsupported SRv6 endpoint behavior %u", + area->area_tag, sid->behavior); + return; + } + + /* Attach the SID to the SRv6 interface */ + ifp = if_lookup_by_name(area->srv6db.config.srv6_ifname, VRF_DEFAULT); + if (!ifp) { + zlog_warn( + "Failed to install SRv6 SID %pI6: %s interface not found", + &sid->sid, area->srv6db.config.srv6_ifname); + return; + } + + /* Send the SID to zebra */ + isis_zebra_send_localsid(ZEBRA_ROUTE_ADD, &sid->sid, prefixlen, + ifp->ifindex, action, &ctx); +} + +/** + * Uninstall SRv6 SID from the forwarding plane through Zebra. + * + * @param area IS-IS area + * @param sid SRv6 SID + */ +void isis_zebra_srv6_sid_uninstall(struct isis_area *area, + struct isis_srv6_sid *sid) +{ + enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; + struct interface *ifp; + uint16_t prefixlen = IPV6_MAX_BITLEN; + + if (!area || !sid) + return; + + sr_debug("ISIS-SRv6 (%s): delete SID %pI6", area->area_tag, &sid->sid); + + switch (sid->behavior) { + case SRV6_ENDPOINT_BEHAVIOR_END: + prefixlen = IPV6_MAX_BITLEN; + break; + case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID: + prefixlen = sid->locator->block_bits_length + + sid->locator->node_bits_length; + break; + case SRV6_ENDPOINT_BEHAVIOR_RESERVED: + case SRV6_ENDPOINT_BEHAVIOR_END_X: + case SRV6_ENDPOINT_BEHAVIOR_END_DT6: + case SRV6_ENDPOINT_BEHAVIOR_END_DT4: + case SRV6_ENDPOINT_BEHAVIOR_END_DT46: + case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID: + case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID: + case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID: + case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID: + case SRV6_ENDPOINT_BEHAVIOR_OPAQUE: + default: + zlog_err( + "ISIS-SRv6 (%s): unsupported SRv6 endpoint behavior %u", + area->area_tag, sid->behavior); + return; + } + + /* The SID is attached to the SRv6 interface */ + ifp = if_lookup_by_name(area->srv6db.config.srv6_ifname, VRF_DEFAULT); + if (!ifp) { + zlog_warn("%s interface not found: nothing to uninstall", + area->srv6db.config.srv6_ifname); + return; + } + + /* Send delete request to zebra */ + isis_zebra_send_localsid(ZEBRA_ROUTE_DELETE, &sid->sid, prefixlen, + ifp->ifindex, action, NULL); +} + +void isis_zebra_srv6_adj_sid_install(struct srv6_adjacency *sra) +{ + enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; + struct seg6local_context ctx = {}; + uint16_t prefixlen = IPV6_MAX_BITLEN; + struct interface *ifp; + struct isis_circuit *circuit; + struct isis_area *area; + + if (!sra) + return; + + circuit = sra->adj->circuit; + area = circuit->area; + + sr_debug("ISIS-SRv6 (%s): setting adjacency SID %pI6", area->area_tag, + &sra->sid); + + switch (sra->behavior) { + case SRV6_ENDPOINT_BEHAVIOR_END_X: + action = ZEBRA_SEG6_LOCAL_ACTION_END_X; + prefixlen = IPV6_MAX_BITLEN; + ctx.nh6 = sra->nexthop; + break; + case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID: + action = ZEBRA_SEG6_LOCAL_ACTION_END_X; + prefixlen = sra->locator->block_bits_length + + sra->locator->node_bits_length + + sra->locator->function_bits_length; + ctx.nh6 = sra->nexthop; + SET_SRV6_FLV_OP(ctx.flv.flv_ops, + ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID); + ctx.flv.lcblock_len = sra->locator->block_bits_length; + ctx.flv.lcnode_func_len = sra->locator->node_bits_length; + break; + case SRV6_ENDPOINT_BEHAVIOR_RESERVED: + case SRV6_ENDPOINT_BEHAVIOR_END: + case SRV6_ENDPOINT_BEHAVIOR_END_DT6: + case SRV6_ENDPOINT_BEHAVIOR_END_DT4: + case SRV6_ENDPOINT_BEHAVIOR_END_DT46: + case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID: + case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID: + case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID: + case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID: + case SRV6_ENDPOINT_BEHAVIOR_OPAQUE: + default: + zlog_err( + "ISIS-SRv6 (%s): unsupported SRv6 endpoint behavior %u", + area->area_tag, sra->behavior); + return; + } + + ifp = sra->adj->circuit->interface; + + isis_zebra_send_localsid(ZEBRA_ROUTE_ADD, &sra->sid, prefixlen, + ifp->ifindex, action, &ctx); +} + +void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra) +{ + enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; + struct interface *ifp; + uint16_t prefixlen = IPV6_MAX_BITLEN; + struct isis_circuit *circuit; + struct isis_area *area; + + if (!sra) + return; + + circuit = sra->adj->circuit; + area = circuit->area; + + switch (sra->behavior) { + case SRV6_ENDPOINT_BEHAVIOR_END_X: + prefixlen = IPV6_MAX_BITLEN; + break; + case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID: + prefixlen = sra->locator->block_bits_length + + sra->locator->node_bits_length + + sra->locator->function_bits_length; + break; + case SRV6_ENDPOINT_BEHAVIOR_RESERVED: + case SRV6_ENDPOINT_BEHAVIOR_END: + case SRV6_ENDPOINT_BEHAVIOR_END_DT6: + case SRV6_ENDPOINT_BEHAVIOR_END_DT4: + case SRV6_ENDPOINT_BEHAVIOR_END_DT46: + case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID: + case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID: + case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID: + case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID: + case SRV6_ENDPOINT_BEHAVIOR_OPAQUE: + default: + zlog_err( + "ISIS-SRv6 (%s): unsupported SRv6 endpoint behavior %u", + area->area_tag, sra->behavior); + return; + } + + ifp = sra->adj->circuit->interface; + + sr_debug("ISIS-SRv6 (%s): delete End.X SID %pI6", area->area_tag, + &sra->sid); + + isis_zebra_send_localsid(ZEBRA_ROUTE_DELETE, &sra->sid, prefixlen, + ifp->ifindex, action, NULL); +} + +/** + * Callback to process an SRv6 locator chunk received from SRv6 Manager (zebra). + * + * @result 0 on success, -1 otherwise + */ +static int isis_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) +{ + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + struct stream *s = NULL; + struct listnode *node; + struct isis_area *area; + struct srv6_locator_chunk *c; + struct srv6_locator_chunk *chunk = srv6_locator_chunk_alloc(); + struct isis_srv6_sid *sid; + struct isis_adjacency *adj; + enum srv6_endpoint_behavior_codepoint behavior; + bool allocated = false; + + if (!isis) { + srv6_locator_chunk_free(&chunk); + return -1; + } + + /* Decode the received zebra message */ + s = zclient->ibuf; + if (zapi_srv6_locator_chunk_decode(s, chunk) < 0) { + srv6_locator_chunk_free(&chunk); + return -1; + } + + sr_debug( + "Received SRv6 locator chunk from zebra: name %s, " + "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", + chunk->locator_name, &chunk->prefix, chunk->block_bits_length, + chunk->node_bits_length, chunk->function_bits_length, + chunk->argument_bits_length); + + /* Walk through all areas of the ISIS instance */ + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + if (strncmp(area->srv6db.config.srv6_locator_name, + chunk->locator_name, + sizeof(area->srv6db.config.srv6_locator_name)) != 0) + continue; + + for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_locator_chunks, + node, c)) { + if (!prefix_cmp(&c->prefix, &chunk->prefix)) { + srv6_locator_chunk_free(&chunk); + return 0; + } + } + + sr_debug( + "SRv6 locator chunk (locator %s, prefix %pFX) assigned to IS-IS area %s", + chunk->locator_name, &chunk->prefix, area->area_tag); + + /* Add the SRv6 Locator chunk to the per-area chunks list */ + listnode_add(area->srv6db.srv6_locator_chunks, chunk); + + /* Decide which behavior to use,depending on the locator type + * (i.e. uSID vs classic locator) */ + behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) + ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID + : SRV6_ENDPOINT_BEHAVIOR_END; + + /* Allocate new SRv6 End SID */ + sid = isis_srv6_sid_alloc(area, chunk, behavior, 0); + if (!sid) + return -1; + + /* Install the new SRv6 End SID in the forwarding plane through + * Zebra */ + isis_zebra_srv6_sid_install(area, sid); + + /* Store the SID */ + listnode_add(area->srv6db.srv6_sids, sid); + + /* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */ + for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) { + if (adj->ll_ipv6_count > 0) + srv6_endx_sid_add(adj); + } + + /* Regenerate LSPs to advertise the new locator and the SID */ + lsp_regenerate_schedule(area, area->is_type, 0); + + allocated = true; + break; + } + + if (!allocated) { + sr_debug("No IS-IS area configured for the locator %s", + chunk->locator_name); + srv6_locator_chunk_free(&chunk); + } + + return 0; +} + +/** + * Callback to process an SRv6 locator received from SRv6 Manager (zebra). + * + * @result 0 on success, -1 otherwise + */ +static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) +{ + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + struct srv6_locator loc = {}; + struct listnode *node; + struct isis_area *area; + + if (!isis) + return -1; + + /* Decode the SRv6 locator */ + if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) + return -1; + + sr_debug( + "New SRv6 locator allocated in zebra: name %s, " + "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", + loc.name, &loc.prefix, loc.block_bits_length, + loc.node_bits_length, loc.function_bits_length, + loc.argument_bits_length); + + /* Lookup on the IS-IS areas */ + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + /* If SRv6 is enabled on this area and the configured locator + * corresponds to the new locator, then request a chunk from the + * locator */ + if (area->srv6db.config.enabled && + strncmp(area->srv6db.config.srv6_locator_name, loc.name, + sizeof(area->srv6db.config.srv6_locator_name)) == 0) { + sr_debug( + "Sending a request to get a chunk from the SRv6 locator %s (%pFX) " + "for IS-IS area %s", + loc.name, &loc.prefix, area->area_tag); + + if (isis_zebra_srv6_manager_get_locator_chunk( + loc.name) < 0) + return -1; + } + } + + return 0; +} + +/** + * Callback to process a notification from SRv6 Manager (zebra) of an SRv6 + * locator deleted. + * + * @result 0 on success, -1 otherwise + */ +static int isis_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) +{ + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + struct srv6_locator loc = {}; + struct isis_area *area; + struct listnode *node, *nnode; + struct srv6_locator_chunk *chunk; + struct isis_srv6_sid *sid; + struct srv6_adjacency *sra; + + if (!isis) + return -1; + + /* Decode the received zebra message */ + if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) + return -1; + + sr_debug( + "SRv6 locator deleted in zebra: name %s, " + "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", + loc.name, &loc.prefix, loc.block_bits_length, + loc.node_bits_length, loc.function_bits_length, + loc.argument_bits_length); + + /* Walk through all areas of the ISIS instance */ + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + if (strncmp(area->srv6db.config.srv6_locator_name, loc.name, + sizeof(area->srv6db.config.srv6_locator_name)) != 0) + continue; + + /* Delete SRv6 SIDs */ + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_sids, node, nnode, + sid)) { + + sr_debug( + "Deleting SRv6 SID (locator %s, sid %pI6) from IS-IS area %s", + area->srv6db.config.srv6_locator_name, + &sid->sid, area->area_tag); + + /* Uninstall the SRv6 SID from the forwarding plane + * through Zebra */ + isis_zebra_srv6_sid_uninstall(area, sid); + + listnode_delete(area->srv6db.srv6_sids, sid); + isis_srv6_sid_free(sid); + } + + /* Uninstall all local Adjacency-SIDs. */ + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, + sra)) + srv6_endx_sid_del(sra); + + /* Free the SRv6 locator chunks */ + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_locator_chunks, node, + nnode, chunk)) { + if (prefix_match((struct prefix *)&loc.prefix, + (struct prefix *)&chunk->prefix)) { + listnode_delete( + area->srv6db.srv6_locator_chunks, + chunk); + srv6_locator_chunk_free(&chunk); + } + } + + /* Regenerate LSPs to advertise that the locator no longer + * exists */ + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return 0; +} + +/** + * Request an SRv6 locator chunk to the SRv6 Manager (zebra) asynchronously. + * + * @param locator_name Name of SRv6 locator + * + * @result 0 on success, -1 otherwise + */ +int isis_zebra_srv6_manager_get_locator_chunk(const char *name) +{ + return srv6_manager_get_locator_chunk(zclient, name); +} + + +/** + * Release an SRv6 locator chunk. + * + * @param locator_name Name of SRv6 locator + * + * @result 0 on success, -1 otherwise + */ +int isis_zebra_srv6_manager_release_locator_chunk(const char *name) +{ + return srv6_manager_release_locator_chunk(zclient, name); +} + static zclient_handler *const isis_handlers[] = { [ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra, [ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add, @@ -831,6 +1379,11 @@ static zclient_handler *const isis_handlers[] = { [ZEBRA_OPAQUE_MESSAGE] = isis_opaque_msg_handler, [ZEBRA_CLIENT_CLOSE_NOTIFY] = isis_zebra_client_close_notify, + + [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = + isis_zebra_process_srv6_locator_chunk, + [ZEBRA_SRV6_LOCATOR_ADD] = isis_zebra_process_srv6_locator_add, + [ZEBRA_SRV6_LOCATOR_DELETE] = isis_zebra_process_srv6_locator_delete, }; void isis_zebra_init(struct event_loop *master, int instance) diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index 1dcd896d0b9c..f1684b7c25d4 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -57,4 +57,15 @@ void isis_zebra_vrf_register(struct isis *isis); void isis_zebra_vrf_deregister(struct isis *isis); int isis_zebra_ls_register(bool up); +extern void isis_zebra_srv6_sid_install(struct isis_area *area, + struct isis_srv6_sid *sid); +extern void isis_zebra_srv6_sid_uninstall(struct isis_area *area, + struct isis_srv6_sid *sid); + +void isis_zebra_srv6_adj_sid_install(struct srv6_adjacency *sra); +void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra); + +extern int isis_zebra_srv6_manager_get_locator_chunk(const char *name); +extern int isis_zebra_srv6_manager_release_locator_chunk(const char *name); + #endif /* _ZEBRA_ISIS_ZEBRA_H */ diff --git a/isisd/isisd.c b/isisd/isisd.c index 942073b70ccb..b1064d894199 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -337,6 +337,7 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) flags_initialize(&area->flags); isis_sr_area_init(area); + isis_srv6_area_init(area); /* * Default values @@ -525,6 +526,7 @@ void isis_area_destroy(struct isis_area *area) #endif /* ifndef FABRICD */ isis_sr_area_term(area); + isis_srv6_area_term(area); isis_mpls_te_term(area); @@ -3830,6 +3832,20 @@ struct cmd_node isis_flex_algo_node = { }; #endif /* ifdnef FABRICD */ +struct cmd_node isis_srv6_node = { + .name = "isis-srv6", + .node = ISIS_SRV6_NODE, + .parent_node = ISIS_NODE, + .prompt = "%s(config-router-srv6)# ", +}; + +struct cmd_node isis_srv6_node_msd_node = { + .name = "isis-srv6-node-msd", + .node = ISIS_SRV6_NODE_MSD_NODE, + .parent_node = ISIS_SRV6_NODE, + .prompt = "%s(config-router-srv6-node-msd)# ", +}; + void isis_init(void) { /* Install IS-IS top node */ @@ -3942,5 +3958,11 @@ void isis_init(void) install_default(ISIS_FLEX_ALGO_NODE); #endif /* ifdnef FABRICD */ + install_node(&isis_srv6_node); + install_default(ISIS_SRV6_NODE); + + install_node(&isis_srv6_node_msd_node); + install_default(ISIS_SRV6_NODE_MSD_NODE); + spf_backoff_cmd_init(); } diff --git a/isisd/isisd.h b/isisd/isisd.h index cd2a69445377..f5042e4ad5c2 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -19,6 +19,7 @@ #include "isisd/isis_pdu_counter.h" #include "isisd/isis_circuit.h" #include "isisd/isis_sr.h" +#include "isisd/isis_srv6.h" #include "isis_flags.h" #include "isis_lsp.h" #include "isis_lfa.h" @@ -208,6 +209,8 @@ struct isis_area { struct mpls_te_area *mta; /* Segment Routing information */ struct isis_sr_db srdb; + /* Segment Routing over IPv6 (SRv6) information */ + struct isis_srv6_db srv6db; int ipv6_circuits; bool purge_originator; /* SPF prefix priorities. */ @@ -339,6 +342,7 @@ void config_end_lsp_generate(struct isis_area *area); /* YANG paths */ #define ISIS_INSTANCE "/frr-isisd:isis/instance" #define ISIS_SR "/frr-isisd:isis/instance/segment-routing" +#define ISIS_SRV6 "/frr-isisd:isis/instance/segment-routing-srv6" /* Master of threads. */ extern struct event_loop *master; diff --git a/isisd/subdir.am b/isisd/subdir.am index 6bd2477b198b..3e7d9a90ecec 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -47,6 +47,7 @@ noinst_HEADERS += \ isisd/isis_spf_private.h \ isisd/isis_sr.h \ isisd/isis_flex_algo.h \ + isisd/isis_srv6.h \ isisd/isis_te.h \ isisd/isis_tlvs.h \ isisd/isis_tx_queue.h \ @@ -80,6 +81,7 @@ LIBISIS_SOURCES = \ isisd/isis_spf.c \ isisd/isis_sr.c \ isisd/isis_flex_algo.c \ + isisd/isis_srv6.c \ isisd/isis_te.c \ isisd/isis_tlvs.c \ isisd/isis_tx_queue.c \ diff --git a/lib/command.c b/lib/command.c index affb551b4598..86da488fdf55 100644 --- a/lib/command.c +++ b/lib/command.c @@ -477,33 +477,18 @@ static int config_write_host(struct vty *vty) } log_config_write(vty); - /* print disable always, but enable only if default is flipped - * => prep for future removal of compile-time knob - */ if (!cputime_enabled) vty_out(vty, "no service cputime-stats\n"); -#ifdef EXCLUDE_CPU_TIME - else - vty_out(vty, "service cputime-stats\n"); -#endif if (!cputime_threshold) vty_out(vty, "no service cputime-warning\n"); -#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000 - else /* again, always print non-default */ -#else - else if (cputime_threshold != 5000000) -#endif + else if (cputime_threshold != CONSUMED_TIME_CHECK) vty_out(vty, "service cputime-warning %lu\n", cputime_threshold / 1000); if (!walltime_threshold) vty_out(vty, "no service walltime-warning\n"); -#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000 - else /* again, always print non-default */ -#else - else if (walltime_threshold != 5000000) -#endif + else if (walltime_threshold != CONSUMED_TIME_CHECK) vty_out(vty, "service walltime-warning %lu\n", walltime_threshold / 1000); @@ -1331,8 +1316,8 @@ DEFUN (config_terminal, config_terminal_cmd, "configure [terminal [file-lock]]", "Configuration from vty interface\n" - "Configuration with locked datastores\n" - "Configuration terminal\n") + "Configuration terminal\n" + "Configuration with locked datastores\n") { return vty_config_enter(vty, false, false, argc == 3); } diff --git a/lib/command.h b/lib/command.h index 3167c652c5e5..36640c493f32 100644 --- a/lib/command.h +++ b/lib/command.h @@ -172,6 +172,9 @@ enum node_type { OPENFABRIC_NODE, /* OpenFabric router configuration node */ VRRP_NODE, /* VRRP node */ BMP_NODE, /* BMP config under router bgp */ + ISIS_SRV6_NODE, /* ISIS SRv6 node */ + ISIS_SRV6_NODE_MSD_NODE, /* ISIS SRv6 Node MSDs node */ + BGP_LS_NODE, /* BGP-LS configuration node */ NODE_TYPE_MAX, /* maximum */ }; /* clang-format on */ diff --git a/lib/compiler.h b/lib/compiler.h index 29fcfbefbf2d..ce6727685f13 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -122,6 +122,14 @@ extern "C" { #define assume(x) #endif +#ifdef __COVERITY__ +/* __coverity_panic__() is named a bit poorly, it's essentially the same as + * __builtin_unreachable(). Used to eliminate false positives. + */ +#undef assume +#define assume(x) do { if (!(x)) __coverity_panic__(); } while (0) +#endif + /* for helper functions defined inside macros */ #define macro_inline static inline __attribute__((unused)) #define macro_pure static inline __attribute__((unused, pure)) diff --git a/lib/darr.c b/lib/darr.c index 2c8b7b8778a1..bef51b8fc4a5 100644 --- a/lib/darr.c +++ b/lib/darr.c @@ -7,8 +7,9 @@ */ #include #include "darr.h" +#include "memory.h" -void __dar_resize(void **a, uint count, size_t esize); +DEFINE_MTYPE_STATIC(LIB, DARR, "Dynamic Array"); static uint _msb(uint count) { @@ -56,15 +57,12 @@ void *__darr_resize(void *a, uint count, size_t esize) uint ncount = darr_next_count(count, esize); size_t osz = (a == NULL) ? 0 : darr_size(darr_cap(a), esize); size_t sz = darr_size(ncount, esize); - struct darr_metadata *dm = realloc(a ? _darr_meta(a) : NULL, sz); - /* do *not* use a */ + struct darr_metadata *dm = XREALLOC(MTYPE_DARR, + a ? _darr_meta(a) : NULL, sz); - assert(dm); if (sz > osz) memset((char *)dm + osz, 0, sz - osz); - dm->cap = ncount; - return (void *)(dm + 1); } @@ -109,6 +107,6 @@ void *__darr_insert_n(void *a, uint at, uint count, size_t esize, bool zero) memset(_a_at(at), 0, esize * count); } - return (void *)a; + return a; #undef _a_at } diff --git a/lib/elf_py.c b/lib/elf_py.c index 81ca668e709a..643495d8c76f 100644 --- a/lib/elf_py.c +++ b/lib/elf_py.c @@ -1089,7 +1089,9 @@ static void elffile_add_dynreloc(struct elffile *w, Elf_Data *reldata, symidx = relw->symidx = GELF_R_SYM(rela->r_info); sym = relw->sym = gelf_getsym(symdata, symidx, &relw->_sym); if (sym) { - relw->symname = elfdata_strptr(strdata, sym->st_name); + if (strdata) + relw->symname = elfdata_strptr(strdata, + sym->st_name); relw->symvalid = GELF_ST_TYPE(sym->st_info) != STT_NOTYPE; relw->unresolved = sym->st_shndx == SHN_UNDEF; diff --git a/lib/event.c b/lib/event.c index 4b4ca9d7eaf2..122d3cd9a1fa 100644 --- a/lib/event.c +++ b/lib/event.c @@ -75,48 +75,48 @@ static struct list *masters; static void thread_free(struct event_loop *master, struct event *thread); -#ifndef EXCLUDE_CPU_TIME -#define EXCLUDE_CPU_TIME 0 -#endif -#ifndef CONSUMED_TIME_CHECK -#define CONSUMED_TIME_CHECK 0 -#endif - -bool cputime_enabled = !EXCLUDE_CPU_TIME; +bool cputime_enabled = true; unsigned long cputime_threshold = CONSUMED_TIME_CHECK; unsigned long walltime_threshold = CONSUMED_TIME_CHECK; /* CLI start ---------------------------------------------------------------- */ #include "lib/event_clippy.c" -static unsigned int cpu_record_hash_key(const struct cpu_event_history *a) +static uint32_t cpu_record_hash_key(const struct cpu_event_history *a) { int size = sizeof(a->func); return jhash(&a->func, size, 0); } -static bool cpu_record_hash_cmp(const struct cpu_event_history *a, - const struct cpu_event_history *b) +static int cpu_record_hash_cmp(const struct cpu_event_history *a, + const struct cpu_event_history *b) { - return a->func == b->func; + return numcmp((uintptr_t)a->func, (uintptr_t)b->func); } -static void *cpu_record_hash_alloc(struct cpu_event_history *a) +DECLARE_HASH(cpu_records, struct cpu_event_history, item, cpu_record_hash_cmp, + cpu_record_hash_key); + +static struct cpu_event_history *cpu_records_get(struct event_loop *loop, + void (*func)(struct event *e), + const char *funcname) { - struct cpu_event_history *new; + struct cpu_event_history ref = { .func = func }, *res; - new = XCALLOC(MTYPE_EVENT_STATS, sizeof(struct cpu_event_history)); - new->func = a->func; - new->funcname = a->funcname; - return new; + res = cpu_records_find(loop->cpu_records, &ref); + if (!res) { + res = XCALLOC(MTYPE_EVENT_STATS, sizeof(*res)); + res->func = func; + res->funcname = funcname; + cpu_records_add(loop->cpu_records, res); + } + return res; } -static void cpu_record_hash_free(void *a) +static void cpu_records_free(struct cpu_event_history **p) { - struct cpu_event_history *hist = a; - - XFREE(MTYPE_EVENT_STATS, hist); + XFREE(MTYPE_EVENT_STATS, *p); } static void vty_out_cpu_event_history(struct vty *vty, @@ -136,14 +136,11 @@ static void vty_out_cpu_event_history(struct vty *vty, a->types & (1 << EVENT_EXECUTE) ? 'X' : ' ', a->funcname); } -static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[]) +static void cpu_record_print_one(struct vty *vty, uint8_t filter, + struct cpu_event_history *totals, + const struct cpu_event_history *a) { - struct cpu_event_history *totals = args[0]; struct cpu_event_history copy; - struct vty *vty = args[1]; - uint8_t *filter = args[2]; - - struct cpu_event_history *a = bucket->data; copy.total_active = atomic_load_explicit(&a->total_active, memory_order_seq_cst); @@ -165,7 +162,7 @@ static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[]) copy.types = atomic_load_explicit(&a->types, memory_order_seq_cst); copy.funcname = a->funcname; - if (!(copy.types & *filter)) + if (!(copy.types & filter)) return; vty_out_cpu_event_history(vty, ©); @@ -185,7 +182,6 @@ static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[]) static void cpu_record_print(struct vty *vty, uint8_t filter) { struct cpu_event_history tmp; - void *args[3] = {&tmp, vty, &filter}; struct event_loop *m; struct listnode *ln; @@ -222,13 +218,13 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) vty_out(vty, " CPU_Warn Wall_Warn Starv_Warn Type Thread\n"); - if (m->cpu_record->count) - hash_iterate( - m->cpu_record, - (void (*)(struct hash_bucket *, - void *))cpu_record_hash_print, - args); - else + if (cpu_records_count(m->cpu_records)) { + struct cpu_event_history *rec; + + frr_each (cpu_records, m->cpu_records, rec) + cpu_record_print_one(vty, filter, &tmp, + rec); + } else vty_out(vty, "No data to display yet.\n"); vty_out(vty, "\n"); @@ -248,35 +244,29 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) vty_out_cpu_event_history(vty, &tmp); } -static void cpu_record_hash_clear(struct hash_bucket *bucket, void *args[]) -{ - uint8_t *filter = args[0]; - struct hash *cpu_record = args[1]; - - struct cpu_event_history *a = bucket->data; - - if (!(a->types & *filter)) - return; - - hash_release(cpu_record, bucket->data); -} - static void cpu_record_clear(uint8_t filter) { - uint8_t *tmp = &filter; struct event_loop *m; struct listnode *ln; frr_with_mutex (&masters_mtx) { for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) { frr_with_mutex (&m->mtx) { - void *args[2] = {tmp, m->cpu_record}; + struct cpu_event_history *item; + struct cpu_records_head old[1]; + + cpu_records_init(old); + cpu_records_swap_all(old, m->cpu_records); - hash_iterate( - m->cpu_record, - (void (*)(struct hash_bucket *, - void *))cpu_record_hash_clear, - args); + while ((item = cpu_records_pop(old))) { + if (item->types & filter) + cpu_records_free(&item); + else + cpu_records_add(m->cpu_records, + item); + } + + cpu_records_fini(old); } } } @@ -565,10 +555,7 @@ struct event_loop *event_master_create(const char *name) snprintf(tmhashname, sizeof(tmhashname), "%s - threadmaster event hash", name); - rv->cpu_record = hash_create_size( - 8, (unsigned int (*)(const void *))cpu_record_hash_key, - (bool (*)(const void *, const void *))cpu_record_hash_cmp, - tmhashname); + cpu_records_init(rv->cpu_records); event_list_init(&rv->event); event_list_init(&rv->ready); @@ -686,6 +673,7 @@ void event_master_free_unused(struct event_loop *m) /* Stop thread scheduler. */ void event_master_free(struct event_loop *m) { + struct cpu_event_history *record; struct event *t; frr_with_mutex (&masters_mtx) { @@ -708,7 +696,9 @@ void event_master_free(struct event_loop *m) list_delete(&m->cancel_req); m->cancel_req = NULL; - hash_clean_and_free(&m->cpu_record, cpu_record_hash_free); + while ((record = cpu_records_pop(m->cpu_records))) + cpu_records_free(&record); + cpu_records_fini(m->cpu_records); XFREE(MTYPE_EVENT_MASTER, m->name); XFREE(MTYPE_EVENT_MASTER, m->handler.pfds); @@ -781,7 +771,6 @@ static struct event *thread_get(struct event_loop *m, uint8_t type, const struct xref_eventsched *xref) { struct event *thread = event_list_pop(&m->unuse); - struct cpu_event_history tmp; if (!thread) { thread = XCALLOC(MTYPE_THREAD, sizeof(struct event)); @@ -795,7 +784,12 @@ static struct event *thread_get(struct event_loop *m, uint8_t type, thread->master = m; thread->arg = arg; thread->yield = EVENT_YIELD_TIME_SLOT; /* default */ - thread->ref = NULL; + /* thread->ref is zeroed either by XCALLOC above or by memset before + * being put on the "unuse" list by thread_add_unuse(). + * Setting it here again makes coverity complain about a missing + * lock :( + */ + /* thread->ref = NULL; */ thread->ignore_timer_late = false; /* @@ -809,13 +803,9 @@ static struct event *thread_get(struct event_loop *m, uint8_t type, * hash_get lookups. */ if ((thread->xref && thread->xref->funcname != xref->funcname) - || thread->func != func) { - tmp.func = func; - tmp.funcname = xref->funcname; - thread->hist = - hash_get(m->cpu_record, &tmp, - (void *(*)(void *))cpu_record_hash_alloc); - } + || thread->func != func) + thread->hist = cpu_records_get(m, func, xref->funcname); + thread->hist->total_active++; thread->func = func; thread->xref = xref; diff --git a/lib/frrevent.h b/lib/frrevent.h index fe33ffd1f240..3f74df359bc2 100644 --- a/lib/frrevent.h +++ b/lib/frrevent.h @@ -18,6 +18,8 @@ extern "C" { #endif +#define CONSUMED_TIME_CHECK 5000000 + extern bool cputime_enabled; extern unsigned long cputime_threshold; /* capturing wallclock time is always enabled since it is fast (reading @@ -65,6 +67,8 @@ struct xref_eventsched { uint32_t event_type; }; +PREDECL_HASH(cpu_records); + /* Master of the theads. */ struct event_loop { char *name; @@ -76,7 +80,7 @@ struct event_loop { struct list *cancel_req; bool canceled; pthread_cond_t cancel_cond; - struct hash *cpu_record; + struct cpu_records_head cpu_records[1]; int io_pipe[2]; int fd_limit; struct fd_handler handler; @@ -130,6 +134,8 @@ struct event { #endif struct cpu_event_history { + struct cpu_records_item item; + void (*func)(struct event *e); atomic_size_t total_cpu_warn; atomic_size_t total_wall_warn; diff --git a/lib/iana_afi.h b/lib/iana_afi.h index b9c19cc3d549..9b4d33fa4d62 100644 --- a/lib/iana_afi.h +++ b/lib/iana_afi.h @@ -26,6 +26,7 @@ typedef enum { IANA_AFI_IPV4 = 1, IANA_AFI_IPV6 = 2, IANA_AFI_L2VPN = 25, + IANA_AFI_LINKSTATE = 16388, /* BGP-LS RFC 7752 */ } iana_afi_t; typedef enum { @@ -35,6 +36,8 @@ typedef enum { IANA_SAFI_LABELED_UNICAST = 4, IANA_SAFI_ENCAP = 7, IANA_SAFI_EVPN = 70, + IANA_SAFI_LINKSTATE = 71, /* BGP-LS RFC 7752 */ + IANA_SAFI_LINKSTATE_VPN = 72, /* BGP-LS RFC 7752 */ IANA_SAFI_MPLS_VPN = 128, IANA_SAFI_FLOWSPEC = 133 } iana_safi_t; @@ -48,6 +51,8 @@ static inline afi_t afi_iana2int(iana_afi_t afi) return AFI_IP6; case IANA_AFI_L2VPN: return AFI_L2VPN; + case IANA_AFI_LINKSTATE: + return AFI_LINKSTATE; case IANA_AFI_RESERVED: return AFI_MAX; } @@ -64,6 +69,8 @@ static inline iana_afi_t afi_int2iana(afi_t afi) return IANA_AFI_IPV6; case AFI_L2VPN: return IANA_AFI_L2VPN; + case AFI_LINKSTATE: + return IANA_AFI_LINKSTATE; case AFI_UNSPEC: case AFI_MAX: return IANA_AFI_RESERVED; @@ -94,6 +101,10 @@ static inline safi_t safi_iana2int(iana_safi_t safi) return SAFI_LABELED_UNICAST; case IANA_SAFI_FLOWSPEC: return SAFI_FLOWSPEC; + case IANA_SAFI_LINKSTATE: + return SAFI_LINKSTATE; + case IANA_SAFI_LINKSTATE_VPN: + return SAFI_LINKSTATE_VPN; case IANA_SAFI_RESERVED: return SAFI_MAX; } @@ -118,6 +129,10 @@ static inline iana_safi_t safi_int2iana(safi_t safi) return IANA_SAFI_LABELED_UNICAST; case SAFI_FLOWSPEC: return IANA_SAFI_FLOWSPEC; + case SAFI_LINKSTATE: + return IANA_SAFI_LINKSTATE; + case SAFI_LINKSTATE_VPN: + return IANA_SAFI_LINKSTATE_VPN; case SAFI_UNSPEC: case SAFI_MAX: return IANA_SAFI_RESERVED; diff --git a/lib/if.c b/lib/if.c index 6f567861d19c..48c01af882a4 100644 --- a/lib/if.c +++ b/lib/if.c @@ -98,8 +98,8 @@ int if_cmp_name_func(const char *p1, const char *p2) if (!*p2) return 1; - x1 = strtol(p1, (char **)&tmp1, 10); - x2 = strtol(p2, (char **)&tmp2, 10); + x1 = strtol(p1, &tmp1, 10); + x2 = strtol(p2, &tmp2, 10); /* let's compare numbers now */ if (x1 < x2) diff --git a/lib/if.h b/lib/if.h index c6b4fd216a37..7b4415da45d4 100644 --- a/lib/if.h +++ b/lib/if.h @@ -252,6 +252,9 @@ struct interface { /* Interface Speed in Mb/s */ uint32_t speed; + /* TX queue len */ + uint32_t txqlen; + /* Interface MTU. */ unsigned int mtu; /* IPv4 MTU */ unsigned int diff --git a/lib/ipaddr.h b/lib/ipaddr.h index e3ad14d7dbff..c86e38c867c0 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -28,6 +28,7 @@ struct ipaddr { enum ipaddr_type_t ipa_type; union { uint8_t addr; + uint8_t addrbytes[16]; struct in_addr _v4_addr; struct in6_addr _v6_addr; } ip; diff --git a/lib/link_state.c b/lib/link_state.c index 105e3e28a96a..25373bdb20a5 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -1739,7 +1739,7 @@ struct ls_message *ls_subnet2msg(struct ls_message *msg, struct ls_vertex *ls_msg2vertex(struct ls_ted *ted, struct ls_message *msg, bool delete) { - struct ls_node *node = (struct ls_node *)msg->data.node; + struct ls_node *node = msg->data.node; struct ls_vertex *vertex = NULL; switch (msg->event) { @@ -1779,7 +1779,7 @@ struct ls_vertex *ls_msg2vertex(struct ls_ted *ted, struct ls_message *msg, struct ls_edge *ls_msg2edge(struct ls_ted *ted, struct ls_message *msg, bool delete) { - struct ls_attributes *attr = (struct ls_attributes *)msg->data.attr; + struct ls_attributes *attr = msg->data.attr; struct ls_edge *edge = NULL; switch (msg->event) { @@ -1819,7 +1819,7 @@ struct ls_edge *ls_msg2edge(struct ls_ted *ted, struct ls_message *msg, struct ls_subnet *ls_msg2subnet(struct ls_ted *ted, struct ls_message *msg, bool delete) { - struct ls_prefix *pref = (struct ls_prefix *)msg->data.prefix; + struct ls_prefix *pref = msg->data.prefix; struct ls_subnet *subnet = NULL; switch (msg->event) { diff --git a/lib/log.c b/lib/log.c index df9b6c717633..ac31faa7951c 100644 --- a/lib/log.c +++ b/lib/log.c @@ -351,7 +351,6 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_VRF_ADD), DESC_ENTRY(ZEBRA_VRF_DELETE), DESC_ENTRY(ZEBRA_VRF_LABEL), - DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE), DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER), DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER), DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV), diff --git a/lib/nexthop.c b/lib/nexthop.c index 4f92ef9c8b52..8df57e36a201 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -56,6 +56,7 @@ static int _nexthop_srv6_cmp(const struct nexthop *nh1, const struct nexthop *nh2) { int ret = 0; + int i = 0; if (!nh1->nh_srv6 && !nh2->nh_srv6) return 0; @@ -78,9 +79,26 @@ static int _nexthop_srv6_cmp(const struct nexthop *nh1, if (ret != 0) return ret; - ret = memcmp(&nh1->nh_srv6->seg6_segs, - &nh2->nh_srv6->seg6_segs, - sizeof(struct in6_addr)); + if (!nh1->nh_srv6->seg6_segs && !nh2->nh_srv6->seg6_segs) + return 0; + + if (!nh1->nh_srv6->seg6_segs && nh2->nh_srv6->seg6_segs) + return -1; + + if (nh1->nh_srv6->seg6_segs && !nh2->nh_srv6->seg6_segs) + return 1; + + if (nh1->nh_srv6->seg6_segs->num_segs != + nh2->nh_srv6->seg6_segs->num_segs) + return -1; + + for (i = 0; i < nh1->nh_srv6->seg6_segs->num_segs; i++) { + ret = memcmp(&nh1->nh_srv6->seg6_segs->seg[i], + &nh2->nh_srv6->seg6_segs->seg[i], + sizeof(struct in6_addr)); + if (ret != 0) + break; + } return ret; } @@ -362,7 +380,7 @@ struct nexthop *nexthop_new(void) * The linux kernel does some weird stuff with adding +1 to * all nexthop weights it gets over netlink. * To handle this, just default everything to 1 right from - * from the beginning so we don't have to special case + * the beginning so we don't have to special case * default weights in the linux netlink code. * * 1 should be a valid on all platforms anyway. @@ -568,15 +586,25 @@ void nexthop_del_srv6_seg6local(struct nexthop *nexthop) if (!nexthop->nh_srv6) return; + if (nexthop->nh_srv6->seg6local_action == ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + return; + nexthop->nh_srv6->seg6local_action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; - if (sid_zero(&nexthop->nh_srv6->seg6_segs)) + if (nexthop->nh_srv6->seg6_segs && + (nexthop->nh_srv6->seg6_segs->num_segs == 0 || + sid_zero(nexthop->nh_srv6->seg6_segs))) + XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6->seg6_segs); + + if (nexthop->nh_srv6->seg6_segs == NULL) XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6); } -void nexthop_add_srv6_seg6(struct nexthop *nexthop, - const struct in6_addr *segs) +void nexthop_add_srv6_seg6(struct nexthop *nexthop, const struct in6_addr *segs, + int num_segs) { + int i; + if (!segs) return; @@ -584,7 +612,22 @@ void nexthop_add_srv6_seg6(struct nexthop *nexthop, nexthop->nh_srv6 = XCALLOC(MTYPE_NH_SRV6, sizeof(struct nexthop_srv6)); - nexthop->nh_srv6->seg6_segs = *segs; + /* Enforce limit on srv6 seg stack size */ + if (num_segs > SRV6_MAX_SIDS) + num_segs = SRV6_MAX_SIDS; + + if (!nexthop->nh_srv6->seg6_segs) { + nexthop->nh_srv6->seg6_segs = + XCALLOC(MTYPE_NH_SRV6, + sizeof(struct seg6_seg_stack) + + num_segs * sizeof(struct in6_addr)); + } + + nexthop->nh_srv6->seg6_segs->num_segs = num_segs; + + for (i = 0; i < num_segs; i++) + memcpy(&nexthop->nh_srv6->seg6_segs->seg[i], &segs[i], + sizeof(struct in6_addr)); } void nexthop_del_srv6_seg6(struct nexthop *nexthop) @@ -592,12 +635,14 @@ void nexthop_del_srv6_seg6(struct nexthop *nexthop) if (!nexthop->nh_srv6) return; - memset(&nexthop->nh_srv6->seg6_segs, 0, - sizeof(nexthop->nh_srv6->seg6_segs)); - - if (nexthop->nh_srv6->seg6local_action == - ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) - XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6); + if (nexthop->nh_srv6->seg6local_action == ZEBRA_SEG6_LOCAL_ACTION_UNSPEC && + nexthop->nh_srv6->seg6_segs) { + memset(nexthop->nh_srv6->seg6_segs->seg, 0, + sizeof(struct in6_addr) * + nexthop->nh_srv6->seg6_segs->num_segs); + XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6->seg6_segs); + } + XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6); } const char *nexthop2str(const struct nexthop *nexthop, char *str, int size) @@ -743,11 +788,32 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop) } if (nexthop->nh_srv6) { - key = jhash_1word(nexthop->nh_srv6->seg6local_action, key); - key = jhash(&nexthop->nh_srv6->seg6local_ctx, - sizeof(nexthop->nh_srv6->seg6local_ctx), key); - key = jhash(&nexthop->nh_srv6->seg6_segs, - sizeof(nexthop->nh_srv6->seg6_segs), key); + int segs_num = 0; + int i = 0; + + if (nexthop->nh_srv6->seg6local_action != + ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) { + key = jhash_1word(nexthop->nh_srv6->seg6local_action, + key); + key = jhash(&nexthop->nh_srv6->seg6local_ctx, + sizeof(nexthop->nh_srv6->seg6local_ctx), + key); + if (nexthop->nh_srv6->seg6_segs) + key = jhash(&nexthop->nh_srv6->seg6_segs->seg[0], + sizeof(struct in6_addr), key); + } else { + if (nexthop->nh_srv6->seg6_segs) { + segs_num = nexthop->nh_srv6->seg6_segs->num_segs; + while (segs_num >= 1) { + key = jhash(&nexthop->nh_srv6->seg6_segs + ->seg[i], + sizeof(struct in6_addr), + key); + segs_num -= 1; + i += 1; + } + } + } } return key; @@ -810,9 +876,13 @@ void nexthop_copy_no_recurse(struct nexthop *copy, nexthop_add_srv6_seg6local(copy, nexthop->nh_srv6->seg6local_action, &nexthop->nh_srv6->seg6local_ctx); - if (!sid_zero(&nexthop->nh_srv6->seg6_segs)) + if (nexthop->nh_srv6->seg6_segs && + nexthop->nh_srv6->seg6_segs->num_segs && + !sid_zero(nexthop->nh_srv6->seg6_segs)) nexthop_add_srv6_seg6(copy, - &nexthop->nh_srv6->seg6_segs); + &nexthop->nh_srv6->seg6_segs->seg[0], + nexthop->nh_srv6->seg6_segs + ->num_segs); } } diff --git a/lib/nexthop.h b/lib/nexthop.h index 2be89f8240bd..bed6447d49ed 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -157,8 +157,8 @@ void nexthop_del_labels(struct nexthop *); void nexthop_add_srv6_seg6local(struct nexthop *nexthop, uint32_t action, const struct seg6local_context *ctx); void nexthop_del_srv6_seg6local(struct nexthop *nexthop); -void nexthop_add_srv6_seg6(struct nexthop *nexthop, - const struct in6_addr *segs); +void nexthop_add_srv6_seg6(struct nexthop *nexthop, const struct in6_addr *seg, + int num_segs); void nexthop_del_srv6_seg6(struct nexthop *nexthop); /* diff --git a/lib/northbound.c b/lib/northbound.c index ef2344ee110c..69b96d365693 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -2691,7 +2691,6 @@ void nb_init(struct event_loop *tm, size_t nmodules, bool db_enabled) { struct yang_module *loaded[nmodules], **loadedp = loaded; - bool explicit_compile; /* * Currently using this explicit compile feature in libyang2 leads to @@ -2699,8 +2698,9 @@ void nb_init(struct event_loop *tm, * of modules until they have all been loaded into the context. This * avoids multiple recompiles of the same modules as they are * imported/augmented etc. + * (Done as a #define to make coverity happy) */ - explicit_compile = false; +#define explicit_compile false nb_db_enabled = db_enabled; diff --git a/lib/plist.c b/lib/plist.c index d8ce83d219ea..2f5827cf4354 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -336,22 +336,6 @@ prefix_list_entry_lookup(struct prefix_list *plist, struct prefix *prefix, return NULL; } -static bool -prefix_list_entry_lookup_prefix(struct prefix_list *plist, - struct prefix_list_entry *plist_entry) -{ - struct prefix_list_entry *pentry = NULL; - - for (pentry = plist->head; pentry; pentry = pentry->next) { - if (pentry == plist_entry) - continue; - if (prefix_same(&pentry->prefix, &plist_entry->prefix)) - return true; - } - - return false; -} - static void trie_walk_affected(size_t validbits, struct pltrie_table *table, uint8_t byte, struct prefix_list_entry *object, void (*fn)(struct prefix_list_entry *object, @@ -418,17 +402,54 @@ static void prefix_list_trie_del(struct prefix_list *plist, } } +/** + * Find duplicated prefix entry (same prefix but different entry) in prefix + * list. + */ +static bool prefix_list_entry_is_duplicated(struct prefix_list *list, + struct prefix_list_entry *entry) +{ + size_t depth, maxdepth = list->master->trie_depth; + uint8_t byte, *bytes = entry->prefix.u.val; + size_t validbits = entry->prefix.prefixlen; + struct pltrie_table *table = list->trie; + struct prefix_list_entry *pentry; + + for (depth = 0; validbits > PLC_BITS && depth < maxdepth - 1; depth++) { + byte = bytes[depth]; + if (!table->entries[byte].next_table) + return NULL; + + table = table->entries[byte].next_table; + validbits -= PLC_BITS; + } + + byte = bytes[depth]; + if (validbits > PLC_BITS) + pentry = table->entries[byte].final_chain; + else + pentry = table->entries[byte].up_chain; + + for (; pentry; pentry = pentry->next_best) { + if (pentry == entry) + continue; + if (prefix_same(&pentry->prefix, &entry->prefix)) + return true; + } + + return false; +} void prefix_list_entry_delete(struct prefix_list *plist, - struct prefix_list_entry *pentry, int update_list) + struct prefix_list_entry *pentry, + int update_list) { - bool duplicate = false; + bool duplicate; if (plist == NULL || pentry == NULL) return; - if (prefix_list_entry_lookup_prefix(plist, pentry)) - duplicate = true; + duplicate = prefix_list_entry_is_duplicated(plist, pentry); prefix_list_trie_del(plist, pentry); @@ -579,14 +600,13 @@ static void prefix_list_entry_add(struct prefix_list *plist, void prefix_list_entry_update_start(struct prefix_list_entry *ple) { struct prefix_list *pl = ple->pl; - bool duplicate = false; + bool duplicate; /* Not installed, nothing to do. */ if (!ple->installed) return; - if (prefix_list_entry_lookup_prefix(pl, ple)) - duplicate = true; + duplicate = prefix_list_entry_is_duplicated(pl, ple); prefix_list_trie_del(pl, ple); diff --git a/lib/prefix.c b/lib/prefix.c index 0b8664411d33..cde8677cf086 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -20,6 +20,7 @@ DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix"); DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec"); +DEFINE_MTYPE_STATIC(LIB, PREFIX_LINKSTATE, "Prefix Link-State"); /* Maskbit. */ static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, @@ -32,6 +33,18 @@ static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, #define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) +char *(*prefix_linkstate_display_hook)(char *buf, size_t size, + uint16_t nlri_type, uintptr_t ptr, + uint16_t len) = NULL; + +void prefix_set_linkstate_display_hook(char *(*func)(char *buf, size_t size, + uint16_t nlri_type, + uintptr_t ptr, + uint16_t len)) +{ + prefix_linkstate_display_hook = func; +} + int is_zero_mac(const struct ethaddr *mac) { int i = 0; @@ -81,6 +94,8 @@ int str2family(const char *string) return AF_ETHERNET; else if (!strcmp("evpn", string)) return AF_EVPN; + else if (!strcmp("link-state", string)) + return AF_LINKSTATE; return -1; } @@ -95,6 +110,8 @@ const char *family2str(int family) return "Ethernet"; case AF_EVPN: return "Evpn"; + case AF_LINKSTATE: + return "Link-State"; } return "?"; } @@ -109,6 +126,8 @@ int afi2family(afi_t afi) else if (afi == AFI_L2VPN) return AF_ETHERNET; /* NOTE: EVPN code should NOT use this interface. */ + else if (afi == AFI_LINKSTATE) + return AF_LINKSTATE; return 0; } @@ -120,6 +139,8 @@ afi_t family2afi(int family) return AFI_IP6; else if (family == AF_ETHERNET || family == AF_EVPN) return AFI_L2VPN; + else if (family == AF_LINKSTATE) + return AFI_LINKSTATE; return 0; } @@ -132,6 +153,8 @@ const char *afi2str_lower(afi_t afi) return "ipv6"; case AFI_L2VPN: return "l2vpn"; + case AFI_LINKSTATE: + return "link-state"; case AFI_MAX: case AFI_UNSPEC: return "bad-value"; @@ -149,6 +172,8 @@ const char *afi2str(afi_t afi) return "IPv6"; case AFI_L2VPN: return "l2vpn"; + case AFI_LINKSTATE: + return "link-state"; case AFI_MAX: case AFI_UNSPEC: return "bad-value"; @@ -174,6 +199,10 @@ const char *safi2str(safi_t safi) return "labeled-unicast"; case SAFI_FLOWSPEC: return "flowspec"; + case SAFI_LINKSTATE: + return "link-state"; + case SAFI_LINKSTATE_VPN: + return "link-state-vpn"; case SAFI_UNSPEC: case SAFI_MAX: return "unknown"; @@ -211,6 +240,21 @@ int prefix_match(union prefixconstptr unet, union prefixconstptr upfx) offset = n->u.prefix_flowspec.prefixlen; + while (offset--) + if (np[offset] != pp[offset]) + return 0; + return 1; + } else if (n->family == AF_LINKSTATE) { + if (n->u.prefix_linkstate.nlri_type != + p->u.prefix_linkstate.nlri_type) + return 0; + + /* Set both prefix's head pointer. */ + np = (const uint8_t *)&n->u.prefix_linkstate.ptr; + pp = (const uint8_t *)&p->u.prefix_linkstate.ptr; + + offset = n->prefixlen; /* length is checked above */ + while (offset--) if (np[offset] != pp[offset]) return 0; @@ -261,7 +305,7 @@ int evpn_type5_prefix_match(const struct prefix *n, const struct prefix *p) return 0; prefixlen = evp->prefix.prefix_addr.ip_prefix_length; - np = &evp->prefix.prefix_addr.ip.ip.addr; + np = evp->prefix.prefix_addr.ip.ip.addrbytes; /* If n's prefix is longer than p's one return 0. */ if (prefixlen > p->prefixlen) @@ -316,6 +360,8 @@ void prefix_copy(union prefixptr udest, union prefixconstptr usrc) { struct prefix *dest = udest.p; const struct prefix *src = usrc.p; + void *temp; + int len; dest->family = src->family; dest->prefixlen = src->prefixlen; @@ -334,9 +380,6 @@ void prefix_copy(union prefixptr udest, union prefixconstptr usrc) dest->u.lp.id = src->u.lp.id; dest->u.lp.adv_router = src->u.lp.adv_router; } else if (src->family == AF_FLOWSPEC) { - void *temp; - int len; - len = src->u.prefix_flowspec.prefixlen; dest->u.prefix_flowspec.prefixlen = src->u.prefix_flowspec.prefixlen; @@ -347,6 +390,14 @@ void prefix_copy(union prefixptr udest, union prefixconstptr usrc) dest->u.prefix_flowspec.ptr = (uintptr_t)temp; memcpy((void *)dest->u.prefix_flowspec.ptr, (void *)src->u.prefix_flowspec.ptr, len); + } else if (src->family == AF_LINKSTATE) { + len = src->prefixlen; + dest->u.prefix_linkstate.nlri_type = + src->u.prefix_linkstate.nlri_type; + temp = XCALLOC(MTYPE_PREFIX_LINKSTATE, len); + dest->u.prefix_linkstate.ptr = (uintptr_t)temp; + memcpy((void *)dest->u.prefix_linkstate.ptr, + (void *)src->u.prefix_linkstate.ptr, len); } else { flog_err(EC_LIB_DEVELOPMENT, "prefix_copy(): Unknown address family %d", @@ -436,6 +487,14 @@ int prefix_same(union prefixconstptr up1, union prefixconstptr up2) p2->u.prefix_flowspec.prefixlen)) return 1; } + if (p1->family == AF_LINKSTATE) { + if (p1->u.prefix_linkstate.nlri_type != + p2->u.prefix_linkstate.nlri_type) + return 0; + if (!memcmp(&p1->u.prefix_linkstate.ptr, + &p2->u.prefix_linkstate.ptr, p2->prefixlen)) + return 1; + } } return 0; } @@ -483,6 +542,22 @@ int prefix_cmp(union prefixconstptr up1, union prefixconstptr up2) if (pp1[offset] != pp2[offset]) return numcmp(pp1[offset], pp2[offset]); return 0; + } else if (p1->family == AF_LINKSTATE) { + pp1 = (const uint8_t *)p1->u.prefix_linkstate.ptr; + pp2 = (const uint8_t *)p2->u.prefix_linkstate.ptr; + + if (p1->u.prefix_linkstate.nlri_type != + p2->u.prefix_linkstate.nlri_type) + return 1; + + if (p1->prefixlen != p2->prefixlen) + return numcmp(p1->prefixlen, p2->prefixlen); + + offset = p1->prefixlen; + while (offset--) + if (pp1[offset] != pp2[offset]) + return numcmp(pp1[offset], pp2[offset]); + return 0; } pp1 = p1->u.val; pp2 = p2->u.val; @@ -1072,10 +1147,26 @@ static const char *prefixevpn2str(const struct prefix_evpn *p, char *str, return str; } +const char *bgp_linkstate_nlri_type_2str(uint16_t nlri_type) +{ + switch (nlri_type) { + case BGP_LINKSTATE_NODE: + return "Node"; + case BGP_LINKSTATE_LINK: + return "Link"; + case BGP_LINKSTATE_PREFIX4: + return "IPv4-Prefix"; + case BGP_LINKSTATE_PREFIX6: + return "IPv6-Prefix"; + } + + return "Unknown"; +} + const char *prefix2str(union prefixconstptr pu, char *str, int size) { const struct prefix *p = pu.p; - char buf[PREFIX2STR_BUFFER]; + char buf[PREFIX_STRLEN_EXTENDED]; int byte, tmp, a, b; bool z = false; size_t l; @@ -1116,6 +1207,22 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) strlcpy(str, "FS prefix", size); break; + case AF_LINKSTATE: + if (prefix_linkstate_display_hook) + snprintf(str, size, "%s/%d", + prefix_linkstate_display_hook( + buf, sizeof(buf), + p->u.prefix_linkstate.nlri_type, + p->u.prefix_linkstate.ptr, + p->prefixlen), + p->prefixlen); + else + snprintf(str, size, "%s/%d", + bgp_linkstate_nlri_type_2str( + p->u.prefix_linkstate.nlri_type), + p->prefixlen); + break; + default: strlcpy(str, "UNK prefix", size); break; @@ -1127,7 +1234,7 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) static ssize_t prefixhost2str(struct fbuf *fbuf, union prefixconstptr pu) { const struct prefix *p = pu.p; - char buf[PREFIX2STR_BUFFER]; + char buf[PREFIX_STRLEN_EXTENDED]; switch (p->family) { case AF_INET: @@ -1139,6 +1246,17 @@ static ssize_t prefixhost2str(struct fbuf *fbuf, union prefixconstptr pu) prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf)); return bputs(fbuf, buf); + case AF_LINKSTATE: + if (prefix_linkstate_display_hook) + prefix_linkstate_display_hook( + buf, sizeof(buf), + p->u.prefix_linkstate.nlri_type, + p->u.prefix_linkstate.ptr, p->prefixlen); + else + snprintf(buf, sizeof(buf), "%s", + bgp_linkstate_nlri_type_2str( + p->u.prefix_linkstate.nlri_type)); + return bputs(fbuf, buf); default: return bprintfrr(fbuf, "{prefix.af=%dPF}", p->family); } @@ -1173,6 +1291,20 @@ const char *prefix_sg2str(const struct prefix_sg *sg, char *sg_str) return sg_str; } + +void prefix_linkstate_ptr_free(struct prefix *p) +{ + void *temp; + + if (!p || p->family != AF_LINKSTATE || !p->u.prefix_linkstate.ptr) + return; + + temp = (void *)p->u.prefix_linkstate.ptr; + XFREE(MTYPE_PREFIX_LINKSTATE, temp); + p->u.prefix_linkstate.ptr = (uintptr_t)NULL; +} + + struct prefix *prefix_new(void) { struct prefix *p; @@ -1322,17 +1454,16 @@ char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size) unsigned prefix_hash_key(const void *pp) { struct prefix copy; + uint32_t len; + void *temp; - if (((struct prefix *)pp)->family == AF_FLOWSPEC) { - uint32_t len; - void *temp; + /* make sure *all* unused bits are zero, particularly including + * alignment / + * padding and unused prefix bytes. */ + memset(©, 0, sizeof(copy)); + prefix_copy(©, (struct prefix *)pp); - /* make sure *all* unused bits are zero, - * particularly including alignment / - * padding and unused prefix bytes. - */ - memset(©, 0, sizeof(copy)); - prefix_copy(©, (struct prefix *)pp); + if (((struct prefix *)pp)->family == AF_FLOWSPEC) { len = jhash((void *)copy.u.prefix_flowspec.ptr, copy.u.prefix_flowspec.prefixlen, 0x55aa5a5a); @@ -1340,12 +1471,13 @@ unsigned prefix_hash_key(const void *pp) XFREE(MTYPE_PREFIX_FLOWSPEC, temp); copy.u.prefix_flowspec.ptr = (uintptr_t)NULL; return len; + } else if (((struct prefix *)pp)->family == AF_LINKSTATE) { + len = jhash((void *)copy.u.prefix_linkstate.ptr, copy.prefixlen, + 0x55aa5a5a); + prefix_linkstate_ptr_free(©); + return len; } - /* make sure *all* unused bits are zero, particularly including - * alignment / - * padding and unused prefix bytes. */ - memset(©, 0, sizeof(copy)); - prefix_copy(©, (struct prefix *)pp); + return jhash(©, offsetof(struct prefix, u.prefix) + PSIZE(copy.prefixlen), 0x55aa5a5a); @@ -1620,7 +1752,7 @@ static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea, if (host_only) return prefixhost2str(buf, (struct prefix *)ptr); else { - char cbuf[PREFIX_STRLEN]; + char cbuf[PREFIX_STRLEN_EXTENDED]; prefix2str(ptr, cbuf, sizeof(cbuf)); return bputs(buf, cbuf); diff --git a/lib/prefix.h b/lib/prefix.h index 7ca525e762a5..f1aff436899c 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -125,6 +125,15 @@ struct evpn_addr { #define prefix_addr u._prefix_addr }; +/* BGP Link-State NRLI types*/ +enum bgp_linkstate_nlri_type { + /* RFC7752 Table 1 */ + BGP_LINKSTATE_NODE = 1, + BGP_LINKSTATE_LINK = 2, + BGP_LINKSTATE_PREFIX4 = 3, /* IPv4 Topology Prefix */ + BGP_LINKSTATE_PREFIX6 = 4, /* IPv6 Topology Prefix */ +}; + /* * A struct prefix contains an address family, a prefix length, and an * address. This can represent either a 'network prefix' as defined @@ -158,12 +167,21 @@ struct evpn_addr { #define AF_FLOWSPEC (AF_MAX + 2) #endif +#if !defined(AF_LINKSTATE) +#define AF_LINKSTATE (AF_MAX + 3) +#endif + struct flowspec_prefix { uint8_t family; uint16_t prefixlen; /* length in bytes */ uintptr_t ptr; }; +struct linkstate_prefix { + uint16_t nlri_type; + uintptr_t ptr; +}; + /* FRR generic prefix structure. */ struct prefix { uint8_t family; @@ -182,6 +200,7 @@ struct prefix { uintptr_t ptr; struct evpn_addr prefix_evpn; /* AF_EVPN */ struct flowspec_prefix prefix_flowspec; /* AF_FLOWSPEC */ + struct linkstate_prefix prefix_linkstate; /* AF_LINKSTATE */ } u __attribute__((aligned(8))); }; @@ -279,6 +298,14 @@ struct prefix_fs { struct flowspec_prefix prefix __attribute__((aligned(8))); }; + +/* Prefix for a BGP-LS entry */ +struct prefix_bgpls { + uint8_t family; + uint16_t prefixlen; + struct linkstate_prefix prefix __attribute__((aligned(8))); +}; + struct prefix_sg { uint8_t family; uint16_t prefixlen; @@ -320,6 +347,11 @@ union prefixconstptr { /* Maximum string length of the result of prefix2str */ #define PREFIX_STRLEN 80 +/* Maximum string length of the result of prefix2str for + * long string prefixes (eg. BGP Link-State) + */ +#define PREFIX_STRLEN_EXTENDED 512 + /* * Longest possible length of a (S,G) string is 34 bytes * 123.123.123.123 = 15 * 2 @@ -376,10 +408,14 @@ static inline void ipv4_addr_copy(struct in_addr *dst, #define s6_addr32 __u6_addr.__u6_addr32 #endif /*s6_addr32*/ +extern void prefix_set_linkstate_display_hook( + char *(*func)(char *buf, size_t size, uint16_t nlri_type, uintptr_t ptr, + uint16_t len)); + /* Prototypes. */ -extern int str2family(const char *); -extern int afi2family(afi_t); -extern afi_t family2afi(int); +extern int str2family(const char *string); +extern int afi2family(afi_t afi); +extern afi_t family2afi(int family); extern const char *family2str(int family); extern const char *safi2str(safi_t safi); extern const char *afi2str(afi_t afi); @@ -401,6 +437,8 @@ static inline afi_t prefix_afi(union prefixconstptr pu) */ extern unsigned int prefix_bit(const uint8_t *prefix, const uint16_t bit_index); +extern void prefix_linkstate_ptr_free(struct prefix *p); + extern struct prefix *prefix_new(void); extern void prefix_free(struct prefix **p); /* @@ -409,14 +447,16 @@ extern void prefix_free(struct prefix **p); extern void prefix_free_lists(void *arg); extern const char *prefix_family_str(union prefixconstptr pu); extern int prefix_blen(union prefixconstptr pu); -extern int str2prefix(const char *, struct prefix *); +extern int str2prefix(const char *string, struct prefix *prefix); #define PREFIX2STR_BUFFER PREFIX_STRLEN 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); -extern const char *prefix2str(union prefixconstptr, char *, int); +extern const char *prefix2str(union prefixconstptr upfx, char *buffer, + int size); +extern const char *bgp_linkstate_nlri_type_2str(uint16_t nlri_type); extern int evpn_type5_prefix_match(const struct prefix *evpn_pfx, const struct prefix *match_pfx); extern int prefix_match(union prefixconstptr unet, union prefixconstptr upfx); @@ -437,36 +477,37 @@ extern bool evpn_addr_same(const struct evpn_addr *e1, const struct evpn_addr *e #define prefix_copy(a, b) ({ memset(a, 0, sizeof(*a)); prefix_copy(a, b); }) #endif -extern struct prefix *sockunion2hostprefix(const union sockunion *, +extern struct prefix *sockunion2hostprefix(const union sockunion *su, struct prefix *p); -extern void prefix2sockunion(const struct prefix *, union sockunion *); +extern void prefix2sockunion(const struct prefix *p, union sockunion *su); -extern int str2prefix_eth(const char *, struct prefix_eth *); +extern int str2prefix_eth(const char *string, struct prefix_eth *p); extern struct prefix_ipv4 *prefix_ipv4_new(void); extern void prefix_ipv4_free(struct prefix_ipv4 **p); -extern int str2prefix_ipv4(const char *, struct prefix_ipv4 *); -extern void apply_mask_ipv4(struct prefix_ipv4 *); +extern int str2prefix_ipv4(const char *string, struct prefix_ipv4 *p); +extern void apply_mask_ipv4(struct prefix_ipv4 *p); -extern int prefix_ipv4_any(const struct prefix_ipv4 *); -extern void apply_classful_mask_ipv4(struct prefix_ipv4 *); +extern int prefix_ipv4_any(const struct prefix_ipv4 *p); +extern void apply_classful_mask_ipv4(struct prefix_ipv4 *p); -extern uint8_t ip_masklen(struct in_addr); -extern void masklen2ip(const int, struct in_addr *); +extern uint8_t ip_masklen(struct in_addr addr); +extern void masklen2ip(const int length, struct in_addr *addr); /* given the address of a host on a network and the network mask length, * calculate the broadcast address for that network; * special treatment for /31 according to RFC3021 section 3.3 */ extern in_addr_t ipv4_broadcast_addr(in_addr_t hostaddr, int masklen); -extern int netmask_str2prefix_str(const char *, const char *, char *, size_t); +extern int netmask_str2prefix_str(const char *net_str, const char *mask_str, + char *prefix_str, size_t prefix_str_len); extern struct prefix_ipv6 *prefix_ipv6_new(void); extern void prefix_ipv6_free(struct prefix_ipv6 **p); -extern int str2prefix_ipv6(const char *, struct prefix_ipv6 *); -extern void apply_mask_ipv6(struct prefix_ipv6 *); +extern int str2prefix_ipv6(const char *str, struct prefix_ipv6 *p); +extern void apply_mask_ipv6(struct prefix_ipv6 *p); -extern int ip6_masklen(struct in6_addr); -extern void masklen2ip6(const int, struct in6_addr *); +extern int ip6_masklen(struct in6_addr netmask); +extern void masklen2ip6(const int masklen, struct in6_addr *netmask); extern int is_zero_mac(const struct ethaddr *mac); extern bool is_mcast_mac(const struct ethaddr *mac); diff --git a/lib/printf/README b/lib/printf/README index ac283642d798..46d51cec6a93 100644 --- a/lib/printf/README +++ b/lib/printf/README @@ -1,6 +1,6 @@ -This is the printf implementation from FreeBSD. It was imported on 2019-05-12, -from SVN revision 347514 (but the code hadn't been touched for 2 years before -that.) +This is the printf implementation from FreeBSD. The history of this code is: +- imported on 2019-05-12, from SVN revision 347514 +- resynced on 2023-09-03, to pick up `%b` implementation Please don't reindent or otherwise mangle the files to make importing fixes easy (not that there are significant changes likely to happen...) diff --git a/lib/printf/printfcommon.h b/lib/printf/printfcommon.h index 5c45520b4c3a..f777be8805ec 100644 --- a/lib/printf/printfcommon.h +++ b/lib/printf/printfcommon.h @@ -8,7 +8,7 @@ * Chris Torek. * * Copyright (c) 2011 The FreeBSD Foundation - * All rights reserved. + * * Portions of this software were developed by David Chisnall * under sponsorship from the FreeBSD Foundation. * @@ -35,8 +35,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ /* @@ -70,7 +68,7 @@ io_print(struct io_state *iop, const CHAR * __restrict ptr, size_t len) { size_t copylen = len; - if (!iop->cb) + if (!iop->cb || !len) return 0; if (iop->avail < copylen) copylen = iop->avail; @@ -171,6 +169,13 @@ __ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs) } while (sval != 0); break; + case 2: + do { + *--cp = to_char(val & 1); + val >>= 1; + } while (val); + break; + case 8: do { *--cp = to_char(val & 7); @@ -221,6 +226,13 @@ __ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs) } while (sval != 0); break; + case 2: + do { + *--cp = to_char(val & 1); + val >>= 1; + } while (val); + break; + case 8: do { *--cp = to_char(val & 7); diff --git a/lib/printf/printflocal.h b/lib/printf/printflocal.h index bac80e801c7c..4b030912fe7e 100644 --- a/lib/printf/printflocal.h +++ b/lib/printf/printflocal.h @@ -30,8 +30,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include "compiler.h" diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c index cc886834faf6..78f8be05cbf9 100644 --- a/lib/printf/vfprintf.c +++ b/lib/printf/vfprintf.c @@ -8,7 +8,7 @@ * Chris Torek. * * Copyright (c) 2011 The FreeBSD Foundation - * All rights reserved. + * * Portions of this software were developed by David Chisnall * under sponsorship from the FreeBSD Foundation. * @@ -419,6 +419,19 @@ reswitch: switch (ch) { case 'z': flags |= SIZET; goto rflag; + case 'B': + case 'b': + if (flags & INTMAX_SIZE) + ujval = UJARG(); + else + ulval = UARG(); + base = 2; + /* leading 0b/B only if non-zero */ + if (flags & ALT && + (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) + ox[1] = ch; + goto nosign; + break; case 'C': flags |= LONGINT; /*FALLTHROUGH*/ diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index a5e66880a75c..20a157e95539 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -729,6 +729,10 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, dnode, "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match")) vty_out(vty, " exact-match"); + if (yang_dnode_get_bool( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any")) + vty_out(vty, " any"); vty_out(vty, "\n"); } else if (IS_MATCH_LCOMMUNITY(condition)) { vty_out(vty, " match large-community %s", @@ -739,6 +743,10 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, dnode, "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match")) vty_out(vty, " exact-match"); + if (yang_dnode_get_bool( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any")) + vty_out(vty, " any"); vty_out(vty, "\n"); } else if (IS_MATCH_EXTCOMMUNITY(condition)) { vty_out(vty, " match extcommunity %s\n", diff --git a/lib/sha256.c b/lib/sha256.c index ccf260fa7b31..08e08eb06b5a 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -344,7 +344,7 @@ void HMAC__SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX *ctx) void PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, const uint8_t *salt, size_t saltlen, uint64_t c, uint8_t *buf, size_t dkLen) { - HMAC_SHA256_CTX PShctx, hctx; + HMAC_SHA256_CTX PShctx = {}, hctx; size_t i; uint8_t ivec[4]; uint8_t U[32]; diff --git a/lib/srv6.h b/lib/srv6.h index 0d3ee7d2ffa8..fb34f861c8c2 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -14,8 +14,11 @@ #include #include -#define SRV6_MAX_SIDS 16 +#define SRV6_MAX_SIDS 16 +#define SRV6_MAX_SEGS 8 #define SRV6_LOCNAME_SIZE 256 +#define SRH_BASE_HEADER_LENGTH 8 +#define SRH_SEGMENT_LENGTH 16 #ifdef __cplusplus extern "C" { @@ -24,6 +27,16 @@ extern "C" { #define sid2str(sid, str, size) \ inet_ntop(AF_INET6, sid, str, size) +/* SRv6 flavors manipulation macros */ +#define CHECK_SRV6_FLV_OP(OPS,OP) ((OPS) & (1 << OP)) +#define SET_SRV6_FLV_OP(OPS,OP) (OPS) |= (1 << OP) +#define UNSET_SRV6_FLV_OP(OPS,OP) (OPS) &= ~(1 << OP) +#define RESET_SRV6_FLV_OP(OPS) (OPS) = 0 + +/* SRv6 Flavors default values */ +#define ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCBLOCK_LEN 32 +#define ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCNODE_FN_LEN 16 + enum seg6_mode_t { INLINE, ENCAP, @@ -50,15 +63,47 @@ enum seg6local_action_t { ZEBRA_SEG6_LOCAL_ACTION_END_DT46 = 16, }; +/* Flavor operations for SRv6 End* Behaviors */ +enum seg6local_flavor_op { + ZEBRA_SEG6_LOCAL_FLV_OP_UNSPEC = 0, + /* PSP Flavor as per RFC 8986 section #4.16.1 */ + ZEBRA_SEG6_LOCAL_FLV_OP_PSP = 1, + /* USP Flavor as per RFC 8986 section #4.16.2 */ + ZEBRA_SEG6_LOCAL_FLV_OP_USP = 2, + /* USD Flavor as per RFC 8986 section #4.16.3 */ + ZEBRA_SEG6_LOCAL_FLV_OP_USD = 3, + /* NEXT-C-SID Flavor as per draft-ietf-spring-srv6-srh-compression-03 + section 4.1 */ + ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID = 4, +}; + +#define SRV6_SEG_STRLEN 1024 + struct seg6_segs { size_t num_segs; struct in6_addr segs[256]; }; +struct seg6local_flavors_info { + /* Flavor operations */ + uint32_t flv_ops; + + /* Locator-Block length, expressed in bits */ + uint8_t lcblock_len; + /* Locator-Node Function length, expressed in bits */ + uint8_t lcnode_func_len; +}; + +struct seg6_seg_stack { + uint8_t num_segs; + struct in6_addr seg[0]; /* 1 or more segs */ +}; + struct seg6local_context { struct in_addr nh4; struct in6_addr nh6; uint32_t table; + struct seg6local_flavors_info flv; }; struct srv6_locator { @@ -115,14 +160,18 @@ struct srv6_locator_chunk { * https://www.iana.org/assignments/segment-routing/segment-routing.xhtml */ enum srv6_endpoint_behavior_codepoint { - SRV6_ENDPOINT_BEHAVIOR_RESERVED = 0x0000, - SRV6_ENDPOINT_BEHAVIOR_END_DT6 = 0x0012, - SRV6_ENDPOINT_BEHAVIOR_END_DT4 = 0x0013, - SRV6_ENDPOINT_BEHAVIOR_END_DT46 = 0x0014, - SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID = 0x003E, - SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID = 0x003F, - SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID = 0x0040, - SRV6_ENDPOINT_BEHAVIOR_OPAQUE = 0xFFFF, + SRV6_ENDPOINT_BEHAVIOR_RESERVED = 0x0000, + SRV6_ENDPOINT_BEHAVIOR_END = 0x0001, + SRV6_ENDPOINT_BEHAVIOR_END_X = 0x0005, + SRV6_ENDPOINT_BEHAVIOR_END_DT6 = 0x0012, + SRV6_ENDPOINT_BEHAVIOR_END_DT4 = 0x0013, + SRV6_ENDPOINT_BEHAVIOR_END_DT46 = 0x0014, + SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID = 0x002B, + SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID = 0x002C, + SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID = 0x003E, + SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID = 0x003F, + SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID = 0x0040, + SRV6_ENDPOINT_BEHAVIOR_OPAQUE = 0xFFFF, }; struct nexthop_srv6 { @@ -131,7 +180,7 @@ struct nexthop_srv6 { struct seg6local_context seg6local_ctx; /* SRv6 Headend-behaviour */ - struct in6_addr seg6_segs; + struct seg6_seg_stack *seg6_segs; }; static inline const char *seg6_mode2str(enum seg6_mode_t mode) @@ -167,12 +216,21 @@ static inline bool sid_diff( return !sid_same(a, b); } -static inline bool sid_zero( - const struct in6_addr *a) + +static inline bool sid_zero(const struct seg6_seg_stack *a) +{ + struct in6_addr zero = {}; + + assert(a); + + return sid_same(&a->seg[0], &zero); +} + +static inline bool sid_zero_ipv6(const struct in6_addr *a) { struct in6_addr zero = {}; - return sid_same(a, &zero); + return sid_same(&a[0], &zero); } static inline void *sid_copy(struct in6_addr *dst, diff --git a/lib/table.c b/lib/table.c index 3bf93894ec0b..dbfc3f8b915d 100644 --- a/lib/table.c +++ b/lib/table.c @@ -142,7 +142,7 @@ static void route_common(const struct prefix *n, const struct prefix *p, const uint8_t *pp; uint8_t *newp; - if (n->family == AF_FLOWSPEC) + if (n->family == AF_FLOWSPEC || n->family == AF_LINKSTATE) return prefix_copy(new, p); np = (const uint8_t *)&n->u.prefix; pp = (const uint8_t *)&p->u.prefix; @@ -281,15 +281,22 @@ struct route_node *route_node_get(struct route_table *table, const uint8_t *prefix = &p->u.prefix; node = rn_hash_node_find(&table->hash, &search); - if (node && node->info) + if (node && node->info) { + if (family2afi(p->family) == AFI_LINKSTATE) + prefix_linkstate_ptr_free(p); + return route_lock_node(node); + } match = NULL; node = table->top; while (node && node->p.prefixlen <= prefixlen && prefix_match(&node->p, p)) { - if (node->p.prefixlen == prefixlen) + if (node->p.prefixlen == prefixlen) { + if (family2afi(p->family) == AFI_LINKSTATE) + prefix_linkstate_ptr_free(p); return route_lock_node(node); + } match = node; node = node->link[prefix_bit(prefix, node->p.prefixlen)]; @@ -324,6 +331,9 @@ struct route_node *route_node_get(struct route_table *table, table->count++; route_lock_node(new); + if (family2afi(p->family) == AFI_LINKSTATE) + prefix_linkstate_ptr_free(p); + return new; } diff --git a/lib/typesafe.h b/lib/typesafe.h index 8eb59c33b709..93258c595410 100644 --- a/lib/typesafe.h +++ b/lib/typesafe.h @@ -17,12 +17,14 @@ extern "C" { /* generic macros for all list-like types */ +/* to iterate using the const variants of the functions, append "_const" to + * the name of the container, e.g. "frr_each (my_list, head, item)" becomes + * "frr_each (my_list_const, head, item)" + */ + #define frr_each(prefix, head, item) \ for (item = prefix##_first(head); item; \ item = prefix##_next(head, item)) -#define frr_each_const(prefix, head, item) \ - for (item = prefix##_const_first(head); item; \ - item = prefix##_const_next(head, item)) #define frr_each_safe(prefix, head, item) \ for (typeof(prefix##_next_safe(head, NULL)) prefix##_safe = \ prefix##_next_safe(head, \ @@ -793,13 +795,16 @@ struct thash_head { uint8_t minshift, maxshift; }; -#define _HASH_SIZE(tabshift) \ - ((1U << (tabshift)) >> 1) +#define _HASH_SIZE(tabshift) \ + ({ \ + assume((tabshift) <= 31); \ + (1U << (tabshift)) >> 1; \ + }) #define HASH_SIZE(head) \ _HASH_SIZE((head).tabshift) #define _HASH_KEY(tabshift, val) \ ({ \ - assume((tabshift) >= 2 && (tabshift) <= 33); \ + assume((tabshift) >= 2 && (tabshift) <= 31); \ (val) >> (33 - (tabshift)); \ }) #define HASH_KEY(head, val) \ diff --git a/lib/vty.c b/lib/vty.c index 23aa2d1f38d0..ed8b71ed22d5 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -2368,8 +2368,7 @@ static void vtysh_read(struct event *thread) printf("result: %d\n", ret); printf("vtysh node: %d\n", vty->node); #endif /* VTYSH_DEBUG */ - - if (vty->pass_fd != -1) { + if (vty->pass_fd >= 0) { memset(vty->pass_fd_status, 0, 4); vty->pass_fd_status[3] = ret; vty->status = VTY_PASSFD; @@ -2387,6 +2386,13 @@ static void vtysh_read(struct event *thread) * => skip vty_event(VTYSH_READ, vty)! */ return; + } else { + assertf(vty->status != VTY_PASSFD, + "%p address=%s passfd=%d", vty, + vty->address, vty->pass_fd); + + /* normalize other invalid values */ + vty->pass_fd = -1; } /* hack for asynchronous "write integrated" @@ -2884,6 +2890,12 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive, } assert(vty->mgmt_locked_candidate_ds); assert(vty->mgmt_locked_running_ds); + + /* + * As datastores are locked explicitly, we don't need implicit + * commits and should allow pending changes. + */ + vty->pending_allowed = true; } vty->node = CONFIG_NODE; @@ -2940,6 +2952,8 @@ int vty_config_node_exit(struct vty *vty) /* TODO: could we check for un-commited changes here? */ + vty->pending_allowed = false; + if (vty->mgmt_locked_running_ds) vty_mgmt_unlock_running_inline(vty); diff --git a/lib/zclient.c b/lib/zclient.c index e40725826ad5..f8f9cf7aba05 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1061,10 +1061,11 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, sizeof(struct seg6local_context)); } - if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_SEG6)) - stream_write(s, &api_nh->seg6_segs, - sizeof(struct in6_addr)); - + if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_SEG6)) { + stream_putc(s, api_nh->seg_num); + stream_put(s, &api_nh->seg6_segs[0], + api_nh->seg_num * sizeof(struct in6_addr)); + } done: return ret; } @@ -1430,9 +1431,18 @@ int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, sizeof(struct seg6local_context)); } - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6)) - STREAM_GET(&api_nh->seg6_segs, s, - sizeof(struct in6_addr)); + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6)) { + STREAM_GETC(s, api_nh->seg_num); + if (api_nh->seg_num > SRV6_MAX_SIDS) { + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: invalid number of SRv6 Segs (%u)", + __func__, api_nh->seg_num); + return -1; + } + + STREAM_GET(&api_nh->seg6_segs[0], s, + api_nh->seg_num * sizeof(struct in6_addr)); + } /* Success */ ret = 0; @@ -2132,8 +2142,8 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) nexthop_add_srv6_seg6local(n, znh->seg6local_action, &znh->seg6local_ctx); - if (!sid_zero(&znh->seg6_segs)) - nexthop_add_srv6_seg6(n, &znh->seg6_segs); + if (znh->seg_num && !sid_zero_ipv6(znh->seg6_segs)) + nexthop_add_srv6_seg6(n, &znh->seg6_segs[0], znh->seg_num); return n; } @@ -2193,10 +2203,14 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, sizeof(struct seg6local_context)); } - if (!sid_zero(&nh->nh_srv6->seg6_segs)) { + if (nh->nh_srv6->seg6_segs && nh->nh_srv6->seg6_segs->num_segs && + !sid_zero(nh->nh_srv6->seg6_segs)) { SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6); - memcpy(&znh->seg6_segs, &nh->nh_srv6->seg6_segs, - sizeof(struct in6_addr)); + znh->seg_num = nh->nh_srv6->seg6_segs->num_segs; + for (i = 0; i < nh->nh_srv6->seg6_segs->num_segs; i++) + memcpy(&znh->seg6_segs[i], + &nh->nh_srv6->seg6_segs->seg[i], + sizeof(struct in6_addr)); } } @@ -2761,6 +2775,7 @@ static void zebra_interface_if_set_value(struct stream *s, STREAM_GETC(s, ifp->ptm_status); STREAM_GETL(s, ifp->metric); STREAM_GETL(s, ifp->speed); + STREAM_GETL(s, ifp->txqlen); STREAM_GETL(s, ifp->mtu); STREAM_GETL(s, ifp->mtu6); STREAM_GETL(s, ifp->bandwidth); diff --git a/lib/zclient.h b/lib/zclient.h index 42c5a5fdac60..f18fc056fce3 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -127,7 +127,6 @@ typedef enum { ZEBRA_VRF_ADD, ZEBRA_VRF_DELETE, ZEBRA_VRF_LABEL, - ZEBRA_INTERFACE_VRF_UPDATE, ZEBRA_BFD_CLIENT_REGISTER, ZEBRA_BFD_CLIENT_DEREGISTER, ZEBRA_INTERFACE_ENABLE_RADV, @@ -438,7 +437,8 @@ struct zapi_nexthop { struct seg6local_context seg6local_ctx; /* SRv6 Headend-behaviour */ - struct in6_addr seg6_segs; + int seg_num; + struct in6_addr seg6_segs[SRV6_MAX_SEGS]; }; /* diff --git a/lib/zebra.h b/lib/zebra.h index ecc87f58f10f..cd0b72834cfc 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -326,13 +326,14 @@ struct in_pktinfo { #define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ #endif -/* Address family numbers from RFC1700. */ +/* Address family numbers. */ typedef enum { AFI_UNSPEC = 0, AFI_IP = 1, AFI_IP6 = 2, AFI_L2VPN = 3, - AFI_MAX = 4 + AFI_LINKSTATE = 4, /* BGP-LS RFC 7752 */ + AFI_MAX = 5, } afi_t; #define IS_VALID_AFI(a) ((a) > AFI_UNSPEC && (a) < AFI_MAX) @@ -347,7 +348,9 @@ typedef enum { SAFI_EVPN = 5, SAFI_LABELED_UNICAST = 6, SAFI_FLOWSPEC = 7, - SAFI_MAX = 8 + SAFI_LINKSTATE = 8, /* BGP-LS RFC 7752 */ + SAFI_LINKSTATE_VPN = 9, /* BGP-LS RFC 7752 */ + SAFI_MAX = 10, } safi_t; #define FOREACH_AFI_SAFI(afi, safi) \ diff --git a/lib/zlog_5424.c b/lib/zlog_5424.c index c15bdece299e..9bc1c819a857 100644 --- a/lib/zlog_5424.c +++ b/lib/zlog_5424.c @@ -877,10 +877,15 @@ static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type) switch (zcf->dst) { case ZLOG_5424_DST_NONE: - break; + return -1; case ZLOG_5424_DST_FD: fd = dup(zcf->fd); + if (fd < 0) { + flog_err_sys(EC_LIB_SYSTEM_CALL, + "failed to dup() log file descriptor: %m (FD limit too low?)"); + return -1; + } optlen = sizeof(sock_type); if (!getsockopt(fd, SOL_SOCKET, SO_TYPE, &sock_type, &optlen)) { @@ -891,7 +896,7 @@ static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type) case ZLOG_5424_DST_FIFO: if (!zcf->filename) - break; + return -1; if (!zcf->file_nocreate) { frr_with_privs (lib_privs) { @@ -904,7 +909,7 @@ static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type) if (err == 0) do_chown = true; else if (errno != EEXIST) - break; + return -1; } flags = O_NONBLOCK; @@ -912,7 +917,7 @@ static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type) case ZLOG_5424_DST_FILE: if (!zcf->filename) - break; + return -1; frr_with_privs (lib_privs) { fd = open(zcf->filename, flags | O_WRONLY | O_APPEND | @@ -924,7 +929,7 @@ static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type) flog_err_sys(EC_LIB_SYSTEM_CALL, "could not open log file %pSE: %m", zcf->filename); - break; + return -1; } frr_with_privs (lib_privs) { @@ -952,11 +957,11 @@ static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type) flog_err_sys(EC_LIB_SYSTEM_CALL, "could not open or create log file %pSE: %m", zcf->filename); - break; + return -1; case ZLOG_5424_DST_UNIX: if (!zcf->filename) - break; + return -1; memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; @@ -988,6 +993,7 @@ static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type) "could not connect to log unix path %pSE: %m", zcf->filename); need_reconnect = true; + /* no return -1 here, trigger retry code below */ } else { /* datagram sockets are connectionless, restarting * the receiver may lose some packets but will resume diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c index 44c6c0097ad6..b49bf80306c1 100644 --- a/mgmtd/mgmt_vty.c +++ b/mgmtd/mgmt_vty.c @@ -239,7 +239,7 @@ DEFPY(show_mgmt_dump_data, LYD_FORMAT format = fmt[0] == 'j' ? LYD_JSON : LYD_XML; FILE *f = NULL; - if (datastore) + if (dsname) datastore = mgmt_ds_name2id(dsname); ds_ctx = mgmt_ds_get_ctx_by_id(mm, datastore); diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c index 8159ac0cd3d3..be1042f26031 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -134,7 +134,7 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, uint16_t length = 0; int sum = 0; - lsah = (struct ospf6_lsa_header *)lsa->header; + lsah = lsa->header; if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) { if (IS_DEBUG_OSPF6_GR) zlog_debug("%s: undersized (%u B) lsa", __func__, @@ -1231,7 +1231,7 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, uint16_t length = 0; int sum = 0; - lsah = (struct ospf6_lsa_header *)lsa->header; + lsah = lsa->header; if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) { if (IS_DEBUG_OSPF6_GR) zlog_debug("%s: undersized (%u B) lsa", __func__, diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 301fccecd77b..eb5514adfb3f 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -87,7 +87,7 @@ static int ospf6_router_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, char buf[32], name[32], bits[16], options[32]; struct ospf6_router_lsa *router_lsa; struct ospf6_router_lsdesc *lsdesc; - json_object *json_arr; + json_object *json_arr = NULL; json_object *json_loop; router_lsa = @@ -460,7 +460,7 @@ static int ospf6_network_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, struct ospf6_network_lsa *network_lsa; struct ospf6_network_lsdesc *lsdesc; char buf[128], options[32]; - json_object *json_arr; + json_object *json_arr = NULL; network_lsa = (struct ospf6_network_lsa *)((caddr_t)lsa->header diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index bf6f0b161490..5baad1754d5a 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -987,6 +987,7 @@ static void ospf_handle_external_aggr_update(struct ospf *ospf) &aggr->match_extnl_hash, (void *)ospf_aggr_handle_external_info); + ospf_external_aggregator_free(aggr); } else if (aggr->action == OSPF_ROUTE_AGGR_MODIFY) { aggr->action = OSPF_ROUTE_AGGR_NONE; diff --git a/ospfd/ospf_auth.c b/ospfd/ospf_auth.c new file mode 100644 index 000000000000..11ee1ddb1889 --- /dev/null +++ b/ospfd/ospf_auth.c @@ -0,0 +1,716 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 Amnesh Inc. + * Mahdi Varasteh + */ + +#include + +#include "linklist.h" +#include "if.h" +#include "checksum.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_errors.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_auth.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_packet.h" +#include "ospfd/ospf_network.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_bfd.h" +#include "ospfd/ospf_gr.h" +#ifdef CRYPTO_INTERNAL +#include "sha256.h" +#include "md5.h" +#endif + +const uint8_t ospf_auth_apad[KEYCHAIN_MAX_HASH_SIZE] = { + 0x87, 0x8F, 0xE1, 0xF3, 0x87, 0x8F, 0xE1, 0xF3, 0x87, 0x8F, 0xE1, + 0xF3, 0x87, 0x8F, 0xE1, 0xF3, 0x87, 0x8F, 0xE1, 0xF3, 0x87, 0x8F, + 0xE1, 0xF3, 0x87, 0x8F, 0xE1, 0xF3, 0x87, 0x8F, 0xE1, 0xF3, 0x87, + 0x8F, 0xE1, 0xF3, 0x87, 0x8F, 0xE1, 0xF3, 0x87, 0x8F, 0xE1, 0xF3, + 0x87, 0x8F, 0xE1, 0xF3, 0x87, 0x8F, 0xE1, 0xF3, 0x87, 0x8F, 0xE1, + 0xF3, 0x87, 0x8F, 0xE1, 0xF3, 0x87, 0x8F, 0xE1, 0xF3 +}; + +static int ospf_check_sum(struct ospf_header *ospfh) +{ + uint32_t ret; + uint16_t sum; + + /* clear auth_data for checksum. */ + memset(ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE); + + /* keep checksum and clear. */ + sum = ospfh->checksum; + memset(&ospfh->checksum, 0, sizeof(uint16_t)); + + /* calculate checksum. */ + ret = in_cksum(ospfh, ntohs(ospfh->length)); + + if (ret != sum) { + zlog_info("%s: checksum mismatch, my %X, his %X", __func__, ret, + sum); + return 0; + } + + return 1; +} + +#ifdef CRYPTO_OPENSSL +static const EVP_MD *ospf_auth_get_openssl_evp_md_from_key(struct key *key) +{ + if (key->hash_algo == KEYCHAIN_ALGO_HMAC_SHA1) + return EVP_get_digestbyname("sha1"); + else if (key->hash_algo == KEYCHAIN_ALGO_HMAC_SHA256) + return EVP_get_digestbyname("sha256"); + else if (key->hash_algo == KEYCHAIN_ALGO_HMAC_SHA384) + return EVP_get_digestbyname("sha384"); + else if (key->hash_algo == KEYCHAIN_ALGO_HMAC_SHA512) + return EVP_get_digestbyname("sha512"); + return NULL; +} +#endif + +static int ospf_auth_check_hmac_sha_digest(struct ospf_interface *oi, + struct ospf_header *ospfh, + struct ip *iph, + struct key *key) +{ + unsigned char digest[KEYCHAIN_MAX_HASH_SIZE]; + struct ospf_neighbor *nbr; + uint16_t length = ntohs(ospfh->length); + uint16_t hash_length = keychain_get_hash_len(key->hash_algo); +#ifdef CRYPTO_OPENSSL + uint32_t openssl_hash_length = hash_length; + HMAC_CTX *ctx; + const EVP_MD *md_alg = ospf_auth_get_openssl_evp_md_from_key(key); + + if (!md_alg) { + flog_warn(EC_OSPF_AUTH, + "interface %s: invalid HMAC algorithm, Router-ID: %pI4", + IF_NAME(oi), &ospfh->router_id); + return 0; + } +#elif CRYPTO_INTERNAL + HMAC_SHA256_CTX ctx; + + if (key->hash_algo != KEYCHAIN_ALGO_HMAC_SHA256) { + flog_warn(EC_OSPF_AUTH, + "interface %s: HMAC algorithm not supported, Router-ID: %pI4", + IF_NAME(oi), &ospfh->router_id); + return 0; + } +#endif + /* check crypto seqnum. */ + nbr = ospf_nbr_lookup(oi, iph, ospfh); + + if (nbr && + ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum)) { + flog_warn(EC_OSPF_AUTH, + "interface %s: ospf_check_hmac_sha bad sequence %u (expect %d), Router-ID: %pI4", + IF_NAME(oi), ntohl(ospfh->u.crypt.crypt_seqnum), + ntohl(nbr->crypt_seqnum), &ospfh->router_id); + return 0; + } +#ifdef CRYPTO_OPENSSL + ctx = HMAC_CTX_new(); + HMAC_Init_ex(ctx, key->string, strlen(key->string), md_alg, NULL); + HMAC_Update(ctx, (const unsigned char *)ospfh, length); + HMAC_Update(ctx, (const unsigned char *)ospf_auth_apad, hash_length); + HMAC_Final(ctx, digest, &openssl_hash_length); + HMAC_CTX_free(ctx); +#elif CRYPTO_INTERNAL + memset(&ctx, 0, sizeof(ctx)); + HMAC__SHA256_Init(&ctx, key->string, strlen(key->string)); + HMAC__SHA256_Update(&ctx, ospfh, length); + HMAC__SHA256_Update(&ctx, ospf_auth_apad, hash_length); + HMAC__SHA256_Final(digest, &ctx); +#endif + if (memcmp((caddr_t)ospfh + length, digest, hash_length)) { + flog_warn(EC_OSPF_AUTH, + "interface %s: ospf_check_hmac_sha checksum mismatch %u, Router-ID: %pI4", + IF_NAME(oi), length, &ospfh->router_id); + return 0; + } + if (nbr) + nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; + return 1; +} + +static int ospf_auth_check_md5_digest(struct ospf_interface *oi, + struct ospf_header *ospfh, struct ip *iph, struct key *key) +{ +#ifdef CRYPTO_OPENSSL + EVP_MD_CTX *ctx; +#elif CRYPTO_INTERNAL + MD5_CTX ctx; +#endif + char auth_key[OSPF_AUTH_MD5_SIZE + 1]; + unsigned char digest[OSPF_AUTH_MD5_SIZE]; + struct ospf_neighbor *nbr; + struct crypt_key *ck = NULL; + uint16_t length = ntohs(ospfh->length); + + if (length < sizeof(struct ospf_header)) {/* for coverity's sake */ + flog_warn(EC_OSPF_AUTH, + "%s: Invalid packet length of %u received on interface %s, Router-ID: %pI4", + __func__, length, IF_NAME(oi), &ospfh->router_id); + return 0; + } + + if (key == NULL) { + ck = ospf_crypt_key_lookup(OSPF_IF_PARAM(oi, auth_crypt), + ospfh->u.crypt.key_id); + if (ck == NULL) { + flog_warn( + EC_OSPF_AUTH, + "interface %s: %s no key %d, Router-ID: %pI4", + IF_NAME(oi), __func__, ospfh->u.crypt.key_id, &ospfh->router_id); + return 0; + } + } + /* check crypto seqnum. */ + nbr = ospf_nbr_lookup(oi, iph, ospfh); + + if (nbr && + ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum)) { + flog_warn(EC_OSPF_AUTH, + "interface %s: %s bad sequence %d (expect %d), Router-ID: %pI4", + IF_NAME(oi), __func__, ntohl(ospfh->u.crypt.crypt_seqnum), + ntohl(nbr->crypt_seqnum), &ospfh->router_id); + return 0; + } + + memset(auth_key, 0, OSPF_AUTH_MD5_SIZE + 1); + if (ck == NULL) + strlcpy(auth_key, key->string, OSPF_AUTH_MD5_SIZE + 1); + else + strlcpy(auth_key, (char *)ck->auth_key, OSPF_AUTH_MD5_SIZE + 1); + /* Generate a digest for the ospf packet - their digest + our digest. */ +#ifdef CRYPTO_OPENSSL + uint32_t md5_size = OSPF_AUTH_MD5_SIZE; + + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_md5()); + EVP_DigestUpdate(ctx, ospfh, length); + EVP_DigestUpdate(ctx, auth_key, OSPF_AUTH_MD5_SIZE); + EVP_DigestFinal(ctx, digest, &md5_size); + EVP_MD_CTX_free(ctx); +#elif CRYPTO_INTERNAL + memset(&ctx, 0, sizeof(ctx)); + MD5Init(&ctx); + MD5Update(&ctx, ospfh, length); + MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE); + MD5Final(digest, &ctx); +#endif + + /* compare the two */ + if (memcmp((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE)) { + flog_warn(EC_OSPF_AUTH, + "interface %s: ospf_check_md5 checksum mismatch, Router-ID: %pI4", + IF_NAME(oi), &ospfh->router_id); + return 0; + } + + /* save neighbor's crypt_seqnum */ + if (nbr) + nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; + return 1; +} + +static int ospf_auth_make_md5_digest(struct ospf_interface *oi, + struct ospf_packet *op, struct key *key) +{ + void *ibuf = STREAM_DATA(op->s); + struct ospf_header *ospfh = (struct ospf_header *)ibuf; + unsigned char digest[OSPF_AUTH_MD5_SIZE]; + uint16_t length = ntohs(ospfh->length); +#ifdef CRYPTO_OPENSSL + EVP_MD_CTX *ctx; +#elif CRYPTO_INTERNAL + MD5_CTX ctx; +#endif + char auth_key[OSPF_AUTH_MD5_SIZE + 1]; + + if ((length < (sizeof(struct ospf_header))) || (length > op->length)) { /* for coverity's sake */ + flog_warn(EC_OSPF_AUTH, + "%s: Invalid packet length of %u received on interface %s, Router-ID: %pI4", + __func__, length, IF_NAME(oi), &ospfh->router_id); + return 0; + } + + memset(auth_key, 0, OSPF_AUTH_MD5_SIZE + 1); + strlcpy(auth_key, key->string, OSPF_AUTH_MD5_SIZE + 1); + /* Generate a digest for the ospf packet - their digest + our digest. */ +#ifdef CRYPTO_OPENSSL + uint32_t md5_size = OSPF_AUTH_MD5_SIZE; + + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_md5()); + EVP_DigestUpdate(ctx, ospfh, length); + EVP_DigestUpdate(ctx, auth_key, OSPF_AUTH_MD5_SIZE); + EVP_DigestFinal(ctx, digest, &md5_size); + EVP_MD_CTX_free(ctx); +#elif CRYPTO_INTERNAL + memset(&ctx, 0, sizeof(ctx)); + MD5Init(&ctx); + MD5Update(&ctx, ospfh, length); + MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE); + MD5Final(digest, &ctx); +#endif + + stream_put(op->s, digest, OSPF_AUTH_MD5_SIZE); + + op->length = ntohs(ospfh->length) + OSPF_AUTH_MD5_SIZE; + + if (stream_get_endp(op->s) != op->length) + /* XXX size_t */ + flog_warn(EC_OSPF_AUTH, + "%s: length mismatch stream %lu ospf_packet %u, Router-ID %pI4", + __func__, (unsigned long)stream_get_endp(op->s), + op->length, &ospfh->router_id); + + return OSPF_AUTH_MD5_SIZE; +} + +static int ospf_auth_make_hmac_sha_digest(struct ospf_interface *oi, + struct ospf_packet *op, + struct key *key) +{ + void *ibuf; + struct ospf_header *ospfh; + unsigned char digest[KEYCHAIN_MAX_HASH_SIZE] = { 0 }; + uint16_t hash_length = keychain_get_hash_len(key->hash_algo); + + ibuf = STREAM_DATA(op->s); + ospfh = (struct ospf_header *)ibuf; +#ifdef CRYPTO_OPENSSL + uint32_t openssl_hash_length = hash_length; + HMAC_CTX *ctx; + const EVP_MD *md_alg = ospf_auth_get_openssl_evp_md_from_key(key); + + if (!md_alg) { + flog_warn(EC_OSPF_AUTH, + "interface %s: invalid HMAC algorithm, Router-ID: %pI4", + IF_NAME(oi), &ospfh->router_id); + return 0; + } +#elif CRYPTO_INTERNAL + HMAC_SHA256_CTX ctx; + + if (key->hash_algo != KEYCHAIN_ALGO_HMAC_SHA256) { + flog_warn(EC_OSPF_AUTH, + "interface %s: HMAC algorithm not supported, Router-ID: %pI4", + IF_NAME(oi), &ospfh->router_id); + return 0; + } +#endif +#ifdef CRYPTO_OPENSSL + ctx = HMAC_CTX_new(); + HMAC_Init_ex(ctx, key->string, strlen(key->string), md_alg, NULL); + HMAC_Update(ctx, (const unsigned char *)ospfh, ntohs(ospfh->length)); + HMAC_Update(ctx, (const unsigned char *)ospf_auth_apad, hash_length); + HMAC_Final(ctx, digest, &openssl_hash_length); + HMAC_CTX_free(ctx); +#elif CRYPTO_INTERNAL + memset(&ctx, 0, sizeof(ctx)); + HMAC__SHA256_Init(&ctx, key->string, strlen(key->string)); + HMAC__SHA256_Update(&ctx, ospfh, ntohs(ospfh->length)); + HMAC__SHA256_Update(&ctx, ospf_auth_apad, hash_length); + HMAC__SHA256_Final(digest, &ctx); +#endif + stream_put(op->s, digest, hash_length); + + op->length = ntohs(ospfh->length) + hash_length; + + if (stream_get_endp(op->s) != op->length) + /* XXX size_t */ + flog_warn(EC_OSPF_AUTH, + "%s: length mismatch stream %lu ospf_packet %u, Router-ID %pI4", + __func__, (unsigned long)stream_get_endp(op->s), + op->length, &ospfh->router_id); + + return hash_length; +} + +int ospf_auth_check_digest(struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh) +{ + struct keychain *keychain = NULL; + struct key *key = NULL; + int key_id = ospfh->u.crypt.key_id; + uint8_t auth_data_len = ospfh->u.crypt.auth_data_len; + + if (!OSPF_IF_PARAM(oi, keychain_name)) + return ospf_auth_check_md5_digest(oi, ospfh, iph, NULL); + + keychain = keychain_lookup(OSPF_IF_PARAM(oi, keychain_name)); + if (!keychain) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn(EC_OSPF_AUTH, + "interface %s: Keychain %s is not available, Router-ID %pI4", + IF_NAME(oi), OSPF_IF_PARAM(oi, keychain_name), + &ospfh->router_id); + return 0; + } + + key = key_lookup_for_accept(keychain, key_id); + if (!key) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn(EC_OSPF_AUTH, + "interface %s: Key ID %d not found in keychain %s, Router-ID %pI4", + IF_NAME(oi), key_id, keychain->name, + &ospfh->router_id); + return 0; + } + + if (key->string == NULL || key->hash_algo == KEYCHAIN_ALGO_NULL) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn(EC_OSPF_AUTH, + "interface %s: Key ID %d in keychain %s is incomplete, Router-ID %pI4", + IF_NAME(oi), key_id, keychain->name, + &ospfh->router_id); + return 0; + } + + if (keychain_get_hash_len(key->hash_algo) != auth_data_len) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn(EC_OSPF_AUTH, + "interface %s: Key ID %d in keychain %s hash length mismatch, Router-ID %pI4", + IF_NAME(oi), key_id, keychain->name, + &ospfh->router_id); + return 0; + } + + /* Backward compatibility with RFC 2328 keyed-MD5 authentication */ + if (key->hash_algo == KEYCHAIN_ALGO_MD5) + return ospf_auth_check_md5_digest(oi, ospfh, iph, key); + + return ospf_auth_check_hmac_sha_digest(oi, ospfh, iph, key); +} + +int ospf_auth_make_digest(struct ospf_interface *oi, struct ospf_packet *op) +{ + struct ospf_header *ospfh; + void *ibuf; + struct keychain *keychain = NULL; + struct key *key = NULL; + int key_id; + + ibuf = STREAM_DATA(op->s); + ospfh = (struct ospf_header *)ibuf; + + key_id = ospfh->u.crypt.key_id; + + if (!OSPF_IF_PARAM(oi, keychain_name)) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn(EC_OSPF_AUTH, + "interface %s: Keychain is not set, Router-ID %pI4", + IF_NAME(oi), &ospfh->router_id); + return 0; + } + + keychain = oi->keychain; + if (!keychain) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, SEND)) + flog_warn(EC_OSPF_AUTH, + "interface %s: Keychain %s is not available to send, Router-ID %pI4", + IF_NAME(oi), OSPF_IF_PARAM(oi, keychain_name), + &ospfh->router_id); + return 0; + } + + key = oi->key; + if (!key) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, SEND)) + flog_warn(EC_OSPF_AUTH, + "interface %s: Key ID %d not found in keychain %s, Router-ID %pI4", + IF_NAME(oi), key_id, keychain->name, + &ospfh->router_id); + return 0; + } + + if (key->string == NULL || key->hash_algo == KEYCHAIN_ALGO_NULL) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, SEND)) + flog_warn(EC_OSPF_AUTH, + "interface %s: Key ID %d in keychain %s is incomplete, Router-ID %pI4", + IF_NAME(oi), key_id, keychain->name, + &ospfh->router_id); + return 0; + } + + /* Backward compatibility with RFC 2328 keyed-MD5 authentication */ + if (key->hash_algo == KEYCHAIN_ALGO_MD5) + return ospf_auth_make_md5_digest(oi, op, key); + else + return ospf_auth_make_hmac_sha_digest(oi, op, key); +} + +/* This function is called from ospf_write(), it will detect the + * authentication scheme and if it is MD5, it will change the sequence + * and update the MD5 digest. + */ + +int ospf_auth_make(struct ospf_interface *oi, struct ospf_packet *op) +{ + struct ospf_header *ospfh; + unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0}; +#ifdef CRYPTO_OPENSSL + EVP_MD_CTX *ctx; +#elif CRYPTO_INTERNAL + MD5_CTX ctx; +#endif + void *ibuf; + uint32_t t; + struct crypt_key *ck; + const uint8_t *auth_key = NULL; + + ibuf = STREAM_DATA(op->s); + ospfh = (struct ospf_header *)ibuf; + + if (ntohs(ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) + return 0; + + /* We do this here so when we dup a packet, we don't have to + * waste CPU rewriting other headers. + + Note that frr_time /deliberately/ is not used here. + */ + t = (time(NULL) & 0xFFFFFFFF); + if (t > oi->crypt_seqnum) + oi->crypt_seqnum = t; + else + oi->crypt_seqnum++; + + ospfh->u.crypt.crypt_seqnum = htonl(oi->crypt_seqnum); + + /* Get MD5 Authentication key from auth_key list. */ + if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt)) && OSPF_IF_PARAM(oi, keychain_name) == NULL) + auth_key = (const uint8_t *)digest; + else if (!list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) { + ck = listgetdata(listtail(OSPF_IF_PARAM(oi, auth_crypt))); + auth_key = ck->auth_key; + } + + if (auth_key) { + /* Generate a digest for the entire packet + our secret key. */ +#ifdef CRYPTO_OPENSSL + uint32_t md5_size = OSPF_AUTH_MD5_SIZE; + + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_md5()); + EVP_DigestUpdate(ctx, ibuf, ntohs(ospfh->length)); + EVP_DigestUpdate(ctx, auth_key, OSPF_AUTH_MD5_SIZE); + EVP_DigestFinal(ctx, digest, &md5_size); + EVP_MD_CTX_free(ctx); +#elif CRYPTO_INTERNAL + memset(&ctx, 0, sizeof(ctx)); + MD5Init(&ctx); + MD5Update(&ctx, ibuf, ntohs(ospfh->length)); + MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE); + MD5Final(digest, &ctx); +#endif + + /* Append md5 digest to the end of the stream. */ + stream_put(op->s, digest, OSPF_AUTH_MD5_SIZE); + + /* We do *NOT* increment the OSPF header length. */ + op->length = ntohs(ospfh->length) + OSPF_AUTH_MD5_SIZE; + + if (stream_get_endp(op->s) != op->length) + /* XXX size_t */ + flog_warn( + EC_OSPF_AUTH, + "%s: length mismatch stream %lu ospf_packet %u, Router-ID %pI4", + __func__, (unsigned long)stream_get_endp(op->s), + op->length, &ospfh->router_id); + + return OSPF_AUTH_MD5_SIZE; + } else + return ospf_auth_make_digest(oi, op); +} + +/* Return 1, if the packet is properly authenticated and checksummed, + * 0 otherwise. In particular, check that AuType header field is valid and + * matches the locally configured AuType, and that D.5 requirements are met. + */ +int ospf_auth_check(struct ospf_interface *oi, struct ip *iph, + struct ospf_header *ospfh) +{ + uint16_t iface_auth_type; + uint16_t pkt_auth_type = ntohs(ospfh->auth_type); + + iface_auth_type = ospf_auth_type(oi); + + switch (pkt_auth_type) { + case OSPF_AUTH_NULL: /* RFC2328 D.5.1 */ + if (iface_auth_type != OSPF_AUTH_NULL) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn( + EC_OSPF_PACKET, + "interface %s: auth-type mismatch, local %s, rcvd Null, Router-ID %pI4", + IF_NAME(oi), + lookup_msg(ospf_auth_type_str, + iface_auth_type, NULL), + &ospfh->router_id); + return 0; + } + if (!ospf_check_sum(ospfh)) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn( + EC_OSPF_PACKET, + "interface %s: Null auth OK, but checksum error, Router-ID %pI4", + IF_NAME(oi), + &ospfh->router_id); + return 0; + } + return 1; + case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */ + if (iface_auth_type != OSPF_AUTH_SIMPLE) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn( + EC_OSPF_PACKET, + "interface %s: auth-type mismatch, local %s, rcvd Simple, Router-ID %pI4", + IF_NAME(oi), + lookup_msg(ospf_auth_type_str, + iface_auth_type, NULL), + &ospfh->router_id); + return 0; + } + if (memcmp(OSPF_IF_PARAM(oi, auth_simple), ospfh->u.auth_data, + OSPF_AUTH_SIMPLE_SIZE)) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn( + EC_OSPF_PACKET, + "interface %s: Simple auth failed, Router-ID %pI4", + IF_NAME(oi), &ospfh->router_id); + return 0; + } + if (!ospf_check_sum(ospfh)) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn( + EC_OSPF_PACKET, + "interface %s: Simple auth OK, checksum error, Router-ID %pI4", + IF_NAME(oi), + &ospfh->router_id); + return 0; + } + return 1; + case OSPF_AUTH_CRYPTOGRAPHIC: /* RFC2328 D.5.3 */ + if (iface_auth_type != OSPF_AUTH_CRYPTOGRAPHIC) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn( + EC_OSPF_PACKET, + "interface %s: auth-type mismatch, local %s, rcvd Cryptographic, Router-ID %pI4", + IF_NAME(oi), + lookup_msg(ospf_auth_type_str, + iface_auth_type, NULL), + &ospfh->router_id); + return 0; + } + if (ospfh->checksum) { + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn( + EC_OSPF_PACKET, + "interface %s: OSPF header checksum is not 0, Router-ID %pI4", + IF_NAME(oi), &ospfh->router_id); + return 0; + } + /* If `authentication message-digest` key is not set, we try keychain crypto */ + if (OSPF_IF_PARAM(oi, keychain_name) || !list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) + return ospf_auth_check_digest(oi, iph, ospfh); + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn( + EC_OSPF_AUTH, + "interface %s: MD5 auth failed, Router-ID %pI4", + IF_NAME(oi), &ospfh->router_id); + return 0; + default: + if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) + flog_warn( + EC_OSPF_PACKET, + "interface %s: invalid packet auth-type (%02x), Router-ID %pI4", + IF_NAME(oi), pkt_auth_type, &ospfh->router_id); + return 0; + } +} + +/* OSPF authentication checking function */ +int ospf_auth_type(struct ospf_interface *oi) +{ + int auth_type; + + if (OSPF_IF_PARAM(oi, auth_type) == OSPF_AUTH_NOTSET) + auth_type = oi->area->auth_type; + else + auth_type = OSPF_IF_PARAM(oi, auth_type); + + /* Handle case where MD5 key list, or a key-chain, is not configured aka Cisco */ + if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC + && (list_isempty(OSPF_IF_PARAM(oi, auth_crypt)) + && OSPF_IF_PARAM(oi, keychain_name) == NULL)) + return OSPF_AUTH_NULL; + + return auth_type; +} + +/* Make Authentication Data. */ +int ospf_auth_make_data(struct ospf_interface *oi, struct ospf_header *ospfh) +{ + struct crypt_key *ck; + + switch (ospf_auth_type(oi)) { + case OSPF_AUTH_NULL: + /* memset (ospfh->u.auth_data, 0, sizeof(ospfh->u.auth_data)); + */ + break; + case OSPF_AUTH_SIMPLE: + memcpy(ospfh->u.auth_data, OSPF_IF_PARAM(oi, auth_simple), + OSPF_AUTH_SIMPLE_SIZE); + break; + case OSPF_AUTH_CRYPTOGRAPHIC: + if (OSPF_IF_PARAM(oi, keychain_name)) { + oi->keychain = keychain_lookup(OSPF_IF_PARAM(oi, keychain_name)); + if (oi->keychain) + oi->key = key_lookup_for_send(oi->keychain); + if (oi->key) { + ospfh->u.crypt.zero = 0; + ospfh->u.crypt.key_id = oi->key->index; + ospfh->u.crypt.auth_data_len = keychain_get_hash_len(oi->key->hash_algo); + } else { + /* If key is not set, then set 0. */ + ospfh->u.crypt.zero = 0; + ospfh->u.crypt.key_id = 0; + ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE; + } + } else { + /* If key is not set, then set 0. */ + if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) { + ospfh->u.crypt.zero = 0; + ospfh->u.crypt.key_id = 0; + ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE; + } else { + ck = listgetdata( + listtail(OSPF_IF_PARAM(oi, auth_crypt))); + ospfh->u.crypt.zero = 0; + ospfh->u.crypt.key_id = ck->key_id; + ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE; + } + } + /* note: the seq is done in ospf_auth_make() */ + break; + default: + /* memset (ospfh->u.auth_data, 0, sizeof(ospfh->u.auth_data)); + */ + break; + } + + return 0; +} diff --git a/ospfd/ospf_auth.h b/ospfd/ospf_auth.h new file mode 100644 index 000000000000..6f6d3db588fd --- /dev/null +++ b/ospfd/ospf_auth.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 Amnesh Inc. + * Mahdi Varasteh + */ + +#ifndef _ZEBRA_OSPF_AUTH_H +#define _ZEBRA_OSPF_AUTH_H + +#include +#include + +int ospf_auth_check(struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh); +int ospf_auth_check_digest(struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh); +int ospf_auth_make(struct ospf_interface *oi, struct ospf_packet *op); +int ospf_auth_make_digest(struct ospf_interface *oi, struct ospf_packet *op); +int ospf_auth_type(struct ospf_interface *oi); +int ospf_auth_make_data(struct ospf_interface *oi, struct ospf_header *ospfh); + +#endif /* _ZEBRA_OSPF_AUTH_H */ diff --git a/ospfd/ospf_errors.c b/ospfd/ospf_errors.c index 16aa3ab5267f..cf58c6ad8b8d 100644 --- a/ospfd/ospf_errors.c +++ b/ospfd/ospf_errors.c @@ -19,9 +19,9 @@ static struct log_ref ferr_ospf_warn[] = { .suggestion = "Do not use this particular set command for an ospf route-map", }, { - .code = EC_OSPF_MD5, - .title = "OSPF has noticed a MD5 issue", - .description = "Something has gone wrong with the calculation of the MD5 data", + .code = EC_OSPF_AUTH, + .title = "OSPF has noticed an authentication issue", + .description = "Something has gone wrong with the calculation of the authentication data", .suggestion = "Ensure your key is correct, gather log data from this side as well as peer and open an Issue", }, { diff --git a/ospfd/ospf_errors.h b/ospfd/ospf_errors.h index dcf9a65ce939..e63cb7409cb5 100644 --- a/ospfd/ospf_errors.h +++ b/ospfd/ospf_errors.h @@ -22,7 +22,7 @@ enum ospf_log_refs { EC_OSPF_INVALID_ALGORITHM, EC_OSPF_FSM_INVALID_STATE, EC_OSPF_SET_METRIC_PLUS, - EC_OSPF_MD5, + EC_OSPF_AUTH, EC_OSPF_PACKET, EC_OSPF_LARGE_LSA, EC_OSPF_LSA_UNEXPECTED, diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index bdab672b475f..7601419325d5 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -549,6 +549,7 @@ static struct ospf_if_params *ospf_new_if_params(void) UNSET_IF_PARAM(oip, auth_type); UNSET_IF_PARAM(oip, if_area); UNSET_IF_PARAM(oip, opaque_capable); + UNSET_IF_PARAM(oip, keychain_name); oip->auth_crypt = list_new(); @@ -566,6 +567,7 @@ static void ospf_del_if_params(struct interface *ifp, struct ospf_if_params *oip) { list_delete(&oip->auth_crypt); + XFREE(MTYPE_OSPF_IF_PARAMS, oip->keychain_name); ospf_interface_disable_bfd(ifp, oip); ldp_sync_info_free(&(oip->ldp_sync_info)); XFREE(MTYPE_OSPF_IF_PARAMS, oip); @@ -601,6 +603,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr) !OSPF_IF_PARAM_CONFIGURED(oip, if_area) && !OSPF_IF_PARAM_CONFIGURED(oip, opaque_capable) && !OSPF_IF_PARAM_CONFIGURED(oip, prefix_suppression) && + !OSPF_IF_PARAM_CONFIGURED(oip, keychain_name) && listcount(oip->auth_crypt) == 0) { ospf_del_if_params(ifp, oip); rn->info = NULL; diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 47b70f803940..e2290a881cc4 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -10,6 +10,7 @@ #include "lib/bfd.h" #include "qobj.h" #include "hook.h" +#include "keychain.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" @@ -92,6 +93,8 @@ struct ospf_if_params { auth_crypt); /* List of Auth cryptographic data. */ DECLARE_IF_PARAM(int, auth_type); /* OSPF authentication type */ + DECLARE_IF_PARAM(char*, keychain_name); /* OSPF HMAC Cryptographic Authentication*/ + /* Other, non-configuration state */ uint32_t network_lsa_seqnum; /* Network LSA seqnum */ @@ -279,6 +282,10 @@ struct ospf_interface { uint32_t full_nbrs; + /* Buffered values for keychain and key */ + struct keychain *keychain; + struct key *key; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(ospf_interface); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 536bd592d238..dd000241f403 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -27,6 +27,7 @@ #include "vrf.h" #include "libfrr.h" #include "routemap.h" +#include "keychain.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -218,6 +219,7 @@ int main(int argc, char **argv) access_list_init(); prefix_list_init(); + keychain_init(); /* Configuration processing callback initialization. */ cmd_init_config_callbacks(ospf_config_start, ospf_config_end); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index cfa0d5d57444..b37efa3efa21 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -41,6 +41,7 @@ #include "ospfd/ospf_errors.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_gr.h" +#include "ospfd/ospf_auth.h" /* * OSPF Fragmentation / fragmented writes @@ -99,27 +100,6 @@ static const uint16_t ospf_lsa_minlen[] = { OSPF_OPAQUE_LSA_MIN_SIZE, /* OSPF_OPAQUE_AS_LSA */ }; -/* for ospf_check_auth() */ -static int ospf_check_sum(struct ospf_header *); - -/* OSPF authentication checking function */ -static int ospf_auth_type(struct ospf_interface *oi) -{ - int auth_type; - - if (OSPF_IF_PARAM(oi, auth_type) == OSPF_AUTH_NOTSET) - auth_type = oi->area->auth_type; - else - auth_type = OSPF_IF_PARAM(oi, auth_type); - - /* Handle case where MD5 key list is not configured aka Cisco */ - if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC - && list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) - return OSPF_AUTH_NULL; - - return auth_type; -} - static struct ospf_packet *ospf_packet_new(size_t size) { struct ospf_packet *new; @@ -258,8 +238,8 @@ static struct ospf_packet *ospf_packet_dup(struct ospf_packet *op) "ospf_packet_dup stream %lu ospf_packet %u size mismatch", (unsigned long)STREAM_SIZE(op->s), op->length); - /* Reserve space for MD5 authentication that may be added later. */ - new = ospf_packet_new(stream_get_endp(op->s) + OSPF_AUTH_MD5_SIZE); + /* Reserve space for MD5/HMAC SHA authentication that may be added later. */ + new = ospf_packet_new(stream_get_endp(op->s) + KEYCHAIN_MAX_HASH_SIZE); stream_copy(new->s, op->s); new->dst = op->dst; @@ -274,7 +254,7 @@ static unsigned int ospf_packet_authspace(struct ospf_interface *oi) int auth = 0; if (ospf_auth_type(oi) == OSPF_AUTH_CRYPTOGRAPHIC) - auth = OSPF_AUTH_MD5_SIZE; + auth = KEYCHAIN_MAX_HASH_SIZE; return auth; } @@ -290,155 +270,6 @@ static unsigned int ospf_packet_max(struct ospf_interface *oi) return max; } - -static int ospf_check_md5_digest(struct ospf_interface *oi, - struct ospf_header *ospfh) -{ -#ifdef CRYPTO_OPENSSL - EVP_MD_CTX *ctx; -#elif CRYPTO_INTERNAL - MD5_CTX ctx; -#endif - unsigned char digest[OSPF_AUTH_MD5_SIZE]; - struct crypt_key *ck; - struct ospf_neighbor *nbr; - uint16_t length = ntohs(ospfh->length); - - /* Get secret key. */ - ck = ospf_crypt_key_lookup(OSPF_IF_PARAM(oi, auth_crypt), - ospfh->u.crypt.key_id); - if (ck == NULL) { - flog_warn( - EC_OSPF_MD5, - "interface %s: ospf_check_md5 no key %d, Router-ID: %pI4", - IF_NAME(oi), ospfh->u.crypt.key_id, &ospfh->router_id); - return 0; - } - - /* check crypto seqnum. */ - nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, &ospfh->router_id); - - if (nbr - && ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum)) { - flog_warn( - EC_OSPF_MD5, - "interface %s: ospf_check_md5 bad sequence %d (expect %d), Router-ID: %pI4", - IF_NAME(oi), ntohl(ospfh->u.crypt.crypt_seqnum), - ntohl(nbr->crypt_seqnum), &ospfh->router_id); - return 0; - } - - /* Generate a digest for the ospf packet - their digest + our digest. */ -#ifdef CRYPTO_OPENSSL - unsigned int md5_size = OSPF_AUTH_MD5_SIZE; - ctx = EVP_MD_CTX_new(); - EVP_DigestInit(ctx, EVP_md5()); - EVP_DigestUpdate(ctx, ospfh, length); - EVP_DigestUpdate(ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE); - EVP_DigestFinal(ctx, digest, &md5_size); - EVP_MD_CTX_free(ctx); -#elif CRYPTO_INTERNAL - memset(&ctx, 0, sizeof(ctx)); - MD5Init(&ctx); - MD5Update(&ctx, ospfh, length); - MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE); - MD5Final(digest, &ctx); -#endif - - /* compare the two */ - if (memcmp((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE)) { - flog_warn( - EC_OSPF_MD5, - "interface %s: ospf_check_md5 checksum mismatch, Router-ID: %pI4", - IF_NAME(oi), &ospfh->router_id); - return 0; - } - - /* save neighbor's crypt_seqnum */ - if (nbr) - nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; - return 1; -} - -/* This function is called from ospf_write(), it will detect the - authentication scheme and if it is MD5, it will change the sequence - and update the MD5 digest. */ -static int ospf_make_md5_digest(struct ospf_interface *oi, - struct ospf_packet *op) -{ - struct ospf_header *ospfh; - unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0}; -#ifdef CRYPTO_OPENSSL - EVP_MD_CTX *ctx; -#elif CRYPTO_INTERNAL - MD5_CTX ctx; -#endif - void *ibuf; - uint32_t t; - struct crypt_key *ck; - const uint8_t *auth_key; - - ibuf = STREAM_DATA(op->s); - ospfh = (struct ospf_header *)ibuf; - - if (ntohs(ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) - return 0; - - /* We do this here so when we dup a packet, we don't have to - waste CPU rewriting other headers. - - Note that frr_time /deliberately/ is not used here */ - t = (time(NULL) & 0xFFFFFFFF); - if (t > oi->crypt_seqnum) - oi->crypt_seqnum = t; - else - oi->crypt_seqnum++; - - ospfh->u.crypt.crypt_seqnum = htonl(oi->crypt_seqnum); - - /* Get MD5 Authentication key from auth_key list. */ - if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) - auth_key = (const uint8_t *)digest; - else { - ck = listgetdata(listtail(OSPF_IF_PARAM(oi, auth_crypt))); - auth_key = ck->auth_key; - } - - /* Generate a digest for the entire packet + our secret key. */ -#ifdef CRYPTO_OPENSSL - unsigned int md5_size = OSPF_AUTH_MD5_SIZE; - ctx = EVP_MD_CTX_new(); - EVP_DigestInit(ctx, EVP_md5()); - EVP_DigestUpdate(ctx, ibuf, ntohs(ospfh->length)); - EVP_DigestUpdate(ctx, auth_key, OSPF_AUTH_MD5_SIZE); - EVP_DigestFinal(ctx, digest, &md5_size); - EVP_MD_CTX_free(ctx); -#elif CRYPTO_INTERNAL - memset(&ctx, 0, sizeof(ctx)); - MD5Init(&ctx); - MD5Update(&ctx, ibuf, ntohs(ospfh->length)); - MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE); - MD5Final(digest, &ctx); -#endif - - /* Append md5 digest to the end of the stream. */ - stream_put(op->s, digest, OSPF_AUTH_MD5_SIZE); - - /* We do *NOT* increment the OSPF header length. */ - op->length = ntohs(ospfh->length) + OSPF_AUTH_MD5_SIZE; - - if (stream_get_endp(op->s) != op->length) - /* XXX size_t */ - flog_warn( - EC_OSPF_MD5, - "%s: length mismatch stream %lu ospf_packet %u, Router-ID %pI4", - __func__, (unsigned long)stream_get_endp(op->s), - op->length, &ospfh->router_id); - - return OSPF_AUTH_MD5_SIZE; -} - - static void ospf_ls_req_timer(struct event *thread) { struct ospf_neighbor *nbr; @@ -677,7 +508,7 @@ static void ospf_write(struct event *thread) ospf_if_ipmulticast(fd, oi->address, oi->ifp->ifindex); /* Rewrite the md5 signature & update the seq */ - ospf_make_md5_digest(oi, op); + ospf_auth_make(oi, op); /* Retrieve OSPF packet type. */ stream_set_getp(op->s, 1); @@ -2476,142 +2307,6 @@ static int ospf_check_network_mask(struct ospf_interface *oi, return 0; } -/* Return 1, if the packet is properly authenticated and checksummed, - 0 otherwise. In particular, check that AuType header field is valid and - matches the locally configured AuType, and that D.5 requirements are met. */ -static int ospf_check_auth(struct ospf_interface *oi, struct ospf_header *ospfh) -{ - struct crypt_key *ck; - uint16_t iface_auth_type; - uint16_t pkt_auth_type = ntohs(ospfh->auth_type); - - switch (pkt_auth_type) { - case OSPF_AUTH_NULL: /* RFC2328 D.5.1 */ - if (OSPF_AUTH_NULL != (iface_auth_type = ospf_auth_type(oi))) { - if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) - flog_warn( - EC_OSPF_PACKET, - "interface %s: auth-type mismatch, local %s, rcvd Null, Router-ID %pI4", - IF_NAME(oi), - lookup_msg(ospf_auth_type_str, - iface_auth_type, NULL), - &ospfh->router_id); - return 0; - } - if (!ospf_check_sum(ospfh)) { - if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) - flog_warn( - EC_OSPF_PACKET, - "interface %s: Null auth OK, but checksum error, Router-ID %pI4", - IF_NAME(oi), - &ospfh->router_id); - return 0; - } - return 1; - case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */ - if (OSPF_AUTH_SIMPLE - != (iface_auth_type = ospf_auth_type(oi))) { - if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) - flog_warn( - EC_OSPF_PACKET, - "interface %s: auth-type mismatch, local %s, rcvd Simple, Router-ID %pI4", - IF_NAME(oi), - lookup_msg(ospf_auth_type_str, - iface_auth_type, NULL), - &ospfh->router_id); - return 0; - } - if (memcmp(OSPF_IF_PARAM(oi, auth_simple), ospfh->u.auth_data, - OSPF_AUTH_SIMPLE_SIZE)) { - if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) - flog_warn( - EC_OSPF_PACKET, - "interface %s: Simple auth failed, Router-ID %pI4", - IF_NAME(oi), &ospfh->router_id); - return 0; - } - if (!ospf_check_sum(ospfh)) { - if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) - flog_warn( - EC_OSPF_PACKET, - "interface %s: Simple auth OK, checksum error, Router-ID %pI4", - IF_NAME(oi), - &ospfh->router_id); - return 0; - } - return 1; - case OSPF_AUTH_CRYPTOGRAPHIC: /* RFC2328 D.5.3 */ - if (OSPF_AUTH_CRYPTOGRAPHIC - != (iface_auth_type = ospf_auth_type(oi))) { - if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) - flog_warn( - EC_OSPF_PACKET, - "interface %s: auth-type mismatch, local %s, rcvd Cryptographic, Router-ID %pI4", - IF_NAME(oi), - lookup_msg(ospf_auth_type_str, - iface_auth_type, NULL), - &ospfh->router_id); - return 0; - } - if (ospfh->checksum) { - if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) - flog_warn( - EC_OSPF_PACKET, - "interface %s: OSPF header checksum is not 0, Router-ID %pI4", - IF_NAME(oi), &ospfh->router_id); - return 0; - } - /* only MD5 crypto method can pass ospf_packet_examin() */ - if (NULL == (ck = listgetdata( - listtail(OSPF_IF_PARAM(oi, auth_crypt)))) - || ospfh->u.crypt.key_id != ck->key_id || - /* Condition above uses the last key ID on the list, - which is - different from what ospf_crypt_key_lookup() does. A - bug? */ - !ospf_check_md5_digest(oi, ospfh)) { - if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) - flog_warn( - EC_OSPF_MD5, - "interface %s: MD5 auth failed, Router-ID %pI4", - IF_NAME(oi), &ospfh->router_id); - return 0; - } - return 1; - default: - if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) - flog_warn( - EC_OSPF_PACKET, - "interface %s: invalid packet auth-type (%02x), Router-ID %pI4", - IF_NAME(oi), pkt_auth_type, &ospfh->router_id); - return 0; - } -} - -static int ospf_check_sum(struct ospf_header *ospfh) -{ - uint32_t ret; - uint16_t sum; - - /* clear auth_data for checksum. */ - memset(ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE); - - /* keep checksum and clear. */ - sum = ospfh->checksum; - memset(&ospfh->checksum, 0, sizeof(uint16_t)); - - /* calculate checksum. */ - ret = in_cksum(ospfh, ntohs(ospfh->length)); - - if (ret != sum) { - zlog_info("%s: checksum mismatch, my %X, his %X", __func__, ret, - sum); - return 0; - } - - return 1; -} - /* Verify, that given link/TOS records are properly sized/aligned and match Router-LSA "# links" and "# TOS" fields as specified in RFC2328 A.4.2. */ static unsigned ospf_router_lsa_links_examin(struct router_lsa_link *link, @@ -2835,14 +2530,14 @@ static unsigned ospf_packet_examin(struct ospf_header *oh, if (ntohs(oh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) bytesauth = 0; else { - if (oh->u.crypt.auth_data_len != OSPF_AUTH_MD5_SIZE) { + if (oh->u.crypt.auth_data_len > KEYCHAIN_MAX_HASH_SIZE) { if (IS_DEBUG_OSPF_PACKET(0, RECV)) zlog_debug( "%s: unsupported crypto auth length (%u B)", __func__, oh->u.crypt.auth_data_len); return MSG_NG; } - bytesauth = OSPF_AUTH_MD5_SIZE; + bytesauth = oh->u.crypt.auth_data_len; } if (bytesdeclared + bytesauth > bytesonwire) { if (IS_DEBUG_OSPF_PACKET(0, RECV)) @@ -2953,7 +2648,7 @@ static int ospf_verify_header(struct stream *ibuf, struct ospf_interface *oi, /* Check authentication. The function handles logging actions, where * required. */ - if (!ospf_check_auth(oi, ospfh)) + if (!ospf_auth_check(oi, iph, ospfh)) return -1; return 0; @@ -3261,44 +2956,6 @@ static void ospf_make_header(int type, struct ospf_interface *oi, stream_forward_endp(s, OSPF_HEADER_SIZE); } -/* Make Authentication Data. */ -static int ospf_make_auth(struct ospf_interface *oi, struct ospf_header *ospfh) -{ - struct crypt_key *ck; - - switch (ospf_auth_type(oi)) { - case OSPF_AUTH_NULL: - /* memset (ospfh->u.auth_data, 0, sizeof(ospfh->u.auth_data)); - */ - break; - case OSPF_AUTH_SIMPLE: - memcpy(ospfh->u.auth_data, OSPF_IF_PARAM(oi, auth_simple), - OSPF_AUTH_SIMPLE_SIZE); - break; - case OSPF_AUTH_CRYPTOGRAPHIC: - /* If key is not set, then set 0. */ - if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) { - ospfh->u.crypt.zero = 0; - ospfh->u.crypt.key_id = 0; - ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE; - } else { - ck = listgetdata( - listtail(OSPF_IF_PARAM(oi, auth_crypt))); - ospfh->u.crypt.zero = 0; - ospfh->u.crypt.key_id = ck->key_id; - ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE; - } - /* note: the seq is done in ospf_make_md5_digest() */ - break; - default: - /* memset (ospfh->u.auth_data, 0, sizeof(ospfh->u.auth_data)); - */ - break; - } - - return 0; -} - /* Fill rest of OSPF header. */ static void ospf_fill_header(struct ospf_interface *oi, struct stream *s, uint16_t length) @@ -3317,7 +2974,9 @@ static void ospf_fill_header(struct ospf_interface *oi, struct stream *s, ospfh->checksum = 0; /* Add Authentication Data. */ - ospf_make_auth(oi, ospfh); + oi->keychain = NULL; + oi->key = NULL; + ospf_auth_make_data(oi, ospfh); } static int ospf_make_hello(struct ospf_interface *oi, struct stream *s) diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index fcc43e7311c2..c9aaa9f97891 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -906,7 +906,7 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name, area = ospf_area_lookup_by_area_id(ospf, *area_id); if (!area) return NULL; - offset += IN_ADDR_SIZE; + offset++; /* Type. */ *type = *offset; @@ -914,7 +914,7 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name, /* LS ID. */ oid2in_addr(offset, IN_ADDR_SIZE, ls_id); - offset += IN_ADDR_SIZE; + offset++; /* Router ID. */ oid2in_addr(offset, IN_ADDR_SIZE, router_id); @@ -971,7 +971,7 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name, } /* Router ID. */ - offset += IN_ADDR_SIZE; + offset++; offsetlen -= IN_ADDR_SIZE; len = offsetlen; @@ -996,11 +996,11 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name, /* Fill in value. */ offset = name + v->namelen; oid_copy_in_addr(offset, area_id); - offset += IN_ADDR_SIZE; + offset++; *offset = lsa->data->type; offset++; oid_copy_in_addr(offset, &lsa->data->id); - offset += IN_ADDR_SIZE; + offset++; oid_copy_in_addr(offset, &lsa->data->adv_router); @@ -1106,7 +1106,7 @@ static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v, if (!area) return NULL; - offset += IN_ADDR_SIZE; + offset++; /* Lookup area range. */ oid2in_addr(offset, IN_ADDR_SIZE, range_net); @@ -1135,7 +1135,7 @@ static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v, return NULL; do { - offset += IN_ADDR_SIZE; + offset++; offsetlen -= IN_ADDR_SIZE; len = offsetlen; @@ -1157,7 +1157,7 @@ static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v, /* Fill in value. */ offset = name + v->namelen; oid_copy_in_addr(offset, area_id); - offset += IN_ADDR_SIZE; + offset++; oid_copy_in_addr(offset, range_net); return range; @@ -1560,7 +1560,7 @@ static struct ospf_interface *ospfIfLookup(struct variable *v, oid *name, *length = v->namelen + IN_ADDR_SIZE + 1; offset = name + v->namelen; oid_copy_in_addr(offset, ifaddr); - offset += IN_ADDR_SIZE; + offset++; *offset = *ifindex; return oi; } @@ -1704,7 +1704,7 @@ static struct ospf_interface *ospfIfMetricLookup(struct variable *v, oid *name, *length = v->namelen + IN_ADDR_SIZE + 1 + 1; offset = name + v->namelen; oid_copy_in_addr(offset, ifaddr); - offset += IN_ADDR_SIZE; + offset++; *offset = *ifindex; offset++; *offset = OSPF_SNMP_METRIC_VALUE; @@ -2242,7 +2242,7 @@ static struct ospf_lsa *ospfExtLsdbLookup(struct variable *v, oid *name, /* LS ID. */ oid2in_addr(offset, IN_ADDR_SIZE, ls_id); - offset += IN_ADDR_SIZE; + offset++; /* Router ID. */ oid2in_addr(offset, IN_ADDR_SIZE, router_id); @@ -2270,7 +2270,7 @@ static struct ospf_lsa *ospfExtLsdbLookup(struct variable *v, oid *name, oid2in_addr(offset, len, ls_id); - offset += IN_ADDR_SIZE; + offset++; offsetlen -= IN_ADDR_SIZE; /* Router ID. */ @@ -2293,7 +2293,7 @@ static struct ospf_lsa *ospfExtLsdbLookup(struct variable *v, oid *name, *offset = OSPF_AS_EXTERNAL_LSA; offset++; oid_copy_in_addr(offset, &lsa->data->id); - offset += IN_ADDR_SIZE; + offset++; oid_copy_in_addr(offset, &lsa->data->adv_router); return lsa; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 158e90df59d5..8c3ad7f372d5 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -21,6 +21,7 @@ #include #include "defaults.h" #include "lib/printfrr.h" +#include "keychain.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_asbr.h" @@ -40,6 +41,7 @@ #include "ospfd/ospf_bfd.h" #include "ospfd/ospf_ldp_sync.h" #include "ospfd/ospf_network.h" +#include "ospfd/ospf_memory.h" FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES, { .val_bool = true, .match_profile = "datacenter", }, @@ -808,6 +810,8 @@ struct ospf_vl_config_data { char *auth_key; /* simple password if present */ int crypto_key_id; /* Cryptographic key ID */ char *md5_key; /* MD5 authentication key */ + char *keychain; /* Cryptographic keychain */ + int del_keychain; int hello_interval; /* Obvious what these are... */ int retransmit_interval; int transmit_delay; @@ -890,6 +894,10 @@ static int ospf_vl_set_security(struct ospf_vl_data *vl_data, strlcpy((char *)IF_DEF_PARAMS(ifp)->auth_simple, vl_config->auth_key, sizeof(IF_DEF_PARAMS(ifp)->auth_simple)); + } else if (vl_config->keychain) { + SET_IF_PARAM(IF_DEF_PARAMS(ifp), keychain_name); + XFREE(MTYPE_OSPF_IF_PARAMS, IF_DEF_PARAMS(ifp)->keychain_name); + IF_DEF_PARAMS(ifp)->keychain_name = XSTRDUP(MTYPE_OSPF_IF_PARAMS, vl_config->keychain); } else if (vl_config->md5_key) { if (ospf_crypt_key_lookup(IF_DEF_PARAMS(ifp)->auth_crypt, vl_config->crypto_key_id) @@ -918,6 +926,9 @@ static int ospf_vl_set_security(struct ospf_vl_data *vl_data, ospf_crypt_key_delete(IF_DEF_PARAMS(ifp)->auth_crypt, vl_config->crypto_key_id); + } else if (vl_config->del_keychain) { + UNSET_IF_PARAM(IF_DEF_PARAMS(ifp), keychain_name); + XFREE(MTYPE_OSPF_IF_PARAMS, IF_DEF_PARAMS(ifp)->keychain_name); } return CMD_SUCCESS; @@ -1022,9 +1033,11 @@ static int ospf_vl_set(struct ospf *ospf, struct ospf_vl_config_data *vl_config) DEFUN (ospf_area_vlink, ospf_area_vlink_cmd, - "area virtual-link A.B.C.D [authentication []] []", + "area virtual-link A.B.C.D [authentication []] []", VLINK_HELPSTR_IPADDR "Enable authentication on this virtual link\n" + "Use a key-chain for cryptographic authentication keys\n" + "Key-chain name\n" "Use message-digest authentication\n" "Use null authentication\n" VLINK_HELPSTR_AUTH_MD5 @@ -1067,7 +1080,10 @@ DEFUN (ospf_area_vlink, vl_config.auth_type = OSPF_AUTH_SIMPLE; } - if (argv_find(argv, argc, "message-digest", &idx)) { + if (argv_find(argv, argc, "key-chain", &idx)) { + vl_config.auth_type = OSPF_AUTH_CRYPTOGRAPHIC; + vl_config.keychain = argv[idx+1]->arg; + } else if (argv_find(argv, argc, "message-digest", &idx)) { /* authentication message-digest */ vl_config.auth_type = OSPF_AUTH_CRYPTOGRAPHIC; } else if (argv_find(argv, argc, "null", &idx)) { @@ -1097,10 +1113,12 @@ DEFUN (ospf_area_vlink, DEFUN (no_ospf_area_vlink, no_ospf_area_vlink_cmd, - "no area virtual-link A.B.C.D [authentication []] []", + "no area virtual-link A.B.C.D [authentication []] []", NO_STR VLINK_HELPSTR_IPADDR "Enable authentication on this virtual link\n" + "Use a key-chain for cryptographic authentication keys\n" + "Key-chain name\n" "Use message-digest authentication\n" "Use null authentication\n" VLINK_HELPSTR_AUTH_MD5 @@ -1160,6 +1178,11 @@ DEFUN (no_ospf_area_vlink, vl_config.auth_type = OSPF_AUTH_NOTSET; } + if (argv_find(argv, argc, "key-chain", &idx)) { + vl_config.del_keychain = 1; + vl_config.keychain = NULL; + } + if (argv_find(argv, argc, "message-digest-key", &idx)) { vl_config.md5_key = NULL; vl_config.crypto_key_id = strtol(argv[idx + 1]->arg, NULL, 10); @@ -3597,18 +3620,41 @@ static void ospf_interface_auth_show(struct vty *vty, struct ospf_interface *oi, case OSPF_AUTH_CRYPTOGRAPHIC: { struct crypt_key *ckey; - if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) - return; - - ckey = listgetdata(listtail(OSPF_IF_PARAM(oi, auth_crypt))); - if (ckey) { + if (OSPF_IF_PARAM(oi, keychain_name)) { if (use_json) { json_object_string_add(json, "authentication", - "authenticationMessageDigest"); + "authenticationKeyChain"); + json_object_string_add(json, "keychain", + OSPF_IF_PARAM(oi, keychain_name)); } else { vty_out(vty, " Cryptographic authentication enabled\n"); - vty_out(vty, " Algorithm:MD5\n"); + struct keychain *keychain = keychain_lookup(OSPF_IF_PARAM(oi, keychain_name)); + + if (keychain) { + struct key *key = key_lookup_for_send(keychain); + + if (key) { + vty_out(vty, " Sending SA: Key %u, Algorithm %s - key chain %s\n", + key->index, keychain_get_algo_name_by_id(key->hash_algo), + OSPF_IF_PARAM(oi, keychain_name)); + } + } + } + } else { + if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) + return; + + ckey = listgetdata(listtail(OSPF_IF_PARAM(oi, auth_crypt))); + if (ckey) { + if (use_json) { + json_object_string_add(json, "authentication", + "authenticationMessageDigest"); + } else { + vty_out(vty, + " Cryptographic authentication enabled\n"); + vty_out(vty, " Algorithm:MD5\n"); + } } } break; @@ -7535,24 +7581,26 @@ DEFPY (show_ip_ospf_database, DEFUN (ip_ospf_authentication_args, ip_ospf_authentication_args_addr_cmd, - "ip ospf authentication [A.B.C.D]", + "ip ospf authentication [A.B.C.D]", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Use null authentication\n" "Use message-digest authentication\n" + "Use a key-chain for cryptographic authentication keys\n" + "Key-chain name\n" "Address of interface\n") { VTY_DECLVAR_CONTEXT(interface, ifp); int idx_encryption = 3; - int idx_ipv4 = 4; + int idx_ipv4 = argc-1; struct in_addr addr; int ret; struct ospf_if_params *params; params = IF_DEF_PARAMS(ifp); - if (argc == 5) { + if (argv[idx_ipv4]->type == IPV4_TKN) { ret = inet_aton(argv[idx_ipv4]->arg, &addr); if (!ret) { vty_out(vty, @@ -7575,6 +7623,17 @@ DEFUN (ip_ospf_authentication_args, if (argv[idx_encryption]->arg[0] == 'm') { SET_IF_PARAM(params, auth_type); params->auth_type = OSPF_AUTH_CRYPTOGRAPHIC; + UNSET_IF_PARAM(params, keychain_name); + XFREE(MTYPE_OSPF_IF_PARAMS, params->keychain_name); + return CMD_SUCCESS; + } + + if (argv[idx_encryption]->arg[0] == 'k') { + SET_IF_PARAM(params, auth_type); + params->auth_type = OSPF_AUTH_CRYPTOGRAPHIC; + SET_IF_PARAM(params, keychain_name); + params->keychain_name = XSTRDUP(MTYPE_OSPF_IF_PARAMS, argv[idx_encryption+1]->arg); + UNSET_IF_PARAM(params, auth_crypt); return CMD_SUCCESS; } @@ -7618,18 +7677,20 @@ DEFUN (ip_ospf_authentication, DEFUN (no_ip_ospf_authentication_args, no_ip_ospf_authentication_args_addr_cmd, - "no ip ospf authentication [A.B.C.D]", + "no ip ospf authentication [A.B.C.D]", NO_STR "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Use null authentication\n" "Use message-digest authentication\n" + "Use a key-chain for cryptographic authentication keys\n" + "Key-chain name\n" "Address of interface\n") { VTY_DECLVAR_CONTEXT(interface, ifp); int idx_encryption = 4; - int idx_ipv4 = 5; + int idx_ipv4 = argc-1; struct in_addr addr; int ret; struct ospf_if_params *params; @@ -7638,7 +7699,7 @@ DEFUN (no_ip_ospf_authentication_args, params = IF_DEF_PARAMS(ifp); - if (argc == 6) { + if (argv[idx_ipv4]->type == IPV4_TKN) { ret = inet_aton(argv[idx_ipv4]->arg, &addr); if (!ret) { vty_out(vty, @@ -7653,6 +7714,10 @@ DEFUN (no_ip_ospf_authentication_args, } params->auth_type = OSPF_AUTH_NOTSET; UNSET_IF_PARAM(params, auth_type); + + XFREE(MTYPE_OSPF_IF_PARAMS, params->keychain_name); + UNSET_IF_PARAM(params, keychain_name); + if (params != IF_DEF_PARAMS(ifp)) { ospf_free_if_params(ifp, addr); ospf_if_update_params(ifp, addr); @@ -7660,7 +7725,8 @@ DEFUN (no_ip_ospf_authentication_args, } else { if (argv[idx_encryption]->arg[0] == 'n') { auth_type = OSPF_AUTH_NULL; - } else if (argv[idx_encryption]->arg[0] == 'm') { + } else if (argv[idx_encryption]->arg[0] == 'm' || + argv[idx_encryption]->arg[0] == 'k') { auth_type = OSPF_AUTH_CRYPTOGRAPHIC; } else { vty_out(vty, "Unexpected input encountered\n"); @@ -7676,6 +7742,8 @@ DEFUN (no_ip_ospf_authentication_args, if (params->auth_type == auth_type) { params->auth_type = OSPF_AUTH_NOTSET; UNSET_IF_PARAM(params, auth_type); + XFREE(MTYPE_OSPF_IF_PARAMS, params->keychain_name); + UNSET_IF_PARAM(params, keychain_name); } for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; @@ -7684,6 +7752,8 @@ DEFUN (no_ip_ospf_authentication_args, if (params->auth_type == auth_type) { params->auth_type = OSPF_AUTH_NOTSET; UNSET_IF_PARAM(params, auth_type); + XFREE(MTYPE_OSPF_IF_PARAMS, params->keychain_name); + UNSET_IF_PARAM(params, keychain_name); if (params != IF_DEF_PARAMS(ifp)) { ospf_free_if_params( ifp, rn->p.u.prefix4); @@ -12098,11 +12168,11 @@ static const char *const ospf_int_type_str[] = { "loopback" }; -static const char *interface_config_auth_str(struct ospf_if_params *params) +static int interface_config_auth_str(struct ospf_if_params *params, char *buf) { if (!OSPF_IF_PARAM_CONFIGURED(params, auth_type) || params->auth_type == OSPF_AUTH_NOTSET) - return NULL; + return 0; /* Translation tables are not that much help * here due to syntax @@ -12110,16 +12180,22 @@ static const char *interface_config_auth_str(struct ospf_if_params *params) switch (params->auth_type) { case OSPF_AUTH_NULL: - return " null"; + snprintf(buf, BUFSIZ, " null"); + break; case OSPF_AUTH_SIMPLE: - return ""; + snprintf(buf, BUFSIZ, " "); + break; case OSPF_AUTH_CRYPTOGRAPHIC: - return " message-digest"; + if (OSPF_IF_PARAM_CONFIGURED(params, keychain_name)) + snprintf(buf, BUFSIZ, " key-chain %s", params->keychain_name); + else + snprintf(buf, BUFSIZ, " message-digest"); + break; } - return ""; + return 1; } static int config_write_interface_one(struct vty *vty, struct vrf *vrf) @@ -12129,7 +12205,8 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) struct crypt_key *ck; struct route_node *rn = NULL; struct ospf_if_params *params; - const char *auth_str; + char buf[BUFSIZ]; + int ret = 0; int write = 0; FOR_ALL_INTERFACES (vrf, ifp) { @@ -12170,10 +12247,10 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) } /* OSPF interface authentication print */ - auth_str = interface_config_auth_str(params); - if (auth_str) { + ret = interface_config_auth_str(params, buf); + if (ret) { vty_out(vty, " ip ospf authentication%s", - auth_str); + buf); if (params != IF_DEF_PARAMS(ifp) && rn) vty_out(vty, " %pI4", &rn->p.u.prefix4); @@ -12613,8 +12690,9 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf) { struct listnode *node; struct ospf_vl_data *vl_data; - const char *auth_str; char buf[INET_ADDRSTRLEN]; + char buf2[BUFSIZ]; + int ret = 0; /* Virtual-Link print */ for (ALL_LIST_ELEMENTS_RO(ospf->vlinks, node, vl_data)) { @@ -12647,12 +12725,12 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf) vty_out(vty, " area %s virtual-link %pI4\n", buf, &vl_data->vl_peer); /* Auth type */ - auth_str = interface_config_auth_str( - IF_DEF_PARAMS(oi->ifp)); - if (auth_str) + ret = interface_config_auth_str( + IF_DEF_PARAMS(oi->ifp), buf2); + if (ret) vty_out(vty, " area %s virtual-link %pI4 authentication%s\n", - buf, &vl_data->vl_peer, auth_str); + buf, &vl_data->vl_peer, buf2); /* Auth key */ if (IF_DEF_PARAMS(vl_data->vl_oi->ifp)->auth_simple[0] != '\0') diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index abc580b13ef4..1af703d88d6d 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -162,29 +162,6 @@ static int ospf_interface_link_params(ZAPI_CALLBACK_ARGS) return 0; } -/* VRF update for an interface. */ -static int ospf_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp = NULL; - vrf_id_t new_vrf_id; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - if (!ifp) - return 0; - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "%s: Rx Interface %s VRF change vrf_id %u New vrf %s id %u", - __func__, ifp->name, vrf_id, - ospf_vrf_id_to_name(new_vrf_id), new_vrf_id); - - /*if_update(ifp, ifp->name, strlen(ifp->name), new_vrf_id);*/ - if_update_to_new_vrf(ifp, new_vrf_id); - - return 0; -} - /* Nexthop, ifindex, distance and metric information. */ static void ospf_zebra_add_nexthop(struct ospf *ospf, struct ospf_path *path, struct zapi_route *api) @@ -2203,7 +2180,6 @@ static zclient_handler *const ospf_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = ospf_interface_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = ospf_interface_address_delete, [ZEBRA_INTERFACE_LINK_PARAMS] = ospf_interface_link_params, - [ZEBRA_INTERFACE_VRF_UPDATE] = ospf_interface_vrf_update, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = ospf_zebra_read_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = ospf_zebra_read_route, diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index aa3cadf99788..e3ed4f2f346d 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -935,6 +935,15 @@ static void ospf_finish_final(struct ospf *ospf) XFREE(MTYPE_OSPF_TOP, ospf); } +static void ospf_range_table_node_destroy(route_table_delegate_t *delegate, + struct route_table *table, struct route_node *node) +{ + XFREE(MTYPE_OSPF_AREA_RANGE, node->info); + XFREE(MTYPE_ROUTE_NODE, node); +} + +route_table_delegate_t ospf_range_table_delegate = {.create_node = route_node_create, + .destroy_node = ospf_range_table_node_destroy}; /* allocate new OSPF Area object */ struct ospf_area *ospf_area_new(struct ospf *ospf, struct in_addr area_id) @@ -971,8 +980,8 @@ struct ospf_area *ospf_area_new(struct ospf *ospf, struct in_addr area_id) ospf_opaque_type10_lsa_init(new); new->oiflist = list_new(); - new->ranges = route_table_init(); - new->nssa_ranges = route_table_init(); + new->ranges = route_table_init_with_delegate(&ospf_range_table_delegate); + new->nssa_ranges = route_table_init_with_delegate(&ospf_range_table_delegate); if (area_id.s_addr == OSPF_AREA_BACKBONE) ospf->backbone = new; diff --git a/ospfd/subdir.am b/ospfd/subdir.am index 44ee3b0f13a9..4803aae68d84 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -56,6 +56,7 @@ ospfd_libfrrospf_a_SOURCES = \ ospfd/ospf_zebra.c \ ospfd/ospfd.c \ ospfd/ospf_gr_helper.c \ + ospfd/ospf_auth.c \ # end if OSPFD @@ -106,6 +107,7 @@ noinst_HEADERS += \ ospfd/ospf_te.h \ ospfd/ospf_vty.h \ ospfd/ospf_zebra.h \ + ospfd/ospf_auth.h \ # end ospfd_ospfd_LDADD = ospfd/libfrrospf.a ospfd/libfrrospfclient.a lib/libfrr.la $(LIBCAP) $(LIBM) diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c index 6c660a3d085c..9880081f35e8 100644 --- a/pathd/path_pcep_cli.c +++ b/pathd/path_pcep_cli.c @@ -52,6 +52,7 @@ static int pcep_cli_pce_config_write(struct vty *vty); static int pcep_cli_pcep_pce_config_write(struct vty *vty); /* Internal Util Function declarations */ +static void reset_pcc_peer(const char *peer_name); static struct pce_opts_cli *pcep_cli_find_pce(const char *pce_name); static bool pcep_cli_add_pce(struct pce_opts_cli *pce_opts_cli); static struct pce_opts_cli *pcep_cli_create_pce_opts(const char *name); @@ -741,64 +742,86 @@ static int path_pcep_cli_show_srte_pcep_pce(struct vty *vty, return CMD_SUCCESS; } -static int path_pcep_cli_peer_sr_draft07(struct vty *vty) +static int path_pcep_cli_peer_sr_draft07(struct vty *vty, bool reset) { struct pcep_config_group_opts *pce_config = NULL; + struct pce_opts *pce_opts = ¤t_pce_opts_g->pce_opts; + bool pce_in_use = false; if (vty->node == PCEP_PCE_NODE) { - /* TODO need to see if the pce is in use, and reset the - * connection */ pce_config = ¤t_pce_opts_g->pce_config_group_opts; current_pce_opts_g->merged = false; + pce_in_use = pcep_cli_pcc_has_pce(pce_opts->pce_name); } else if (vty->node == PCEP_PCE_CONFIG_NODE) { pce_config = current_pcep_config_group_opts_g; } else { return CMD_ERR_NO_MATCH; } - pce_config->draft07 = true; + pce_config->draft07 = reset ? DEFAULT_SR_DRAFT07 : true; + + if (pce_in_use) { + vty_out(vty, "%% PCE in use, resetting pcc peer session...\n"); + reset_pcc_peer(pce_opts->pce_name); + } return CMD_SUCCESS; } -static int path_pcep_cli_peer_pce_initiated(struct vty *vty) +static int path_pcep_cli_peer_pce_initiated(struct vty *vty, bool reset) { struct pcep_config_group_opts *pce_config = NULL; + struct pce_opts *pce_opts = ¤t_pce_opts_g->pce_opts; + bool pce_in_use = false; if (vty->node == PCEP_PCE_NODE) { - /* TODO need to see if the pce is in use, and reset the - * connection */ pce_config = ¤t_pce_opts_g->pce_config_group_opts; current_pce_opts_g->merged = false; + pce_in_use = pcep_cli_pcc_has_pce(pce_opts->pce_name); } else if (vty->node == PCEP_PCE_CONFIG_NODE) { pce_config = current_pcep_config_group_opts_g; } else { return CMD_ERR_NO_MATCH; } - pce_config->pce_initiated = true; + pce_config->pce_initiated = reset ? DEFAULT_PCE_INITIATED : true; + + if (pce_in_use) { + vty_out(vty, "%% PCE in use, resetting pcc peer session...\n"); + reset_pcc_peer(pce_opts->pce_name); + } return CMD_SUCCESS; } static int path_pcep_cli_peer_tcp_md5_auth(struct vty *vty, - const char *tcp_md5_auth) + const char *tcp_md5_auth, + bool reset) { struct pcep_config_group_opts *pce_config = NULL; + struct pce_opts *pce_opts = ¤t_pce_opts_g->pce_opts; + bool pce_in_use = false; if (vty->node == PCEP_PCE_NODE) { - /* TODO need to see if the pce is in use, and reset the - * connection */ pce_config = ¤t_pce_opts_g->pce_config_group_opts; current_pce_opts_g->merged = false; + pce_in_use = pcep_cli_pcc_has_pce(pce_opts->pce_name); } else if (vty->node == PCEP_PCE_CONFIG_NODE) { pce_config = current_pcep_config_group_opts_g; } else { return CMD_ERR_NO_MATCH; } - strlcpy(pce_config->tcp_md5_auth, tcp_md5_auth, - sizeof(pce_config->tcp_md5_auth)); + if (reset) + pce_config->tcp_md5_auth[0] = '\0'; + else + strlcpy(pce_config->tcp_md5_auth, tcp_md5_auth, + sizeof(pce_config->tcp_md5_auth)); + + if (pce_in_use) { + vty_out(vty, "%% PCE in use, resetting pcc peer session...\n"); + reset_pcc_peer(pce_opts->pce_name); + } return CMD_SUCCESS; } @@ -841,20 +864,29 @@ static int path_pcep_cli_peer_source_address(struct vty *vty, struct in_addr *ip, const char *ipv6_str, struct in6_addr *ipv6, - const char *port_str, long port) + const char *port_str, long port, + bool reset) { struct pcep_config_group_opts *pce_config = NULL; + struct pce_opts *pce_opts = ¤t_pce_opts_g->pce_opts; + bool pce_in_use = false; + if (vty->node == PCEP_PCE_NODE) { - /* TODO need to see if the pce is in use, and reset the - * connection */ pce_config = ¤t_pce_opts_g->pce_config_group_opts; current_pce_opts_g->merged = false; + pce_in_use = pcep_cli_pcc_has_pce(pce_opts->pce_name); } else if (vty->node == PCEP_PCE_CONFIG_NODE) { pce_config = current_pcep_config_group_opts_g; } else { return CMD_ERR_NO_MATCH; } + if (reset) { + pce_config->source_ip.ipa_type = IPADDR_NONE; + pce_config->source_port = 0; + return CMD_SUCCESS; + } + /* Handle the optional source IP */ if (ipv6_str != NULL) { pce_config->source_ip.ipa_type = IPADDR_V6; @@ -870,6 +902,11 @@ static int path_pcep_cli_peer_source_address(struct vty *vty, PCEP_VTYSH_INT_ARG_CHECK(port_str, port, pce_config->source_port, 0, 65535); + if (pce_in_use) { + vty_out(vty, "%% PCE in use, resetting pcc peer session...\n"); + reset_pcc_peer(pce_opts->pce_name); + } + return CMD_SUCCESS; } @@ -910,11 +947,13 @@ static int path_pcep_cli_peer_timers( const char *delegation_timeout_str, long delegation_timeout) { struct pcep_config_group_opts *pce_config = NULL; + struct pce_opts *pce_opts = ¤t_pce_opts_g->pce_opts; + bool pce_in_use = false; + if (vty->node == PCEP_PCE_NODE) { - /* TODO need to see if the pce is in use, and reset the - * connection */ pce_config = ¤t_pce_opts_g->pce_config_group_opts; current_pce_opts_g->merged = false; + pce_in_use = pcep_cli_pcc_has_pce(pce_opts->pce_name); } else if (vty->node == PCEP_PCE_CONFIG_NODE) { pce_config = current_pcep_config_group_opts_g; } else { @@ -952,6 +991,11 @@ static int path_pcep_cli_peer_timers( PCEP_VTYSH_INT_ARG_CHECK(delegation_timeout_str, delegation_timeout, pce_config->delegation_timeout_seconds, 0, 61); + if (pce_in_use) { + vty_out(vty, "%% PCE in use, resetting pcc peer session...\n"); + reset_pcc_peer(pce_opts->pce_name); + } + return CMD_SUCCESS; } @@ -982,6 +1026,37 @@ static int path_pcep_cli_pcc_pcc_msd(struct vty *vty, const char *msd_str, return CMD_SUCCESS; } +void reset_pcc_peer(const char *peer_name) +{ + struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(peer_name); + + /* Remove the pcc peer */ + pcep_cli_remove_pce_connection(&pce_opts_cli->pce_opts); + struct pce_opts *pce_opts_copy = + XMALLOC(MTYPE_PCEP, sizeof(struct pce_opts)); + memcpy(pce_opts_copy, &pce_opts_cli->pce_opts, sizeof(struct pce_opts)); + pcep_ctrl_remove_pcc(pcep_g->fpt, pce_opts_copy); + + /* Re-add the pcc peer */ + pcep_cli_merge_pcep_pce_config_options(pce_opts_cli); + pcep_cli_add_pce_connection(&pce_opts_cli->pce_opts); + + /* Update the pcc_opts */ + struct pcc_opts *pcc_opts_copy = + XMALLOC(MTYPE_PCEP, sizeof(struct pcc_opts)); + memcpy(&pcc_opts_copy->addr, + &pce_opts_cli->pce_opts.config_opts.source_ip, + sizeof(pcc_opts_copy->addr)); + pcc_opts_copy->msd = pcc_msd_g; + pcc_opts_copy->port = pce_opts_cli->pce_opts.config_opts.source_port; + pcep_ctrl_update_pcc_options(pcep_g->fpt, pcc_opts_copy); + + /* Update the pce_opts */ + pce_opts_copy = XMALLOC(MTYPE_PCEP, sizeof(struct pce_opts)); + memcpy(pce_opts_copy, &pce_opts_cli->pce_opts, sizeof(struct pce_opts)); + pcep_ctrl_update_pce_options(pcep_g->fpt, pce_opts_copy); +} + static int path_pcep_cli_pcc_pcc_peer(struct vty *vty, const char *peer_name, const char *precedence_str, long precedence) @@ -1810,27 +1885,30 @@ DEFPY(pcep_cli_show_srte_pcep_pce, DEFPY(pcep_cli_peer_sr_draft07, pcep_cli_peer_sr_draft07_cmd, - "sr-draft07", + "[no] sr-draft07", + NO_STR "Configure PCC to send PCEP Open with SR draft07\n") { - return path_pcep_cli_peer_sr_draft07(vty); + return path_pcep_cli_peer_sr_draft07(vty, no); } DEFPY(pcep_cli_peer_pce_initiated, pcep_cli_peer_pce_initiated_cmd, - "pce-initiated", + "[no] pce-initiated", + NO_STR "Configure PCC to accept PCE initiated LSPs\n") { - return path_pcep_cli_peer_pce_initiated(vty); + return path_pcep_cli_peer_pce_initiated(vty, no); } DEFPY(pcep_cli_peer_tcp_md5_auth, pcep_cli_peer_tcp_md5_auth_cmd, - "tcp-md5-auth WORD", + "[no] tcp-md5-auth WORD", + NO_STR "Configure PCC TCP-MD5 RFC2385 Authentication\n" "TCP-MD5 Authentication string\n") { - return path_pcep_cli_peer_tcp_md5_auth(vty, tcp_md5_auth); + return path_pcep_cli_peer_tcp_md5_auth(vty, tcp_md5_auth, no); } DEFPY(pcep_cli_peer_address, @@ -1850,7 +1928,8 @@ DEFPY(pcep_cli_peer_address, DEFPY(pcep_cli_peer_source_address, pcep_cli_peer_source_address_cmd, - "source-address [ip A.B.C.D | ipv6 X:X::X:X] [port (1024-65535)]", + "[no] source-address [ip A.B.C.D | ipv6 X:X::X:X] [port (1024-65535)]", + NO_STR "PCE source IP Address configuration\n" "PCE source IPv4 address\n" "PCE source IPv4 address value\n" @@ -1860,7 +1939,7 @@ DEFPY(pcep_cli_peer_source_address, "Source PCE server port value\n") { return path_pcep_cli_peer_source_address(vty, ip_str, &ip, ipv6_str, - &ipv6, port_str, port); + &ipv6, port_str, port, no); } DEFPY(pcep_cli_peer_pcep_pce_config_ref, diff --git a/pathd/path_pcep_debug.c b/pathd/path_pcep_debug.c index 7d04587b8d76..7bff9c7b9c0e 100644 --- a/pathd/path_pcep_debug.c +++ b/pathd/path_pcep_debug.c @@ -1312,6 +1312,8 @@ void _format_path_hop(int ps, struct path_hop *hop) void _format_pcep_event(int ps, pcep_event *event) { + char buf[32]; + if (event == NULL) { PATHD_FORMAT("NULL\n"); } else { @@ -1320,7 +1322,7 @@ void _format_pcep_event(int ps, pcep_event *event) PATHD_FORMAT("%*sevent_type: %s\n", ps2, "", pcep_event_type_name(event->event_type)); PATHD_FORMAT("%*sevent_time: %s", ps2, "", - ctime(&event->event_time)); + ctime_r(&event->event_time, buf)); if (event->session == NULL) { PATHD_FORMAT("%*ssession: NULL\n", ps2, ""); } else { diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 774e7ee85ac6..8f7a46377c86 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -357,6 +357,11 @@ extern void pbr_map_delete(struct pbr_map_sequence *pbrms) if (pbrms->nhg) pbr_nht_delete_individual_nexthop(pbrms); + if (pbrms->nhgrp_name) + XFREE(MTYPE_TMP, pbrms->nhgrp_name); + + prefix_free(&pbrms->dst); + listnode_delete(pbrm->seqnumbers, pbrms); if (pbrm->seqnumbers->count == 0) { diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index ee17a193f46f..876f9e19e024 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -129,29 +129,6 @@ int pbr_ifp_down(struct interface *ifp) return 0; } -static int interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - - if (!ifp) { - DEBUGD(&pbr_dbg_zebra, "%s: VRF change interface not found", - __func__); - - return 0; - } - - DEBUGD(&pbr_dbg_zebra, "%s: %s VRF change %u -> %u", __func__, - ifp->name, vrf_id, new_vrf_id); - - if_update_to_new_vrf(ifp, new_vrf_id); - - return 0; -} - static int route_notify_owner(ZAPI_CALLBACK_ARGS) { struct prefix p; @@ -335,6 +312,11 @@ void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, "%s: Asked to install unsupported route type: L2VPN", __func__); break; + case AFI_LINKSTATE: + DEBUGD(&pbr_dbg_zebra, + "%s: Asked to install unsupported route type: Link-State", + __func__); + break; case AFI_UNSPEC: DEBUGD(&pbr_dbg_zebra, "%s: Asked to install unspecified route type", __func__); @@ -380,6 +362,11 @@ void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi) "%s: Asked to delete unsupported route type: L2VPN", __func__); break; + case AFI_LINKSTATE: + DEBUGD(&pbr_dbg_zebra, + "%s: Asked to delete unsupported route type: Link-State", + __func__); + break; case AFI_UNSPEC: DEBUGD(&pbr_dbg_zebra, "%s: Asked to delete unspecified route type", __func__); @@ -426,7 +413,6 @@ extern struct zebra_privs_t pbr_privs; static zclient_handler *const pbr_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete, - [ZEBRA_INTERFACE_VRF_UPDATE] = interface_vrf_update, [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner, [ZEBRA_RULE_NOTIFY_OWNER] = rule_notify_owner, [ZEBRA_NEXTHOP_UPDATE] = pbr_zebra_nexthop_update, diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index 20ef9216a9c9..7cf492d4b644 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -2151,6 +2151,15 @@ static void gm_start(struct interface *ifp) } } +void pim_gm_if_reset(struct interface *ifp) +{ + struct pim_interface *pim_ifp = ifp->info; + struct gm_if *gm_ifp = pim_ifp->mld; + + if (gm_ifp) + gm_group_delete(gm_ifp); +} + void gm_group_delete(struct gm_if *gm_ifp) { struct gm_sg *sg; diff --git a/pimd/pim6_mld.h b/pimd/pim6_mld.h index 183ab2fc508d..f8d7dafece93 100644 --- a/pimd/pim6_mld.h +++ b/pimd/pim6_mld.h @@ -357,6 +357,7 @@ struct gm_if { #if PIM_IPV == 6 extern void gm_ifp_update(struct interface *ifp); extern void gm_ifp_teardown(struct interface *ifp); +extern void pim_gm_if_reset(struct interface *ifp); extern void gm_group_delete(struct gm_if *gm_ifp); #else static inline void gm_ifp_update(struct interface *ifp) diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index 4c7bc91213d8..c3eb49d5f31d 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -1078,7 +1078,7 @@ void pim_show_state(struct pim_instance *pim, struct vty *vty, oil_mcastgrp(c_oil)); snprintfrr(src_str, sizeof(src_str), "%pPAs", oil_origin(c_oil)); - ifp_in = pim_if_find_by_vif_index(pim, *oil_parent(c_oil)); + ifp_in = pim_if_find_by_vif_index(pim, *oil_incoming_vif(c_oil)); if (ifp_in) strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname)); @@ -3723,7 +3723,7 @@ void show_mroute(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg, if (pim_channel_oil_empty(c_oil)) strlcat(state_str, "P", sizeof(state_str)); - ifp_in = pim_if_find_by_vif_index(pim, *oil_parent(c_oil)); + ifp_in = pim_if_find_by_vif_index(pim, *oil_incoming_vif(c_oil)); if (ifp_in) strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname)); @@ -3789,7 +3789,7 @@ void show_mroute(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg, if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_MUTE) continue; - if (*oil_parent(c_oil) == oif_vif_index && + if (*oil_incoming_vif(c_oil) == oif_vif_index && !pim_mroute_allow_iif_in_oil(c_oil, oif_vif_index)) continue; @@ -3840,7 +3840,7 @@ void show_mroute(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg, "inboundInterface", in_ifname); json_object_int_add(json_ifp_out, "iVifI", - *oil_parent(c_oil)); + *oil_incoming_vif(c_oil)); json_object_string_add(json_ifp_out, "outboundInterface", out_ifname); @@ -3989,9 +3989,9 @@ void show_mroute(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg, json_object_string_add(json_ifp_out, "inboundInterface", in_ifname); - json_object_int_add( - json_ifp_out, "iVifI", - *oil_parent(&s_route->c_oil)); + json_object_int_add(json_ifp_out, "iVifI", + *oil_incoming_vif( + &s_route->c_oil)); json_object_string_add(json_ifp_out, "outboundInterface", out_ifname); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 85e0fdf3afbe..cfbbdf55f240 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -201,7 +201,7 @@ void pim_if_delete(struct interface *ifp) pim_if_del_vif(ifp); - pim_igmp_if_fini(pim_ifp); + pim_igmp_if_fini(ifp); list_delete(&pim_ifp->pim_neighbor_list); list_delete(&pim_ifp->upstream_switch_list); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index da5518994193..0d6625e5b03b 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -1232,8 +1232,6 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, pim_sgaddr *sg) pim_ifp = ifp->info; if (!pim_ifp) return; - if (!pim_ifp->pim_enable) - return; orig = ch = pim_ifchannel_find(ifp, sg); if (!ch) diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 063ba6edd275..cb46fc0eebc3 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -1074,10 +1074,12 @@ void igmp_sock_free(struct gm_sock *igmp) void igmp_sock_delete(struct gm_sock *igmp) { + struct interface *ifp; struct pim_interface *pim_ifp; sock_close(igmp); + ifp = igmp->interface; pim_ifp = igmp->interface->info; listnode_delete(pim_ifp->gm_socket_list, igmp); @@ -1085,7 +1087,7 @@ void igmp_sock_delete(struct gm_sock *igmp) igmp_sock_free(igmp); if (!listcount(pim_ifp->gm_socket_list)) - pim_igmp_if_reset(pim_ifp); + pim_gm_if_reset(ifp); } void igmp_sock_delete_all(struct interface *ifp) @@ -1135,8 +1137,9 @@ void pim_igmp_if_init(struct pim_interface *pim_ifp, struct interface *ifp) igmp_group_hash_equal, hash_name); } -void pim_igmp_if_reset(struct pim_interface *pim_ifp) +void pim_gm_if_reset(struct interface *ifp) { + struct pim_interface *pim_ifp = ifp->info; struct listnode *grp_node, *grp_nextnode; struct gm_group *grp; @@ -1146,9 +1149,11 @@ void pim_igmp_if_reset(struct pim_interface *pim_ifp) } } -void pim_igmp_if_fini(struct pim_interface *pim_ifp) +void pim_igmp_if_fini(struct interface *ifp) { - pim_igmp_if_reset(pim_ifp); + struct pim_interface *pim_ifp = ifp->info; + + pim_gm_if_reset(ifp); assert(pim_ifp->gm_group_list); assert(!listcount(pim_ifp->gm_group_list)); diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index a1f19b3c6e1c..2bf7f9cc7449 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -82,8 +82,8 @@ struct pim_interface; #if PIM_IPV == 4 void pim_igmp_if_init(struct pim_interface *pim_ifp, struct interface *ifp); -void pim_igmp_if_reset(struct pim_interface *pim_ifp); -void pim_igmp_if_fini(struct pim_interface *pim_ifp); +void pim_gm_if_reset(struct interface *ifp); +void pim_igmp_if_fini(struct interface *ifp); struct gm_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, struct in_addr ifaddr); @@ -108,7 +108,7 @@ static inline void pim_igmp_if_init(struct pim_interface *pim_ifp, { } -static inline void pim_igmp_if_fini(struct pim_interface *pim_ifp) +static inline void pim_igmp_if_fini(struct interface *ifp) { } diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index b64fcdeb8723..7ea6ed9e1407 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -253,7 +253,7 @@ int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg) up->channel_oil->cc.pktcnt++; // resolve mfcc_parent prior to mroute_add in channel_add_oif if (up->rpf.source_nexthop.interface && - *oil_parent(up->channel_oil) >= MAXVIFS) { + *oil_incoming_vif(up->channel_oil) >= MAXVIFS) { pim_upstream_mroute_iif_update(up->channel_oil, __func__); } pim_register_join(up); @@ -1042,10 +1042,10 @@ static inline void pim_mroute_copy(struct channel_oil *out, *oil_origin(out) = *oil_origin(in); *oil_mcastgrp(out) = *oil_mcastgrp(in); - *oil_parent(out) = *oil_parent(in); + *oil_incoming_vif(out) = *oil_incoming_vif(in); for (i = 0; i < MAXVIFS; ++i) { - if (*oil_parent(out) == i && + if (*oil_incoming_vif(out) == i && !pim_mroute_allow_iif_in_oil(in, i)) { oil_if_set(out, i, 0); continue; @@ -1080,7 +1080,7 @@ static int pim_mroute_add(struct channel_oil *c_oil, const char *name) * in the case of a (*,G). */ if (pim_addr_is_any(*oil_origin(c_oil))) { - oil_if_set(tmp_oil, *oil_parent(c_oil), 1); + oil_if_set(tmp_oil, *oil_incoming_vif(c_oil), 1); } /* @@ -1090,18 +1090,17 @@ static int pim_mroute_add(struct channel_oil *c_oil, const char *name) * the packets to be forwarded. Then set it * to the correct IIF afterwords. */ - if (!c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil)) - && *oil_parent(c_oil) != 0) { - *oil_parent(tmp_oil) = 0; + if (!c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil)) && + *oil_incoming_vif(c_oil) != 0) { + *oil_incoming_vif(tmp_oil) = 0; } /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */ err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC, &tmp_oil->oil, sizeof(tmp_oil->oil)); - if (!err && !c_oil->installed - && !pim_addr_is_any(*oil_origin(c_oil)) - && *oil_parent(c_oil) != 0) { - *oil_parent(tmp_oil) = *oil_parent(c_oil); + if (!err && !c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil)) && + *oil_incoming_vif(c_oil) != 0) { + *oil_incoming_vif(tmp_oil) = *oil_incoming_vif(c_oil); err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC, &tmp_oil->oil, sizeof(tmp_oil->oil)); } @@ -1158,7 +1157,7 @@ static int pim_upstream_mroute_update(struct channel_oil *c_oil, { char buf[1000]; - if (*oil_parent(c_oil) >= MAXVIFS) { + if (*oil_incoming_vif(c_oil) >= MAXVIFS) { /* the c_oil cannot be installed as a mroute yet */ if (PIM_DEBUG_MROUTE) zlog_debug( @@ -1205,13 +1204,13 @@ int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name) iif = pim_upstream_get_mroute_iif(c_oil, name); - if (*oil_parent(c_oil) != iif) { - *oil_parent(c_oil) = iif; + if (*oil_incoming_vif(c_oil) != iif) { + *oil_incoming_vif(c_oil) = iif; if (pim_addr_is_any(*oil_origin(c_oil)) && c_oil->up) pim_upstream_all_sources_iif_update(c_oil->up); } else { - *oil_parent(c_oil) = iif; + *oil_incoming_vif(c_oil) = iif; } return pim_upstream_mroute_update(c_oil, name); @@ -1226,11 +1225,11 @@ int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name) char buf[1000]; iif = pim_upstream_get_mroute_iif(c_oil, name); - if (*oil_parent(c_oil) == iif) { + if (*oil_incoming_vif(c_oil) == iif) { /* no change */ return 0; } - *oil_parent(c_oil) = iif; + *oil_incoming_vif(c_oil) = iif; if (pim_addr_is_any(*oil_origin(c_oil)) && c_oil->up) @@ -1255,10 +1254,10 @@ void pim_static_mroute_iif_update(struct channel_oil *c_oil, int input_vif_index, const char *name) { - if (*oil_parent(c_oil) == input_vif_index) + if (*oil_incoming_vif(c_oil) == input_vif_index) return; - *oil_parent(c_oil) = input_vif_index; + *oil_incoming_vif(c_oil) = input_vif_index; if (input_vif_index == MAXVIFS) pim_mroute_del(c_oil, name); else @@ -1276,10 +1275,15 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name) if (!c_oil->installed) { if (PIM_DEBUG_MROUTE) { char buf[1000]; - zlog_debug( - "%s %s: vifi %d for route is %s not installed, do not need to send del req. ", - __FILE__, __func__, *oil_parent(c_oil), - pim_channel_oil_dump(c_oil, buf, sizeof(buf))); + struct interface *iifp = + pim_if_find_by_vif_index(pim, *oil_incoming_vif( + c_oil)); + + zlog_debug("%s %s: incoming interface %s for route is %s not installed, do not need to send del req. ", + __FILE__, __func__, + iifp ? iifp->name : "Unknown", + pim_channel_oil_dump(c_oil, buf, + sizeof(buf))); } return -2; } diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index b1b6958fe166..623c14bb0391 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -374,6 +374,8 @@ void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, pim_sgaddr *sg, struct in_addr rp) { struct pim_msdp_sa *sa; + struct rp_info *rp_info; + struct prefix grp; sa = pim_msdp_sa_add(pim, sg, rp); if (!sa) { @@ -406,6 +408,14 @@ void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, sa->sg_str); } /* send an immediate SA update to peers */ + pim_addr_to_prefix(&grp, sa->sg.grp); + rp_info = pim_rp_find_match_group(pim, &grp); + if (rp_info) { + sa->rp = rp_info->rp.rpf_addr; + } else + { + sa->rp = pim->msdp.originator_id; + } sa->rp = pim->msdp.originator_id; pim_msdp_pkt_sa_tx_one(sa); } diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index a414736cccf1..4324a96bef89 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -14,7 +14,9 @@ #include "pimd.h" #include "pim_instance.h" +#include "pim_rp.h" #include "pim_str.h" +#include "pim_util.h" #include "pim_errors.h" #include "pim_msdp.h" @@ -387,6 +389,9 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, { struct listnode *sanode; struct pim_msdp_sa *sa; + struct rp_info *rp_info; + struct prefix group_all; + struct in_addr rp; int sa_count; int local_cnt = pim->msdp.local_cnt; @@ -395,8 +400,15 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, zlog_debug(" sa gen %d", local_cnt); } - local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt, - pim->msdp.originator_id); + rp = pim->msdp.originator_id; + if (pim_get_all_mcast_group(&group_all)) { + rp_info = pim_rp_find_match_group(pim, &group_all); + if (rp_info) { + rp = rp_info->rp.rpf_addr; + } + } + + local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt, rp); for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) { @@ -418,7 +430,7 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, local_cnt); } local_cnt = pim_msdp_pkt_sa_fill_hdr( - pim, local_cnt, pim->msdp.originator_id); + pim, local_cnt, rp); } } diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 30d84710e667..be05b69401e4 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1633,7 +1633,7 @@ int lib_interface_pim_address_family_hello_interval_modify( ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; pim_ifp->pim_hello_period = - yang_dnode_get_uint8(args->dnode, NULL); + yang_dnode_get_uint16(args->dnode, NULL); pim_ifp->pim_default_holdtime = -1; break; } diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index e1ec9b34a113..d18406d55d96 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -31,7 +31,7 @@ char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size) sg.src = *oil_origin(c_oil); sg.grp = *oil_mcastgrp(c_oil); - ifp = pim_if_find_by_vif_index(c_oil->pim, *oil_parent(c_oil)); + ifp = pim_if_find_by_vif_index(c_oil->pim, *oil_incoming_vif(c_oil)); snprintfrr(buf, size, "%pSG IIF: %s, OIFS: ", &sg, ifp ? ifp->name : "(?)"); @@ -135,7 +135,7 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, *oil_mcastgrp(c_oil) = sg->grp; *oil_origin(c_oil) = sg->src; - *oil_parent(c_oil) = MAXVIFS; + *oil_incoming_vif(c_oil) = MAXVIFS; c_oil->oil_ref_count = 1; c_oil->installed = 0; c_oil->up = pim_upstream_find(pim, sg); @@ -164,7 +164,7 @@ void pim_clear_nocache_state(struct pim_interface *pim_ifp) !(PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(c_oil->up->flags))) continue; - if (*oil_parent(c_oil) != pim_ifp->mroute_vif_index) + if (*oil_incoming_vif(c_oil) != pim_ifp->mroute_vif_index) continue; EVENT_OFF(c_oil->up->t_ka_timer); @@ -286,13 +286,15 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif, --channel_oil->oil_size; if (PIM_DEBUG_MROUTE) { - zlog_debug( - "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u IIF:%d OIF=%s vif_index=%d", - __func__, caller, oil_origin(channel_oil), - oil_mcastgrp(channel_oil), - proto_mask, - *oil_parent(channel_oil), oif->name, - pim_ifp->mroute_vif_index); + struct interface *iifp = + pim_if_find_by_vif_index(pim_ifp->pim, + *oil_incoming_vif(channel_oil)); + + zlog_debug("%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u IIF:%s OIF=%s vif_index=%d", + __func__, caller, oil_origin(channel_oil), + oil_mcastgrp(channel_oil), proto_mask, + iifp ? iifp->name : "Unknown", oif->name, + pim_ifp->mroute_vif_index); } return 0; @@ -522,7 +524,7 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not * valid to get installed in kernel. */ - if (*oil_parent(channel_oil) != MAXVIFS) { + if (*oil_incoming_vif(channel_oil) != MAXVIFS) { if (pim_upstream_mroute_add(channel_oil, __func__)) { if (PIM_DEBUG_MROUTE) { zlog_debug( diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index dc66eaace454..6a5222753b1d 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -112,7 +112,7 @@ static inline pim_addr *oil_mcastgrp(struct channel_oil *c_oil) return &c_oil->oil.mfcc_mcastgrp; } -static inline vifi_t *oil_parent(struct channel_oil *c_oil) +static inline vifi_t *oil_incoming_vif(struct channel_oil *c_oil) { return &c_oil->oil.mfcc_parent; } @@ -143,7 +143,7 @@ static inline pim_addr *oil_mcastgrp(struct channel_oil *c_oil) return &c_oil->oil.mf6cc_mcastgrp.sin6_addr; } -static inline mifi_t *oil_parent(struct channel_oil *c_oil) +static inline mifi_t *oil_incoming_vif(struct channel_oil *c_oil) { return &c_oil->oil.mf6cc_parent; } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index a4c9178bb9fc..4be1d06f12b1 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -29,6 +29,7 @@ #include "pim_register.h" #include "pim_errors.h" #include "pim_bsm.h" +#include "pim6_mld.h" #include static void on_pim_hello_send(struct event *t); @@ -102,6 +103,8 @@ static void sock_close(struct interface *ifp) void pim_sock_delete(struct interface *ifp, const char *delete_message) { + struct pim_interface *pim_ifp = ifp->info; + zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp->name, delete_message); @@ -124,6 +127,10 @@ void pim_sock_delete(struct interface *ifp, const char *delete_message) pim_neighbor_delete_all(ifp, delete_message); sock_close(ifp); + + if (pim_ifp->gm_enable) { + pim_gm_if_reset(ifp); + } } /* For now check dst address for hello, assrt and join/prune is all pim rtr */ diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index dadf29f5353a..27dbb0d6b4e8 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -185,7 +185,6 @@ static int ssmpingd_socket(pim_addr addr, int port, int mttl) ret = ssmpingd_setsockopt(fd, addr, mttl); if (ret) { zlog_warn("ssmpingd_setsockopt failed"); - close(fd); return -1; } diff --git a/pimd/pim_static.c b/pimd/pim_static.c index f4320f0c62a9..b9effa26d1ac 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -44,7 +44,7 @@ static struct static_route *static_route_new(ifindex_t iif, ifindex_t oif, s_route->c_oil.oil_ref_count = 1; *oil_origin(&s_route->c_oil) = source; *oil_mcastgrp(&s_route->c_oil) = group; - *oil_parent(&s_route->c_oil) = iif; + *oil_incoming_vif(&s_route->c_oil) = iif; oil_if_set(&s_route->c_oil, oif, 1); s_route->c_oil.oif_creation[oif] = pim_time_monotonic_sec(); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index fd99e7776112..743a047b0acb 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -1977,7 +1977,7 @@ static bool pim_upstream_kat_start_ok(struct pim_upstream *up) return false; pim_ifp = ifp->info; - if (pim_ifp->mroute_vif_index != *oil_parent(c_oil)) + if (pim_ifp->mroute_vif_index != *oil_incoming_vif(c_oil)) return false; if (pim_if_connected_to_source(up->rpf.source_nexthop.interface, diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 92dcbf9d1d5b..62f00dbf865c 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -51,39 +51,6 @@ static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS) return 0; } -static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - struct pim_instance *pim; - struct pim_interface *pim_ifp; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - if (!ifp) - return 0; - - if (PIM_DEBUG_ZEBRA) - zlog_debug("%s: %s updating from %u to %u", __func__, ifp->name, - vrf_id, new_vrf_id); - - pim = pim_get_pim_instance(new_vrf_id); - if (!pim) - return 0; - - if_update_to_new_vrf(ifp, new_vrf_id); - - pim_ifp = ifp->info; - if (!pim_ifp) - return 0; - - pim_ifp->pim->mcast_if_count--; - pim_ifp->pim = pim; - pim_ifp->pim->mcast_if_count++; - - return 0; -} - #ifdef PIM_DEBUG_IFADDR_DUMP static void dump_if_address(struct interface *ifp) { @@ -463,7 +430,6 @@ static zclient_handler *const pim_handlers[] = { [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update, [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra, - [ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update, #if PIM_IPV == 4 [ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc, diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 05a72269d664..6a026f994767 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -497,14 +497,14 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) int ret; pim_sgaddr more = {}; struct interface *ifp = - pim_if_find_by_vif_index(c_oil->pim, *oil_parent(c_oil)); + pim_if_find_by_vif_index(c_oil->pim, *oil_incoming_vif(c_oil)); if (PIM_DEBUG_ZEBRA) { more.src = *oil_origin(c_oil); more.grp = *oil_mcastgrp(c_oil); - zlog_debug( - "Sending Request for New Channel Oil Information%pSG VIIF %d(%s)", - &more, *oil_parent(c_oil), c_oil->pim->vrf->name); + zlog_debug("Sending Request for New Channel Oil Information%pSG VIIF %d(%s:%s)", + &more, *oil_incoming_vif(c_oil), + ifp ? ifp->name : "Unknown", c_oil->pim->vrf->name); } if (!ifp) diff --git a/python/xref2vtysh.py b/python/xref2vtysh.py index 6dd5c8866ed4..0a7e28ec7ac1 100644 --- a/python/xref2vtysh.py +++ b/python/xref2vtysh.py @@ -36,7 +36,7 @@ "lib/filter.c": "VTYSH_ACL", "lib/filter_cli.c": "VTYSH_ACL", "lib/if.c": "VTYSH_INTERFACE", - "lib/keychain.c": "VTYSH_RIPD|VTYSH_EIGRPD|VTYSH_OSPF6D", + "lib/keychain.c": "VTYSH_KEYS", "lib/mgmt_be_client.c": "VTYSH_STATICD", "lib/mgmt_fe_client.c": "VTYSH_MGMTD", "lib/lib_vty.c": "VTYSH_ALL", diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index b58015a67d89..505290ed3134 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -383,31 +383,6 @@ static int rip_ifp_destroy(struct interface *ifp) return 0; } -/* VRF update for an interface. */ -int rip_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - if (!ifp) - return 0; - - if (IS_RIP_DEBUG_ZEBRA) { - struct vrf *nvrf = vrf_lookup_by_id(new_vrf_id); - - zlog_debug("interface %s VRF change vrf %s(%u) new vrf %s(%u)", - ifp->name, ifp->vrf->name, vrf_id, VRF_LOGNAME(nvrf), - new_vrf_id); - } - - if_update_to_new_vrf(ifp, new_vrf_id); - rip_interface_sync(ifp); - - return 0; -} - static void rip_interface_clean(struct rip_interface *ri) { ri->enable_network = 0; diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 5bf51c2f1528..36b58cb20be1 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -222,7 +222,6 @@ static void rip_zebra_connected(struct zclient *zclient) zclient_handler *const rip_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = rip_interface_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = rip_interface_address_delete, - [ZEBRA_INTERFACE_VRF_UPDATE] = rip_interface_vrf_update, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = rip_zebra_read_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = rip_zebra_read_route, }; diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index a37cb7d092a5..4cb4bb5ef38e 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -264,31 +264,6 @@ static int ripng_ifp_destroy(struct interface *ifp) return 0; } -/* VRF update for an interface. */ -int ripng_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - if (!ifp) - return 0; - - if (IS_RIPNG_DEBUG_ZEBRA) { - struct vrf *nvrf = vrf_lookup_by_id(new_vrf_id); - - zlog_debug("interface %s VRF change vrf %s(%u) new vrf %s(%u)", - ifp->name, ifp->vrf->name, vrf_id, VRF_LOGNAME(nvrf), - new_vrf_id); - } - - if_update_to_new_vrf(ifp, new_vrf_id); - ripng_interface_sync(ifp); - - return 0; -} - void ripng_interface_clean(struct ripng *ripng) { struct interface *ifp; diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 49b8a197add1..bb5a880c0214 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -222,7 +222,6 @@ static void ripng_zebra_connected(struct zclient *zclient) static zclient_handler *const ripng_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = ripng_interface_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = ripng_interface_address_delete, - [ZEBRA_INTERFACE_VRF_UPDATE] = ripng_interface_vrf_update, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = ripng_zebra_read_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = ripng_zebra_read_route, }; diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index c7468b6317c5..3a2bc0c9d37d 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -413,7 +413,6 @@ extern int ripng_interface_add(ZAPI_CALLBACK_ARGS); extern int ripng_interface_delete(ZAPI_CALLBACK_ARGS); extern int ripng_interface_address_add(ZAPI_CALLBACK_ARGS); extern int ripng_interface_address_delete(ZAPI_CALLBACK_ARGS); -extern int ripng_interface_vrf_update(ZAPI_CALLBACK_ARGS); extern void ripng_interface_sync(struct interface *ifp); extern struct ripng *ripng_lookup_by_vrf_id(vrf_id_t vrf_id); diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index f0a75a5fc23a..cf79bacc6b6e 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -402,7 +402,7 @@ DEFPY (install_seg6_routes, sg.r.nhop.gate.ipv6 = seg6_nh6; sg.r.nhop.vrf_id = vrf->vrf_id; sg.r.nhop_group.nexthop = &sg.r.nhop; - nexthop_add_srv6_seg6(&sg.r.nhop, &seg6_seg); + nexthop_add_srv6_seg6(&sg.r.nhop, &seg6_seg, 1); sg.r.vrf_id = vrf->vrf_id; sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, 0, @@ -948,7 +948,7 @@ DEFPY (import_te, static void sharp_srv6_locator_chunk_free(struct prefix_ipv6 *chunk) { - prefix_ipv6_free((struct prefix_ipv6 **)&chunk); + prefix_ipv6_free(&chunk); } DEFPY (sharp_srv6_manager_get_locator_chunk, diff --git a/staticd/static_nb.c b/staticd/static_nb.c index d8b5b167cf22..1c69a58035b9 100644 --- a/staticd/static_nb.c +++ b/staticd/static_nb.c @@ -74,6 +74,21 @@ const struct frr_yang_module_info frr_staticd_info = { .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_color_destroy, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/srv6-segs-stack/entry", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_destroy, + + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/srv6-segs-stack/entry/seg", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_destroy, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry", .cbs = { @@ -182,6 +197,20 @@ const struct frr_yang_module_info frr_staticd_info = { .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_color_destroy, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/srv6-segs-stack/entry", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/srv6-segs-stack/entry/seg", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_destroy, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry", .cbs = { diff --git a/staticd/static_nb.h b/staticd/static_nb.h index ce3644076c01..9f80653b762d 100644 --- a/staticd/static_nb.h +++ b/staticd/static_nb.h @@ -35,6 +35,14 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa struct nb_cb_modify_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_color_destroy( struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_destroy( + struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_destroy( @@ -80,6 +88,14 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr struct nb_cb_modify_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_color_destroy( struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_destroy( + struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_destroy( @@ -147,6 +163,10 @@ int routing_control_plane_protocols_name_validate( #define FRR_STATIC_ROUTE_NHLB_KEY_XPATH "/entry[id='%u']/label" +#define FRR_STATIC_ROUTE_NH_SRV6_SEGS_XPATH "/srv6-segs-stack" + +#define FRR_STATIC_ROUTE_NH_SRV6_KEY_SEG_XPATH "/entry[id='%u']/seg" + /* route-list/srclist */ #define FRR_S_ROUTE_SRC_INFO_KEY_XPATH \ "/frr-routing:routing/control-plane-protocols/" \ diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c index 6673cce108b3..ede2e387544c 100644 --- a/staticd/static_nb_config.c +++ b/staticd/static_nb_config.c @@ -209,6 +209,98 @@ static bool static_nexthop_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +static int nexthop_srv6_segs_stack_entry_create(struct nb_cb_create_args *args) +{ + struct static_nexthop *nh; + uint32_t pos; + uint8_t index; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + nh = nb_running_get_entry(args->dnode, NULL, true); + pos = yang_get_list_pos(args->dnode); + if (!pos) { + flog_warn(EC_LIB_NB_CB_CONFIG_APPLY, + "libyang returns invalid seg position"); + return NB_ERR; + } + /* Mapping to array = list-index -1 */ + index = pos - 1; + memset(&nh->snh_seg.seg[index], 0, sizeof(struct in6_addr)); + nh->snh_seg.num_segs++; + break; + } + + return NB_OK; +} + +static int nexthop_srv6_segs_stack_entry_destroy(struct nb_cb_destroy_args *args) +{ + struct static_nexthop *nh; + uint32_t pos; + uint8_t index; + int old_num_segs; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + nh = nb_running_get_entry(args->dnode, NULL, true); + pos = yang_get_list_pos(args->dnode); + if (!pos) { + flog_warn(EC_LIB_NB_CB_CONFIG_APPLY, + "libyang returns invalid seg position"); + return NB_ERR; + } + index = pos - 1; + old_num_segs = nh->snh_seg.num_segs; + memset(&nh->snh_seg.seg[index], 0, sizeof(struct in6_addr)); + nh->snh_seg.num_segs--; + + if (old_num_segs != nh->snh_seg.num_segs) + nh->state = STATIC_START; + break; + } + + return NB_OK; +} + +static int static_nexthop_srv6_segs_modify(struct nb_cb_modify_args *args) +{ + struct static_nexthop *nh; + uint32_t pos; + uint8_t index; + struct in6_addr old_seg; + struct in6_addr cli_seg; + + nh = nb_running_get_entry(args->dnode, NULL, true); + pos = yang_get_list_pos(lyd_parent(args->dnode)); + if (!pos) { + flog_warn(EC_LIB_NB_CB_CONFIG_APPLY, + "libyang returns invalid seg position"); + return NB_ERR; + } + /* Mapping to array = list-index -1 */ + index = pos - 1; + + old_seg = nh->snh_seg.seg[index]; + yang_dnode_get_ipv6(&cli_seg, args->dnode, NULL); + + memcpy(&nh->snh_seg.seg[index], &cli_seg, sizeof(struct in6_addr)); + + if (memcmp(&old_seg, &nh->snh_seg.seg[index], + sizeof(struct in6_addr)) != 0) + nh->state = STATIC_START; + + return NB_OK; +} + static int nexthop_mpls_label_stack_entry_create(struct nb_cb_create_args *args) { struct static_nexthop *nh; @@ -382,6 +474,13 @@ static int static_nexthop_bh_type_modify(struct nb_cb_modify_args *args) nh_vrf = yang_dnode_get_string(args->dnode, "../vrf"); if (nh_ifname && nh_vrf) { struct vrf *vrf = vrf_lookup_by_name(nh_vrf); + + if (!vrf) { + snprintf(args->errmsg, args->errmsg_len, + "nexthop vrf %s not found", nh_vrf); + return NB_ERR_VALIDATION; + } + struct interface *ifp = if_lookup_by_name(nh_ifname, vrf->vrf_id); @@ -634,6 +733,60 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa return NB_OK; } +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/srv6-segs-stack/entry + */ +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_create( + struct nb_cb_create_args *args) +{ + return nexthop_srv6_segs_stack_entry_create(args); +} + +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_destroy( + struct nb_cb_destroy_args *args) +{ + return nexthop_srv6_segs_stack_entry_destroy(args); +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/srv6-segs-stack/entry/seg + */ +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + if (static_nexthop_srv6_segs_modify(args) != NB_OK) + return NB_ERR; + break; + } + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_destroy( + struct nb_cb_destroy_args *args) +{ + /* + * No operation is required in this call back. + * nexthop_srv6_segs_stack_entry_destroy() will take care + * to reset the seg vaue. + */ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + return NB_OK; +} + /* * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry @@ -1012,6 +1165,60 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr return NB_OK; } +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/srv6-segs-stack/entry + */ +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_create( + struct nb_cb_create_args *args) +{ + return nexthop_srv6_segs_stack_entry_create(args); +} + +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_destroy( + struct nb_cb_destroy_args *args) +{ + return nexthop_srv6_segs_stack_entry_destroy(args); +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/srv6-segs-stack/entry/seg + */ +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + if (static_nexthop_srv6_segs_modify(args) != NB_OK) + return NB_ERR; + break; + } + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_srv6_segs_stack_entry_seg_destroy( + struct nb_cb_destroy_args *args) +{ + /* + * No operation is required in this call back. + * nexthop_mpls_seg_stack_entry_destroy() will take care + * to reset the seg vaue. + */ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + return NB_OK; +} + /* * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry diff --git a/staticd/static_routes.h b/staticd/static_routes.h index 3be6fd6b1402..548148b187f5 100644 --- a/staticd/static_routes.h +++ b/staticd/static_routes.h @@ -9,6 +9,7 @@ #include "lib/bfd.h" #include "lib/mpls.h" +#include "lib/srv6.h" #include "table.h" #include "memory.h" @@ -27,6 +28,12 @@ struct static_nh_label { mpls_label_t label[MPLS_MAX_LABELS]; }; +/* Static route seg information */ +struct static_nh_seg { + int num_segs; + struct in6_addr seg[SRV6_MAX_SIDS]; +}; + enum static_blackhole_type { STATIC_BLACKHOLE_DROP = 0, STATIC_BLACKHOLE_NULL, @@ -129,6 +136,9 @@ struct static_nexthop { /* Label information */ struct static_nh_label snh_label; + /* SRv6 Seg information */ + struct static_nh_seg snh_seg; + /* * Whether to pretend the nexthop is directly attached to the specified * link. Only meaningful when both a gateway address and interface name diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 16e4cb7d83bc..3c60cd7315dd 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -47,6 +47,7 @@ struct static_route_args { const char *source; const char *gateway; const char *interface_name; + const char *segs; const char *flag; const char *tag; const char *distance; @@ -73,12 +74,16 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) char xpath_nexthop[XPATH_MAXLEN]; char xpath_mpls[XPATH_MAXLEN]; char xpath_label[XPATH_MAXLEN]; + char xpath_segs[XPATH_MAXLEN]; + char xpath_seg[XPATH_MAXLEN]; char ab_xpath[XPATH_MAXLEN]; char buf_prefix[PREFIX_STRLEN]; char buf_src_prefix[PREFIX_STRLEN] = {}; char buf_nh_type[PREFIX_STRLEN] = {}; char buf_tag[PREFIX_STRLEN]; uint8_t label_stack_id = 0; + uint8_t segs_stack_id = 0; + char *orig_label = NULL, *orig_seg = NULL; const char *buf_gate_str; uint8_t distance = ZEBRA_STATIC_DISTANCE_DEFAULT; route_tag_t tag = 0; @@ -126,6 +131,7 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) assert(!!str2prefix(args->source, &src)); break; case AFI_L2VPN: + case AFI_LINKSTATE: case AFI_UNSPEC: case AFI_MAX: break; @@ -324,7 +330,7 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY, NULL); - ostr = XSTRDUP(MTYPE_TMP, args->label); + orig_label = ostr = XSTRDUP(MTYPE_TMP, args->label); while ((nump = strsep(&ostr, "/")) != NULL) { snprintf(ab_xpath, sizeof(ab_xpath), FRR_STATIC_ROUTE_NHLB_KEY_XPATH, @@ -337,7 +343,6 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) NB_OP_MODIFY, nump); label_stack_id++; } - XFREE(MTYPE_TMP, ostr); } else { strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls)); strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH, @@ -345,7 +350,38 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY, NULL); } + if (args->segs) { + /* copy of seg string (start) */ + char *ostr; + /* pointer to next segment */ + char *nump; + + strlcpy(xpath_segs, xpath_nexthop, sizeof(xpath_segs)); + strlcat(xpath_segs, FRR_STATIC_ROUTE_NH_SRV6_SEGS_XPATH, + sizeof(xpath_segs)); + nb_cli_enqueue_change(vty, xpath_segs, NB_OP_DESTROY, + NULL); + + orig_seg = ostr = XSTRDUP(MTYPE_TMP, args->segs); + while ((nump = strsep(&ostr, "/")) != NULL) { + snprintf(ab_xpath, sizeof(ab_xpath), + FRR_STATIC_ROUTE_NH_SRV6_KEY_SEG_XPATH, + segs_stack_id); + strlcpy(xpath_seg, xpath_segs, + sizeof(xpath_seg)); + strlcat(xpath_seg, ab_xpath, sizeof(xpath_seg)); + nb_cli_enqueue_change(vty, xpath_seg, + NB_OP_MODIFY, nump); + segs_stack_id++; + } + } else { + strlcpy(xpath_segs, xpath_nexthop, sizeof(xpath_segs)); + strlcat(xpath_segs, FRR_STATIC_ROUTE_NH_SRV6_SEGS_XPATH, + sizeof(xpath_segs)); + nb_cli_enqueue_change(vty, xpath_segs, NB_OP_DESTROY, + NULL); + } if (args->bfd) { char xpath_bfd[XPATH_MAXLEN]; @@ -381,6 +417,11 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) } ret = nb_cli_apply_changes(vty, "%s", xpath_prefix); + + if (orig_label) + XFREE(MTYPE_TMP, orig_label); + if (orig_seg) + XFREE(MTYPE_TMP, orig_seg); } else { if (args->source) { if (args->distance) @@ -951,9 +992,8 @@ DEFPY_YANG(ipv6_route_blackhole_vrf, return static_route_nb_run(vty, &args); } -DEFPY_YANG(ipv6_route_address_interface, - ipv6_route_address_interface_cmd, - "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ +DEFPY_YANG(ipv6_route_address_interface, ipv6_route_address_interface_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ X:X::X:X$gate \ $ifname \ [{ \ @@ -966,33 +1006,28 @@ DEFPY_YANG(ipv6_route_address_interface, |onlink$onlink \ |color (1-4294967295) \ |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \ + |segments WORD \ }]", - NO_STR - IPV6_STR - "Establish static routes\n" - "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 source-dest route\n" - "IPv6 source prefix\n" - "IPv6 gateway address\n" - "IPv6 gateway interface name\n" - "Null interface\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this prefix\n" - VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR - "Treat the nexthop as directly attached to the interface\n" - "SR-TE color\n" - "The SR-TE color to configure\n" - BFD_INTEGRATION_STR - BFD_INTEGRATION_MULTI_HOP_STR - BFD_INTEGRATION_SOURCE_STR - BFD_INTEGRATION_SOURCEV4_STR - BFD_PROFILE_STR - BFD_PROFILE_NAME_STR) + NO_STR IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" VRF_CMD_HELP_STR MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" VRF_CMD_HELP_STR + "Treat the nexthop as directly attached to the interface\n" + "SR-TE color\n" + "The SR-TE color to configure\n" BFD_INTEGRATION_STR + BFD_INTEGRATION_MULTI_HOP_STR BFD_INTEGRATION_SOURCE_STR + BFD_INTEGRATION_SOURCEV4_STR BFD_PROFILE_STR + BFD_PROFILE_NAME_STR "Value of segs\n" + "Segs (SIDs)\n") { struct static_route_args args = { .delete = !!no, @@ -1014,14 +1049,15 @@ DEFPY_YANG(ipv6_route_address_interface, .bfd_multi_hop = !!bfd_multi_hop, .bfd_source = bfd_source_str, .bfd_profile = bfd_profile, + .segs = segments, }; return static_route_nb_run(vty, &args); } DEFPY_YANG(ipv6_route_address_interface_vrf, - ipv6_route_address_interface_vrf_cmd, - "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + ipv6_route_address_interface_vrf_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ X:X::X:X$gate \ $ifname \ [{ \ @@ -1033,32 +1069,28 @@ DEFPY_YANG(ipv6_route_address_interface_vrf, |onlink$onlink \ |color (1-4294967295) \ |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \ + |segments WORD \ }]", - NO_STR - IPV6_STR - "Establish static routes\n" - "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 source-dest route\n" - "IPv6 source prefix\n" - "IPv6 gateway address\n" - "IPv6 gateway interface name\n" - "Null interface\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this prefix\n" - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR - "Treat the nexthop as directly attached to the interface\n" - "SR-TE color\n" - "The SR-TE color to configure\n" - BFD_INTEGRATION_STR - BFD_INTEGRATION_MULTI_HOP_STR - BFD_INTEGRATION_SOURCE_STR - BFD_INTEGRATION_SOURCEV4_STR - BFD_PROFILE_STR - BFD_PROFILE_NAME_STR) + NO_STR IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" VRF_CMD_HELP_STR + "Treat the nexthop as directly attached to the interface\n" + "SR-TE color\n" + "The SR-TE color to configure\n" BFD_INTEGRATION_STR + BFD_INTEGRATION_MULTI_HOP_STR BFD_INTEGRATION_SOURCE_STR + BFD_INTEGRATION_SOURCEV4_STR BFD_PROFILE_STR + BFD_PROFILE_NAME_STR "Value of segs\n" + "Segs (SIDs)\n") { struct static_route_args args = { .delete = !!no, @@ -1080,14 +1112,14 @@ DEFPY_YANG(ipv6_route_address_interface_vrf, .bfd_multi_hop = !!bfd_multi_hop, .bfd_source = bfd_source_str, .bfd_profile = bfd_profile, + .segs = segments, }; return static_route_nb_run(vty, &args); } -DEFPY_YANG(ipv6_route, - ipv6_route_cmd, - "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ +DEFPY_YANG(ipv6_route, ipv6_route_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ $ifname> \ [{ \ tag (1-4294967295) \ @@ -1098,32 +1130,26 @@ DEFPY_YANG(ipv6_route, |nexthop-vrf NAME \ |color (1-4294967295) \ |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \ + |segments WORD \ }]", - NO_STR - IPV6_STR - "Establish static routes\n" - "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 source-dest route\n" - "IPv6 source prefix\n" - "IPv6 gateway address\n" - "IPv6 gateway interface name\n" - "Null interface\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this prefix\n" - VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR - "SR-TE color\n" - "The SR-TE color to configure\n" - BFD_INTEGRATION_STR - BFD_INTEGRATION_MULTI_HOP_STR - BFD_INTEGRATION_SOURCE_STR - BFD_INTEGRATION_SOURCEV4_STR - BFD_PROFILE_STR - BFD_PROFILE_NAME_STR) + NO_STR IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" VRF_CMD_HELP_STR MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" VRF_CMD_HELP_STR "SR-TE color\n" + "The SR-TE color to configure\n" BFD_INTEGRATION_STR + BFD_INTEGRATION_MULTI_HOP_STR BFD_INTEGRATION_SOURCE_STR + BFD_INTEGRATION_SOURCEV4_STR BFD_PROFILE_STR + BFD_PROFILE_NAME_STR "Value of segs\n" + "Segs (SIDs)\n") { struct static_route_args args = { .delete = !!no, @@ -1144,14 +1170,15 @@ DEFPY_YANG(ipv6_route, .bfd_multi_hop = !!bfd_multi_hop, .bfd_source = bfd_source_str, .bfd_profile = bfd_profile, + .segs = segments, + }; return static_route_nb_run(vty, &args); } -DEFPY_YANG(ipv6_route_vrf, - ipv6_route_vrf_cmd, - "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ +DEFPY_YANG(ipv6_route_vrf, ipv6_route_vrf_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ $ifname> \ [{ \ tag (1-4294967295) \ @@ -1161,31 +1188,26 @@ DEFPY_YANG(ipv6_route_vrf, |nexthop-vrf NAME \ |color (1-4294967295) \ |bfd$bfd [{multi-hop$bfd_multi_hop|source X:X::X:X$bfd_source|profile BFDPROF$bfd_profile}] \ + |segments WORD \ }]", - NO_STR - IPV6_STR - "Establish static routes\n" - "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 source-dest route\n" - "IPv6 source prefix\n" - "IPv6 gateway address\n" - "IPv6 gateway interface name\n" - "Null interface\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this prefix\n" - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR - "SR-TE color\n" - "The SR-TE color to configure\n" - BFD_INTEGRATION_STR - BFD_INTEGRATION_MULTI_HOP_STR - BFD_INTEGRATION_SOURCE_STR - BFD_INTEGRATION_SOURCEV4_STR - BFD_PROFILE_STR - BFD_PROFILE_NAME_STR) + NO_STR IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Null interface\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" VRF_CMD_HELP_STR "SR-TE color\n" + "The SR-TE color to configure\n" BFD_INTEGRATION_STR + BFD_INTEGRATION_MULTI_HOP_STR BFD_INTEGRATION_SOURCE_STR + BFD_INTEGRATION_SOURCEV4_STR BFD_PROFILE_STR + BFD_PROFILE_NAME_STR "Value of segs\n" + "Segs (SIDs)\n") { struct static_route_args args = { .delete = !!no, @@ -1206,6 +1228,7 @@ DEFPY_YANG(ipv6_route_vrf, .bfd_multi_hop = !!bfd_multi_hop, .bfd_source = bfd_source_str, .bfd_profile = bfd_profile, + .segs = segments, }; return static_route_nb_run(vty, &args); @@ -1252,6 +1275,39 @@ static int mpls_label_iter_cb(const struct lyd_node *dnode, void *arg) return YANG_ITER_CONTINUE; } +struct srv6_seg_iter { + struct vty *vty; + bool first; +}; + +static int srv6_seg_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct srv6_seg_iter *iter = arg; + char buffer[INET6_ADDRSTRLEN]; + struct in6_addr cli_seg; + + if (yang_dnode_exists(dnode, "./seg")) { + if (iter->first) { + yang_dnode_get_ipv6(&cli_seg, dnode, "./seg"); + if (inet_ntop(AF_INET6, &cli_seg, buffer, + INET6_ADDRSTRLEN) == NULL) { + return 1; + } + vty_out(iter->vty, " segments %s", buffer); + } else { + yang_dnode_get_ipv6(&cli_seg, dnode, "./seg"); + if (inet_ntop(AF_INET6, &cli_seg, buffer, + INET6_ADDRSTRLEN) == NULL) { + return 1; + } + vty_out(iter->vty, "/%s", buffer); + } + iter->first = false; + } + + return YANG_ITER_CONTINUE; +} + static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route, const struct lyd_node *src, const struct lyd_node *path, @@ -1266,6 +1322,7 @@ static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route, uint32_t tag; uint8_t distance; struct mpls_label_iter iter; + struct srv6_seg_iter seg_iter; const char *nexthop_vrf; uint32_t table_id; bool onlink; @@ -1342,6 +1399,11 @@ static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route, yang_dnode_iterate(mpls_label_iter_cb, &iter, nexthop, "./mpls-label-stack/entry"); + seg_iter.vty = vty; + seg_iter.first = true; + yang_dnode_iterate(srv6_seg_iter_cb, &seg_iter, nexthop, + "./srv6-segs-stack/entry"); + nexthop_vrf = yang_dnode_get_string(nexthop, "./vrf"); if (strcmp(vrf, nexthop_vrf)) vty_out(vty, " nexthop-vrf %s", nexthop_vrf); diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 4f3ccde53dab..6abbdadc085d 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -499,6 +499,21 @@ extern void static_zebra_route_add(struct static_path *pn, bool install) for (i = 0; i < api_nh->label_num; i++) api_nh->labels[i] = nh->snh_label.label[i]; } + if (nh->snh_seg.num_segs) { + int i; + + api_nh->seg6local_action = + ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; + SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6); + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); + api.safi = SAFI_UNICAST; + + api_nh->seg_num = nh->snh_seg.num_segs; + for (i = 0; i < api_nh->seg_num; i++) + memcpy(&api_nh->seg6_segs[i], + &nh->snh_seg.seg[i], + sizeof(struct in6_addr)); + } nh_num++; } diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index 84c9f530666b..9d3d0ecbc128 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -847,7 +847,7 @@ static void parse_test(struct peer *peer, struct test_segment *t, int type) ret = bgp_open_option_parse(peer, len, &capability); break; case DYNCAP: - ret = bgp_capability_receive(peer, t->len); + ret = bgp_capability_receive(peer->connection, peer, t->len); break; default: printf("unknown type %u\n", type); diff --git a/tests/bgpd/test_mpath.c b/tests/bgpd/test_mpath.c index bc2c1e8a442f..ebbe3ac3e28f 100644 --- a/tests/bgpd/test_mpath.c +++ b/tests/bgpd/test_mpath.c @@ -467,9 +467,10 @@ int main(void) { int pass_count, fail_count; time_t cur_time; + char buf[32]; time(&cur_time); - printf("BGP Multipath Tests Run at %s", ctime(&cur_time)); + printf("BGP Multipath Tests Run at %s", ctime_r(&cur_time, buf)); if (global_test_init() != 0) { printf("Global init failed. Terminating.\n"); exit(1); diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index bc6eba906905..761b23bf978f 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -660,6 +660,8 @@ static const char *str_from_afi(afi_t afi) return "ipv6"; case AFI_L2VPN: return "l2vpn"; + case AFI_LINKSTATE: + return "link-state"; case AFI_MAX: case AFI_UNSPEC: return "bad-value"; diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz index 20b1dc33f959..195a7dd8c152 100644 Binary files a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz and b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz differ diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c index 0ab40b2ecd8b..66699ec7c056 100644 --- a/tests/lib/test_printfrr.c +++ b/tests/lib/test_printfrr.c @@ -166,6 +166,9 @@ int main(int argc, char **argv) printchk("-77385308584349683 18369358765125201933 feed1278cafef00d", "%Ld %Lu %Lx", ui64, ui64, ui64); + FMT_NSTD(printchk("11110000000011111010010111000011", "%b", 0xf00fa5c3)); + FMT_NSTD(printchk("0b01011010", "%#010b", 0x5a)); + inet_aton("192.168.1.2", &ip); printchk("192.168.1.2", "%pI4", &ip); printchk(" 192.168.1.2", "%20pI4", &ip); diff --git a/tests/topotests/all_protocol_startup/r1/ip_nht.ref b/tests/topotests/all_protocol_startup/r1/ip_nht.ref index 0ef3f4b67535..a2f3d3b0db4e 100644 --- a/tests/topotests/all_protocol_startup/r1/ip_nht.ref +++ b/tests/topotests/all_protocol_startup/r1/ip_nht.ref @@ -1,3 +1,5 @@ +VRF default: + Resolve via default: on 1.1.1.1 resolved via static is directly connected, r1-eth1 (vrf default), weight 1 diff --git a/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref b/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref index 8c9372800758..100a36a8d6ab 100644 --- a/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref +++ b/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref @@ -1,3 +1,5 @@ +VRF default: + Resolve via default: on fc00::2 resolved via connected is directly connected, r1-eth0 (vrf default) @@ -10,4 +12,4 @@ fc00:0:0:8::2000(Connected) resolved via connected is directly connected, r1-eth8 (vrf default) Client list: bgp(fd XX) - + diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py index 4b7c4de80618..c319477c8ae3 100644 --- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py +++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py @@ -38,6 +38,9 @@ required_linux_kernel_version, ) +from lib.topolog import logger +import json + fatal_error = "" @@ -1611,10 +1614,21 @@ def test_resilient_nexthop_group(): ) output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp"') - output = re.findall(r"Buckets", output) + buckets = re.findall(r"Buckets", output) + + output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp json"') + + joutput = json.loads(output) + + # Use the json output and collect the nhg id from it + + for nhgid in joutput: + n = joutput[nhgid] + if "buckets" in n: + break - verify_nexthop_group(185483878) - assert len(output) == 1, "Resilient NHG not created in zebra" + verify_nexthop_group(int(nhgid)) + assert len(buckets) == 1, "Resilient NHG not created in zebra" def test_shutdown_check_stderr(): diff --git a/tests/topotests/bgp_blackhole_community/r4/bgpd.conf b/tests/topotests/bgp_blackhole_community/r4/bgpd.conf index 0ac963e6424c..eca12bd3d9a0 100644 --- a/tests/topotests/bgp_blackhole_community/r4/bgpd.conf +++ b/tests/topotests/bgp_blackhole_community/r4/bgpd.conf @@ -4,3 +4,10 @@ router bgp 65002 no bgp ebgp-requires-policy neighbor r4-eth0 interface remote-as internal ! +address-family ipv4 unicast + neighbor r4-eth0 route-map FOO in +exit-address-family +! +route-map FOO permit 10 + set ipv6 next-hop local fe80::202:ff:fe00:99 +exit diff --git a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py index 16191911a914..9f5c0ef924bd 100644 --- a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py +++ b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py @@ -107,6 +107,23 @@ def _bgp_no_advertise_ibgp(): return topotest.json_cmp(output, expected) + def _bgp_verify_nexthop_validity(): + output = json.loads(tgen.gears["r4"].vtysh_cmd("show bgp nexthop json")) + + expected = { + "ipv6": { + "fe80::202:ff:fe00:99": { + "valid": True, + "complete": True, + "igpMetric": 0, + "pathCount": 2, + "nexthops": [{"interfaceName": "r4-eth0"}], + }, + } + } + + return topotest.json_cmp(output, expected) + test_func = functools.partial(_bgp_converge) success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) @@ -124,7 +141,6 @@ def _bgp_no_advertise_ibgp(): ) step("Check if 172.16.255.254/32 is advertised to iBGP peers") - test_func = functools.partial(_bgp_no_advertise_ibgp) success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) @@ -134,6 +150,11 @@ def _bgp_no_advertise_ibgp(): tgen.gears["r2"] ) + step("Verify if the nexthop set via route-map on r4 is marked valid") + test_func = functools.partial(_bgp_verify_nexthop_validity) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, 'Nexthops are not valid "{}"'.format(tgen.gears["r4"]) + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_comm_list_match/r1/bgpd.conf b/tests/topotests/bgp_comm_list_match/r1/bgpd.conf index 89c9f7728e60..bac841208818 100644 --- a/tests/topotests/bgp_comm_list_match/r1/bgpd.conf +++ b/tests/topotests/bgp_comm_list_match/r1/bgpd.conf @@ -11,6 +11,7 @@ router bgp 65001 ! ip prefix-list p1 seq 5 permit 172.16.255.1/32 ip prefix-list p3 seq 5 permit 172.16.255.3/32 +ip prefix-list p4 seq 5 permit 172.16.255.4/32 ! route-map r2 permit 10 match ip address prefix-list p1 @@ -19,5 +20,9 @@ route-map r2 permit 20 match ip address prefix-list p3 set community 65001:3 route-map r2 permit 30 + match ip address prefix-list p4 + set community 65001:10 65001:12 65001:13 +exit +route-map r2 permit 40 exit ! diff --git a/tests/topotests/bgp_comm_list_match/r1/zebra.conf b/tests/topotests/bgp_comm_list_match/r1/zebra.conf index 17d0ecceaf0d..4219a7ca3a4e 100644 --- a/tests/topotests/bgp_comm_list_match/r1/zebra.conf +++ b/tests/topotests/bgp_comm_list_match/r1/zebra.conf @@ -3,6 +3,7 @@ interface lo ip address 172.16.255.1/32 ip address 172.16.255.2/32 ip address 172.16.255.3/32 + ip address 172.16.255.4/32 ! interface r1-eth0 ip address 192.168.0.1/24 diff --git a/tests/topotests/bgp_comm_list_match/r2/bgpd.conf b/tests/topotests/bgp_comm_list_match/r2/bgpd.conf index 98a978068888..cb2f89e5c5ad 100644 --- a/tests/topotests/bgp_comm_list_match/r2/bgpd.conf +++ b/tests/topotests/bgp_comm_list_match/r2/bgpd.conf @@ -6,6 +6,9 @@ router bgp 65002 neighbor 192.168.0.1 remote-as external neighbor 192.168.0.1 timers 1 3 neighbor 192.168.0.1 timers connect 1 + neighbor 192.168.1.3 remote-as external + neighbor 192.168.1.3 timers 1 3 + neighbor 192.168.1.3 timers connect 1 address-family ipv4 neighbor 192.168.0.1 route-map r1 in neighbor 192.168.0.1 soft-reconfiguration inbound diff --git a/tests/topotests/bgp_comm_list_match/r2/zebra.conf b/tests/topotests/bgp_comm_list_match/r2/zebra.conf index a69c622352b8..7fe82bac8ff7 100644 --- a/tests/topotests/bgp_comm_list_match/r2/zebra.conf +++ b/tests/topotests/bgp_comm_list_match/r2/zebra.conf @@ -2,5 +2,8 @@ interface r2-eth0 ip address 192.168.0.2/24 ! +interface r2-eth1 + ip address 192.168.1.2/24 +! ip forwarding ! diff --git a/tests/topotests/bgp_comm_list_match/r3/bgpd.conf b/tests/topotests/bgp_comm_list_match/r3/bgpd.conf new file mode 100644 index 000000000000..e68a3e44e0c7 --- /dev/null +++ b/tests/topotests/bgp_comm_list_match/r3/bgpd.conf @@ -0,0 +1,21 @@ +! +!debug bgp updates +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + address-family ipv4 + neighbor 192.168.1.2 route-map r1 in + neighbor 192.168.1.2 soft-reconfiguration inbound + exit-address-family +! +bgp community-list 2 seq 10 permit 65001:12 +! +route-map r1 deny 10 + match community 2 any +exit +route-map r1 permit 20 +exit +! diff --git a/tests/topotests/bgp_comm_list_match/r3/zebra.conf b/tests/topotests/bgp_comm_list_match/r3/zebra.conf new file mode 100644 index 000000000000..755dd18bfe88 --- /dev/null +++ b/tests/topotests/bgp_comm_list_match/r3/zebra.conf @@ -0,0 +1,6 @@ +! +interface r3-eth0 + ip address 192.168.1.3/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py index 03fa8da9d4bc..de69ea9387ed 100644 --- a/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py +++ b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py @@ -39,12 +39,15 @@ def build_topo(tgen): - for routern in range(1, 3): + for routern in range(1, 4): tgen.add_router("r{}".format(routern)) switch = tgen.add_switch("s1") switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r2"]) def setup_module(mod): @@ -95,12 +98,41 @@ def _bgp_converge(): } return topotest.json_cmp(output, expected) - step("Initial BGP converge") + step("Initial BGP converge between R1 and R2") test_func = functools.partial(_bgp_converge) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to filter BGP UPDATES with community-list on R2" +def test_bgp_comm_list_match_any(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r3"] + + def _bgp_converge(): + output = json.loads( + router.vtysh_cmd( + "show bgp ipv4 unicast neighbors 192.168.1.2 filtered-routes json" + ) + ) + expected = { + "receivedRoutes": { + "172.16.255.4/32": { + "path": "65002 65001", + }, + } + } + return topotest.json_cmp(output, expected) + + step("Initial BGP converge between R3 and R2") + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to filter BGP UPDATES with community-list on R3" + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_dynamic_capability/r1/frr.conf b/tests/topotests/bgp_dynamic_capability/r1/frr.conf new file mode 100644 index 000000000000..50280a912669 --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/r1/frr.conf @@ -0,0 +1,15 @@ +! +!debug bgp neighbor +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + bgp graceful-restart + bgp long-lived stale-time 10 + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.2 capability dynamic +! diff --git a/tests/topotests/bgp_dynamic_capability/r1/zebra.conf b/tests/topotests/bgp_dynamic_capability/r1/zebra.conf deleted file mode 100644 index b29940f46a31..000000000000 --- a/tests/topotests/bgp_dynamic_capability/r1/zebra.conf +++ /dev/null @@ -1,4 +0,0 @@ -! -int r1-eth0 - ip address 192.168.1.1/24 -! diff --git a/tests/topotests/bgp_dynamic_capability/r2/frr.conf b/tests/topotests/bgp_dynamic_capability/r2/frr.conf new file mode 100644 index 000000000000..16b83a5c58d8 --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/r2/frr.conf @@ -0,0 +1,22 @@ +! +!debug bgp neighbor +! +int lo + ip address 10.10.10.10/32 +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65002 + bgp graceful-restart + bgp long-lived stale-time 20 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + neighbor 192.168.1.1 capability dynamic + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_dynamic_capability/r2/zebra.conf b/tests/topotests/bgp_dynamic_capability/r2/zebra.conf deleted file mode 100644 index cffe8273636d..000000000000 --- a/tests/topotests/bgp_dynamic_capability/r2/zebra.conf +++ /dev/null @@ -1,4 +0,0 @@ -! -int r2-eth0 - ip address 192.168.1.2/24 -! diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py new file mode 100644 index 000000000000..db1eb2723b35 --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" +Test if BGP graceful restart / long-lived graceful restart capabilities +(restart time, stale time and notification flag) are exchanged dynamically +via BGP dynamic capability. +""" + +import os +import re +import sys +import json +import pytest +import functools + +pytestmark = pytest.mark.bgpd + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_dynamic_capability_graceful_restart(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "gracefulRestart": "advertisedAndReceived", + "longLivedGracefulRestart": "advertisedAndReceived", + }, + "gracefulRestartInfo": { + "nBit": True, + "timers": { + "receivedRestartTimer": 120, + "configuredLlgrStaleTime": 10, + }, + "ipv4Unicast": { + "timers": { + "llgrStaleTime": 10, + } + }, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + step( + "Change Graceful-Restart restart-time, LLGR stale-time and check if they changed dynamically" + ) + + # Clear message stats to check if we receive a notification or not after we + # change the settings fo LLGR. + r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") + r2.vtysh_cmd( + """ + configure terminal + router bgp + bgp graceful-restart restart-time 123 + bgp long-lived-graceful-restart stale-time 5 + """ + ) + + def _bgp_check_if_session_not_reset_after_changing_gr_settings(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "gracefulRestart": "advertisedAndReceived", + "longLivedGracefulRestart": "advertisedAndReceived", + }, + "gracefulRestartInfo": { + "nBit": True, + "timers": { + "receivedRestartTimer": 123, + "configuredLlgrStaleTime": 10, + }, + "ipv4Unicast": { + "timers": { + "llgrStaleTime": 5, + } + }, + }, + "messageStats": { + "notificationsRecv": 0, + "capabilityRecv": 2, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_session_not_reset_after_changing_gr_settings, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "Session was reset after changing Graceful-Restart restart-time" + + step( + "Disable Graceful-Restart notification support, and check if it's changed dynamically" + ) + + # Clear message stats to check if we receive a notification or not after we + # change the settings fo LLGR. + r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") + r2.vtysh_cmd( + """ + configure terminal + router bgp + no bgp graceful-restart notification + """ + ) + + def _bgp_check_if_session_not_reset_after_changing_notification(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "gracefulRestart": "advertisedAndReceived", + "longLivedGracefulRestart": "advertisedAndReceived", + }, + "gracefulRestartInfo": { + "nBit": False, + "timers": { + "receivedRestartTimer": 123, + "configuredLlgrStaleTime": 10, + }, + "ipv4Unicast": { + "timers": { + "llgrStaleTime": 5, + } + }, + }, + "messageStats": { + "notificationsRecv": 0, + "capabilityRecv": 1, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_session_not_reset_after_changing_notification, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "Session was reset after changing Graceful-Restart notification support" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py index 9f37440566d8..da45110e3936 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py @@ -36,13 +36,8 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - router.load_config( - TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) - ) + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() @@ -71,8 +66,6 @@ def _bgp_converge(): "neighborCapabilities": { "dynamic": "advertisedAndReceived", }, - "connectionsEstablished": 1, - "connectionsDropped": 0, } } return topotest.json_cmp(output, expected) @@ -85,6 +78,9 @@ def _bgp_converge(): step("Set local-role and check if it's exchanged dynamically") + # Clear message stats to check if we receive a notification or not after we + # change the settings fo LLGR. + r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") r1.vtysh_cmd( """ configure terminal @@ -112,8 +108,10 @@ def _bgp_check_if_session_not_reset(): "dynamic": "advertisedAndReceived", "role": "advertisedAndReceived", }, - "connectionsEstablished": 1, - "connectionsDropped": 0, + "messageStats": { + "notificationsRecv": 0, + "capabilityRecv": 1, + }, } } return topotest.json_cmp(output, expected) diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py index eb81ffeb6962..a653da4655b8 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py @@ -36,13 +36,8 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - router.load_config( - TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) - ) + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() @@ -73,8 +68,6 @@ def _bgp_converge(): "receivedSoftwareVersion": None, }, }, - "connectionsEstablished": 1, - "connectionsDropped": 0, } } return topotest.json_cmp(output, expected) @@ -87,6 +80,9 @@ def _bgp_converge(): step("Enable software version capability and check if it's exchanged dynamically") + # Clear message stats to check if we receive a notification or not after we + # change the settings fo LLGR. + r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") r1.vtysh_cmd( """ configure terminal @@ -115,7 +111,7 @@ def _bgp_software_version(): if not adv and not rcv: return "" - pattern = "FRRouting/\\d.+" + pattern = "^FRRouting/\\d.+" if re.search(pattern, adv) and re.search(pattern, rcv): return adv, rcv except: @@ -133,8 +129,10 @@ def _bgp_software_version(): "receivedSoftwareVersion": rcv, }, }, - "connectionsEstablished": 1, - "connectionsDropped": 0, + "messageStats": { + "notificationsRecv": 0, + "capabilityRecv": 1, + }, } } return topotest.json_cmp(output, expected) diff --git a/tests/topotests/bgp_features/r1/zebra.conf b/tests/topotests/bgp_features/r1/zebra.conf index 61564f1a1a8e..a4e51fdf586d 100644 --- a/tests/topotests/bgp_features/r1/zebra.conf +++ b/tests/topotests/bgp_features/r1/zebra.conf @@ -26,3 +26,4 @@ interface r1-eth3 ip address 192.168.101.1/24 ipv6 address fc00:100:0:1::1/64 ! +no ip nht resolve-via-default diff --git a/tests/topotests/bgp_large_comm_list_match/__init__.py b/tests/topotests/bgp_large_comm_list_match/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/bgp_large_comm_list_match/r1/bgpd.conf b/tests/topotests/bgp_large_comm_list_match/r1/bgpd.conf new file mode 100644 index 000000000000..1a91f0f5ccfe --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r1/bgpd.conf @@ -0,0 +1,28 @@ +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.0.2 remote-as external + neighbor 192.168.0.2 timers 1 3 + neighbor 192.168.0.2 timers connect 1 + address-family ipv4 + redistribute connected + neighbor 192.168.0.2 route-map r2 out + exit-address-family +! +ip prefix-list p1 seq 5 permit 172.16.255.1/32 +ip prefix-list p3 seq 5 permit 172.16.255.3/32 +ip prefix-list p4 seq 5 permit 172.16.255.4/32 +! +route-map r2 permit 10 + match ip address prefix-list p1 + set large-community 65001:1:1 65001:2:1 +route-map r2 permit 20 + match ip address prefix-list p3 + set large-community 65001:3:1 +route-map r2 permit 30 + match ip address prefix-list p4 + set large-community 65001:10:1 65001:12:1 65001:13:1 +exit +route-map r2 permit 40 +exit +! diff --git a/tests/topotests/bgp_large_comm_list_match/r1/zebra.conf b/tests/topotests/bgp_large_comm_list_match/r1/zebra.conf new file mode 100644 index 000000000000..4219a7ca3a4e --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r1/zebra.conf @@ -0,0 +1,12 @@ +! +interface lo + ip address 172.16.255.1/32 + ip address 172.16.255.2/32 + ip address 172.16.255.3/32 + ip address 172.16.255.4/32 +! +interface r1-eth0 + ip address 192.168.0.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_large_comm_list_match/r2/bgpd.conf b/tests/topotests/bgp_large_comm_list_match/r2/bgpd.conf new file mode 100644 index 000000000000..779b705b58ba --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r2/bgpd.conf @@ -0,0 +1,24 @@ +! +!debug bgp updates +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.0.1 remote-as external + neighbor 192.168.0.1 timers 1 3 + neighbor 192.168.0.1 timers connect 1 + neighbor 192.168.1.3 remote-as external + neighbor 192.168.1.3 timers 1 3 + neighbor 192.168.1.3 timers connect 1 + address-family ipv4 + neighbor 192.168.0.1 route-map r1 in + neighbor 192.168.0.1 soft-reconfiguration inbound + exit-address-family +! +bgp large-community-list 1 seq 5 permit 65001:1:1 65001:2:1 +bgp large-community-list 1 seq 10 permit 65001:3:1 +! +route-map r1 deny 10 + match large-community 1 +route-map r1 permit 20 +exit +! diff --git a/tests/topotests/bgp_large_comm_list_match/r2/zebra.conf b/tests/topotests/bgp_large_comm_list_match/r2/zebra.conf new file mode 100644 index 000000000000..7fe82bac8ff7 --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r2/zebra.conf @@ -0,0 +1,9 @@ +! +interface r2-eth0 + ip address 192.168.0.2/24 +! +interface r2-eth1 + ip address 192.168.1.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_large_comm_list_match/r3/bgpd.conf b/tests/topotests/bgp_large_comm_list_match/r3/bgpd.conf new file mode 100644 index 000000000000..e7cb76a43665 --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r3/bgpd.conf @@ -0,0 +1,21 @@ +! +!debug bgp updates +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + address-family ipv4 + neighbor 192.168.1.2 route-map r1 in + neighbor 192.168.1.2 soft-reconfiguration inbound + exit-address-family +! +bgp large-community-list 2 seq 10 permit 65001:12:1 +! +route-map r1 deny 10 + match large-community 2 any +exit +route-map r1 permit 20 +exit +! diff --git a/tests/topotests/bgp_large_comm_list_match/r3/zebra.conf b/tests/topotests/bgp_large_comm_list_match/r3/zebra.conf new file mode 100644 index 000000000000..755dd18bfe88 --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r3/zebra.conf @@ -0,0 +1,6 @@ +! +interface r3-eth0 + ip address 192.168.1.3/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py b/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py new file mode 100644 index 000000000000..483c048d25cf --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright 2023 by 6WIND S.A. +# + +""" +Check if BGP large-community-list works +when used as match rule in incoming route-maps. + +- case 1 should deny incoming updates with large-community-list 1 +bgp large-community-list 1 seq 5 permit 65001:1:1 65001:2:1 +bgp large-community-list 1 seq 10 permit 65001:3:1 +! +route-map r1 deny 10 + match large-community 1 + +route-map test deny 10 + match community 1 + +- case 2 should deny incoming updates with any large-community-list 1 +bgp large-community-list 2 seq 10 permit 65001:12:1 +! +route-map r1 deny 10 + match large-community 2 any +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 4): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_large_comm_list_match(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads( + router.vtysh_cmd( + "show bgp ipv4 unicast neighbors 192.168.0.1 filtered-routes json" + ) + ) + expected = { + "receivedRoutes": { + "172.16.255.1/32": { + "path": "65001", + }, + "172.16.255.3/32": { + "path": "65001", + }, + } + } + return topotest.json_cmp(output, expected) + + step("BGP filtering check with large-community-list on R2") + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), "Failed to filter BGP UPDATES with large-community-list on R2" + + +def test_bgp_large_comm_list_match_any(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r3"] + + def _bgp_converge(): + output = json.loads( + router.vtysh_cmd( + "show bgp ipv4 unicast neighbors 192.168.1.2 filtered-routes json" + ) + ) + expected = { + "receivedRoutes": { + "172.16.255.4/32": { + "path": "65002 65001", + }, + } + } + return topotest.json_cmp(output, expected) + + step("BGP filtering check with large-community-list on R3") + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to filter BGP UPDATES with large-community-list on R3" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_linkstate_topo1/__init__.py b/tests/topotests/bgp_linkstate_topo1/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/bgp_linkstate_topo1/r1/bgp_injector.cfg b/tests/topotests/bgp_linkstate_topo1/r1/bgp_injector.cfg new file mode 100644 index 000000000000..3e4ff6cde3cc --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r1/bgp_injector.cfg @@ -0,0 +1,215 @@ +// Check content with +// cat bgp_injector.cfg | sed -e 's|//.*||g' | jq . +{ +"my_as": 65001, +"hold_time": 30, +"bgp_identifier": "192.0.2.1", +"local_address": "192.0.2.1", +"peer_address": "192.0.2.2", +"mss": 4000, +"port": 179, +"path_attributes": +{ + "as-path": "65001", + "next-hop": "192.0.2.1", + "origin": 0 +}, +"link_states": +[ + { + "nlri": + { + "proto": "01", // IS-IS L1 + "id": "0000000000000020", + "type": "0002", // Link-NLRI + "256": { // Local Link-Node Descriptor TLV + "512": "0000fde9", // AS 65001 + "513": "00000000", // BGP-LS ID + "515": "000000001001" // router-id: 0000.0000.1001 + }, + "257": { // Remote Link-Node Descriptor TLV + "512": "0000fde9", // AS 65001 + "513": "00000000", // BGP-LS ID + "515": "000000001000" // router-id: 0000.0000.1000 + }, + "259": "0a010001", // IPv4 interface address TLV + "260": "0a010002", // IPv4 Neighbor address TLV + "261": "20010000000000000000000000000001", // IPv6 interface address TLV + "262": "20010000000000000000000000000002", // IPv6 Neighbor address TLV + "263": "00000002" // MT-ID + }, + "attr": + { + "1028": "01010101", //IPv4 Router-ID of Local Node TLV + "1030": "0a0a0a0a", //IPv4 Router-ID of Remote Node TLV + "1089": "4d2817c8", // Maximum link bandwidth TLV 1410.07 Mbps + "1090": "4d2817c8", // Maximum reservable link bandwidth TLV 1410.07 Mbps + "1091": "4d2817c84d2817c84d2817c84d2817c84d2817c84d2817c84d2817c84d2817c8", // Unreserved bandwidth TLV + "1092": "00000064", // TE Default Metric TLV + "1095": "00000a", // Metric TLV + // Adjacency SID TLV + // Flags: 0x30, Value Flag (V), Local Flag (L) + // Weight: 0 + // .... 0000 0011 1010 1001 1000 = SID/Label: 15000 + "1099": "30000000003a98", + //Unidirectional Link Delay TLV + // TE Metric Flags: 0x00 + // Delay: 8500 + "1114": "00002134", + //Min/Max Unidirectional Link Delay TLV + // TE Metric Flags: 0x00 + // Min Delay: 8000 + // Reserved: 0x00 + // Max Delay: 9000 + "1115": "00001f4000002328", + "1122": { //Application-Specific Link Attributes TLV + // Type: 1122 + // Length: 48 + // SABM Length: 4 + // UDABM Length: 4 + // Reserved: 0x0000 + // Standard Application Identifier Bit Mask: 0x10000000, Flexible Algorithm (X) + // User-Defined Application Identifier Bit Mask: 00 00 00 00 + "0": "040400001000000000000000", // 0 means encode data directly + "1088": "00000001", // Administrative group (color) TLV + "1092": "00000064", // TE Default Metric TLV + "1115": "00001f4000002328", // Min/Max Unidirectional Link Delay TLV + "1173": "00000001"// Extended Administrative Group TLV + } + } + }, + { + "nlri": + { + "proto": "01", // IS-IS L1 + "id": "0000000000000020", + "type": "0001", // Node-NLRI + "256": { // Local Link-Node Descriptor TLV + "512": "0000fde9", // AS 65001 + "513": "00000000", // BGP-LS ID + "515": "00000000100300" // router-id: 0000.0000.1003.00 + } + }, + "attr": + { + "0": "0107000400000002010a00020108040200027233040300034910000404000403030303040a000cc000000fa004890003004e20040b0003008082040c000c00000003e804890003003a98" + } + }, + { + "nlri": + { + "proto": "03", // OSPFv2 + "id": "0000000000000020", + "type": "0001", // Node-NLRI + "256": { // Local Link-Node Descriptor TLV + "512": "0000fde9", // AS 65001 + "513": "00000000", // BGP-LS ID + "514": "00000000", // Area 0 + "515": "0a0a0a0a" // router-id: 10.10.10.10 + } + }, + "attr": // Attributes to test display + { + "1152": "80", // IGP flags + "1097": "000b00020123000500020123", //opaque Link TLV + "1105": "d123ed", // RTM capabilities + "1172": "dc12fceb04400004000f0001", // L2 bundle member attributes + "1117": "00FFFFFF", //Packet Loss 50.331642% + "1039": "820000800411000400000001041500040000000a0413000480000000", //flex-algo definition + "1044": "82800000000003e8", // flex-algo prefix metric + "1121": "", // graceful link shutdown + "1171": "00120012000000000000000000120012", // source router IPv6 + "1871": "00120012000000000000000000" // Unknown TLV + } + }, + { + "nlri": + { + "proto": "03", // OSPFv2 + "id": "0000000000000020", + "type": "0001", // Node-NLRI + "256": { // Local Link-Node Descriptor TLV + "512": "0000fde9", // AS 65001 + "513": "00000000", // BGP-LS ID + "514": "00000000", // Area 0 + "515": "0a0a0a0a01010101" // router-id: 10.10.10.10:1.1.1.1 + } + } + }, + { + "nlri": + { + "proto": "03", // OSPFv2 + "id": "0000000000000020", + "type": "0003", // IPv4-topo-prefix-NLRI + "256": { // Local Link-Node Descriptor TLV + "512": "0000fde9", // AS 65001 + "513": "00000000", // BGP-LS ID + "514": "00000000", // Area 0 + "515": "0a0a0a0a01010101" // router-id: 10.10.10.10:1.1.1.1 + }, + "265": "18590a0b" // IP Reachability Information TLV (89.10.11.0/24) + } + }, + { + "nlri": + { + "proto": "02", // IS-IS L2 + "id": "0000000000000020", + "type": "0004", // IPv6-topo-prefix-NLRI + "256": { // Local Link-Node Descriptor TLV + "512": "0000fde9", // AS 65001 + "513": "00000000", // BGP-LS ID + "515": "00000000100300" // router-id: 0000.0000.1003.00 + }, + "263": "0002", // MT-ID + // IP Reachability Information TLV (12:12::12:12/128) + "265": "8000120012000000000000000000120012" + } + }, + { + "nlri": + { + "proto": "06", // OSPFv3 + "id": "0000000000000020", + "type": "0004", // IPv6-topo-prefix-NLRI + "256": { // Local Link-Node Descriptor TLV + "512": "0000fde9", // AS 65001 + "513": "00000000", // BGP-LS ID + "514": "00000000", // Area 0 + "515": "0a0a0a0a" // router-id: 10.10.10.10 + }, + "263": "0002", // MT-ID + "264": "01", // OSPF: route-type Intra-Area (0x1) + // IP Reachability Information TLV (12:12::12:12/128) + "265": "8000120012000000000000000000120012" + } + }, + { + "nlri": + { + "proto": "06", // OSPFv3 + "id": "ffffffffffffffff", + "type": "0002", // Link-NLRI + "256": { // Local Link-Node Descriptor TLV + "512": "ffffffff", // AS + "513": "ffffffff", // BGP-LS ID + "514": "ffffffff", // OSPF area ID + "515": "0a0a0a0b02020202" // router-id: 10.10.10.11:2.2.2.2 + }, + "257": { // Remote Link-Node Descriptor TLV + "512": "ffffffff", // AS + "513": "ffffffff", // BGP-LS ID + "514": "ffffffff", // OSPF area ID + "515": "0a0a0a0a01010101" // router-id: 10.10.10.10:1.1.1.1 + }, + "259": "0a010001", // IPv4 interface address TLV + "260": "0a010002", // IPv4 Neighbor address TLV + "261": "20010000000000000000000000000001", // IPv6 interface address TLV + "262": "20010000000000000000000000000002", // IPv6 Neighbor address TLV + "263": "00000002", // MT-ID + "424": "200100000000000001" // unknown TLV + } + } +] +} diff --git a/tests/topotests/bgp_linkstate_topo1/r1/bgp_injector.py b/tests/topotests/bgp_linkstate_topo1/r1/bgp_injector.py new file mode 100755 index 000000000000..314b8fe44c95 --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r1/bgp_injector.py @@ -0,0 +1,596 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MIT + +# +# Copyright 2018 Jorge Borreicho +# Copyright 2023 6WIND S.A. + +""" + BGP prefix injection tool +""" + +import socket +import sys +import time +from datetime import datetime +import struct +import threading +import json +import os +import re +import signal +import errno + + +AFI_IPV4 = 1 +SAFI_UNICAST = 1 + +AFI_LINKSTATE = 16388 +SAFI_LINKSTATE = 71 + +saved_pid = False +global pid_file + +class Unbuffered(object): + def __init__(self, stream): + self.stream = stream + def write(self, data): + self.stream.write(data) + self.stream.flush() + def writelines(self, datas): + self.stream.writelines(datas) + self.stream.flush() + def __getattr__(self, attr): + return getattr(self.stream, attr) + +def keepalive_thread(conn, interval): + + # infinite loop so that function do not terminate and thread do not end. + while True: + time.sleep(interval) + keepalive_bgp(conn) + + +def receive_thread(conn): + + # infinite loop so that function do not terminate and thread do not end. + while True: + + # Receiving from client + r = conn.recv(1500) + while True: + start_ptr = ( + r.find( + b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + ) + + 16 + ) + end_ptr = ( + r[16:].find( + b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + ) + + 16 + ) + if ( + start_ptr >= end_ptr + ): # a single message was sent in the BGP packet OR it is the last message of the BGP packet + decode_bgp(r[start_ptr:]) + break + else: # more messages left to decode + decode_bgp(r[start_ptr:end_ptr]) + r = r[end_ptr:] + + +def decode_bgp(msg): + if len(msg) < 3: + return + msg_length, msg_type = struct.unpack("!HB", msg[0:3]) + if msg_type == 4: + # print(timestamp + " - " + "Received KEEPALIVE") #uncomment to debug + pass + elif msg_type == 2: + timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + print(timestamp + " - " + "Received UPDATE") + elif msg_type == 1: + version, remote_as, holdtime, i1, i2, i3, i4, opt_length = struct.unpack( + "!BHHBBBBB", msg[3:13] + ) + timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + print(timestamp + " - " + "Received OPEN") + print() + print( + "--> Version:" + + str(version) + + ", Remote AS: " + + str(remote_as) + + ", Hold Time:" + + str(holdtime) + + ", Remote ID: " + + str(i1) + + "." + + str(i2) + + "." + + str(i3) + + "." + + str(i4) + ) + print() + elif msg_type == 3: + timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + print(timestamp + " - " + "Received NOTIFICATION") + + +def multiprotocol_capability(afi, safi): + hexstream = bytes.fromhex("02060104") + hexstream += struct.pack("!H", afi) + hexstream += struct.pack("!B", 0) + hexstream += struct.pack("!B", safi) + + return hexstream + + +def open_bgp(conn, config): + + # Build the BGP Message + bgp_version = b"\x04" + bgp_as = struct.pack("!H", config["my_as"]) + bgp_hold_time = struct.pack("!H", config["hold_time"]) + + octet = config["bgp_identifier"].split(".") + bgp_identifier = struct.pack( + "!BBBB", int(octet[0]), int(octet[1]), int(octet[2]), int(octet[3]) + ) + + bgp_opt = b"" + bgp_opt += multiprotocol_capability(AFI_IPV4, SAFI_UNICAST) + bgp_opt += multiprotocol_capability(AFI_LINKSTATE, SAFI_LINKSTATE) + + bgp_opt_lenght = struct.pack("!B", len(bgp_opt)) + + bgp_message = ( + bgp_version + bgp_as + bgp_hold_time + bgp_identifier + bgp_opt_lenght + bgp_opt + ) + + # Build the BGP Header + total_length = len(bgp_message) + 16 + 2 + 1 + bgp_marker = b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + bgp_length = struct.pack("!H", total_length) + bgp_type = b"\x01" + bgp_header = bgp_marker + bgp_length + bgp_type + + bgp_packet = bgp_header + bgp_message + + conn.send(bgp_packet) + return 0 + + +def keepalive_bgp(conn): + + # Build the BGP Header + total_length = 16 + 2 + 1 + bgp_marker = b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + bgp_length = struct.pack("!H", total_length) + bgp_type = b"\x04" + bgp_header = bgp_marker + bgp_length + bgp_type + + bgp_packet = bgp_header + + conn.send(bgp_packet) + return 0 + + +def encode_ipv4_prefix(address, netmask): + + octet = address.split(".") + length = struct.pack("!B", int(netmask)) + + if int(netmask) <= 8: + prefix = struct.pack("!B", int(octet[0])) + elif int(netmask) <= 16: + prefix = struct.pack("!BB", int(octet[0]), int(octet[1])) + elif int(netmask) <= 24: + prefix = struct.pack("!BBB", int(octet[0]), int(octet[1]), int(octet[2])) + else: + prefix = struct.pack( + "!BBBB", int(octet[0]), int(octet[1]), int(octet[2]), int(octet[3]) + ) + + return length + prefix + + +def encode_path_attribute_mp_reach_nrli(afi, safi, data, config): + hexstream = b"" + hexstream += b"\x90" # flags optional, extended + hexstream += struct.pack("!B", 14) # type code MP_REACH_NLRI + + hexstream2 = b"" + hexstream2 += struct.pack("!H", afi) + hexstream2 += struct.pack("!B", safi) + hexstream2 += struct.pack("!B", 4) # nexthop length + hexstream2 += socket.inet_aton(config["local_address"]) # nexthop IPv4 + hexstream2 += b"\x00" # SNPA + hexstream2 += data + + hexstream += struct.pack("!H", len(hexstream2)) # length + hexstream += hexstream2 + + return hexstream + + +def encode_path_attribute_linkstate(data): + hexstream = b"" + hexstream += b"\x80" # flags optional + hexstream += struct.pack("!B", 29) # type code BGP-LS + hexstream += struct.pack("!B", len(data)) # length + hexstream += data + + return hexstream + + +def encode_path_attribute(type, value): + + path_attributes = { + "origin": [b"\x40", 1], + "as-path": [b"\x40", 2], + "next-hop": [b"\x40", 3], + "med": [b"\x80", 4], + "local_pref": [b"\x40", 5], + "communities": [b"\xc0", 8], + } + + attribute_flag = path_attributes[type][0] + attribute_type_code = struct.pack("!B", int(path_attributes[type][1])) + + if type == "origin": + attribute_value = struct.pack("!B", value) + elif type == "as-path": + as_number_list = value.split(" ") + attribute_value = struct.pack("!BB", 2, len(as_number_list)) + for as_number in as_number_list: + attribute_value += struct.pack("!H", int(as_number)) + elif type == "next-hop": + octet = value.split(".") + attribute_value = struct.pack( + "!BBBB", int(octet[0]), int(octet[1]), int(octet[2]), int(octet[3]) + ) + elif type == "med": + attribute_value = struct.pack("!I", value) + elif type == "local_pref": + attribute_value = struct.pack("!I", value) + elif type == "communities": + communities_list = value.split(" ") + attribute_value = b"" + for community in communities_list: + aux = community.split(":") + attribute_value += struct.pack("!HH", int(aux[0]), int(aux[1])) + + attribute_length = struct.pack("!B", len(attribute_value)) + + return attribute_flag + attribute_type_code + attribute_length + attribute_value + + +def encode_tlvs(tlvs): + stream = b"" + for key, tlv_data in tlvs.items(): + if isinstance(key, str) and key.isdigit(): + tlv_type = int(key) + else: + # key is not a TLV + continue + if isinstance(tlv_data, str): + if tlv_type != 0: + # TLV type 0 is fake TLV + stream += struct.pack("!H", tlv_type) + stream += struct.pack("!H", len(bytes.fromhex(tlv_data))) + stream += bytes.fromhex(tlv_data) + elif isinstance(tlv_data, dict): + # TLV contains sub-TLV + stream += struct.pack("!H", tlv_type) + + stream_subtlv = encode_tlvs(tlv_data) + stream += struct.pack("!H", len(stream_subtlv)) + stream += stream_subtlv + else: + # invalid input + assert 0 + + return stream + + +def encode_linkstate_nrli_tlv(nlri): + stream = b"" + stream += bytes.fromhex(nlri["type"]) + + stream2 = b"" + stream2 += bytes.fromhex(nlri["proto"]) + stream2 += bytes.fromhex(nlri["id"]) + stream2 += encode_tlvs(nlri) + + stream += struct.pack("!H", len(stream2)) + stream += stream2 + + return stream + + +def update_bgp(conn, link_state, config): + + # Build the BGP Message + + # Expired Routes + # 1 - Withdrawn Routes + + bgp_withdrawn_routes = b"" + max_length_reached = False + + bgp_withdrawn_routes_length = struct.pack("!H", len(bgp_withdrawn_routes)) + bgp_withdrawn_routes = bgp_withdrawn_routes_length + bgp_withdrawn_routes + + # New Routes + # 2 - Path Attributes + + path_attributes = config["path_attributes"] + bgp_mss = config["mss"] + + bgp_total_path_attributes = b"" + + # encode link-state MP_REACH NLRI + data = encode_linkstate_nrli_tlv(link_state["nlri"]) + bgp_total_path_attributes += encode_path_attribute_mp_reach_nrli( + AFI_LINKSTATE, SAFI_LINKSTATE, data, config + ) + + # encode classic attributes + for key in path_attributes.keys(): + bgp_total_path_attributes += encode_path_attribute(key, path_attributes[key]) + + # encode link-state attributes + if "attr" in link_state: + data = encode_tlvs(link_state["attr"]) + else: + data = b"" + bgp_total_path_attributes += encode_path_attribute_linkstate(data) + + bgp_total_path_attributes_length = struct.pack("!H", len(bgp_total_path_attributes)) + bgp_total_path_attributes = ( + bgp_total_path_attributes_length + bgp_total_path_attributes + ) + + # 3- Network Layer Reachability Information (NLRI) + + bgp_new_routes = b"" + + bgp_message = bgp_withdrawn_routes + bgp_total_path_attributes + bgp_new_routes + + # Build the BGP Header + total_length = len(bgp_message) + 16 + 2 + 1 + bgp_marker = b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + bgp_length = struct.pack("!H", total_length) + bgp_type = b"\x02" + bgp_header = bgp_marker + bgp_length + bgp_type + + bgp_packet = bgp_header + bgp_message + + conn.send(bgp_packet) + + timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + print(timestamp + " - " + "Sent UPDATE") + + return 0 + + +def str2ip(ip_str): + s_octet = ip_str.split(".") + ip_addr = struct.pack( + "!BBBB", int(s_octet[0]), int(s_octet[1]), int(s_octet[2]), int(s_octet[3]) + ) + return ip_addr + + +def check_pid(pid): + if pid < 0: # user input error + return False + if pid == 0: # all processes + return False + try: + os.kill(pid, 0) + return True + except OSError as err: + if err.errno == errno.EPERM: # a process we were denied access to + return True + if err.errno == errno.ESRCH: # No such process + return False + # should never happen + return False + + +def savepid(): + ownid = os.getpid() + + flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY + mode = ((os.R_OK | os.W_OK) << 6) | (os.R_OK << 3) | os.R_OK + + try: + fd = os.open(pid_file, flags, mode) + except OSError: + try: + pid = open(pid_file, "r").readline().strip() + if check_pid(int(pid)): + sys.stderr.write( + "PIDfile already exists and program still running %s\n" % pid_file + ) + return False + else: + # If pid is not running, reopen file without O_EXCL + fd = os.open(pid_file, flags ^ os.O_EXCL, mode) + except (OSError, IOError, ValueError): + sys.stderr.write( + "issue accessing PID file %s (most likely permission or ownership)\n" + % pid_file + ) + return False + + try: + f = os.fdopen(fd, "w") + line = "%d\n" % ownid + f.write(line) + f.close() + saved_pid = True + except IOError: + sys.stderr.write("Can not create PIDfile %s\n" % pid_file) + return False + print("Created PIDfile %s with value %d\n" % (pid_file, ownid)) + return True + + +def removepid(): + if not saved_pid: + return + try: + os.remove(pid_file) + except OSError as exc: + if exc.errno == errno.ENOENT: + pass + else: + sys.stderr.write("Can not remove PIDfile %s\n" % pid_file) + return + sys.stderr.write("Removed PIDfile %s\n" % pid_file) + + +def daemonize(): + try: + pid = os.fork() + if pid > 0: + # Exit first parent + sys.exit(0) + except OSError as e: + print("Fork #1 failed: %d (%s)" % (e.errno, e.strerror)) + sys.exit(1) + + # Decouple from parent environment + os.chdir("/") + os.setsid() + os.umask(0) + + # Do second fork + try: + pid = os.fork() + if pid > 0: + # Exit from second parent + sys.exit(0) + except OSError as e: + print("Fork #2 failed: %d (%s)" % (e.errno, e.strerror)) + sys.exit(1) + + # Redirect standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = open(os.devnull, "r") + so = open(os.devnull, "a+") + se = open(os.devnull, "a+") + + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + + +def term(signal, frame): + timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + print(timestamp + " - " + "^C received, shutting down.\n") + bgp_socket.close() + removepid() + exit() + + +if __name__ == "__main__": + if len(sys.argv) > 1: + # daemonize and log to file + daemonize() + pid_file = os.path.join(sys.argv[1], "bgp_injector.pid") + savepid() + # deal with daemon termination + signal.signal(signal.SIGTERM, term) + signal.signal(signal.SIGINT, term) # CTRL + C + + log_dir = os.path.join(sys.argv[1], "bgp_injector.log") + f = open(log_dir, 'w') + sys.stdout = Unbuffered(f) + sys.stderr = Unbuffered(f) + + timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + print(timestamp + " - " + "Starting BGP injector ") + + CONFIG_FILENAME = os.path.join(sys.path[0], "bgp_injector.cfg") + + timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + print(timestamp + " - " + "Reading config file " + CONFIG_FILENAME) + + input_file = open(CONFIG_FILENAME, "r") + + input = input_file.read() + # cleanup comments that are not supported by JSON + json_input = re.sub(r"//.*\n", "", input, flags=re.MULTILINE) + + config = json.loads(json_input) + + bgp_peer = config["peer_address"] + bgp_local = config["local_address"] + bgp_mss = config["mss"] + bgp_port = config["port"] + rib = dict() + timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + print(timestamp + " - " + "Starting BGP... (peer: " + str(bgp_peer) + ")") + + retry = 30 + while retry: + retry -= 1 + try: + bgp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + bgp_socket.bind((bgp_local, 0)) + bgp_socket.connect((bgp_peer, bgp_port)) + open_bgp(bgp_socket, config) + break + except TimeoutError: + if retry == 0: + timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + print(timestamp + " - " + "Error: timeout connecting to the peer.") + exit() + time.sleep(1) + except OSError as e: + if retry == 0: + timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + print(timestamp + " - " + "Error: cannot connect to the peer: " + str(e)) + exit() + time.sleep(1) + + receive_worker = threading.Thread( + target=receive_thread, args=(bgp_socket,) + ) # wait from BGP msg from peer and process them + receive_worker.setDaemon(True) + receive_worker.start() + + keepalive_worker = threading.Thread( + target=keepalive_thread, + args=( + bgp_socket, + (config["hold_time"]) / 3, + ), + ) # send keep alives every 10s by default + keepalive_worker.setDaemon(True) + keepalive_worker.start() + + # send a first keepalive packet before sending the initial UPDATE packet + keepalive_bgp(bgp_socket) + + timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + print(timestamp + " - " + "BGP is up.") + + time.sleep(3) + for link_state in config["link_states"]: + update_bgp( + bgp_socket, + link_state, + config, + ) + + while True: + time.sleep(60) diff --git a/tests/topotests/bgp_linkstate_topo1/r1/staticd.conf b/tests/topotests/bgp_linkstate_topo1/r1/staticd.conf new file mode 100644 index 000000000000..7f2f057bfeec --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r1/staticd.conf @@ -0,0 +1 @@ +ip route 192.0.2.2/32 192.168.1.2 diff --git a/tests/topotests/bgp_linkstate_topo1/r1/zebra.conf b/tests/topotests/bgp_linkstate_topo1/r1/zebra.conf new file mode 100644 index 000000000000..3307c123f862 --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r1/zebra.conf @@ -0,0 +1,7 @@ +! +interface lo + ip address 192.0.2.1/32 +! +interface r1-eth0 + ip address 192.168.1.1/24 +! \ No newline at end of file diff --git a/tests/topotests/bgp_linkstate_topo1/r2/bgpd.conf b/tests/topotests/bgp_linkstate_topo1/r2/bgpd.conf new file mode 100644 index 000000000000..26ffee9c1b1b --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r2/bgpd.conf @@ -0,0 +1,20 @@ +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.0.2.1 remote-as 65001 + neighbor 192.0.2.1 timers connect 1 + neighbor 192.0.2.1 ebgp-multihop 3 + neighbor 192.0.2.1 update-source 192.0.2.2 + neighbor 192.0.2.3 remote-as 65003 + neighbor 192.0.2.3 timers 1 3 + neighbor 192.0.2.3 timers connect 1 + neighbor 192.0.2.3 ebgp-multihop 3 + neighbor 192.0.2.3 update-source 192.0.2.2 + address-family ipv4 unicast + no neighbor 192.0.2.1 activate + no neighbor 192.0.2.3 activate + exit-address-family + address-family link-state link-state + neighbor 192.0.2.1 activate + neighbor 192.0.2.3 activate + exit-address-family +! \ No newline at end of file diff --git a/tests/topotests/bgp_linkstate_topo1/r2/linkstate.json b/tests/topotests/bgp_linkstate_topo1/r2/linkstate.json new file mode 100644 index 000000000000..1e653c55314a --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r2/linkstate.json @@ -0,0 +1,189 @@ +{ + "routes": { + "Link OSPFv3 ID:0xffffffffffffffff {Local {AS:4294967295 ID:4294967295 Area:4294967295 Rtr:10.10.10.11:2.2.2.2} Remote {AS:4294967295 ID:4294967295 Area:4294967295 Rtr:10.10.10.10:1.1.1.1} IPv4:10.1.0.1 Neigh-IPv4:10.1.0.2 IPv6:2001::1 Neigh-IPv6:2001::2 MT:0,2 424:0x200100000000000001}/XX": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "linkStateNLRI": { + "nlriType": "Link", + "protocol": "OSPFv3", + "identifier": "0xffffffffffffffff", + "localNode": { + "as": 4294967295, + "identifier": 4294967295, + "area": 4294967295, + "routerID": "10.10.10.11:2.2.2.2" + }, + "remoteNode": { + "as": 4294967295, + "identifier": 4294967295, + "area": 4294967295, + "routerID": "10.10.10.10:1.1.1.1" + }, + "interfaceIPv4": "10.1.0.1", + "neighborIPv4": "10.1.0.2", + "interfaceIPv6": "2001::1", + "neighborIPv6": "2001::2", + "mtID": [0, 2], + "424": ["0x2001000000000000", "0x01"] + }, + "weight": 0, + "origin": "IGP" + } + ], + "IPv6-Prefix OSPFv3 ID:0x20 {Local {AS:65001 ID:0 Area:0 Rtr:10.10.10.10} MT:2 OSPF-Route-Type:1 IPv6:12:12::12:12/128}/XX": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "linkStateNLRI": { + "nlriType": "IPv6-Prefix", + "protocol": "OSPFv3", + "identifier": "0x20", + "localNode": { + "as": 65001, + "identifier": 0, + "area": 0, + "routerID": "10.10.10.10" + }, + "ospfRouteType": 1, + "ipReachability": "12:12::12:12/128", + "mtID": [2] + }, + "weight": 0, + "origin": "IGP" + } + ], + "IPv6-Prefix ISIS-L2 ID:0x20 {Local {AS:65001 ID:0 Rtr:0000.0000.1003.00} MT:2 IPv6:12:12::12:12/128}/XX": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "linkStateNLRI": { + "nlriType": "IPv6-Prefix", + "protocol": "ISIS-L2", + "identifier": "0x20", + "localNode": { + "as": 65001, + "identifier": 0, + "routerID": "0000.0000.1003.00" + }, + "ipReachability": "12:12::12:12/128", + "mtID": [2] + }, + "weight": 0, + "origin": "IGP" + } + ], + "IPv4-Prefix OSPFv2 ID:0x20 {Local {AS:65001 ID:0 Area:0 Rtr:10.10.10.10:1.1.1.1} IPv4:89.10.11.0/24}/XX": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "linkStateNLRI": { + "nlriType": "IPv4-Prefix", + "protocol": "OSPFv2", + "identifier": "0x20", + "localNode": { + "as": 65001, + "identifier": 0, + "area": 0, + "routerID": "10.10.10.10:1.1.1.1" + }, + "ipReachability": "89.10.11.0/24" + }, + "weight": 0, + "origin": "IGP" + } + ], + "Node OSPFv2 ID:0x20 {Local {AS:65001 ID:0 Area:0 Rtr:10.10.10.10:1.1.1.1}}/XX": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "linkStateNLRI": { + "nlriType": "Node", + "protocol": "OSPFv2", + "identifier": "0x20", + "localNode": { + "as": 65001, + "identifier": 0, + "area": 0, + "routerID": "10.10.10.10:1.1.1.1" + } + }, + "weight": 0, + "origin": "IGP" + } + ], + "Node OSPFv2 ID:0x20 {Local {AS:65001 ID:0 Area:0 Rtr:10.10.10.10}}/XX": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "linkStateNLRI": { + "nlriType": "Node", + "protocol": "OSPFv2", + "identifier": "0x20", + "localNode": { + "as": 65001, + "identifier": 0, + "area": 0, + "routerID": "10.10.10.10" + } + }, + "weight": 0, + "origin": "IGP" + } + ], + "Node ISIS-L1 ID:0x20 {Local {AS:65001 ID:0 Rtr:0000.0000.1003.00}}/XX": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "linkStateNLRI": { + "nlriType": "Node", + "protocol": "ISIS-L1", + "identifier": "0x20", + "localNode": { + "as": 65001, + "identifier": 0, + "routerID": "0000.0000.1003.00" + } + }, + "weight": 0, + "origin": "IGP" + } + ], + "Link ISIS-L1 ID:0x20 {Local {AS:65001 ID:0 Rtr:0000.0000.1001} Remote {AS:65001 ID:0 Rtr:0000.0000.1000} IPv4:10.1.0.1 Neigh-IPv4:10.1.0.2 IPv6:2001::1 Neigh-IPv6:2001::2 MT:0,2}/XX": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "linkStateNLRI": { + "nlriType": "Link", + "protocol": "ISIS-L1", + "identifier": "0x20", + "localNode": { + "as": 65001, + "identifier": 0, + "routerID": "0000.0000.1001" + }, + "remoteNode": { + "as": 65001, + "identifier": 0, + "routerID": "0000.0000.1000" + }, + "interfaceIPv4": "10.1.0.1", + "neighborIPv4": "10.1.0.2", + "interfaceIPv6": "2001::1", + "neighborIPv6": "2001::2", + "mtID": [0, 2] + }, + "weight": 0, + "origin": "IGP" + } + ] + } +} diff --git a/tests/topotests/bgp_linkstate_topo1/r2/linkstate_detail.json b/tests/topotests/bgp_linkstate_topo1/r2/linkstate_detail.json new file mode 100644 index 000000000000..06498f3bb98d --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r2/linkstate_detail.json @@ -0,0 +1,325 @@ +{ + "Node OSPFv2 ID:0x20 {Local {AS:65001 ID:0 Area:0 Rtr:10.10.10.10}}/XX": { + "1152": { + "description": "IGP Flags", + "type": 1152, + "length": 1, + "data": "0b10000000" + }, + "1097": { + "description": "Opaque Link Attribute", + "type": 1097, + "length": 12, + "data": { + "11": { + "type": 11, + "length": 2, + "data": "0x0123" + }, + "5": { + "type": 5, + "length": 2, + "data": "0x0123" + } + } + }, + "1105": { + "description": "RTM Capability", + "type": 1105, + "length": 3, + "data": { + "flags": "0b110", + "values": "0x11ed" + } + }, + "1172": { + "description": "L2 Bundle Member Attributes", + "type": 1172, + "length": 12, + "data": { + "descriptor": "0xdc12fceb", + "1088": { + "description": "Administrative group", + "type": 1088, + "length": 4, + "data": "0x000f0001" + } + } + }, + "1117": { + "description": "Unidirectional Link Loss", + "type": 1117, + "length": 4, + "data": { + "anomalous": false, + "lossPercent": 50.33164596557617 + } + }, + "1039": { + "description": "Flexible Algorithm Definition", + "type": 1039, + "length": 28, + "data": { + "flexAlgo": 130, + "metricType": 0, + "calcType": 0, + "priority": 128, + "1041": { + "description": "Flexible Algorithm Include Any Affinity", + "type": 1041, + "length": 4, + "data": "0x00000001" + }, + "1045": { + "description": "Flexible Algorithm Exclude SRLG", + "type": 1045, + "length": 4, + "data": [ + 10 + ] + }, + "1043": { + "description": "Flexible Algorithm Definition Flags", + "type": 1043, + "length": 4, + "data": "0b10000000 00000000 00000000 00000000" + } + } + }, + "1044": { + "description": "Flexible Algorithm Prefix Metric", + "type": 1044, + "length": 8, + "data": { + "flexAlgo": 130, + "flags": "0b10000000", + "metric": 1000 + } + }, + "1121": { + "description": "Graceful-Link-Shutdown TLV", + "type": 1121, + "length": 0 + }, + "1171": { + "description": "Source Router Identifier", + "type": 1171, + "length": 16, + "data": "12:12::12:12" + }, + "1871": { + "type": 1871, + "length": 13, + "data": "0x00120012000000000000000000" + } + }, + "Node ISIS-L1 ID:0x20 {Local {AS:65001 ID:0 Rtr:0000.0000.1003.00}}/XX": { + "263": { + "description": "Multi-Topology ID", + "type": 263, + "length": 4, + "data": [ + 0, + 2 + ] + }, + "266": { + "description": "Node MSD", + "type": 266, + "length": 2, + "data": [ + { + "type": 1, + "value": 8 + } + ] + }, + "1026": { + "description": "Node Name", + "type": 1026, + "length": 2, + "data": "r3" + }, + "1027": { + "description": "IS-IS Area Identifier", + "type": 1027, + "length": 3, + "data": "49.1000" + }, + "1028": { + "description": "IPv4 Router-ID of Local Node", + "type": 1028, + "length": 4, + "data": "3.3.3.3" + }, + "1034": { + "description": "SR Capabilities", + "type": 1034, + "length": 12, + "data": { + "flags": "0b11000000", + "range": 4000, + "1161": { + "description": "SID/Label", + "type": 1161, + "length": 3, + "data": { + "fromLabel": 20000 + } + } + } + }, + "1035": { + "description": "SR Algorithm", + "type": 1035, + "length": 3, + "data": [ + 0, + 128, + 130 + ] + }, + "1036": { + "description": "SR Local Block", + "type": 1036, + "length": 12, + "data": { + "flags": "0b00000000", + "range": 1000, + "1161": { + "description": "SID/Label", + "type": 1161, + "length": 3, + "data": { + "fromLabel": 15000 + } + } + } + } + }, + "Link ISIS-L1 ID:0x20 {Local {AS:65001 ID:0 Rtr:0000.0000.1001} Remote {AS:65001 ID:0 Rtr:0000.0000.1000} IPv4:10.1.0.1 Neigh-IPv4:10.1.0.2 IPv6:2001::1 Neigh-IPv6:2001::2 MT:0,2}/XX": { + "1028": { + "description": "IPv4 Router-ID of Local Node", + "type": 1028, + "length": 4, + "data": "1.1.1.1" + }, + "1030": { + "description": "IPv4 Router-ID of Remote Node", + "type": 1030, + "length": 4, + "data": "10.10.10.10" + }, + "1089": { + "description": "Maximum link bandwidth", + "type": 1089, + "length": 4, + "data": 176258176, + "dataUnit": "bps" + }, + "1090": { + "description": "Max. reservable link bandwidth", + "type": 1090, + "length": 4, + "data": 176258176, + "dataUnit": "bps" + }, + "1091": { + "description": "Unreserved bandwidth", + "type": 1091, + "length": 32, + "dataUnit": "bps", + "data": { + "0": 176258176, + "1": 176258176, + "2": 176258176, + "3": 176258176, + "4": 176258176, + "5": 176258176, + "6": 176258176, + "7": 176258176 + } + }, + "1092": { + "description": "TE Default Metric", + "type": 1092, + "length": 4, + "data": 100 + }, + "1095": { + "description": "IGP Metric", + "type": 1095, + "length": 3, + "data": 10 + }, + "1099": { + "description": "Adjacency SID", + "type": 1099, + "length": 7, + "data": { + "flags": "0b00110000", + "weight": 0, + "sid": 15000 + } + }, + "1114": { + "description": "Unidirectional Link Delay", + "type": 1114, + "length": 4, + "data": { + "anomalous": false, + "delay": 8500 + }, + "dataUnit": "microseconds" + }, + "1115": { + "description": "Min/Max Unidirectional Link Delay", + "type": 1115, + "length": 8, + "data": { + "anomalous": false, + "minDelay": 8000, + "maxDelay": 9000 + }, + "dataUnit": "microseconds" + }, + "1122": { + "description": "Application-Specific Link Attributes", + "type": 1122, + "length": 48, + "data": { + "sabmFlags": "0b00010000 00000000 00000000 00000000", + "udabmFlags": "0b00000000 00000000 00000000 00000000", + "1088": { + "description": "Administrative group", + "type": 1088, + "length": 4, + "data": "0x00000001" + }, + "1092": { + "description": "TE Default Metric", + "type": 1092, + "length": 4, + "data": 100 + }, + "1115": { + "description": "Min/Max Unidirectional Link Delay", + "type": 1115, + "length": 8, + "data": { + "anomalous": false, + "minDelay": 8000, + "maxDelay": 9000 + }, + "dataUnit": "microseconds" + }, + "1173": { + "description": "Extended Administrative Group", + "type": 1173, + "length": 4, + "data": "0x00000001" + } + } + } + } +} diff --git a/tests/topotests/bgp_linkstate_topo1/r2/staticd.conf b/tests/topotests/bgp_linkstate_topo1/r2/staticd.conf new file mode 100644 index 000000000000..4ce3f7b9b131 --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r2/staticd.conf @@ -0,0 +1,2 @@ +ip route 192.0.2.1/32 192.168.1.1 +ip route 192.0.2.3/32 192.168.2.3 \ No newline at end of file diff --git a/tests/topotests/bgp_linkstate_topo1/r2/zebra.conf b/tests/topotests/bgp_linkstate_topo1/r2/zebra.conf new file mode 100644 index 000000000000..586dc0acad4d --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r2/zebra.conf @@ -0,0 +1,11 @@ +! +int lo + ip address 192.0.2.2/32 +! +interface r2-eth0 + ip address 192.168.1.2/24 +! +interface r2-eth1 + ip address 192.168.2.2/24 +! + diff --git a/tests/topotests/bgp_linkstate_topo1/r3/bgpd.conf b/tests/topotests/bgp_linkstate_topo1/r3/bgpd.conf new file mode 100644 index 000000000000..88693a375000 --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r3/bgpd.conf @@ -0,0 +1,14 @@ +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.0.2.2 remote-as 65002 + neighbor 192.0.2.2 timers 1 3 + neighbor 192.0.2.2 timers connect 1 + neighbor 192.0.2.2 ebgp-multihop 3 + neighbor 192.0.2.2 update-source 192.0.2.3 + address-family ipv4 unicast + no neighbor 192.0.2.2 activate + exit-address-family + address-family link-state link-state + neighbor 192.0.2.2 activate + exit-address-family +! \ No newline at end of file diff --git a/tests/topotests/bgp_linkstate_topo1/r3/linkstate.json b/tests/topotests/bgp_linkstate_topo1/r3/linkstate.json new file mode 120000 index 000000000000..588691dcf79b --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r3/linkstate.json @@ -0,0 +1 @@ +../r2/linkstate.json \ No newline at end of file diff --git a/tests/topotests/bgp_linkstate_topo1/r3/linkstate_detail.json b/tests/topotests/bgp_linkstate_topo1/r3/linkstate_detail.json new file mode 120000 index 000000000000..ec06e56c667b --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r3/linkstate_detail.json @@ -0,0 +1 @@ +../r2/linkstate_detail.json \ No newline at end of file diff --git a/tests/topotests/bgp_linkstate_topo1/r3/staticd.conf b/tests/topotests/bgp_linkstate_topo1/r3/staticd.conf new file mode 100644 index 000000000000..e8a3198ba7e6 --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r3/staticd.conf @@ -0,0 +1 @@ +ip route 192.0.2.2/32 192.168.2.2 \ No newline at end of file diff --git a/tests/topotests/bgp_linkstate_topo1/r3/zebra.conf b/tests/topotests/bgp_linkstate_topo1/r3/zebra.conf new file mode 100644 index 000000000000..532aede2e864 --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/r3/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 192.0.2.3/32 +! +interface r3-eth0 + ip address 192.168.2.3/24 +! diff --git a/tests/topotests/bgp_linkstate_topo1/test_bgp_linkstate_topo1.py b/tests/topotests/bgp_linkstate_topo1/test_bgp_linkstate_topo1.py new file mode 100644 index 000000000000..5593b45fba33 --- /dev/null +++ b/tests/topotests/bgp_linkstate_topo1/test_bgp_linkstate_topo1.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright 2023 6WIND S.A. + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 4): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname)) + ) + if rname == "r1": + # use bgp_injector.py to inject BGP prefixes + continue + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + r1_path = os.path.join(CWD, "r1") + log_dir = os.path.join(tgen.logdir, "r1") + tgen.gears["r1"].cmd("chmod u+x {}/bgp_injector.py".format(r1_path)) + tgen.gears["r1"].run("{}/bgp_injector.py {}".format(r1_path, log_dir)) + + +def teardown_module(mod): + tgen = get_topogen() + + log_dir = os.path.join(tgen.logdir, "r1") + pid_file = os.path.join(log_dir, "bgp_injector.pid") + + logger.info("r1: sending SIGTERM to bgp_injector") + tgen.gears["r1"].cmd("kill $(cat {})".format(pid_file)) + tgen.stop_topology() + + +def test_show_bgp_link_state(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _remove_prefixlen(tmp_json): + new_json = { + prefix.split("}/")[0] + "}/XX": data + for prefix, data in tmp_json["routes"].items() + } + + return new_json + + def _show_bgp_link_state_json(rname, tmp_expected): + tmp_output = json.loads( + tgen.gears[rname].vtysh_cmd("show bgp link-state link-state json") + ) + # prefix length is the size of prefix in memory + # which differs on 32 and 64 bits. + # do not compare the prefix length + output = _remove_prefixlen(tmp_output) + expected = _remove_prefixlen(tmp_expected) + + return topotest.json_cmp(output, expected) + + step("Check BGP Link-State tables") + for rname in ["r2", "r3"]: + expected = open(os.path.join(CWD, "{}/linkstate.json".format(rname))).read() + expected_json = json.loads(expected) + test_func = functools.partial(_show_bgp_link_state_json, rname, expected_json) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see BGP prefixes on {}".format(rname) + + +def test_show_bgp_link_state_detail(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _show_bgp_link_state_json(rname, expected): + output = json.loads( + tgen.gears[rname].vtysh_cmd("show bgp link-state link-state detail-routes json") + ) + json_output = { + prefix.split("/")[0] + "/XX": item["linkStateAttributes"] + for prefix, data in output["routes"].items() + for item in data + if "linkStateAttributes" in item + } + + return topotest.json_cmp(json_output, expected) + + step("Check BGP Link-State Attributes tables") + for rname in ["r2", "r3"]: + expected = open( + os.path.join(CWD, "{}/linkstate_detail.json".format(rname)) + ).read() + expected_json = json.loads(expected) + test_func = functools.partial(_show_bgp_link_state_json, rname, expected_json) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to display BGP-LS Attributes on {}".format(rname) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_remove_private_as_route_map/__init__.py b/tests/topotests/bgp_remove_private_as_route_map/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/bgp_dynamic_capability/r1/bgpd.conf b/tests/topotests/bgp_remove_private_as_route_map/r1/frr.conf similarity index 73% rename from tests/topotests/bgp_dynamic_capability/r1/bgpd.conf rename to tests/topotests/bgp_remove_private_as_route_map/r1/frr.conf index 113936df4c0f..b2dba7d3fe9b 100644 --- a/tests/topotests/bgp_dynamic_capability/r1/bgpd.conf +++ b/tests/topotests/bgp_remove_private_as_route_map/r1/frr.conf @@ -1,10 +1,10 @@ ! -!debug bgp neighbor +int r1-eth0 + ip address 192.168.1.1/24 ! router bgp 65001 no bgp ebgp-requires-policy neighbor 192.168.1.2 remote-as external neighbor 192.168.1.2 timers 1 3 neighbor 192.168.1.2 timers connect 1 - neighbor 192.168.1.2 capability dynamic ! diff --git a/tests/topotests/bgp_remove_private_as_route_map/r2/frr.conf b/tests/topotests/bgp_remove_private_as_route_map/r2/frr.conf new file mode 100644 index 000000000000..9c423cea8cf4 --- /dev/null +++ b/tests/topotests/bgp_remove_private_as_route_map/r2/frr.conf @@ -0,0 +1,19 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 + ip address 192.168.2.1/32 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + address-family ipv4 unicast + redistribute connected + neighbor 192.168.1.1 route-map r1 out + neighbor 192.168.1.1 remove-private-AS all + exit-address-family +! +route-map r1 permit 10 + set as-path prepend 65123 4200000001 +! diff --git a/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py new file mode 100644 index 000000000000..2ae6f7fc9ebe --- /dev/null +++ b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" +Test if private AS is removed from AS_PATH attribute when route-map is used (prepend). +""" + +import os +import re +import sys +import json +import pytest +import functools + +pytestmark = pytest.mark.bgpd + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 3): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_remove_private_as_route_map(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _check_routes(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "192.168.2.1/32": [ + { + "valid": True, + "path": "65002", + } + ] + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_routes, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "65123 4200000001 ASNs should be removed from AS_PATH attribute" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py index 583d89d40f02..6b6153db4630 100755 --- a/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py +++ b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py @@ -146,8 +146,8 @@ def _bgp_converge_prefixes(): def _snmpwalk_remote_addr(): expected = { - "1.3.6.1.3.5.1.1.2.1.5.1.4.192.168.12.1": "C0 A8 0C 01", - "1.3.6.1.3.5.1.1.2.1.5.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "20 01 0D B8 00 00 00 00 00 00 00 00 00 12 00 01", + "1.3.6.1.3.5.1.1.2.1.5.1.1.192.168.12.1": "C0 A8 0C 01", + "1.3.6.1.3.5.1.1.2.1.5.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "20 01 0D B8 00 00 00 00 00 00 00 00 00 12 00 01", } # bgp4V2PeerRemoteAddr @@ -160,8 +160,8 @@ def _snmpwalk_remote_addr(): def _snmpwalk_peer_state(): expected = { - "1.3.6.1.3.5.1.1.2.1.13.1.4.192.168.12.1": "6", - "1.3.6.1.3.5.1.1.2.1.13.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "6", + "1.3.6.1.3.5.1.1.2.1.13.1.1.192.168.12.1": "6", + "1.3.6.1.3.5.1.1.2.1.13.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "6", } # bgp4V2PeerState @@ -174,8 +174,8 @@ def _snmpwalk_peer_state(): def _snmpwalk_peer_last_error_code_received(): expected = { - "1.3.6.1.3.5.1.1.3.1.1.1.4.192.168.12.1": "0", - "1.3.6.1.3.5.1.1.3.1.1.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "0", + "1.3.6.1.3.5.1.1.3.1.1.1.1.192.168.12.1": "0", + "1.3.6.1.3.5.1.1.3.1.1.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "0", } # bgp4V2PeerLastErrorCodeReceived @@ -190,10 +190,10 @@ def _snmpwalk_peer_last_error_code_received(): def _snmpwalk_origin(): expected = { - "1.3.6.1.3.5.1.1.9.1.9.1.4.10.0.0.0.31.192.168.12.1": "1", - "1.3.6.1.3.5.1.1.9.1.9.1.4.10.0.0.2.32.192.168.12.1": "3", - "1.3.6.1.3.5.1.1.9.1.9.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1", - "1.3.6.1.3.5.1.1.9.1.9.2.16.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "3", + "1.3.6.1.3.5.1.1.9.1.9.1.1.10.0.0.0.31.192.168.12.1": "1", + "1.3.6.1.3.5.1.1.9.1.9.1.1.10.0.0.2.32.192.168.12.1": "3", + "1.3.6.1.3.5.1.1.9.1.9.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1", + "1.3.6.1.3.5.1.1.9.1.9.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "3", } # bgp4V2NlriOrigin @@ -206,10 +206,10 @@ def _snmpwalk_origin(): def _snmpwalk_med(): expected = { - "1.3.6.1.3.5.1.1.9.1.17.1.4.10.0.0.0.31.192.168.12.1": "1", - "1.3.6.1.3.5.1.1.9.1.17.1.4.10.0.0.2.32.192.168.12.1": "2", - "1.3.6.1.3.5.1.1.9.1.17.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1", - "1.3.6.1.3.5.1.1.9.1.17.2.16.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "2", + "1.3.6.1.3.5.1.1.9.1.17.1.1.10.0.0.0.31.192.168.12.1": "1", + "1.3.6.1.3.5.1.1.9.1.17.1.1.10.0.0.2.32.192.168.12.1": "2", + "1.3.6.1.3.5.1.1.9.1.17.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1", + "1.3.6.1.3.5.1.1.9.1.17.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "2", } # bgp4V2NlriMed diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/snmpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/snmpd.conf index 4aff57acaf17..c8d0bab04869 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/snmpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:10.5.5.5:161 +agentAddress udp:161 com2sec public localhost public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/snmpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/snmpd.conf index 29c2041d12fa..c8d0bab04869 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/snmpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:10.6.6.6:161 +agentAddress udp:161 com2sec public localhost public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/snmpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/snmpd.conf index 4aff57acaf17..c8d0bab04869 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/snmpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:10.5.5.5:161 +agentAddress udp:161 com2sec public localhost public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/snmpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/snmpd.conf index 4aff57acaf17..c8d0bab04869 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/snmpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:10.5.5.5:161 +agentAddress udp:161 com2sec public localhost public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r1/snmpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r1/snmpd.conf index 2ada53ced999..d7886e51329c 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r1/snmpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r1/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:10.1.1.1:161 +agentAddress udp:161 com2sec public 10.1.1.1 public @@ -17,4 +17,4 @@ master agentx noRangeCheck yes agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r2/snmpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r2/snmpd.conf index 3db1ab7acedb..c8d0bab04869 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r2/snmpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r2/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:10.2.2.2:161 +agentAddress udp:161 com2sec public localhost public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r3/snmpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r3/snmpd.conf index 494df81ffb4a..c8d0bab04869 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r3/snmpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r3/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:10.3.3.3:161 +agentAddress udp:161 com2sec public localhost public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r4/snmpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r4/snmpd.conf index f3809607e35e..c8d0bab04869 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r4/snmpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r4/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:10.4.4.4:161 +agentAddress udp:161 com2sec public localhost public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py index 189d2baf17aa..984cf97e288b 100755 --- a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py +++ b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py @@ -39,7 +39,7 @@ def build_topo(tgen): - """ + r""" CE1 CE3 CE5 (eth0) (eth0) (eth0) :2 :2 :2 diff --git a/tests/topotests/bgp_tcp_mss_passive/__init__.py b/tests/topotests/bgp_tcp_mss_passive/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/bgp_tcp_mss_passive/r1/frr.conf b/tests/topotests/bgp_tcp_mss_passive/r1/frr.conf new file mode 100644 index 000000000000..a0fcd52a1824 --- /dev/null +++ b/tests/topotests/bgp_tcp_mss_passive/r1/frr.conf @@ -0,0 +1,12 @@ +! +interface r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.2 passive + neighbor 192.168.1.2 tcp-mss 300 +! diff --git a/tests/topotests/bgp_dynamic_capability/r2/bgpd.conf b/tests/topotests/bgp_tcp_mss_passive/r2/frr.conf similarity index 73% rename from tests/topotests/bgp_dynamic_capability/r2/bgpd.conf rename to tests/topotests/bgp_tcp_mss_passive/r2/frr.conf index 587b241a90cf..7213975cc03a 100644 --- a/tests/topotests/bgp_dynamic_capability/r2/bgpd.conf +++ b/tests/topotests/bgp_tcp_mss_passive/r2/frr.conf @@ -1,10 +1,10 @@ ! -!debug bgp neighbor +interface r2-eth0 + ip address 192.168.1.2/24 ! router bgp 65002 no bgp ebgp-requires-policy neighbor 192.168.1.1 remote-as external neighbor 192.168.1.1 timers 1 3 neighbor 192.168.1.1 timers connect 1 - neighbor 192.168.1.1 capability dynamic ! diff --git a/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py new file mode 100644 index 000000000000..cd405f7b2289 --- /dev/null +++ b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" +Test if TCP MSS is synced with passive neighbor. +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 3): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_tcp_mss_passive(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_check_tcp_mss_configured(router, neighbor, mss): + output = json.loads(router.vtysh_cmd("show bgp neighbors json")) + expected = { + neighbor: { + "bgpTcpMssConfigured": mss, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_tcp_mss_configured, tgen.gears["r1"], "192.168.1.2", 300 + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "r1 is not configured with TCP MSS 300" + + test_func = functools.partial( + _bgp_check_tcp_mss_configured, tgen.gears["r2"], "192.168.1.1", 0 + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "r2 is not configured with the default TCP MSS (1500)" + + def _bgp_check_tcp_mss_synced(router, neighbor, mss): + output = json.loads(router.vtysh_cmd("show bgp neighbors json")) + expected = { + neighbor: { + "bgpTcpMssSynced": mss, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_tcp_mss_synced, tgen.gears["r1"], "192.168.1.2", 288 + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "r1 is not synced with TCP MSS 300" + + test_func = functools.partial( + _bgp_check_tcp_mss_synced, tgen.gears["r2"], "192.168.1.1", 288 + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "r2 is not synced with the default TCP MSS (1488)" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py index 533af19d93fc..84ef603d6e3c 100644 --- a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py +++ b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py @@ -115,10 +115,56 @@ def _bgp_vpn_nexthop_changed(): } return topotest.json_cmp(output, expected) + def _bgp_verify_v4_nexthop_validity(): + output = json.loads(tgen.gears["cpe1"].vtysh_cmd("show bgp nexthop json")) + expected = { + "ipv4": { + "192.168.1.2": { + "valid": True, + "complete": True, + "igpMetric": 0, + "pathCount": 0, + "nexthops": [{"interfaceName": "cpe1-eth0"}], + }, + } + } + return topotest.json_cmp(output, expected) + + def _bgp_verify_v6_global_nexthop_validity(): + output = json.loads(tgen.gears["pe2"].vtysh_cmd("show bgp nexthop json")) + expected = { + "ipv6": { + "2001:db8::1": { + "valid": True, + "complete": True, + "igpMetric": 0, + "pathCount": 2, + "nexthops": [{"interfaceName": "pe2-eth0"}], + }, + "2001:db8:1::1": { + "valid": True, + "complete": True, + "igpMetric": 20, + "pathCount": 2, + "peer": "2001:db8:1::1", + "nexthops": [{"interfaceName": "pe2-eth0"}], + }, + } + } + return topotest.json_cmp(output, expected) + test_func = functools.partial(_bgp_vpn_nexthop_changed) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed overriding IPv6 next-hop for VPN underlay" + test_func = functools.partial(_bgp_verify_v4_nexthop_validity) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "IPv4 nexthop is invalid" + + test_func = functools.partial(_bgp_verify_v6_global_nexthop_validity) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "IPv6 nexthop is invalid" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_init.json b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_init.json new file mode 100644 index 000000000000..2769c6eb3f22 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_init.json @@ -0,0 +1,156 @@ +{ + "default": { + "vrfName": "default", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.204.0.0/24": [ + { + "pathFrom": "external", + "prefix": "10.204.0.0", + "prefixLen": 24, + "network": "10.204.0.0/24", + "metric": 0, + "locPrf": 100, + "weight": 0, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.2", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf1": { + "vrfName": "vrf1", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.101.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.101.0.0", + "prefixLen": 24, + "network": "10.101.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.201.0.0/24": [ + { + "pathFrom": "external", + "prefix": "10.201.0.0", + "prefixLen": 24, + "network": "10.201.0.0/24", + "metric": 0, + "locPrf": 100, + "weight": 0, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.2", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf3": { + "vrfName": "vrf3", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.103.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.103.0.0", + "prefixLen": 24, + "network": "10.103.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf4": { + "vrfName": "vrf4", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.103.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.103.0.0", + "prefixLen": 24, + "network": "10.103.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "vrf3", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } +} diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r1_vrf1.json b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r1_vrf1.json new file mode 100644 index 000000000000..488dc4aab917 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r1_vrf1.json @@ -0,0 +1,190 @@ +{ + "default": { + "vrfName": "default", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.204.0.0/24": [ + { + "pathFrom": "external", + "prefix": "10.204.0.0", + "prefixLen": 24, + "network": "10.204.0.0/24", + "metric": 0, + "locPrf": 100, + "weight": 0, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.2", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf1": { + "vrfName": "vrf1", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.101.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.101.0.0", + "prefixLen": 24, + "network": "10.101.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.201.0.0/24": [ + { + "pathFrom": "external", + "prefix": "10.201.0.0", + "prefixLen": 24, + "network": "10.201.0.0/24", + "metric": 0, + "locPrf": 100, + "weight": 0, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.2", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf3": { + "vrfName": "vrf3", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.103.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.103.0.0", + "prefixLen": 24, + "network": "10.103.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf4": { + "vrfName": "vrf4", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.103.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.103.0.0", + "prefixLen": 24, + "network": "10.103.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "vrf3", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf2": { + "vrfName": "vrf2", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.101.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.101.0.0", + "prefixLen": 24, + "network": "10.101.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "vrf1", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } +} diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf2.json b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf2.json new file mode 100644 index 000000000000..b751756fcec2 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf2.json @@ -0,0 +1,188 @@ +{ + "default": { + "vrfName": "default", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.204.0.0/24": [ + { + "pathFrom": "external", + "prefix": "10.204.0.0", + "prefixLen": 24, + "network": "10.204.0.0/24", + "metric": 0, + "locPrf": 100, + "weight": 0, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.2", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf1": { + "vrfName": "vrf1", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.101.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.101.0.0", + "prefixLen": 24, + "network": "10.101.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.201.0.0/24": [ + { + "pathFrom": "external", + "prefix": "10.201.0.0", + "prefixLen": 24, + "network": "10.201.0.0/24", + "metric": 0, + "locPrf": 100, + "weight": 0, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.2", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf3": { + "vrfName": "vrf3", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.103.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.103.0.0", + "prefixLen": 24, + "network": "10.103.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf4": { + "vrfName": "vrf4", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.103.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.103.0.0", + "prefixLen": 24, + "network": "10.103.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "vrf3", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf2": { + "vrfName": "vrf2", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.202.0.0/24": [ + { + "pathFrom": "external", + "prefix": "10.202.0.0", + "prefixLen": 24, + "network": "10.202.0.0/24", + "metric": 0, + "locPrf": 100, + "weight": 0, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.2", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } +} diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf3.json b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf3.json new file mode 100644 index 000000000000..49d4066e1956 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf3.json @@ -0,0 +1,188 @@ +{ + "default": { + "vrfName": "default", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.204.0.0/24": [ + { + "pathFrom": "external", + "prefix": "10.204.0.0", + "prefixLen": 24, + "network": "10.204.0.0/24", + "metric": 0, + "locPrf": 100, + "weight": 0, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.2", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf1": { + "vrfName": "vrf1", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.101.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.101.0.0", + "prefixLen": 24, + "network": "10.101.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.201.0.0/24": [ + { + "pathFrom": "external", + "prefix": "10.201.0.0", + "prefixLen": 24, + "network": "10.201.0.0/24", + "metric": 0, + "locPrf": 100, + "weight": 0, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.2", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf3": { + "vrfName": "vrf3", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.103.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.103.0.0", + "prefixLen": 24, + "network": "10.103.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf4": { + "vrfName": "vrf4", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.103.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.103.0.0", + "prefixLen": 24, + "network": "10.103.0.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "vrf3", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + }, + "vrf2": { + "vrfName": "vrf2", + "routerId": "192.0.2.1", + "defaultLocPrf": 100, + "localAS": 65500, + "routes": { + "10.203.0.0/24": [ + { + "pathFrom": "external", + "prefix": "10.203.0.0", + "prefixLen": 24, + "network": "10.203.0.0/24", + "metric": 0, + "locPrf": 100, + "weight": 0, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.2", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } +} diff --git a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py index f2865fec9e70..037dd4039085 100644 --- a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py +++ b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py @@ -157,6 +157,36 @@ def router_json_cmp_exact_filter(router, cmd, expected): return topotest.json_cmp(json_output, expected, exact=True) +def router_vrf_json_cmp_exact_filter(router, cmd, expected): + output = router.vtysh_cmd(cmd) + logger.info("{}: {}\n{}".format(router.name, cmd, output)) + + json_output = json.loads(output) + + # filter out tableVersion, version, nhVrfId and vrfId + for vrf, data in json_output.items(): + if "vrfId" in data: + data.pop("vrfId") + if "tableVersion" in data: + data.pop("tableVersion") + if "routes" not in data: + continue + for route, attrs in data["routes"].items(): + for attr in attrs: + if "nhVrfId" in attr: + attr.pop("nhVrfId") + if "version" in attr: + attr.pop("version") + + # filter out VRF with no routes + json_tmp = deepcopy(json_output) + for vrf, data in json_tmp.items(): + if "routes" not in data or len(data["routes"].keys()) == 0: + json_output.pop(vrf) + + return topotest.json_cmp(json_output, expected, exact=True) + + def check_show_bgp_ipv4_vpn(rname, json_file): tgen = get_topogen() if tgen.routers_have_failure(): @@ -178,6 +208,27 @@ def check_show_bgp_ipv4_vpn(rname, json_file): assert result is None, assertmsg +def check_show_bgp_vrf_ipv4(rname, json_file): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears[rname] + + logger.info("Checking VRF IPv4 routes for convergence on {}".format(rname)) + + json_file = "{}/{}/{}".format(CWD, router.name, json_file) + expected = json.loads(open(json_file).read()) + test_func = partial( + router_vrf_json_cmp_exact_filter, + router, + "show bgp vrf all ipv4 unicast 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_protocols_convergence_step0(): """ Assert that all protocols have converged @@ -211,6 +262,8 @@ def test_bgp_no_retain_step1(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_no_retain_init.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_init.json") + def test_bgp_retain_step2(): """ @@ -234,6 +287,8 @@ def test_bgp_retain_step2(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_all.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_init.json") + def test_bgp_no_retain_step3(): """ @@ -253,10 +308,12 @@ def test_bgp_no_retain_step3(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_no_retain_init.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_init.json") + def test_bgp_no_retain_add_vrf2_step4(): """ - Add vrf2 on r1 and check bgp vpnv4 table + Add vrf2 on r1 and check bgp tables """ rname = "r1" @@ -283,10 +340,12 @@ def test_bgp_no_retain_add_vrf2_step4(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_no_retain_init_plus_r2_vrf2.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_plus_r2_vrf2.json") + def test_bgp_no_retain_unimport_vrf2_step5(): """ - Unimport to vrf2 on r1 and check bgp vpnv4 table + Unimport to vrf2 on r1 and check bgp tables """ rname = "r1" @@ -308,10 +367,12 @@ def test_bgp_no_retain_unimport_vrf2_step5(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_no_retain_init.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_init.json") + def test_bgp_no_retain_import_vrf2_step6(): """ - Re-import to vrf2 on r1 and check bgp vpnv4 table + Re-import to vrf2 on r1 and check bgp tables """ rname = "r1" @@ -333,10 +394,12 @@ def test_bgp_no_retain_import_vrf2_step6(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_no_retain_init_plus_r2_vrf2.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_plus_r2_vrf2.json") + def test_bgp_no_retain_import_vrf1_step7(): """ - Import r2 vrf1 into r1 vrf2 and check bgp vpnv4 table + Import r1 vrf1 into r1 vrf2 and check bgp tables """ rname = "r1" @@ -358,10 +421,12 @@ def test_bgp_no_retain_import_vrf1_step7(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_no_retain_init.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_plus_r1_vrf1.json") + def test_bgp_no_retain_import_vrf3_step8(): """ - Import r2 vrf3 into r1 vrf2 and check bgp vpnv4 table + Import r2 vrf3 into r1 vrf2 and check bgp tables """ rname = "r1" @@ -383,10 +448,12 @@ def test_bgp_no_retain_import_vrf3_step8(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_no_retain_init_plus_r2_vrf3.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_plus_r2_vrf3.json") + def test_bgp_no_retain_unimport_vrf3_step9(): """ - Un-import r2 vrf3 into r1 vrf2 and check bgp vpnv4 table + Un-import r2 vrf3 into r1 vrf2 and check bgp tables """ rname = "r1" @@ -408,10 +475,12 @@ def test_bgp_no_retain_unimport_vrf3_step9(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_no_retain_init.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_init.json") + def test_bgp_no_retain_import_vrf3_step10(): """ - Import r2 vrf3 into r1 vrf2 and check bgp vpnv4 table + Import r2 vrf3 into r1 vrf2 and check bgp tables """ rname = "r1" @@ -433,10 +502,12 @@ def test_bgp_no_retain_import_vrf3_step10(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_no_retain_init_plus_r2_vrf3.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_plus_r2_vrf3.json") + def test_bgp_no_retain_remove_vrf2_step11(): """ - Import r2 vrf3 into r1 vrf2 and check bgp vpnv4 table + Remove BGP vrf2 on r1 and check bgp tables """ rname = "r1" @@ -454,10 +525,12 @@ def test_bgp_no_retain_remove_vrf2_step11(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_no_retain_init.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_init.json") + def test_bgp_retain_step12(): """ - Configure retain and check bgp vpnv4 table + Configure retain and check bgp tables """ rname = "r1" @@ -477,6 +550,8 @@ def test_bgp_retain_step12(): check_show_bgp_ipv4_vpn(rname, "ipv4_vpn_routes_all.json") check_show_bgp_ipv4_vpn("r2", "ipv4_vpn_routes_all.json") + check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_init.json") + def test_memory_leak(): "Run the memory leak test and report results." diff --git a/tests/topotests/isis_snmp/r1/snmpd.conf b/tests/topotests/isis_snmp/r1/snmpd.conf index 3fd5e982e8fb..cdcd9a2b372d 100644 --- a/tests/topotests/isis_snmp/r1/snmpd.conf +++ b/tests/topotests/isis_snmp/r1/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:1.1.1.1:161 +agentAddress udp:161 com2sec public 1.1.1.1 public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/isis_snmp/r2/snmpd.conf b/tests/topotests/isis_snmp/r2/snmpd.conf index fc648057a5e1..e511929f67ac 100644 --- a/tests/topotests/isis_snmp/r2/snmpd.conf +++ b/tests/topotests/isis_snmp/r2/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:2.2.2.2:161 +agentAddress udp::161 com2sec public 2.2.2.2 public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/isis_snmp/r3/snmpd.conf b/tests/topotests/isis_snmp/r3/snmpd.conf index 20af65e431bd..19fb256b9ab0 100644 --- a/tests/topotests/isis_snmp/r3/snmpd.conf +++ b/tests/topotests/isis_snmp/r3/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:3.3.3.3:161 +agentAddress udp:161 com2sec public 3.3.3.3 public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/isis_snmp/r4/snmpd.conf b/tests/topotests/isis_snmp/r4/snmpd.conf index 76e4b7906961..2178a3e1d8eb 100644 --- a/tests/topotests/isis_snmp/r4/snmpd.conf +++ b/tests/topotests/isis_snmp/r4/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:4.4.4.4:161 +agentAddress udp:161 com2sec public 4.4.4.4 public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/isis_snmp/r5/snmpd.conf b/tests/topotests/isis_snmp/r5/snmpd.conf index af59194bc9e2..5b11cfc5e0e8 100644 --- a/tests/topotests/isis_snmp/r5/snmpd.conf +++ b/tests/topotests/isis_snmp/r5/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:5.5.5.5:161 +agentAddress udp::161 com2sec public 5.5.5.5 public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/isis_srv6_topo1/dst/sharpd.conf b/tests/topotests/isis_srv6_topo1/dst/sharpd.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/isis_srv6_topo1/dst/zebra.conf b/tests/topotests/isis_srv6_topo1/dst/zebra.conf new file mode 100644 index 000000000000..80741856cba8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/dst/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname dst +! +! debug zebra kernel +! debug zebra packet +! debug zebra mpls +! +interface lo + ip address 9.9.9.2/32 + ipv6 address fc00:0:9::1/128 +! +interface eth-rt6 + ip address 10.0.10.2/24 + ipv6 address 2001:db8:10::2/64 +! +ip forwarding +! +ip route 2001:db8:1::1 2001:db8:10::1 +! +line vty +! diff --git a/tests/topotests/isis_srv6_topo1/rt1/isisd.conf b/tests/topotests/isis_srv6_topo1/rt1/isisd.conf new file mode 100644 index 000000000000..29e1a3117165 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/isisd.conf @@ -0,0 +1,35 @@ +password 1 +hostname rt1 +log file isisd.log +! +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen +! +interface lo + ip router isis 1 + ipv6 router isis 1 + isis passive +! +interface eth-sw1 + ip router isis 1 + ipv6 router isis 1 + isis hello-interval 1 + isis hello-multiplier 10 +! +router isis 1 + lsp-gen-interval 2 + net 49.0000.0000.0000.0001.00 + is-type level-1 + topology ipv6-unicast + segment-routing srv6 + locator loc1 + node-msd + max-segs-left 3 + max-end-pop 3 + max-h-encaps 2 + max-end-d 5 + interface sr0 +! diff --git a/tests/topotests/isis_srv6_topo1/rt1/sharpd.conf b/tests/topotests/isis_srv6_topo1/rt1/sharpd.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/isis_srv6_topo1/rt1/step1/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step1/show_ip_route.ref new file mode 100644 index 000000000000..590d75afbf99 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step1/show_ip_route.ref @@ -0,0 +1,276 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step1/show_ipv6_route.ref new file mode 100644 index 000000000000..2d30fc4d17e2 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step1/show_ipv6_route.ref @@ -0,0 +1,270 @@ +{ + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:1:1::\/64":[ + { + "prefix":"fc00:0:1:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:1:2::\/64":[ + { + "prefix":"fc00:0:1:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref new file mode 100644 index 000000000000..bb10aba9424d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:1::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:1::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..9c5901b90ff1 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,32 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step2/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step2/show_ip_route.ref new file mode 100644 index 000000000000..590d75afbf99 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step2/show_ip_route.ref @@ -0,0 +1,276 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step2/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..9dda5dc3e810 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step2/show_ipv6_route.ref @@ -0,0 +1,204 @@ +{ + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step2/show_srv6_locator_table.ref new file mode 100644 index 000000000000..2c63c0851048 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step2/show_srv6_locator_table.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt1/step2/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..9c5901b90ff1 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step2/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,32 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step3/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step3/show_ip_route.ref new file mode 100644 index 000000000000..590d75afbf99 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step3/show_ip_route.ref @@ -0,0 +1,276 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step3/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..2d30fc4d17e2 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step3/show_ipv6_route.ref @@ -0,0 +1,270 @@ +{ + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:1:1::\/64":[ + { + "prefix":"fc00:0:1:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:1:2::\/64":[ + { + "prefix":"fc00:0:1:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref new file mode 100644 index 000000000000..bb10aba9424d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:1::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:1::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt1/step3/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..9c5901b90ff1 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step3/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,32 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step4/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step4/show_ip_route.ref new file mode 100644 index 000000000000..590d75afbf99 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step4/show_ip_route.ref @@ -0,0 +1,276 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step4/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..9dda5dc3e810 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step4/show_ipv6_route.ref @@ -0,0 +1,204 @@ +{ + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step4/show_srv6_locator_table.ref new file mode 100644 index 000000000000..f9561be5f238 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step4/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:1::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:1::/48", + "proto":"system" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt1/step4/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..9c5901b90ff1 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step4/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,32 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step5/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step5/show_ip_route.ref new file mode 100644 index 000000000000..590d75afbf99 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step5/show_ip_route.ref @@ -0,0 +1,276 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step5/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..2d30fc4d17e2 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step5/show_ipv6_route.ref @@ -0,0 +1,270 @@ +{ + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:1:1::\/64":[ + { + "prefix":"fc00:0:1:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:1:2::\/64":[ + { + "prefix":"fc00:0:1:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref new file mode 100644 index 000000000000..bb10aba9424d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:1::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:1::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt1/step5/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..9c5901b90ff1 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step5/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,32 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step6/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step6/show_ip_route.ref new file mode 100644 index 000000000000..590d75afbf99 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step6/show_ip_route.ref @@ -0,0 +1,276 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step6/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..9dda5dc3e810 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step6/show_ipv6_route.ref @@ -0,0 +1,204 @@ +{ + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step6/show_srv6_locator_table.ref new file mode 100644 index 000000000000..f9561be5f238 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step6/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:1::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:1::/48", + "proto":"system" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt1/step6/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..9c5901b90ff1 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step6/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,32 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step7/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step7/show_ip_route.ref new file mode 100644 index 000000000000..590d75afbf99 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step7/show_ip_route.ref @@ -0,0 +1,276 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step7/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..2d30fc4d17e2 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step7/show_ipv6_route.ref @@ -0,0 +1,270 @@ +{ + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:1:1::\/64":[ + { + "prefix":"fc00:0:1:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:1:2::\/64":[ + { + "prefix":"fc00:0:1:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref new file mode 100644 index 000000000000..bb10aba9424d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:1::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:1::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt1/step7/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..9c5901b90ff1 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step7/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,32 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step8/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step8/show_ip_route.ref new file mode 100644 index 000000000000..590d75afbf99 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step8/show_ip_route.ref @@ -0,0 +1,276 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step8/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..9dda5dc3e810 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step8/show_ipv6_route.ref @@ -0,0 +1,204 @@ +{ + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step8/show_srv6_locator_table.ref new file mode 100644 index 000000000000..2c63c0851048 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step8/show_srv6_locator_table.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt1/step8/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..9c5901b90ff1 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step8/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,32 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step9/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step9/show_ip_route.ref new file mode 100644 index 000000000000..590d75afbf99 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step9/show_ip_route.ref @@ -0,0 +1,276 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step9/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt1/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..2d30fc4d17e2 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step9/show_ipv6_route.ref @@ -0,0 +1,270 @@ +{ + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:1:1::\/64":[ + { + "prefix":"fc00:0:1:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:1:2::\/64":[ + { + "prefix":"fc00:0:1:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref new file mode 100644 index 000000000000..bb10aba9424d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:1::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:1::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt1/step9/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..9c5901b90ff1 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/step9/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,32 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt1/zebra.conf b/tests/topotests/isis_srv6_topo1/rt1/zebra.conf new file mode 100644 index 000000000000..05f60fe82e62 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt1/zebra.conf @@ -0,0 +1,28 @@ +log file zebra.log +! +hostname rt1 +! +! debug zebra kernel +! debug zebra packet +! +interface lo + ip address 1.1.1.1/32 + ipv6 address fc00:0:1::1/128 +! +interface eth-sw1 + ip address 10.0.1.1/24 + ipv6 address 2001:db8:1::1/64 +! +segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16 + behavior usid + ! + ! +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis_srv6_topo1/rt2/isisd.conf b/tests/topotests/isis_srv6_topo1/rt2/isisd.conf new file mode 100644 index 000000000000..b095f049101f --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/isisd.conf @@ -0,0 +1,48 @@ +hostname rt2 +log file isisd.log +! +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen +! +interface lo + ip router isis 1 + ipv6 router isis 1 + isis passive +! +interface eth-sw1 + ip router isis 1 + ipv6 router isis 1 + isis hello-interval 1 + isis hello-multiplier 10 +! +interface eth-rt4-1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +interface eth-rt4-2 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +router isis 1 + lsp-gen-interval 2 + net 49.0000.0000.0000.0002.00 + is-type level-1 + topology ipv6-unicast + segment-routing srv6 + locator loc1 + node-msd + max-segs-left 3 + max-end-pop 3 + max-h-encaps 2 + max-end-d 5 + interface sr0 +! diff --git a/tests/topotests/isis_srv6_topo1/rt2/step1/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step1/show_ip_route.ref new file mode 100644 index 000000000000..1d4a9e9a25bf --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step1/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1" + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step1/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step1/show_ipv6_route.ref new file mode 100644 index 000000000000..150fa92241df --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step1/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:2:1::\/64":[ + { + "prefix":"fc00:0:2:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:2::\/64":[ + { + "prefix":"fc00:0:2:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:3::\/64":[ + { + "prefix":"fc00:0:2:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:4::\/64":[ + { + "prefix":"fc00:0:2:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref new file mode 100644 index 000000000000..f3399319f3e5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:2::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:2::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..5e46ddf72819 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step2/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step2/show_ip_route.ref new file mode 100644 index 000000000000..1d4a9e9a25bf --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step2/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1" + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step2/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..f9c2d098cc60 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step2/show_ipv6_route.ref @@ -0,0 +1,327 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:2:1::\/64":[ + { + "prefix":"fc00:0:2:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:2::\/64":[ + { + "prefix":"fc00:0:2:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:3::\/64":[ + { + "prefix":"fc00:0:2:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:4::\/64":[ + { + "prefix":"fc00:0:2:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref new file mode 100644 index 000000000000..f3399319f3e5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:2::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:2::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt2/step2/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..5e46ddf72819 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step2/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step3/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step3/show_ip_route.ref new file mode 100644 index 000000000000..1d4a9e9a25bf --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step3/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1" + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step3/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..150fa92241df --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step3/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:2:1::\/64":[ + { + "prefix":"fc00:0:2:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:2::\/64":[ + { + "prefix":"fc00:0:2:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:3::\/64":[ + { + "prefix":"fc00:0:2:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:4::\/64":[ + { + "prefix":"fc00:0:2:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref new file mode 100644 index 000000000000..f3399319f3e5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:2::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:2::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt2/step3/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..5e46ddf72819 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step3/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step4/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step4/show_ip_route.ref new file mode 100644 index 000000000000..1d4a9e9a25bf --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step4/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1" + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step4/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..f9c2d098cc60 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step4/show_ipv6_route.ref @@ -0,0 +1,327 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:2:1::\/64":[ + { + "prefix":"fc00:0:2:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:2::\/64":[ + { + "prefix":"fc00:0:2:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:3::\/64":[ + { + "prefix":"fc00:0:2:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:4::\/64":[ + { + "prefix":"fc00:0:2:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref new file mode 100644 index 000000000000..f3399319f3e5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:2::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:2::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt2/step4/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..5e46ddf72819 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step4/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step5/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step5/show_ip_route.ref new file mode 100644 index 000000000000..1d4a9e9a25bf --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step5/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1" + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step5/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..150fa92241df --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step5/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:2:1::\/64":[ + { + "prefix":"fc00:0:2:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:2::\/64":[ + { + "prefix":"fc00:0:2:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:3::\/64":[ + { + "prefix":"fc00:0:2:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:4::\/64":[ + { + "prefix":"fc00:0:2:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref new file mode 100644 index 000000000000..f3399319f3e5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:2::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:2::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt2/step5/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..5e46ddf72819 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step5/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step6/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step6/show_ip_route.ref new file mode 100644 index 000000000000..1d4a9e9a25bf --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step6/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1" + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step6/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..f9c2d098cc60 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step6/show_ipv6_route.ref @@ -0,0 +1,327 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:2:1::\/64":[ + { + "prefix":"fc00:0:2:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:2::\/64":[ + { + "prefix":"fc00:0:2:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:3::\/64":[ + { + "prefix":"fc00:0:2:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:4::\/64":[ + { + "prefix":"fc00:0:2:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref new file mode 100644 index 000000000000..f3399319f3e5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:2::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:2::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt2/step6/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..5e46ddf72819 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step6/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step7/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step7/show_ip_route.ref new file mode 100644 index 000000000000..1d4a9e9a25bf --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step7/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1" + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step7/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..150fa92241df --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step7/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:2:1::\/64":[ + { + "prefix":"fc00:0:2:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:2::\/64":[ + { + "prefix":"fc00:0:2:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:3::\/64":[ + { + "prefix":"fc00:0:2:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:4::\/64":[ + { + "prefix":"fc00:0:2:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref new file mode 100644 index 000000000000..f3399319f3e5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:2::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:2::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt2/step7/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..5e46ddf72819 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step7/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step8/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step8/show_ip_route.ref new file mode 100644 index 000000000000..1d4a9e9a25bf --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step8/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1" + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step8/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..f9c2d098cc60 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step8/show_ipv6_route.ref @@ -0,0 +1,327 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:2:1::\/64":[ + { + "prefix":"fc00:0:2:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:2::\/64":[ + { + "prefix":"fc00:0:2:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:3::\/64":[ + { + "prefix":"fc00:0:2:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:4::\/64":[ + { + "prefix":"fc00:0:2:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref new file mode 100644 index 000000000000..f3399319f3e5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:2::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:2::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt2/step8/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..5e46ddf72819 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step8/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step9/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step9/show_ip_route.ref new file mode 100644 index 000000000000..1d4a9e9a25bf --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step9/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1" + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step9/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt2/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..150fa92241df --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step9/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:2:1::\/64":[ + { + "prefix":"fc00:0:2:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:2::\/64":[ + { + "prefix":"fc00:0:2:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:3::\/64":[ + { + "prefix":"fc00:0:2:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:2:4::\/64":[ + { + "prefix":"fc00:0:2:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref new file mode 100644 index 000000000000..f3399319f3e5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:2::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:2::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt2/step9/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..5e46ddf72819 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/step9/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt2/zebra.conf b/tests/topotests/isis_srv6_topo1/rt2/zebra.conf new file mode 100644 index 000000000000..a846a6ea070c --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt2/zebra.conf @@ -0,0 +1,34 @@ +log file zebra.log +! +hostname rt2 +! +! debug zebra kernel +! debug zebra packet +! +interface lo + ip address 2.2.2.2/32 + ipv6 address fc00:0:2::1/128 +! +interface eth-sw1 + ip address 10.0.1.2/24 + ipv6 address 2001:db8:1::2/64 +! +interface eth-rt4-1 + ip address 10.0.2.2/24 +! +interface eth-rt4-2 + ip address 10.0.3.2/24 +! +segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:2::/48 block-len 32 node-len 16 func-bits 16 + behavior usid + ! + ! +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis_srv6_topo1/rt3/isisd.conf b/tests/topotests/isis_srv6_topo1/rt3/isisd.conf new file mode 100644 index 000000000000..e237db2f4940 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/isisd.conf @@ -0,0 +1,48 @@ +hostname rt3 +log file isisd.log +! +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen +! +interface lo + ip router isis 1 + ipv6 router isis 1 + isis passive +! +interface eth-sw1 + ip router isis 1 + ipv6 router isis 1 + isis hello-interval 1 + isis hello-multiplier 10 +! +interface eth-rt5-1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +interface eth-rt5-2 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +router isis 1 + lsp-gen-interval 2 + net 49.0000.0000.0000.0003.00 + is-type level-1 + topology ipv6-unicast + segment-routing srv6 + locator loc1 + node-msd + max-segs-left 3 + max-end-pop 3 + max-h-encaps 2 + max-end-d 5 + interface sr0 +! diff --git a/tests/topotests/isis_srv6_topo1/rt3/step1/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step1/show_ip_route.ref new file mode 100644 index 000000000000..6ce5760e4f1d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step1/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1" + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step1/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step1/show_ipv6_route.ref new file mode 100644 index 000000000000..fc0e5161c221 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step1/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:3:1::\/64":[ + { + "prefix":"fc00:0:3:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:2::\/64":[ + { + "prefix":"fc00:0:3:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:3::\/64":[ + { + "prefix":"fc00:0:3:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:4::\/64":[ + { + "prefix":"fc00:0:3:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref new file mode 100644 index 000000000000..ffa626123da8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:3::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:3::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..a284240d24f7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt5-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step2/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step2/show_ip_route.ref new file mode 100644 index 000000000000..6ce5760e4f1d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step2/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1" + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step2/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..a24d95e78ed7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step2/show_ipv6_route.ref @@ -0,0 +1,327 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:3:1::\/64":[ + { + "prefix":"fc00:0:3:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:2::\/64":[ + { + "prefix":"fc00:0:3:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:3::\/64":[ + { + "prefix":"fc00:0:3:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:4::\/64":[ + { + "prefix":"fc00:0:3:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref new file mode 100644 index 000000000000..ffa626123da8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:3::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:3::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt3/step2/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..a284240d24f7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step2/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt5-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step3/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step3/show_ip_route.ref new file mode 100644 index 000000000000..6ce5760e4f1d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step3/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1" + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step3/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..fc0e5161c221 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step3/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:3:1::\/64":[ + { + "prefix":"fc00:0:3:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:2::\/64":[ + { + "prefix":"fc00:0:3:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:3::\/64":[ + { + "prefix":"fc00:0:3:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:4::\/64":[ + { + "prefix":"fc00:0:3:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref new file mode 100644 index 000000000000..ffa626123da8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:3::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:3::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt3/step3/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..a284240d24f7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step3/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt5-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step4/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step4/show_ip_route.ref new file mode 100644 index 000000000000..6ce5760e4f1d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step4/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1" + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step4/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..a24d95e78ed7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step4/show_ipv6_route.ref @@ -0,0 +1,327 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:3:1::\/64":[ + { + "prefix":"fc00:0:3:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:2::\/64":[ + { + "prefix":"fc00:0:3:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:3::\/64":[ + { + "prefix":"fc00:0:3:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:4::\/64":[ + { + "prefix":"fc00:0:3:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref new file mode 100644 index 000000000000..ffa626123da8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:3::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:3::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt3/step4/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..a284240d24f7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step4/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt5-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step5/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step5/show_ip_route.ref new file mode 100644 index 000000000000..6ce5760e4f1d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step5/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1" + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step5/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..fc0e5161c221 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step5/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:3:1::\/64":[ + { + "prefix":"fc00:0:3:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:2::\/64":[ + { + "prefix":"fc00:0:3:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:3::\/64":[ + { + "prefix":"fc00:0:3:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:4::\/64":[ + { + "prefix":"fc00:0:3:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref new file mode 100644 index 000000000000..ffa626123da8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:3::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:3::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt3/step5/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..a284240d24f7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step5/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt5-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step6/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step6/show_ip_route.ref new file mode 100644 index 000000000000..6ce5760e4f1d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step6/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1" + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step6/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..a24d95e78ed7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step6/show_ipv6_route.ref @@ -0,0 +1,327 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:3:1::\/64":[ + { + "prefix":"fc00:0:3:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:2::\/64":[ + { + "prefix":"fc00:0:3:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:3::\/64":[ + { + "prefix":"fc00:0:3:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:4::\/64":[ + { + "prefix":"fc00:0:3:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref new file mode 100644 index 000000000000..ffa626123da8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:3::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:3::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt3/step6/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..a284240d24f7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step6/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt5-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step7/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step7/show_ip_route.ref new file mode 100644 index 000000000000..6ce5760e4f1d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step7/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1" + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step7/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..fc0e5161c221 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step7/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:3:1::\/64":[ + { + "prefix":"fc00:0:3:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:2::\/64":[ + { + "prefix":"fc00:0:3:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:3::\/64":[ + { + "prefix":"fc00:0:3:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:4::\/64":[ + { + "prefix":"fc00:0:3:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref new file mode 100644 index 000000000000..ffa626123da8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:3::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:3::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt3/step7/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..a284240d24f7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step7/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt5-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step8/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step8/show_ip_route.ref new file mode 100644 index 000000000000..6ce5760e4f1d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step8/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1" + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step8/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..a24d95e78ed7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step8/show_ipv6_route.ref @@ -0,0 +1,327 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:3:1::\/64":[ + { + "prefix":"fc00:0:3:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:2::\/64":[ + { + "prefix":"fc00:0:3:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:3::\/64":[ + { + "prefix":"fc00:0:3:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:4::\/64":[ + { + "prefix":"fc00:0:3:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref new file mode 100644 index 000000000000..ffa626123da8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:3::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:3::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt3/step8/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..a284240d24f7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step8/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt5-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step9/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step9/show_ip_route.ref new file mode 100644 index 000000000000..6ce5760e4f1d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step9/show_ip_route.ref @@ -0,0 +1,320 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1" + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step9/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt3/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..fc0e5161c221 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step9/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:3:1::\/64":[ + { + "prefix":"fc00:0:3:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:2::\/64":[ + { + "prefix":"fc00:0:3:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:3::\/64":[ + { + "prefix":"fc00:0:3:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:3:4::\/64":[ + { + "prefix":"fc00:0:3:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref new file mode 100644 index 000000000000..ffa626123da8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:3::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:3::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt3/step9/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..a284240d24f7 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/step9/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,70 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt5-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-sw1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + }, + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 64, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt3/zebra.conf b/tests/topotests/isis_srv6_topo1/rt3/zebra.conf new file mode 100644 index 000000000000..e3bc4dbbb037 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt3/zebra.conf @@ -0,0 +1,33 @@ +log file zebra.log +! +hostname rt3 +! +! debug zebra kernel +! debug zebra packet +! +interface lo + ip address 3.3.3.3/32 + ipv6 address fc00:0:3::1/128 +! +interface eth-sw1 + ip address 10.0.1.3/24 +! +interface eth-rt5-1 + ip address 10.0.4.3/24 +! +interface eth-rt5-2 + ip address 10.0.5.3/24 +! +segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:3::/48 block-len 32 node-len 16 func-bits 16 + behavior usid + ! + ! +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis_srv6_topo1/rt4/isisd.conf b/tests/topotests/isis_srv6_topo1/rt4/isisd.conf new file mode 100644 index 000000000000..b4c92146a1f6 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/isisd.conf @@ -0,0 +1,56 @@ +hostname rt4 +log file isisd.log +! +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen +! +interface lo + ip router isis 1 + ipv6 router isis 1 + isis passive +! +interface eth-rt2-1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +interface eth-rt2-2 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +interface eth-rt5 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +interface eth-rt6 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +router isis 1 + lsp-gen-interval 2 + net 49.0000.0000.0000.0004.00 + is-type level-1 + topology ipv6-unicast + segment-routing srv6 + locator loc1 + node-msd + max-segs-left 3 + max-end-pop 3 + max-h-encaps 2 + max-end-d 5 + interface sr0 +! diff --git a/tests/topotests/isis_srv6_topo1/rt4/step1/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step1/show_ip_route.ref new file mode 100644 index 000000000000..0f26fa5d7aed --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step1/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1" + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step1/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step1/show_ipv6_route.ref new file mode 100644 index 000000000000..2878c24cc85d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step1/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:4:1::\/64":[ + { + "prefix":"fc00:0:4:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:2::\/64":[ + { + "prefix":"fc00:0:4:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:3::\/64":[ + { + "prefix":"fc00:0:4:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:4::\/64":[ + { + "prefix":"fc00:0:4:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref new file mode 100644 index 000000000000..189943f737a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:4::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:4::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..0ca7a76bd44d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt2-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step2/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step2/show_ip_route.ref new file mode 100644 index 000000000000..0f26fa5d7aed --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step2/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1" + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step2/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..bea54ba6b282 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step2/show_ipv6_route.ref @@ -0,0 +1,321 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:4:1::\/64":[ + { + "prefix":"fc00:0:4:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:2::\/64":[ + { + "prefix":"fc00:0:4:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:3::\/64":[ + { + "prefix":"fc00:0:4:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:4::\/64":[ + { + "prefix":"fc00:0:4:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref new file mode 100644 index 000000000000..189943f737a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:4::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:4::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt4/step2/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..0ca7a76bd44d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step2/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt2-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step3/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step3/show_ip_route.ref new file mode 100644 index 000000000000..0f26fa5d7aed --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step3/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1" + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step3/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..2878c24cc85d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step3/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:4:1::\/64":[ + { + "prefix":"fc00:0:4:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:2::\/64":[ + { + "prefix":"fc00:0:4:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:3::\/64":[ + { + "prefix":"fc00:0:4:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:4::\/64":[ + { + "prefix":"fc00:0:4:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref new file mode 100644 index 000000000000..189943f737a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:4::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:4::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt4/step3/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..0ca7a76bd44d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step3/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt2-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step4/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step4/show_ip_route.ref new file mode 100644 index 000000000000..0f26fa5d7aed --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step4/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1" + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step4/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..bea54ba6b282 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step4/show_ipv6_route.ref @@ -0,0 +1,321 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:4:1::\/64":[ + { + "prefix":"fc00:0:4:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:2::\/64":[ + { + "prefix":"fc00:0:4:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:3::\/64":[ + { + "prefix":"fc00:0:4:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:4::\/64":[ + { + "prefix":"fc00:0:4:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref new file mode 100644 index 000000000000..189943f737a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:4::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:4::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt4/step4/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..0ca7a76bd44d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step4/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt2-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step5/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step5/show_ip_route.ref new file mode 100644 index 000000000000..0f26fa5d7aed --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step5/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1" + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step5/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..2878c24cc85d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step5/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:4:1::\/64":[ + { + "prefix":"fc00:0:4:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:2::\/64":[ + { + "prefix":"fc00:0:4:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:3::\/64":[ + { + "prefix":"fc00:0:4:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:4::\/64":[ + { + "prefix":"fc00:0:4:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref new file mode 100644 index 000000000000..189943f737a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:4::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:4::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt4/step5/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..0ca7a76bd44d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step5/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt2-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step6/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step6/show_ip_route.ref new file mode 100644 index 000000000000..0f26fa5d7aed --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step6/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1" + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step6/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..bea54ba6b282 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step6/show_ipv6_route.ref @@ -0,0 +1,321 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:4:1::\/64":[ + { + "prefix":"fc00:0:4:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:2::\/64":[ + { + "prefix":"fc00:0:4:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:3::\/64":[ + { + "prefix":"fc00:0:4:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:4::\/64":[ + { + "prefix":"fc00:0:4:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref new file mode 100644 index 000000000000..189943f737a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:4::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:4::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt4/step6/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..0ca7a76bd44d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step6/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt2-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step7/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step7/show_ip_route.ref new file mode 100644 index 000000000000..0f26fa5d7aed --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step7/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1" + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step7/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..2878c24cc85d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step7/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:4:1::\/64":[ + { + "prefix":"fc00:0:4:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:2::\/64":[ + { + "prefix":"fc00:0:4:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:3::\/64":[ + { + "prefix":"fc00:0:4:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:4::\/64":[ + { + "prefix":"fc00:0:4:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref new file mode 100644 index 000000000000..189943f737a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:4::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:4::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt4/step7/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..0ca7a76bd44d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step7/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt2-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step8/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step8/show_ip_route.ref new file mode 100644 index 000000000000..0f26fa5d7aed --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step8/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1" + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step8/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..bea54ba6b282 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step8/show_ipv6_route.ref @@ -0,0 +1,321 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:4:1::\/64":[ + { + "prefix":"fc00:0:4:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:2::\/64":[ + { + "prefix":"fc00:0:4:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:3::\/64":[ + { + "prefix":"fc00:0:4:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:4::\/64":[ + { + "prefix":"fc00:0:4:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref new file mode 100644 index 000000000000..189943f737a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:4::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:4::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt4/step8/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..0ca7a76bd44d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step8/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt2-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step9/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step9/show_ip_route.ref new file mode 100644 index 000000000000..0f26fa5d7aed --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step9/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1" + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step9/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt4/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..2878c24cc85d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step9/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:4:1::\/64":[ + { + "prefix":"fc00:0:4:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:2::\/64":[ + { + "prefix":"fc00:0:4:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:3::\/64":[ + { + "prefix":"fc00:0:4:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:4:4::\/64":[ + { + "prefix":"fc00:0:4:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref new file mode 100644 index 000000000000..189943f737a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:4::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:4::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt4/step9/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..0ca7a76bd44d --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/step9/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt2-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt4/zebra.conf b/tests/topotests/isis_srv6_topo1/rt4/zebra.conf new file mode 100644 index 000000000000..551b35d29478 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt4/zebra.conf @@ -0,0 +1,36 @@ +log file zebra.log +! +hostname rt4 +! +! debug zebra kernel +! debug zebra packet +! +interface lo + ip address 4.4.4.4/32 + ipv6 address fc00:0:4::1/128 +! +interface eth-rt2-1 + ip address 10.0.2.4/24 +! +interface eth-rt2-2 + ip address 10.0.3.4/24 +! +interface eth-rt5 + ip address 10.0.6.4/24 +! +interface eth-rt6 + ip address 10.0.7.4/24 +! +segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:4::/48 block-len 32 node-len 16 func-bits 16 + behavior usid + ! + ! +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis_srv6_topo1/rt5/isisd.conf b/tests/topotests/isis_srv6_topo1/rt5/isisd.conf new file mode 100644 index 000000000000..26f895dd82ea --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/isisd.conf @@ -0,0 +1,56 @@ +hostname rt5 +log file isisd.log +! +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen +! +interface lo + ip router isis 1 + ipv6 router isis 1 + isis passive +! +interface eth-rt3-1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +interface eth-rt3-2 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +interface eth-rt4 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +interface eth-rt6 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +router isis 1 + lsp-gen-interval 2 + net 49.0000.0000.0000.0005.00 + is-type level-1 + topology ipv6-unicast + segment-routing srv6 + locator loc1 + node-msd + max-segs-left 3 + max-end-pop 3 + max-h-encaps 2 + max-end-d 5 + interface sr0 +! diff --git a/tests/topotests/isis_srv6_topo1/rt5/step1/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step1/show_ip_route.ref new file mode 100644 index 000000000000..65beaa59987c --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step1/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1" + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step1/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step1/show_ipv6_route.ref new file mode 100644 index 000000000000..d6ad4c2aad24 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step1/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:5:1::\/64":[ + { + "prefix":"fc00:0:5:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:2::\/64":[ + { + "prefix":"fc00:0:5:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:3::\/64":[ + { + "prefix":"fc00:0:5:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:4::\/64":[ + { + "prefix":"fc00:0:5:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref new file mode 100644 index 000000000000..54780fce8adc --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:5::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:5::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..f40b0d353d7a --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt3-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt3-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step2/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step2/show_ip_route.ref new file mode 100644 index 000000000000..65beaa59987c --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step2/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1" + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step2/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..c24527017709 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step2/show_ipv6_route.ref @@ -0,0 +1,321 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:5:1::\/64":[ + { + "prefix":"fc00:0:5:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:2::\/64":[ + { + "prefix":"fc00:0:5:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:3::\/64":[ + { + "prefix":"fc00:0:5:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:4::\/64":[ + { + "prefix":"fc00:0:5:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref new file mode 100644 index 000000000000..54780fce8adc --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:5::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:5::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt5/step2/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..f40b0d353d7a --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step2/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt3-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt3-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step3/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step3/show_ip_route.ref new file mode 100644 index 000000000000..65beaa59987c --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step3/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1" + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step3/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..d6ad4c2aad24 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step3/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:5:1::\/64":[ + { + "prefix":"fc00:0:5:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:2::\/64":[ + { + "prefix":"fc00:0:5:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:3::\/64":[ + { + "prefix":"fc00:0:5:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:4::\/64":[ + { + "prefix":"fc00:0:5:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref new file mode 100644 index 000000000000..54780fce8adc --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:5::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:5::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt5/step3/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..f40b0d353d7a --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step3/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt3-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt3-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step4/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step4/show_ip_route.ref new file mode 100644 index 000000000000..65beaa59987c --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step4/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1" + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step4/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..c24527017709 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step4/show_ipv6_route.ref @@ -0,0 +1,321 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:5:1::\/64":[ + { + "prefix":"fc00:0:5:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:2::\/64":[ + { + "prefix":"fc00:0:5:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:3::\/64":[ + { + "prefix":"fc00:0:5:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:4::\/64":[ + { + "prefix":"fc00:0:5:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref new file mode 100644 index 000000000000..54780fce8adc --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:5::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:5::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt5/step4/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..f40b0d353d7a --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step4/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt3-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt3-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step5/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step5/show_ip_route.ref new file mode 100644 index 000000000000..65beaa59987c --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step5/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1" + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step5/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..d6ad4c2aad24 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step5/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:5:1::\/64":[ + { + "prefix":"fc00:0:5:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:2::\/64":[ + { + "prefix":"fc00:0:5:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:3::\/64":[ + { + "prefix":"fc00:0:5:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:4::\/64":[ + { + "prefix":"fc00:0:5:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref new file mode 100644 index 000000000000..54780fce8adc --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:5::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:5::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt5/step5/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..f40b0d353d7a --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step5/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt3-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt3-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step6/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step6/show_ip_route.ref new file mode 100644 index 000000000000..65beaa59987c --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step6/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1" + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step6/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..c24527017709 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step6/show_ipv6_route.ref @@ -0,0 +1,321 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:5:1::\/64":[ + { + "prefix":"fc00:0:5:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:2::\/64":[ + { + "prefix":"fc00:0:5:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:3::\/64":[ + { + "prefix":"fc00:0:5:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:4::\/64":[ + { + "prefix":"fc00:0:5:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref new file mode 100644 index 000000000000..54780fce8adc --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:5::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:5::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt5/step6/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..f40b0d353d7a --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step6/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt3-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt3-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step7/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step7/show_ip_route.ref new file mode 100644 index 000000000000..65beaa59987c --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step7/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1" + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step7/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..d6ad4c2aad24 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step7/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:5:1::\/64":[ + { + "prefix":"fc00:0:5:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:2::\/64":[ + { + "prefix":"fc00:0:5:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:3::\/64":[ + { + "prefix":"fc00:0:5:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:4::\/64":[ + { + "prefix":"fc00:0:5:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref new file mode 100644 index 000000000000..54780fce8adc --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:5::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:5::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt5/step7/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..f40b0d353d7a --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step7/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt3-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt3-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step8/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step8/show_ip_route.ref new file mode 100644 index 000000000000..65beaa59987c --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step8/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1" + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step8/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..c24527017709 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step8/show_ipv6_route.ref @@ -0,0 +1,321 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:5:1::\/64":[ + { + "prefix":"fc00:0:5:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:2::\/64":[ + { + "prefix":"fc00:0:5:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:3::\/64":[ + { + "prefix":"fc00:0:5:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:4::\/64":[ + { + "prefix":"fc00:0:5:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref new file mode 100644 index 000000000000..54780fce8adc --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:5::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:5::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt5/step8/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..f40b0d353d7a --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step8/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt3-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt3-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step9/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step9/show_ip_route.ref new file mode 100644 index 000000000000..65beaa59987c --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step9/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1" + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step9/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt5/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..d6ad4c2aad24 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step9/show_ipv6_route.ref @@ -0,0 +1,346 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::1\/128":[ + { + "prefix":"fc00:0:6::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:5:1::\/64":[ + { + "prefix":"fc00:0:5:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:2::\/64":[ + { + "prefix":"fc00:0:5:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:3::\/64":[ + { + "prefix":"fc00:0:5:3::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:5:4::\/64":[ + { + "prefix":"fc00:0:5:4::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref new file mode 100644 index 000000000000..54780fce8adc --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:5::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:5::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt5/step9/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..f40b0d353d7a --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/step9/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,82 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt3-1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt3-2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt5/zebra.conf b/tests/topotests/isis_srv6_topo1/rt5/zebra.conf new file mode 100644 index 000000000000..acd01bd72672 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt5/zebra.conf @@ -0,0 +1,36 @@ +log file zebra.log +! +hostname rt5 +! +! debug zebra kernel +! debug zebra packet +! +interface lo + ip address 5.5.5.5/32 + ipv6 address fc00:0:5::1/128 +! +interface eth-rt3-1 + ip address 10.0.4.5/24 +! +interface eth-rt3-2 + ip address 10.0.5.5/24 +! +interface eth-rt4 + ip address 10.0.6.5/24 +! +interface eth-rt6 + ip address 10.0.8.5/24 +! +segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:5::/48 block-len 32 node-len 16 func-bits 16 + behavior usid + ! + ! +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis_srv6_topo1/rt6/isisd.conf b/tests/topotests/isis_srv6_topo1/rt6/isisd.conf new file mode 100644 index 000000000000..f8816db43aac --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/isisd.conf @@ -0,0 +1,42 @@ +hostname rt6 +log file isisd.log +! +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen +! +interface lo + ip router isis 1 + ipv6 router isis 1 + isis passive +! +interface eth-rt4 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +interface eth-rt5 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +router isis 1 + lsp-gen-interval 2 + net 49.0000.0000.0000.0006.00 + is-type level-1 + topology ipv6-unicast + segment-routing srv6 + locator loc1 + node-msd + max-segs-left 3 + max-end-pop 3 + max-h-encaps 2 + max-end-d 5 + interface sr0 +! diff --git a/tests/topotests/isis_srv6_topo1/rt6/sharpd.conf b/tests/topotests/isis_srv6_topo1/rt6/sharpd.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/isis_srv6_topo1/rt6/step1/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step1/show_ip_route.ref new file mode 100644 index 000000000000..5fc293b6d8a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step1/show_ip_route.ref @@ -0,0 +1,273 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step1/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step1/show_ipv6_route.ref new file mode 100644 index 000000000000..407e2d0f4cfe --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step1/show_ipv6_route.ref @@ -0,0 +1,268 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:6:1::\/64":[ + { + "prefix":"fc00:0:6:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:6:2::\/64":[ + { + "prefix":"fc00:0:6:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref new file mode 100644 index 000000000000..35aa61d8e6d5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:6::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:6::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..8300ca0b5cd8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step2/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step2/show_ip_route.ref new file mode 100644 index 000000000000..5fc293b6d8a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step2/show_ip_route.ref @@ -0,0 +1,273 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step2/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..6c64bd7d1eec --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step2/show_ipv6_route.ref @@ -0,0 +1,243 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:6:1::\/64":[ + { + "prefix":"fc00:0:6:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:6:2::\/64":[ + { + "prefix":"fc00:0:6:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref new file mode 100644 index 000000000000..35aa61d8e6d5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:6::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:6::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt6/step2/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..8300ca0b5cd8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step2/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step3/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step3/show_ip_route.ref new file mode 100644 index 000000000000..5fc293b6d8a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step3/show_ip_route.ref @@ -0,0 +1,273 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step3/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..407e2d0f4cfe --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step3/show_ipv6_route.ref @@ -0,0 +1,268 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:6:1::\/64":[ + { + "prefix":"fc00:0:6:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:6:2::\/64":[ + { + "prefix":"fc00:0:6:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref new file mode 100644 index 000000000000..35aa61d8e6d5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:6::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:6::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt6/step3/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..8300ca0b5cd8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step3/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step4/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step4/show_ip_route.ref new file mode 100644 index 000000000000..5fc293b6d8a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step4/show_ip_route.ref @@ -0,0 +1,273 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step4/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..6c64bd7d1eec --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step4/show_ipv6_route.ref @@ -0,0 +1,243 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:6:1::\/64":[ + { + "prefix":"fc00:0:6:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:6:2::\/64":[ + { + "prefix":"fc00:0:6:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref new file mode 100644 index 000000000000..35aa61d8e6d5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:6::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:6::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt6/step4/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..8300ca0b5cd8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step4/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step5/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step5/show_ip_route.ref new file mode 100644 index 000000000000..5fc293b6d8a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step5/show_ip_route.ref @@ -0,0 +1,273 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step5/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..407e2d0f4cfe --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step5/show_ipv6_route.ref @@ -0,0 +1,268 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:6:1::\/64":[ + { + "prefix":"fc00:0:6:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:6:2::\/64":[ + { + "prefix":"fc00:0:6:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref new file mode 100644 index 000000000000..35aa61d8e6d5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:6::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:6::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt6/step5/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..8300ca0b5cd8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step5/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step6/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step6/show_ip_route.ref new file mode 100644 index 000000000000..5fc293b6d8a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step6/show_ip_route.ref @@ -0,0 +1,273 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step6/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..6c64bd7d1eec --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step6/show_ipv6_route.ref @@ -0,0 +1,243 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:6:1::\/64":[ + { + "prefix":"fc00:0:6:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:6:2::\/64":[ + { + "prefix":"fc00:0:6:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref new file mode 100644 index 000000000000..35aa61d8e6d5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:6::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:6::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt6/step6/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..8300ca0b5cd8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step6/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step7/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step7/show_ip_route.ref new file mode 100644 index 000000000000..5fc293b6d8a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step7/show_ip_route.ref @@ -0,0 +1,273 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step7/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..407e2d0f4cfe --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step7/show_ipv6_route.ref @@ -0,0 +1,268 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:6:1::\/64":[ + { + "prefix":"fc00:0:6:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:6:2::\/64":[ + { + "prefix":"fc00:0:6:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref new file mode 100644 index 000000000000..35aa61d8e6d5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:6::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:6::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt6/step7/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..8300ca0b5cd8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step7/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step8/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step8/show_ip_route.ref new file mode 100644 index 000000000000..5fc293b6d8a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step8/show_ip_route.ref @@ -0,0 +1,273 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step8/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..6c64bd7d1eec --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step8/show_ipv6_route.ref @@ -0,0 +1,243 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:6:1::\/64":[ + { + "prefix":"fc00:0:6:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:6:2::\/64":[ + { + "prefix":"fc00:0:6:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref new file mode 100644 index 000000000000..35aa61d8e6d5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:6::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:6::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt6/step8/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..8300ca0b5cd8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step8/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step9/show_ip_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step9/show_ip_route.ref new file mode 100644 index 000000000000..5fc293b6d8a5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step9/show_ip_route.ref @@ -0,0 +1,273 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step9/show_ipv6_route.ref b/tests/topotests/isis_srv6_topo1/rt6/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..407e2d0f4cfe --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step9/show_ipv6_route.ref @@ -0,0 +1,268 @@ +{ + "fc00:0:1::1\/128":[ + { + "prefix":"fc00:0:1::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::1\/128":[ + { + "prefix":"fc00:0:2::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::1\/128":[ + { + "prefix":"fc00:0:3::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::1\/128":[ + { + "prefix":"fc00:0:4::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::1\/128":[ + { + "prefix":"fc00:0:5::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:1::\/48":[ + { + "prefix":"fc00:0:1::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:2::\/48":[ + { + "prefix":"fc00:0:2::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:3::\/48":[ + { + "prefix":"fc00:0:3::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:4::\/48":[ + { + "prefix":"fc00:0:4::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "fc00:0:5::\/48":[ + { + "prefix":"fc00:0:5::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "fc00:0:6::\/48":[ + { + "prefix":"fc00:0:6::\/48", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"sr0", + "active":true, + "seg6local":{ + "action":"End" + } + } + ] + } + ], + "fc00:0:6:1::\/64":[ + { + "prefix":"fc00:0:6:1::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ], + "fc00:0:6:2::\/64":[ + { + "prefix":"fc00:0:6:2::\/64", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "active":true, + "seg6local":{ + "action":"End.X" + } + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref new file mode 100644 index 000000000000..35aa61d8e6d5 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref @@ -0,0 +1,19 @@ +{ + "locators":[ + { + "name":"loc1", + "prefix":"fc00:0:6::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "statusUp":true, + "chunks":[ + { + "prefix":"fc00:0:6::/48", + "proto":"isis" + } + ] + } + ] +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_srv6_topo1/rt6/step9/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000000..8300ca0b5cd8 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/step9/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 10, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis_srv6_topo1/rt6/zebra.conf b/tests/topotests/isis_srv6_topo1/rt6/zebra.conf new file mode 100644 index 000000000000..83e7f528a465 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/rt6/zebra.conf @@ -0,0 +1,36 @@ +log file zebra.log +! +hostname rt6 +! +! debug zebra kernel +! debug zebra packet +! +interface lo + ip address 6.6.6.6/32 + ipv6 address fc00:0:6::1/128 +! +interface eth-rt4 + ip address 10.0.7.6/24 +! +interface eth-rt5 + ip address 10.0.8.6/24 +! +interface eth-dst + ip address 10.0.10.1/24 + ip address 2001:db8:10::1/64 +! +segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:6::/48 block-len 32 node-len 16 func-bits 16 + behavior usid + ! + ! +! +ip forwarding +! +ip route fc00:0:9::1/128 2001:db8:10::2 +! +line vty +! diff --git a/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py b/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py new file mode 100644 index 000000000000..892f6e1d0e71 --- /dev/null +++ b/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py @@ -0,0 +1,1124 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2023 by +# Carmine Scarpitta +# + +""" +test_isis_srv6_topo1.py: + + +---------+ + | | + | RT1 | + | 1.1.1.1 | + | | + +---------+ + |eth-sw1 + | + | + | + +---------+ | +---------+ + | | | | | + | RT2 |eth-sw1 | eth-sw1| RT3 | + | 2.2.2.2 +----------+----------+ 3.3.3.3 | + | | 10.0.1.0/24 | | + +---------+ +---------+ + eth-rt4-1| |eth-rt4-2 eth-rt5-1| |eth-rt5-2 + | | | | + 10.0.2.0/24| |10.0.3.0/24 10.0.4.0/24| |10.0.5.0/24 + | | | | + eth-rt2-1| |eth-rt2-2 eth-rt3-1| |eth-rt3-2 + +---------+ +---------+ + | | | | + | RT4 | 10.0.6.0/24 | RT5 | + | 4.4.4.4 +---------------------+ 5.5.5.5 | + | |eth-rt5 eth-rt4| | + +---------+ +---------+ + eth-rt6| |eth-rt6 + | | + 10.0.7.0/24| |10.0.8.0/24 + | +---------+ | + | | | | + | | RT6 | | + +----------+ 6.6.6.6 +-----------+ + eth-rt4| |eth-rt5 + +---------+ + |eth-dst (.1) + | + |10.0.10.0/24 + | + |eth-rt6 (.2) + +---------+ + | | + | DST | + | 9.9.9.2 | + | | + +---------+ + +""" + +import os +import re +import sys +import json +import functools +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.common_config import ( + required_linux_kernel_version, + create_interface_in_kernel, +) + +pytestmark = [pytest.mark.isisd, pytest.mark.sharpd] + + +def build_topo(tgen): + """Build function""" + + # Define FRR Routers + tgen.add_router("rt1") + tgen.add_router("rt2") + tgen.add_router("rt3") + tgen.add_router("rt4") + tgen.add_router("rt5") + tgen.add_router("rt6") + tgen.add_router("dst") + + # Define connections + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["rt1"], nodeif="eth-sw1") + switch.add_link(tgen.gears["rt2"], nodeif="eth-sw1") + switch.add_link(tgen.gears["rt3"], nodeif="eth-sw1") + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-1") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-1") + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-2") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-2") + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-1") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-1") + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-2") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-2") + + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4") + + switch = tgen.add_switch("s7") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4") + + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5") + + switch = tgen.add_switch("s9") + switch.add_link(tgen.gears["rt6"], nodeif="eth-dst") + switch.add_link(tgen.gears["dst"], nodeif="eth-rt6") + + # Add dummy interface for SRv6 + create_interface_in_kernel( + tgen, + "rt1", + "sr0", + "2001:db8::1", + netmask="128", + create=True, + ) + create_interface_in_kernel( + tgen, + "rt2", + "sr0", + "2001:db8::2", + netmask="128", + create=True, + ) + create_interface_in_kernel( + tgen, + "rt3", + "sr0", + "2001:db8::3", + netmask="128", + create=True, + ) + create_interface_in_kernel( + tgen, + "rt4", + "sr0", + "2001:db8::4", + netmask="128", + create=True, + ) + create_interface_in_kernel( + tgen, + "rt5", + "sr0", + "2001:db8::5", + netmask="128", + create=True, + ) + create_interface_in_kernel( + tgen, + "rt6", + "sr0", + "2001:db8::6", + netmask="128", + create=True, + ) + + +def setup_module(mod): + """Sets up the pytest environment""" + + # Verify if kernel requirements are satisfied + result = required_linux_kernel_version("4.10") + if result is not True: + pytest.skip("Kernel requirements are not met") + + # Build the topology + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + # For all registered routers, load the zebra and isis configuration files + for rname, router in tgen.routers().items(): + router.load_config(TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname))) + router.load_config(TopoRouter.RD_ISIS, + os.path.join(CWD, '{}/isisd.conf'.format(rname))) + if (os.path.exists('{}/sharpd.conf'.format(rname))): + router.load_config(TopoRouter.RD_SHARP, + os.path.join(CWD, '{}/sharpd.conf'.format(rname))) + + # Start routers + tgen.start_router() + + +def teardown_module(mod): + "Teardown the pytest environment" + + # Teardown the topology + tgen = get_topogen() + tgen.stop_topology() + + +def router_compare_json_output(rname, command, reference): + "Compare router JSON output" + + logger.info('Comparing router "%s" "%s" output', rname, command) + + tgen = get_topogen() + filename = "{}/{}/{}".format(CWD, rname, reference) + expected = json.loads(open(filename).read()) + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = functools.partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) + _, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + + +def check_ping6(name, dest_addr, expect_connected): + def _check(name, dest_addr, match): + tgen = get_topogen() + output = tgen.gears[name].run("ping6 {} -c 1 -w 1".format(dest_addr)) + logger.info(output) + if match not in output: + return "ping fail" + + match = "{} packet loss".format("0%" if expect_connected else "100%") + logger.info("[+] check {} {} {}".format(name, dest_addr, match)) + tgen = get_topogen() + func = functools.partial(_check, name, dest_addr, match) + success, result = topotest.run_and_expect(func, None, count=10, wait=1) + assert result is None, "Failed" + + +# +# Step 1 +# +# Test initial network convergence +# +def test_isis_adjacencies_step1(): + logger.info("Test (step 1): check IS-IS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "step1/show_yang_interface_isis_adjacencies.ref", + ) + + +def test_rib_ipv4_step1(): + logger.info("Test (step 1): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", "step1/show_ip_route.ref" + ) + + +def test_rib_ipv6_step1(): + logger.info("Test (step 1): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", "step1/show_ipv6_route.ref" + ) + + +def test_srv6_locator_step1(): + logger.info("Test (step 1): verify SRv6 Locator") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show segment-routing srv6 locator json", "step1/show_srv6_locator_table.ref" + ) + + +def test_ping_step1(): + logger.info("Test (step 1): verify ping") + tgen = get_topogen() + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("6.1") + if result is not True: + pytest.skip("Kernel requirements are not met, kernel version should be >=6.1") + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Setup encap route on rt1, decap route on rt2 + tgen.gears["rt1"].vtysh_cmd("sharp install seg6-routes fc00:0:9::1 nexthop-seg6 2001:db8:1::2 encap fc00:0:1:2:6:f00d:: 1") + tgen.gears["rt6"].vtysh_cmd("sharp install seg6local-routes fc00:0:f00d:: nexthop-seg6local eth-dst End_DT6 254 1") + tgen.gears["dst"].vtysh_cmd("sharp install route 2001:db8:1::1 nexthop 2001:db8:10::1 1") + + # Try to ping dst from rt1 + check_ping6("rt1", "fc00:0:9::1", True) + + +# +# Step 2 +# +# Action(s): +# -Disable SRv6 Locator on zebra on rt1 +# +# Expected changes: +# -rt1 should uninstall the SRv6 End SID +# -rt1 should remove the SRv6 Locator from zebra +# -rt1 should remove the SRv6 Locator TLV from the LSPs +# -rt1 should remove the SRv6 Capabilities Sub-TLV from the Router Capability TLV +# -rt2, rt3, rt4, rt5, rt6 should uninstall the route pointing to the rt1's SRv6 Locator from the RIB +# +def test_isis_adjacencies_step2(): + logger.info("Test (step 2): check IS-IS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Disabling SRv6 Locator on zebra on rt1") + tgen.gears["rt1"].vtysh_cmd( + """ + configure terminal + segment-routing + srv6 + locators + no locator loc1 + """ + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "step2/show_yang_interface_isis_adjacencies.ref", + ) + + +def test_rib_ipv4_step2(): + logger.info("Test (step 2): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", "step2/show_ip_route.ref" + ) + + +def test_rib_ipv6_step2(): + logger.info("Test (step 2): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", "step2/show_ipv6_route.ref" + ) + + +def test_srv6_locator_step2(): + logger.info("Test (step 2): verify SRv6 Locator") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show segment-routing srv6 locator json", "step2/show_srv6_locator_table.ref" + ) + + +def test_ping_step2(): + logger.info("Test (step 2): verify ping") + tgen = get_topogen() + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("6.1") + if result is not True: + pytest.skip("Kernel requirements are not met, kernel version should be >=6.1") + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ping6("rt1", "fc00:0:9::1", False) + + +# +# Step 3 +# +# Action(s): +# -Enable SRv6 Locator on zebra on rt1 +# +# Expected changes: +# -rt1 should install the SRv6 End SID +# -rt1 should install the SRv6 Locator in zebra +# -rt1 should add the SRv6 Locator TLV to the LSPs +# -rt1 should add the SRv6 Capabilities Sub-TLV to the Router Capability TLV +# -rt2, rt3, rt4, rt5, rt6 should install a route pointing to the rt1's SRv6 Locator in the RIB +# +def test_isis_adjacencies_step3(): + logger.info("Test (step 3): check IS-IS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Enabling SRv6 Locator on zebra on rt1") + tgen.gears["rt1"].vtysh_cmd( + """ + configure terminal + segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16 + behavior usid + """ + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "step3/show_yang_interface_isis_adjacencies.ref", + ) + + +def test_rib_ipv4_step3(): + logger.info("Test (step 3): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", "step3/show_ip_route.ref" + ) + + +def test_rib_ipv6_step3(): + logger.info("Test (step 3): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", "step3/show_ipv6_route.ref" + ) + + +def test_srv6_locator_step3(): + logger.info("Test (step 3): verify SRv6 Locator") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show segment-routing srv6 locator json", "step3/show_srv6_locator_table.ref" + ) + + +def test_ping_step3(): + logger.info("Test (step 3): verify ping") + tgen = get_topogen() + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("6.1") + if result is not True: + pytest.skip("Kernel requirements are not met, kernel version should be >=6.1") + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ping6("rt1", "fc00:0:9::1", True) + + +# +# Step 4 +# +# Action(s): +# -Disable SRv6 Locator on ISIS on rt1 +# +# Expected changes: +# -rt1 should uninstall the SRv6 End SID +# -rt1 should remove the SRv6 Locator TLV from the LSPs +# -rt1 should remove the SRv6 Capabilities Sub-TLV from the Router Capability TLV +# -rt2, rt3, rt4, rt5, rt6 should uninstall the route pointing to the rt1's SRv6 Locator from the RIB +# +def test_isis_adjacencies_step4(): + logger.info("Test (step 4): check IS-IS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Disabling SRv6 Locator on ISIS on rt1") + tgen.gears["rt1"].vtysh_cmd( + """ + configure terminal + router isis 1 + segment-routing srv6 + no locator loc1 + """ + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "step4/show_yang_interface_isis_adjacencies.ref", + ) + + +def test_rib_ipv4_step4(): + logger.info("Test (step 4): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", "step4/show_ip_route.ref" + ) + + +def test_rib_ipv6_step4(): + logger.info("Test (step 4): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", "step4/show_ipv6_route.ref" + ) + + +def test_srv6_locator_step4(): + logger.info("Test (step 4): verify SRv6 Locator") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show segment-routing srv6 locator json", "step4/show_srv6_locator_table.ref" + ) + + +def test_ping_step4(): + logger.info("Test (step 4): verify ping") + tgen = get_topogen() + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("6.1") + if result is not True: + pytest.skip("Kernel requirements are not met, kernel version should be >=6.1") + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ping6("rt1", "fc00:0:9::1", False) + + +# +# Step 5 +# +# Action(s): +# -Enable SRv6 Locator on ISIS on rt1 +# +# Expected changes: +# -rt1 should install the SRv6 End SID +# -rt1 should add the SRv6 Locator TLV to the LSPs +# -rt1 should add the SRv6 Capabilities Sub-TLV to the Router Capability TLV +# -rt2, rt3, rt4, rt5, rt6 should install a route pointing to the rt1's SRv6 Locator in the RIB +# +def test_isis_adjacencies_step5(): + logger.info("Test (step 5): check IS-IS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Enabling SRv6 Locator on ISIS on rt1") + tgen.gears["rt1"].vtysh_cmd( + """ + configure terminal + router isis 1 + segment-routing srv6 + locator loc1 + """ + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "step5/show_yang_interface_isis_adjacencies.ref", + ) + + +def test_rib_ipv4_step5(): + logger.info("Test (step 5): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", "step5/show_ip_route.ref" + ) + + +def test_rib_ipv6_step5(): + logger.info("Test (step 5): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", "step5/show_ipv6_route.ref" + ) + + +def test_srv6_locator_step5(): + logger.info("Test (step 5): verify SRv6 Locator") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show segment-routing srv6 locator json", "step5/show_srv6_locator_table.ref" + ) + + +def test_ping_step5(): + logger.info("Test (step 5): verify ping") + tgen = get_topogen() + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("6.1") + if result is not True: + pytest.skip("Kernel requirements are not met, kernel version should be >=6.1") + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ping6("rt1", "fc00:0:9::1", True) + + +# +# Step 6 +# +# Action(s): +# -Disable SRv6 on ISIS on rt1 +# +# Expected changes: +# -rt1 should uninstall the SRv6 End SID +# -rt1 should remove the SRv6 Locator TLV from the LSPs +# -rt1 should remove the SRv6 Capabilities Sub-TLV from the Router Capability TLV +# -rt2, rt3, rt4, rt5, rt6 should uninstall the route pointing to the rt1's SRv6 Locator from the RIB +# +def test_isis_adjacencies_step6(): + logger.info("Test (step 6): check IS-IS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Disabling SRv6 on ISIS on rt1") + tgen.gears["rt1"].vtysh_cmd( + """ + configure terminal + router isis 1 + no segment-routing srv6 + """ + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "step6/show_yang_interface_isis_adjacencies.ref", + ) + + +def test_rib_ipv4_step6(): + logger.info("Test (step 6): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", "step6/show_ip_route.ref" + ) + + +def test_rib_ipv6_step6(): + logger.info("Test (step 6): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", "step6/show_ipv6_route.ref" + ) + + +def test_srv6_locator_step6(): + logger.info("Test (step 6): verify SRv6 Locator") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show segment-routing srv6 locator json", "step6/show_srv6_locator_table.ref" + ) + + +def test_ping_step6(): + logger.info("Test (step 6): verify ping") + tgen = get_topogen() + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("6.1") + if result is not True: + pytest.skip("Kernel requirements are not met, kernel version should be >=6.1") + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ping6("rt1", "fc00:0:9::1", False) + + +# +# Step 7 +# +# Action(s): +# -Enable SRv6 on ISIS on rt1 +# +# Expected changes: +# -rt1 should install the SRv6 End SID +# -rt1 should add the SRv6 Locator TLV to the LSPs +# -rt1 should add the SRv6 Capabilities Sub-TLV to the Router Capability TLV +# -rt2, rt3, rt4, rt5, rt6 should install a route pointing to the rt1's SRv6 Locator in the RIB +# +def test_isis_adjacencies_step7(): + logger.info("Test (step 7): check IS-IS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Enabling SRv6 on ISIS on rt1") + tgen.gears["rt1"].vtysh_cmd( + """ + configure terminal + router isis 1 + segment-routing srv6 + locator loc1 + """ + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "step7/show_yang_interface_isis_adjacencies.ref", + ) + + +def test_rib_ipv4_step7(): + logger.info("Test (step 7): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", "step7/show_ip_route.ref" + ) + + +def test_rib_ipv6_step7(): + logger.info("Test (step 7): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", "step7/show_ipv6_route.ref" + ) + + +def test_srv6_locator_step7(): + logger.info("Test (step 7): verify SRv6 Locator") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show segment-routing srv6 locator json", "step7/show_srv6_locator_table.ref" + ) + + +def test_ping_step7(): + logger.info("Test (step 7): verify ping") + tgen = get_topogen() + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("6.1") + if result is not True: + pytest.skip("Kernel requirements are not met, kernel version should be >=6.1") + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ping6("rt1", "fc00:0:9::1", True) + + +# +# Step 8 +# +# Action(s): +# -Disable SRv6 on zebra on rt1 +# +# Expected changes: +# -rt1 should uninstall the SRv6 End SID +# -rt1 should remove the SRv6 Locator TLV from the LSPs +# -rt1 should remove the SRv6 Capabilities Sub-TLV from the Router Capability TLV +# -rt2, rt3, rt4, rt5, rt6 should uninstall the route pointing to the rt1's SRv6 Locator from the RIB +# +def test_isis_adjacencies_step8(): + logger.info("Test (step 8): check IS-IS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Disabling SRv6 on zebra on rt1") + tgen.gears["rt1"].vtysh_cmd( + """ + configure terminal + segment-routing + no srv6 + """ + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "step8/show_yang_interface_isis_adjacencies.ref", + ) + + +def test_rib_ipv4_step8(): + logger.info("Test (step 8): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", "step8/show_ip_route.ref" + ) + + +def test_rib_ipv6_step8(): + logger.info("Test (step 8): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", "step8/show_ipv6_route.ref" + ) + + +def test_srv6_locator_step8(): + logger.info("Test (step 8): verify SRv6 Locator") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show segment-routing srv6 locator json", "step8/show_srv6_locator_table.ref" + ) + + +def test_ping_step8(): + logger.info("Test (step 8): verify ping") + tgen = get_topogen() + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("6.1") + if result is not True: + pytest.skip("Kernel requirements are not met, kernel version should be >=6.1") + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ping6("rt1", "fc00:0:9::1", False) + + +# +# Step 9 +# +# Action(s): +# -Enable SRv6 on zebra on rt1 +# +# Expected changes: +# -rt1 should install the SRv6 End SID +# -rt1 should add the SRv6 Locator TLV to the LSPs +# -rt1 should add the SRv6 Capabilities Sub-TLV to the Router Capability TLV +# -rt2, rt3, rt4, rt5, rt6 should install a route pointing to the rt1's SRv6 Locator in the RIB +# +def test_isis_adjacencies_step9(): + logger.info("Test (step 9): check IS-IS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Enabling SRv6 on zebra on rt1") + tgen.gears["rt1"].vtysh_cmd( + """ + configure terminal + segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16 + behavior usid + """ + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "step9/show_yang_interface_isis_adjacencies.ref", + ) + + +def test_rib_ipv4_step9(): + logger.info("Test (step 9): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", "step9/show_ip_route.ref" + ) + + +def test_rib_ipv6_step9(): + logger.info("Test (step 9): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", "step9/show_ipv6_route.ref" + ) + + +def test_srv6_locator_step9(): + logger.info("Test (step 9): verify SRv6 Locator") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show segment-routing srv6 locator json", "step9/show_srv6_locator_table.ref" + ) + + +def test_ping_step9(): + logger.info("Test (step 9): verify ping") + tgen = get_topogen() + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("6.1") + if result is not True: + pytest.skip("Kernel requirements are not met, kernel version should be >=6.1") + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ping6("rt1", "fc00:0:9::1", True) + + +# Memory leak test template +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ldp_snmp/r1/snmpd.conf b/tests/topotests/ldp_snmp/r1/snmpd.conf index 3fd5e982e8fb..cdcd9a2b372d 100644 --- a/tests/topotests/ldp_snmp/r1/snmpd.conf +++ b/tests/topotests/ldp_snmp/r1/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:1.1.1.1:161 +agentAddress udp:161 com2sec public 1.1.1.1 public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/ldp_snmp/r2/snmpd.conf b/tests/topotests/ldp_snmp/r2/snmpd.conf index fc648057a5e1..17ddc2a1f9a8 100644 --- a/tests/topotests/ldp_snmp/r2/snmpd.conf +++ b/tests/topotests/ldp_snmp/r2/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:2.2.2.2:161 +agentAddress udp:161 com2sec public 2.2.2.2 public @@ -15,4 +15,4 @@ rouser frr master agentx agentXSocket /etc/frr/agentx -agentXPerms 777 755 root frr \ No newline at end of file +agentXPerms 777 755 root frr diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 21d4567d6ba0..3a16ed5a090d 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -1325,7 +1325,7 @@ def verify_router_id(tgen, topo, input_dict, expected=True): @retry(retry_timeout=150) -def verify_bgp_convergence(tgen, topo=None, dut=None, expected=True): +def verify_bgp_convergence(tgen, topo=None, dut=None, expected=True, addr_type=None): """ API will verify if BGP is converged with in the given time frame. Running "show bgp summary json" command and verify bgp neighbor @@ -1336,6 +1336,7 @@ def verify_bgp_convergence(tgen, topo=None, dut=None, expected=True): * `tgen`: topogen object * `topo`: input json file data * `dut`: device under test + * `addr_type` : address type for which verification to be done, by-default both v4 and v6 Usage ----- @@ -1439,20 +1440,27 @@ def verify_bgp_convergence(tgen, topo=None, dut=None, expected=True): return errormsg else: total_peer = 0 - for addr_type in bgp_addr_type.keys(): - if not check_address_types(addr_type): + for _addr_type in bgp_addr_type.keys(): + if not check_address_types(_addr_type): + continue + + if addr_type and addr_type != _addr_type: continue - bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] + bgp_neighbors = bgp_addr_type[_addr_type]["unicast"]["neighbor"] for bgp_neighbor in bgp_neighbors: total_peer += len(bgp_neighbors[bgp_neighbor]["dest_link"]) no_of_peer = 0 - for addr_type in bgp_addr_type.keys(): + for _addr_type in bgp_addr_type.keys(): if not check_address_types(addr_type): continue - bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] + + if addr_type and addr_type != _addr_type: + continue + + bgp_neighbors = bgp_addr_type[_addr_type]["unicast"]["neighbor"] for bgp_neighbor, peer_data in bgp_neighbors.items(): for dest_link in peer_data["dest_link"].keys(): @@ -1473,7 +1481,7 @@ def verify_bgp_convergence(tgen, topo=None, dut=None, expected=True): elif "source_link" in peer_details: neighbor_ip = topo["routers"][bgp_neighbor][ "links" - ][peer_details["source_link"]][addr_type].split( + ][peer_details["source_link"]][_addr_type].split( "/" )[ 0 @@ -1484,12 +1492,12 @@ def verify_bgp_convergence(tgen, topo=None, dut=None, expected=True): ): neighbor_ip = data[dest_link]["peer-interface"] else: - neighbor_ip = data[dest_link][addr_type].split("/")[ - 0 - ] + neighbor_ip = data[dest_link][_addr_type].split( + "/" + )[0] nh_state = None neighbor_ip = neighbor_ip.lower() - if addr_type == "ipv4": + if _addr_type == "ipv4": ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][ "peers" ] diff --git a/tests/topotests/lib/grpc-query.py b/tests/topotests/lib/grpc-query.py index 5dd12d581edd..8c4701c24390 100755 --- a/tests/topotests/lib/grpc-query.py +++ b/tests/topotests/lib/grpc-query.py @@ -26,7 +26,7 @@ commander.cmd_raises(f"cp {CWD}/../../../grpc/frr-northbound.proto .") commander.cmd_raises( - f"python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I . frr-northbound.proto" + f"python3 -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I . frr-northbound.proto" ) except Exception as error: logging.error("can't create proto definition modules %s", error) @@ -36,17 +36,6 @@ sys.path[0:0] = "." import frr_northbound_pb2 import frr_northbound_pb2_grpc - - # Would be nice if compiling the modules internally from the source worked - # # import grpc_tools.protoc - # # proto_include = pkg_resources.resource_filename("grpc_tools", "_proto") - # from grpc_tools.protoc import _proto_file_to_module_name, _protos_and_services - # try: - # frr_northbound_pb2, frr_northbound_pb2_grpc = _protos_and_services( - # "frr_northbound.proto" - # ) - # finally: - # os.chdir(CWD) except Exception as error: logging.error("can't import proto definition modules %s", error) raise diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 5486e904df74..5b18f8b679ce 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -426,6 +426,10 @@ def config_ospf_interface( cmd = "ip ospf authentication null" elif data_ospf_auth == "message-digest": cmd = "ip ospf authentication message-digest" + elif data_ospf_auth == "key-chain": + cmd = "ip ospf authentication key-chain {}".format( + ospf_data["keychain"] + ) else: cmd = "ip ospf authentication" diff --git a/tests/topotests/multicast_mld_join_topo1/test_multicast_mld_local_join.py b/tests/topotests/multicast_mld_join_topo1/test_multicast_mld_local_join.py index 826d6e294106..84a13aedeeee 100644 --- a/tests/topotests/multicast_mld_join_topo1/test_multicast_mld_local_join.py +++ b/tests/topotests/multicast_mld_join_topo1/test_multicast_mld_local_join.py @@ -42,6 +42,10 @@ verify_pim_rp_info, verify_upstream_iif, ) +from lib.bgp import ( + verify_bgp_convergence, +) + from lib.topogen import Topogen, get_topogen from lib.topojson import build_config_from_json from lib.topolog import logger @@ -126,6 +130,13 @@ def setup_module(mod): # Creating configuration from JSON build_config_from_json(tgen, topo) + + # Verify BGP convergence + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + # Verify PIM neighbors result = verify_pim_neighbors(tgen, topo) assert result is True, " Verify PIM neighbor: Failed Error: {}".format(result) @@ -177,6 +188,10 @@ def test_mld_local_joins_p0(request): reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + step("configure BGP on R1, R2, R3, R4 and enable redistribute static/connected") step("Enable the MLD on R11 interfac of R1 and configure local mld groups") intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] @@ -249,6 +264,10 @@ def test_mroute_with_mld_local_joins_p0(request): reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + app_helper.stop_all_hosts() step("Enable the PIM on all the interfaces of R1, R2, R3, R4") @@ -442,6 +461,10 @@ def test_remove_add_mld_local_joins_p1(request): reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + app_helper.stop_all_hosts() step("Enable the PIM on all the interfaces of R1, R2, R3, R4") @@ -694,6 +717,10 @@ def test_remove_add_mld_config_with_local_joins_p1(request): reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + app_helper.stop_all_hosts() step("Enable the PIM on all the interfaces of R1, R2, R3, R4") diff --git a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py index aff623705c6b..7eb583803715 100644 --- a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py +++ b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py @@ -61,6 +61,9 @@ verify_sg_traffic, verify_upstream_iif, ) +from lib.bgp import ( + verify_bgp_convergence, +) from lib.topogen import Topogen, get_topogen from lib.topojson import build_config_from_json from lib.topolog import logger @@ -140,6 +143,12 @@ def setup_module(mod): global app_helper app_helper = McastTesterHelper(tgen) + # Verify BGP convergence + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + logger.info("Running setup_module() done") @@ -276,6 +285,10 @@ def test_multicast_data_traffic_static_RP_send_traffic_then_join_p0(request): # Creating configuration from JSON reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + app_helper.stop_all_hosts() # Don"t run this test if we have any failure. @@ -480,6 +493,10 @@ def test_verify_mroute_when_receiver_is_outside_frr_p0(request): # Creating configuration from JSON reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -648,6 +665,10 @@ def test_verify_mroute_when_frr_is_transit_router_p2(request): # Creating configuration from JSON reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + app_helper.stop_all_hosts() # Don"t run this test if we have any failure. @@ -803,6 +824,10 @@ def test_verify_mroute_when_RP_unreachable_p1(request): # Creating configuration from JSON reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + app_helper.stop_all_hosts() # Don"t run this test if we have any failure. @@ -929,6 +954,10 @@ def test_modify_mld_query_timer_p0(request): # Creating configuration from JSON reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + app_helper.stop_all_hosts() # Don"t run this test if we have any failure. @@ -1108,6 +1137,10 @@ def test_modify_mld_max_query_response_timer_p0(request): # Creating configuration from JSON reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + app_helper.stop_all_hosts() # Don"t run this test if we have any failure. @@ -1377,6 +1410,10 @@ def test_verify_impact_on_multicast_traffic_when_RP_removed_p0(request): # Creating configuration from JSON reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + app_helper.stop_all_hosts() # Don"t run this test if we have any failure. diff --git a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py index 767264a7c04b..8b174bf9b833 100644 --- a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py +++ b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py @@ -43,6 +43,9 @@ verify_sg_traffic, verify_upstream_iif, ) +from lib.bgp import ( + verify_bgp_convergence, +) from lib.topogen import Topogen, get_topogen from lib.topojson import build_config_from_json from lib.topolog import logger @@ -129,6 +132,12 @@ def setup_module(mod): # Creating configuration from JSON build_config_from_json(tgen, tgen.json_topo) + # Verify BGP convergence + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + logger.info("Running setup_module() done") @@ -213,6 +222,10 @@ def test_clear_mroute_and_verify_multicast_data_p0(request, app_helper): # Creating configuration from JSON reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + app_helper.stop_all_hosts() # Don"t run this test if we have any failure. @@ -444,6 +457,10 @@ def test_verify_SPT_switchover_when_RPT_and_SPT_path_is_different_p0( # Creating configuration from JSON reset_config_on_routers(tgen) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo, addr_type="ipv6") + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) diff --git a/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py b/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py index b50573e77564..5728a4d08eee 100644 --- a/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py +++ b/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py @@ -52,7 +52,10 @@ create_static_routes, required_linux_kernel_version, ) -from lib.bgp import create_router_bgp +from lib.bgp import ( + create_router_bgp, + verify_bgp_convergence, +) from lib.pim import ( create_pim_config, create_igmp_config, @@ -152,6 +155,12 @@ def setup_module(mod): global app_helper app_helper = McastTesterHelper(tgen) + # Verify BGP convergence + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + logger.info("Running setup_module() done") @@ -191,7 +200,6 @@ def get_interfaces_names(topo): """ for link in range(1, 5): - intf = topo["routers"]["r1"]["links"]["r2-link{}".format(link)]["interface"] r1_r2_links.append(intf) @@ -401,6 +409,10 @@ def test_mroutes_updated_with_correct_oil_iif_when_receiver_is_in_and_outside_DU reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -795,6 +807,10 @@ def test_mroutes_updated_with_correct_oil_iif_when_source_is_in_and_outside_DUT_ reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -1164,6 +1180,10 @@ def test_verify_mroutes_forwarding_p0(request): reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -1478,6 +1498,10 @@ def test_mroutes_updated_correctly_after_source_interface_shut_noshut_p1(request reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -1838,6 +1862,10 @@ def test_mroutes_updated_correctly_after_receiver_interface_shut_noshut_p1(reque reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -2153,6 +2181,10 @@ def test_mroutes_updated_after_sending_IGMP_prune_and_join_p1(request): reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -2412,6 +2444,10 @@ def test_mroutes_updated_after_after_clear_mroute_p1(request): reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -2601,6 +2637,10 @@ def test_mroutes_updated_after_changing_rp_config_p1(request): reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -3067,6 +3107,10 @@ def test_mroutes_after_restart_frr_services_p2(request): reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) diff --git a/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py b/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py index eb3246b51398..1fb81c0d7091 100644 --- a/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py +++ b/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py @@ -23,6 +23,7 @@ import sys import time import pytest +from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -56,6 +57,9 @@ verify_pim_interface_traffic, McastTesterHelper, ) +from lib.bgp import ( + verify_bgp_convergence, +) from lib.topolog import logger from lib.topojson import build_config_from_json @@ -131,6 +135,12 @@ def setup_module(mod): global app_helper app_helper = McastTesterHelper(tgen) + # Verify BGP convergence + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + logger.info("Running setup_module() done") @@ -170,7 +180,6 @@ def get_interfaces_names(topo): """ for link in range(1, 5): - intf = topo["routers"]["r1"]["links"]["r2-link{}".format(link)]["interface"] r1_r2_links.append(intf) @@ -255,6 +264,10 @@ def test_iif_oil_when_RP_address_changes_from_static_to_BSR_p1(request): reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -418,7 +431,15 @@ def test_iif_oil_when_RP_address_changes_from_static_to_BSR_p1(request): } ] } - }, + } + } + result = create_pim_config(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + # Need to wait for 10 sec to make sure prune is received before below RP change is executed + sleep(10) + + input_dict = { "r5": { "pim": { "rp": [ @@ -432,7 +453,6 @@ def test_iif_oil_when_RP_address_changes_from_static_to_BSR_p1(request): } }, } - result = create_pim_config(tgen, topo, input_dict) assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) @@ -516,6 +536,10 @@ def test_mroute_when_RPT_and_SPT_path_is_different_p1(request): reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -724,6 +748,10 @@ def test_mroutes_updated_with_correct_oil_iif_after_shut_noshut_upstream_interfa reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -1094,6 +1122,10 @@ def test_mroutes_updated_with_correct_oil_iif_after_shut_noshut_downstream_inter reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) diff --git a/tests/topotests/multicast_pim_uplink_topo3/test_multicast_pim_uplink_topo3.py b/tests/topotests/multicast_pim_uplink_topo3/test_multicast_pim_uplink_topo3.py index 19a8cd0c1700..bed2f2f322f4 100644 --- a/tests/topotests/multicast_pim_uplink_topo3/test_multicast_pim_uplink_topo3.py +++ b/tests/topotests/multicast_pim_uplink_topo3/test_multicast_pim_uplink_topo3.py @@ -53,6 +53,9 @@ verify_local_igmp_groups, McastTesterHelper, ) +from lib.bgp import ( + verify_bgp_convergence, +) from lib.topolog import logger from lib.topojson import build_config_from_json @@ -181,6 +184,12 @@ def setup_module(mod): global app_helper app_helper = McastTesterHelper(tgen) + # Verify BGP convergence + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + logger.info("Running setup_module() done") @@ -220,7 +229,6 @@ def get_interfaces_names(topo): """ for link in range(1, 5): - intf = topo["routers"]["r1"]["links"]["r2-link{}".format(link)]["interface"] r1_r2_links.append(intf) @@ -331,6 +339,10 @@ def test_ip_igmp_local_joins_p0(request): reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -412,6 +424,10 @@ def test_mroute_with_igmp_local_joins_p0(request): reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -606,6 +622,10 @@ def test_igmp_local_join_with_reserved_address_p0(request): reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) @@ -671,6 +691,10 @@ def test_remove_add_igmp_local_joins_p1(request): reset_config_on_routers(tgen) clear_pim_interface_traffic(tgen, topo) + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + # Don"t run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py index 88219b84006e..8dd103013b4e 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py @@ -64,7 +64,9 @@ TESTCASES = 1. Verify ospf authentication with Simple password authentication. 2. Verify ospf authentication with MD5 authentication. -3. Verify ospf authentication with different authentication methods. +3. Verify ospf authentication with MD5 keychain authentication. +4. Verify ospf authentication with SHA256 keychain authentication. +5. Verify ospf authentication with different authentication methods. """ @@ -535,7 +537,477 @@ def test_ospf_authentication_md5_tc29_p1(request): write_test_footer(tc_name) -def test_ospf_authentication_different_auths_tc30_p1(request): +def test_ospf_authentication_md5_keychain_tc30_p1(request): + """ + OSPF Authentication - Verify ospf authentication with MD5 authentication. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf with on R1 and R2, enable ospf on R1 interface " + "connected to R2 with message-digest authentication using ip " + "ospf authentication key-chain cmd." + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf + cryptographic-algorithm md5""" + ) + + r1_ospf_auth = { + "r1": { + "links": { + "r2": { + "ospf": { + "authentication": "key-chain", + "keychain": "auth", + } + } + } + } + } + result = config_ospf_interface(tgen, topo, r1_ospf_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.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf_covergence = verify_ospf_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=6 + ) + assert ospf_covergence is not True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + step( + "On R2 enable ospf on interface with message-digest authentication" + " using ip ospf authentication message-digest password cmd." + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf + cryptographic-algorithm md5""" + ) + + r2_ospf_auth = { + "r2": { + "links": { + "r1": { + "ospf": { + "authentication": "key-chain", + "keychain": "auth", + } + } + } + } + } + result = config_ospf_interface(tgen, topo, r2_ospf_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ip ospf neighbor cmd." + ) + + dut = "r2" + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) + assert ospf_covergence is True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + step( + "Disable message-digest authentication on R2 using no ip ospf " + "authentication key-chain cmd." + ) + + r2_ospf_auth = { + "r2": { + "links": { + "r1": { + "ospf": { + "authentication": "key-chain", + "keychain": "auth", + "del_action": True, + } + } + } + } + } + result = config_ospf_interface(tgen, topo, r2_ospf_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry") + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf_covergence = verify_ospf_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=10 + ) + assert ospf_covergence is not True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + step("Again On R2 enable ospf on interface with key-chain auth") + r2_ospf_auth = { + "r2": { + "links": { + "r1": { + "ospf": { + "authentication": "key-chain", + "keychain": "auth", + } + } + } + } + } + result = config_ospf_interface(tgen, topo, r2_ospf_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 using" + " show ip ospf neighbor cmd." + ) + + dut = "r2" + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) + assert ospf_covergence is True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + step("Shut no shut interface on R1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r2" + step( + "Verify that the neighbour is not FULL between R1 and R2 using " + "show ip ospf neighbor cmd." + ) + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf_covergence is not True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + dut = "r1" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "Verify that the neighbour is FULL between R1 and R2 using " + "show ip ospf neighbor cmd." + ) + + dut = "r2" + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) + assert ospf_covergence is True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + step("Change Ip address on R1 and R2") + + topo_modify_change_ip = deepcopy(topo) + + intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] + + topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str( + IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3 + ) + "/{}".format(intf_ip.split("/")[1]) + + build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False) + + reset_config_on_routers(tgen, routerName="r1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + shutdown_bringup_interface(tgen, dut, intf, True) + clear_ospf(tgen, "r1") + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf + cryptographic-algorithm md5""" + ) + r1_ospf_auth = { + "r1": { + "links": { + "r2": { + "ospf": { + "authentication": "key-chain", + "keychain": "auth", + } + } + } + } + } + result = config_ospf_interface(tgen, topo, r1_ospf_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 with new " + "ip address using show ip ospf " + ) + + dut = "r1" + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) + assert ospf_covergence is True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + write_test_footer(tc_name) + + +def test_ospf_authentication_sha256_keychain_tc32_p1(request): + """ + OSPF Authentication - Verify ospf authentication with MD5 authentication. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf with on R1 and R2, enable ospf on R1 interface " + "connected to R2 with message-digest authentication using ip " + "ospf authentication key-chain cmd." + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf + cryptographic-algorithm hmac-sha-256""" + ) + + r1_ospf_auth = { + "r1": { + "links": { + "r2": { + "ospf": { + "authentication": "key-chain", + "keychain": "auth", + } + } + } + } + } + result = config_ospf_interface(tgen, topo, r1_ospf_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.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf_covergence = verify_ospf_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=6 + ) + assert ospf_covergence is not True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + step( + "On R2 enable ospf on interface with message-digest authentication" + " using ip ospf authentication message-digest password cmd." + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf + cryptographic-algorithm hmac-sha-256""" + ) + + r2_ospf_auth = { + "r2": { + "links": { + "r1": { + "ospf": { + "authentication": "key-chain", + "keychain": "auth", + } + } + } + } + } + result = config_ospf_interface(tgen, topo, r2_ospf_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ip ospf neighbor cmd." + ) + + dut = "r2" + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) + assert ospf_covergence is True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + step( + "Disable message-digest authentication on R2 using no ip ospf " + "authentication key-chain cmd." + ) + + r2_ospf_auth = { + "r2": { + "links": { + "r1": { + "ospf": { + "authentication": "key-chain", + "keychain": "auth", + "del_action": True, + } + } + } + } + } + result = config_ospf_interface(tgen, topo, r2_ospf_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry") + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf_covergence = verify_ospf_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=10 + ) + assert ospf_covergence is not True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + step("Again On R2 enable ospf on interface with key-chain auth") + r2_ospf_auth = { + "r2": { + "links": { + "r1": { + "ospf": { + "authentication": "key-chain", + "keychain": "auth", + } + } + } + } + } + result = config_ospf_interface(tgen, topo, r2_ospf_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 using" + " show ip ospf neighbor cmd." + ) + + dut = "r2" + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) + assert ospf_covergence is True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + step("Shut no shut interface on R1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r2" + step( + "Verify that the neighbour is not FULL between R1 and R2 using " + "show ip ospf neighbor cmd." + ) + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf_covergence is not True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + dut = "r1" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "Verify that the neighbour is FULL between R1 and R2 using " + "show ip ospf neighbor cmd." + ) + + dut = "r2" + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) + assert ospf_covergence is True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + step("Change Ip address on R1 and R2") + + topo_modify_change_ip = deepcopy(topo) + + intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] + + topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str( + IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3 + ) + "/{}".format(intf_ip.split("/")[1]) + + build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False) + + reset_config_on_routers(tgen, routerName="r1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + shutdown_bringup_interface(tgen, dut, intf, True) + clear_ospf(tgen, "r1") + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf + cryptographic-algorithm hmac-sha-256""" + ) + r1_ospf_auth = { + "r1": { + "links": { + "r2": { + "ospf": { + "authentication": "key-chain", + "keychain": "auth", + } + } + } + } + } + result = config_ospf_interface(tgen, topo, r1_ospf_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 with new " + "ip address using show ip ospf " + ) + + dut = "r1" + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) + assert ospf_covergence is True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) + + write_test_footer(tc_name) + + +def test_ospf_authentication_different_auths_tc35_p1(request): """ OSPF Authentication - Verify ospf authentication with different authentication methods. @@ -553,6 +1025,9 @@ def test_ospf_authentication_different_auths_tc30_p1(request): "ospf authentication message-digest cmd." ) + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + r1_ospf_auth = { "r1": { "links": { @@ -769,16 +1244,23 @@ def test_ospf_authentication_different_auths_tc30_p1(request): ospf_covergence ) - step("Enable Md5 authentication on the interface") + step("Enable SHA-256 authentication on the interface") + + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf + cryptographic-algorithm hmac-sha-256""" + ) r1_ospf_auth = { "r1": { "links": { "r2": { "ospf": { - "authentication": "message-digest", - "authentication-key": "ospf", - "message-digest-key": "10", + "authentication": "key-chain", + "keychain": "auth", } } } @@ -787,14 +1269,21 @@ def test_ospf_authentication_different_auths_tc30_p1(request): result = config_ospf_interface(tgen, topo, r1_ospf_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf + cryptographic-algorithm hmac-sha-256""" + ) + r2_ospf_auth = { "r2": { "links": { "r1": { "ospf": { - "authentication": "message-digest", - "authentication-key": "ospf", - "message-digest-key": "10", + "authentication": "key-chain", + "keychain": "auth", } } } @@ -814,39 +1303,27 @@ def test_ospf_authentication_different_auths_tc30_p1(request): ospf_covergence ) - step("Change the MD5 authentication password") + step("Change the SHA-256 authentication password") - r1_ospf_auth = { - "r1": { - "links": { - "r2": { - "ospf": { - "authentication": "message-digest", - "authentication-key": "OSPFv4", - "message-digest-key": "10", - } - } - } - } - } - result = config_ospf_interface(tgen, topo, r1_ospf_auth) - assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string OSPFv4 + cryptographic-algorithm hmac-sha-512""" + ) - r2_ospf_auth = { - "r2": { - "links": { - "r1": { - "ospf": { - "authentication": "message-digest", - "authentication-key": "OSPFv4", - "message-digest-key": "10", - } - } - } - } - } - result = config_ospf_interface(tgen, topo, r2_ospf_auth) - assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string OSPFv4 + cryptographic-algorithm hmac-sha-512""" + ) + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) + assert ospf_covergence is True, "Testcase Failed \n Error {}".format( + ospf_covergence + ) write_test_footer(tc_name) diff --git a/tests/topotests/simple_snmp_test/r1/snmpd.conf b/tests/topotests/simple_snmp_test/r1/snmpd.conf index 740574cb8e9a..cdcd9a2b372d 100644 --- a/tests/topotests/simple_snmp_test/r1/snmpd.conf +++ b/tests/topotests/simple_snmp_test/r1/snmpd.conf @@ -1,4 +1,4 @@ -agentAddress udp:1.1.1.1:161 +agentAddress udp:161 com2sec public 1.1.1.1 public diff --git a/tests/topotests/srv6_static_route/__init__.py b/tests/topotests/srv6_static_route/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/srv6_static_route/expected_srv6_route.json b/tests/topotests/srv6_static_route/expected_srv6_route.json new file mode 100644 index 000000000000..45de6171fe69 --- /dev/null +++ b/tests/topotests/srv6_static_route/expected_srv6_route.json @@ -0,0 +1,49 @@ +{ + "2001:db8:aaaa::/64": [ + { + "prefix": "2001:db8:aaaa::/64", + "prefixLen": 64, + "protocol": "static", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "nexthops": [ + { + "directlyConnected": true, + "active": true, + "weight": 1 + } + ] + } + ], + "2005::/64": [ + { + "prefix": "2005::/64", + "prefixLen": 64, + "protocol": "static", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "nexthops": [ + { + "directlyConnected": true, + "active": true, + "weight": 1, + "seg6local": { + "action": "unspec" + }, + "seg6": [ + "2001:db8:aaaa::7", + "2002::2", + "2003::3", + "2004::4" + ] + } + ] + } + ] +} diff --git a/tests/topotests/srv6_static_route/r1/mgmtd.conf b/tests/topotests/srv6_static_route/r1/mgmtd.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/srv6_static_route/r1/setup.sh b/tests/topotests/srv6_static_route/r1/setup.sh new file mode 100644 index 000000000000..36ed713f2416 --- /dev/null +++ b/tests/topotests/srv6_static_route/r1/setup.sh @@ -0,0 +1,2 @@ +ip link add dummy0 type dummy +ip link set dummy0 up diff --git a/tests/topotests/srv6_static_route/r1/staticd.conf b/tests/topotests/srv6_static_route/r1/staticd.conf new file mode 100644 index 000000000000..a75c69f26b5f --- /dev/null +++ b/tests/topotests/srv6_static_route/r1/staticd.conf @@ -0,0 +1,9 @@ +hostname r1 +! +log stdout notifications +log monitor notifications +log commands +log file staticd.log debugging +! +ipv6 route 2001:db8:aaaa::/64 dummy0 +ipv6 route 2005::/64 dummy0 segments 2001:db8:aaaa::7/2002::2/2003::3/2004::4 diff --git a/tests/topotests/srv6_static_route/r1/zebra.conf b/tests/topotests/srv6_static_route/r1/zebra.conf new file mode 100644 index 000000000000..cc704186010c --- /dev/null +++ b/tests/topotests/srv6_static_route/r1/zebra.conf @@ -0,0 +1,10 @@ +hostname r1 +! +! debug zebra events +! debug zebra rib detailed +! +log stdout notifications +log monitor notifications +log commands +log file zebra.log debugging +! diff --git a/tests/topotests/srv6_static_route/test_srv6_route.py b/tests/topotests/srv6_static_route/test_srv6_route.py new file mode 100755 index 000000000000..7a4cd39f2ddd --- /dev/null +++ b/tests/topotests/srv6_static_route/test_srv6_route.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_srv6_route.py +# +# Copyright 2023 6WIND S.A. +# Dmytro Shytyi +# + +""" +test_srv6_route.py: +Test for SRv6 static route on zebra +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd, pytest.mark.sharpd] + + +def open_json_file(filename): + try: + with open(filename, "r") as f: + return json.load(f) + except IOError: + assert False, "Could not read file {}".format(filename) + + +def setup_module(mod): + tgen = Topogen({None: "r1"}, mod.__name__) + tgen.start_topology() + for rname, router in tgen.routers().items(): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_MGMTD, os.path.join(CWD, "{}/mgmtd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname)) + ) + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_srv6_static_route(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + + def _check_srv6_static_route(router, expected_route_file): + logger.info("checking zebra srv6 static route with multiple segs status") + output = json.loads(router.vtysh_cmd("show ipv6 route static json")) + expected = open_json_file("{}/{}".format(CWD, expected_route_file)) + return topotest.json_cmp(output, expected) + + def check_srv6_static_route(router, expected_file): + func = functools.partial(_check_srv6_static_route, router, expected_file) + success, result = topotest.run_and_expect(func, None, count=15, wait=1) + assert result is None, "Failed" + + # FOR DEVELOPER: + # If you want to stop some specific line and start interactive shell, + # please use tgen.mininet_cli() to start it. + + logger.info("Test for srv6 route configuration") + check_srv6_static_route(router, "expected_srv6_route.json") + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf index a727f86a03c3..b7a170824802 100644 --- a/tools/etc/frr/support_bundle_commands.conf +++ b/tools/etc/frr/support_bundle_commands.conf @@ -241,3 +241,19 @@ show ipv6 pim bsr show ipv6 pim bsrp-info show ipv6 pim bsm-databases CMD_LIST_END + +#MGMT Support Bundle Command List +PROC_NAME:mgmt +CMD_LIST_START +show mgmt backend-adapter all +show mgmt backend-yang-xpath-registry +show mgmt commit-history +show mgmt datastore all +show mgmt datastore-contents candidate json +show mgmt datastore-contents running json +show mgmt frontend-adapter all detail +show mgmt get-config candidate / +show mgmt get-config running / +show mgmt transaction all +show mgmt yang-xpath-subscription / +CMD_LIST_END diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in index f1f70119097e..00b63a78e2bc 100755 --- a/tools/frrcommon.sh.in +++ b/tools/frrcommon.sh.in @@ -207,8 +207,8 @@ daemon_stop() { [ -z "$fail" -a -z "$pid" ] && fail="pid file is empty" [ -n "$fail" ] || kill -0 "$pid" 2>/dev/null || fail="pid $pid not running" - if [ -n "$fail" ] && [ "$2" != "--quiet" ]; then - log_failure_msg "Cannot stop $dmninst: $fail" + if [ -n "$fail" ]; then + [ "$2" = "--quiet" ] || log_failure_msg "Cannot stop $dmninst: $fail" return 1 fi @@ -220,11 +220,11 @@ daemon_stop() { [ $(( cnt -= 1 )) -gt 0 ] || break done if kill -0 "$pid" 2>/dev/null; then - log_failure_msg "Failed to stop $dmninst, pid $pid still running" + [ "$2" = "--quiet" ] || log_failure_msg "Failed to stop $dmninst, pid $pid still running" still_running=1 return 1 else - log_success_msg "Stopped $dmninst" + [ "$2" = "--quiet" ] || log_success_msg "Stopped $dmninst" rm -f "$pidfile" return 0 fi diff --git a/tools/gcc-plugins/Makefile b/tools/gcc-plugins/Makefile index d6edd745cecd..2af28fe2b191 100644 --- a/tools/gcc-plugins/Makefile +++ b/tools/gcc-plugins/Makefile @@ -5,11 +5,15 @@ CXX=g++-9 PLUGBASE=`$(CXX) -print-file-name=plugin` CPPFLAGS=-I$(PLUGBASE)/include -I$(PLUGBASE)/include/c-family +# NB: compiler flags must match those used to build gcc, otherwise inlining +# behavior is different and linker errors will result due to missing symbols +# (which should in fact be inlined) + frr-format.so: frr-format.o - $(CXX) -g -shared -o $@ $^ + $(CXX) -fno-rtti -fno-exceptions -fasynchronous-unwind-tables -ggdb -shared -o $@ $^ frr-format.o: frr-format.c gcc-common.h - $(CXX) -g $(CPPFLAGS) -fPIC -Wall -Wextra -Wno-unused-parameter -c -o $@ $< + $(CXX) -fno-rtti -fno-exceptions -fasynchronous-unwind-tables -ggdb $(CPPFLAGS) -fPIC -Wall -Wextra -Wno-unused-parameter -c -o $@ $< install: install -d $(DESTDIR)$(PLUGBASE) diff --git a/tools/gcc-plugins/frr-format.c b/tools/gcc-plugins/frr-format.c index 2240a171b40e..4e2c2d3ba9c2 100644 --- a/tools/gcc-plugins/frr-format.c +++ b/tools/gcc-plugins/frr-format.c @@ -486,7 +486,7 @@ static const format_char_info print_char_table[] = /* C89 conversion specifiers. */ /* none, hh, h, l, ll, L, z, t, j, H, D, DD */ { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_S64, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "-wp0 +'I", "i", NULL, ext_d }, - { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_U64, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL, NULL }, + { "oxXb",0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_U64, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL, NULL }, { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_U64, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0'I", "i", NULL, NULL }, { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL, NULL }, { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#I", "", NULL, NULL }, @@ -3464,7 +3464,7 @@ class frr_range_label_for_type_mismatch : public range_label { } - label_text get_text (unsigned range_idx) const OVERRIDE; + label_text get_text (unsigned range_idx) const override; protected: tree m_labelled_type; @@ -3564,19 +3564,26 @@ class range_label_for_format_type_mismatch { } - label_text get_text (unsigned range_idx) const FINAL OVERRIDE +#if BUILDING_GCC_VERSION >= 13000 +#define text_get(text) text.get() +#define text_return(text, result) return label_text::take(result) +#else +#define text_get(text) text.m_buffer +#define text_return(text, result) text.maybe_free(); return label_take(result) +#endif + + label_text get_text (unsigned range_idx) const final override { label_text text = range_label_for_type_mismatch::get_text (range_idx); - if (text.m_buffer == NULL) + if (text_get(text) == NULL) return text; indirection_suffix suffix (m_pointer_count); char *p = (char *) alloca (suffix.get_buffer_size ()); suffix.fill_buffer (p); - char *result = concat (text.m_buffer, p, NULL); - text.maybe_free (); - return label_take(result); + char *result = concat (text_get(text), p, NULL); + text_return(text, result); } private: diff --git a/tools/gcc-plugins/gcc-common.h b/tools/gcc-plugins/gcc-common.h index 9f59447d6334..6eaea9bf74db 100644 --- a/tools/gcc-plugins/gcc-common.h +++ b/tools/gcc-plugins/gcc-common.h @@ -111,6 +111,10 @@ #include "varasm.h" #include "stor-layout.h" #include "internal-fn.h" +#if BUILDING_GCC_VERSION >= 13000 +#include "gimple.h" +#include "gimple-iterator.h" +#endif #include "gimple-expr.h" #include "gimple-fold.h" #include "context.h" diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 8b223d1aa482..9c61146c2d86 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1189,6 +1189,20 @@ static struct cmd_node isis_flex_algo_node = { .parent_node = ISIS_NODE, .prompt = "%s(config-router-flex-algo)# ", }; + +static struct cmd_node isis_srv6_node = { + .name = "isis-srv6", + .node = ISIS_SRV6_NODE, + .parent_node = ISIS_NODE, + .prompt = "%s(config-router-srv6)# ", +}; + +static struct cmd_node isis_srv6_node_msd_node = { + .name = "isis-srv6-node-msd", + .node = ISIS_SRV6_NODE_MSD_NODE, + .parent_node = ISIS_SRV6_NODE, + .prompt = "%s(config-router-srv6-node-msd)# ", +}; #endif /* HAVE_ISISD */ #ifdef HAVE_FABRICD @@ -1433,6 +1447,13 @@ static struct cmd_node bgp_ipv6l_node = { .no_xpath = true, }; +static struct cmd_node bgp_ls_node = { + .name = "bgp link-state", + .node = BGP_LS_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-af-ls)# ", +}; + #ifdef ENABLE_BGP_VNC static struct cmd_node bgp_vnc_defaults_node = { .name = "bgp vnc defaults", @@ -1744,6 +1765,14 @@ DEFUNSH(VTYSH_BGPD, address_family_flowspecv6, address_family_flowspecv6_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_BGPD, address_family_linkstate, address_family_linkstate_cmd, + "address-family link-state link-state", + "Enter Address Family command mode\n" BGP_AF_STR BGP_AF_MODIFIER_STR) +{ + vty->node = BGP_LS_NODE; + return CMD_SUCCESS; +} + DEFUNSH(VTYSH_BGPD, address_family_ipv4_multicast, address_family_ipv4_multicast_cmd, "address-family ipv4 multicast", "Enter Address Family command mode\n" @@ -2117,6 +2146,23 @@ DEFUNSH(VTYSH_ISISD, isis_flex_algo, isis_flex_algo_cmd, "flex-algo (128-255)", vty->node = ISIS_FLEX_ALGO_NODE; return CMD_SUCCESS; } + +DEFUNSH(VTYSH_ISISD, isis_srv6_enable, isis_srv6_enable_cmd, + "segment-routing srv6", + SR_STR + "Enable Segment Routing over IPv6 (SRv6)\n") +{ + vty->node = ISIS_SRV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ISISD, isis_srv6_node_msd, isis_srv6_node_msd_cmd, + "node-msd", + "Segment Routing over IPv6 (SRv6) Maximum SRv6 SID Depths\n") +{ + vty->node = ISIS_SRV6_NODE_MSD_NODE; + return CMD_SUCCESS; +} #endif /* HAVE_ISISD */ #ifdef HAVE_FABRICD @@ -2333,15 +2379,26 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_disable, vtysh_disable_cmd, "disable", } DEFUNSH(VTYSH_REALLYALL, vtysh_config_terminal, vtysh_config_terminal_cmd, - "configure [terminal [file-lock]]", + "configure [terminal]", "Configuration from vty interface\n" - "Configuration with locked datastores\n" "Configuration terminal\n") { vty->node = CONFIG_NODE; return CMD_SUCCESS; } +DEFUNSH(VTYSH_REALLYALL, vtysh_config_terminal_file_lock, + vtysh_config_terminal_file_lock_cmd, + "configure terminal file-lock", + "Configuration from vty interface\n" + "Configuration terminal\n" + "Configuration with locked datastores\n") +{ + vty->node = CONFIG_NODE; + vty->vtysh_file_locked = true; + return CMD_SUCCESS; +} + static int vtysh_exit(struct vty *vty) { struct cmd_node *cnode = vector_lookup(cmdvec, vty->node); @@ -2389,7 +2446,8 @@ DEFUNSH(VTYSH_BGPD, exit_address_family, exit_address_family_cmd, || vty->node == BGP_IPV6L_NODE || vty->node == BGP_IPV6M_NODE || vty->node == BGP_EVPN_NODE || vty->node == BGP_FLOWSPECV4_NODE - || vty->node == BGP_FLOWSPECV6_NODE) + || vty->node == BGP_FLOWSPECV6_NODE + || vty->node == BGP_LS_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; } @@ -2619,6 +2677,30 @@ DEFUNSH(VTYSH_ISISD, vtysh_quit_isis_flex_algo, vtysh_quit_isis_flex_algo_cmd, { return vtysh_exit_isisd(self, vty, argc, argv); } + +DEFUNSH(VTYSH_ISISD, vtysh_exit_isis_srv6_enable, vtysh_exit_isis_srv6_enable_cmd, + "exit", "Exit current mode and down to previous mode\n") +{ + return vtysh_exit_isisd(self, vty, argc, argv); +} + +DEFUNSH(VTYSH_ISISD, vtysh_quit_isis_srv6_enable, vtysh_quit_isis_srv6_enable_cmd, + "quit", "Exit current mode and down to previous mode\n") +{ + return vtysh_exit_isisd(self, vty, argc, argv); +} + +DEFUNSH(VTYSH_ISISD, vtysh_exit_isis_srv6_node_msd, vtysh_exit_isis_srv6_node_msd_cmd, + "exit", "Exit current mode and down to previous mode\n") +{ + return vtysh_exit(vty); +} + +DEFUNSH(VTYSH_ISISD, vtysh_quit_isis_srv6_node_msd, vtysh_quit_isis_srv6_node_msd_cmd, + "quit", "Exit current mode and down to previous mode\n") +{ + return vtysh_exit_isisd(self, vty, argc, argv); +} #endif /* HAVE_ISISD */ #if HAVE_BFDD > 0 @@ -4616,6 +4698,13 @@ void vtysh_init_vty(void) install_element(BGP_EVPN_VNI_NODE, &vtysh_end_all_cmd); install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd); + install_node(&bgp_ls_node); + install_element(BGP_NODE, &address_family_linkstate_cmd); + install_element(BGP_LS_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_LS_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_LS_NODE, &vtysh_end_all_cmd); + install_element(BGP_LS_NODE, &exit_address_family_cmd); + install_node(&rpki_node); install_element(CONFIG_NODE, &rpki_cmd); install_element(RPKI_NODE, &rpki_exit_cmd); @@ -4749,6 +4838,19 @@ void vtysh_init_vty(void) install_element(ISIS_FLEX_ALGO_NODE, &vtysh_exit_isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_quit_isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_end_all_cmd); + + install_node(&isis_srv6_node); + install_element(ISIS_NODE, &isis_srv6_enable_cmd); + install_element(ISIS_SRV6_NODE, &isis_srv6_node_msd_cmd); + install_element(ISIS_SRV6_NODE, &vtysh_exit_isis_srv6_enable_cmd); + install_element(ISIS_SRV6_NODE, &vtysh_quit_isis_srv6_enable_cmd); + install_element(ISIS_SRV6_NODE, &vtysh_end_all_cmd); + install_node(&isis_srv6_node_msd_node); + install_element(ISIS_SRV6_NODE_MSD_NODE, + &vtysh_exit_isis_srv6_node_msd_cmd); + install_element(ISIS_SRV6_NODE_MSD_NODE, + &vtysh_quit_isis_srv6_node_msd_cmd); + install_element(ISIS_SRV6_NODE_MSD_NODE, &vtysh_end_all_cmd); #endif /* HAVE_ISISD */ /* fabricd */ @@ -4930,6 +5032,7 @@ void vtysh_init_vty(void) if (!user_mode) install_element(VIEW_NODE, &vtysh_enable_cmd); install_element(ENABLE_NODE, &vtysh_config_terminal_cmd); + install_element(ENABLE_NODE, &vtysh_config_terminal_file_lock_cmd); install_element(ENABLE_NODE, &vtysh_disable_cmd); /* "exit" command. */ diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 9d67003f35d5..65733ca61b4c 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -59,7 +59,7 @@ extern struct event_loop *master; VTYSH_VRRPD #define VTYSH_INTERFACE VTYSH_INTERFACE_SUBSET | VTYSH_BGPD #define VTYSH_VRF VTYSH_INTERFACE_SUBSET | VTYSH_MGMTD -#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D +#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D | VTYSH_OSPFD /* Daemons who can process nexthop-group configs */ #define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD #define VTYSH_SR VTYSH_ZEBRA|VTYSH_PATHD diff --git a/yang/frr-bgp-common-multiprotocol.yang b/yang/frr-bgp-common-multiprotocol.yang index c22bdf996473..f7f4ff507597 100644 --- a/yang/frr-bgp-common-multiprotocol.yang +++ b/yang/frr-bgp-common-multiprotocol.yang @@ -204,5 +204,15 @@ submodule frr-bgp-common-multiprotocol { description "IPv6 flowspec configuration options."; } + + container linkstate-linkstate { + when "derived-from-or-self(../afi-safi-name, 'frr-rt:linkstate-linkstate')" { + description + "Include this container for Link-State specific + configuration."; + } + description + "Link-State configuration options."; + } } } diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang index 05fe57c7d7cc..c50c51389eca 100644 --- a/yang/frr-bgp-route-map.yang +++ b/yang/frr-bgp-route-map.yang @@ -777,6 +777,13 @@ identity set-extcommunity-color { description "Do exact matching of communities"; } + + leaf comm-list-name-any { + type boolean; + description + "Do matching of any community"; + } + } } diff --git a/yang/frr-bgp.yang b/yang/frr-bgp.yang index b34fd43e78de..557b9ef81b95 100644 --- a/yang/frr-bgp.yang +++ b/yang/frr-bgp.yang @@ -819,6 +819,17 @@ module frr-bgp { uses structure-neighbor-group-filter-config; } + + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/linkstate-linkstate" { + uses structure-neighbor-route-reflector; + + uses structure-neighbor-route-server; + + uses structure-neighbor-group-soft-reconfiguration; + + uses structure-neighbor-group-filter-config; + } + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast" { uses structure-neighbor-group-add-paths; @@ -1090,6 +1101,16 @@ module frr-bgp { uses structure-neighbor-group-filter-config; } + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/linkstate-linkstate" { + uses structure-neighbor-route-reflector; + + uses structure-neighbor-route-server; + + uses structure-neighbor-group-soft-reconfiguration; + + uses structure-neighbor-group-filter-config; + } + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast" { uses structure-neighbor-group-add-paths; @@ -1366,4 +1387,14 @@ module frr-bgp { uses structure-neighbor-group-filter-config; } + + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/linkstate-linkstate" { + uses structure-neighbor-route-reflector; + + uses structure-neighbor-route-server; + + uses structure-neighbor-group-soft-reconfiguration; + + uses structure-neighbor-group-filter-config; + } } diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 478d058c192d..5d7c739c05d2 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -1994,6 +1994,71 @@ module frr-isisd { } } + container segment-routing-srv6 { + description + "Segment Routing over IPv6 (SRv6) global configuration."; + leaf enabled { + type boolean; + default "false"; + description + "Enable IS-IS extensions to support Segment Routing over + IPv6 data plane (SRv6)."; + reference + "RFC 9352"; + } + leaf locator { + type string; + description + "SRv6 locator."; + } + container msd { + description + "SRv6 Maximum SRv6 SID Depths."; + container node-msd { + description + "SRv6 Node Maximum SRv6 SID Depths."; + leaf max-segs-left { + type uint8 { + range "0..255"; + } + default 3; + description + "Maximum Segments Left MSD."; + } + leaf max-end-pop { + type uint8 { + range "0..255"; + } + default 3; + description + "Maximum End Pop MSD."; + } + leaf max-h-encaps { + type uint8 { + range "0..255"; + } + default 2; + description + "Maximum H.Encaps MSD."; + } + leaf max-end-d { + type uint8 { + range "0..255"; + } + default 5; + description + "Maximum End D MSD."; + } + } + } + leaf interface { + type string; + description + "Dummy interface used to install SRv6 SIDs into the Linux data plane."; + default "sr0"; + } + } + container mpls { description "Configuration of MPLS parameters"; diff --git a/yang/frr-nexthop.yang b/yang/frr-nexthop.yang index d73fdb8bd3d6..175487d78b57 100644 --- a/yang/frr-nexthop.yang +++ b/yang/frr-nexthop.yang @@ -201,6 +201,11 @@ module frr-nexthop { description "Nexthop's MPLS label stack."; } + + uses srv6-segs-stack { + description + "Nexthop's SRv6 segs SIDs stack."; + } } /* @@ -298,6 +303,32 @@ module frr-nexthop { } } + /* Contaner for SRv6 segs SIDs */ + grouping srv6-segs-stack { + description + "This grouping specifies an SRv6 segs SIDs stack. The segs + SIDs stack is encoded as a list of SID entries. The + list key is an identifier that indicates the relative + ordering of each entry."; + container srv6-segs-stack { + description + "Container for a list of SRv6 segs SIDs entries."; + list entry { + key "id"; + description + "List of SRv6 segs SIDs entries."; + leaf id { + type uint8; + description + "Identifies the entry in a sequence of SRv6 segs SIDs + entries."; + } + leaf seg { + type inet:ipv6-address; + } + } + } + } container frr-nexthop-group { description "A nexthop-group, represented as a list of nexthop objects."; diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index 105dab895da5..e9b3f675073d 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -343,7 +343,7 @@ module frr-pim { } leaf hello-interval { - type uint8 { + type uint16 { range "1..max"; } default "30"; diff --git a/yang/frr-routing.yang b/yang/frr-routing.yang index b304c241a41c..f6e1f8e74a23 100644 --- a/yang/frr-routing.yang +++ b/yang/frr-routing.yang @@ -172,6 +172,13 @@ module frr-routing { } + identity linkstate-linkstate { + base afi-safi-type; + description + "This identity represents the link-state address family."; + } + + identity control-plane-protocol { description "Base identity from which control-plane protocol identities are diff --git a/zebra/connected.c b/zebra/connected.c index ee0823f56f45..46f2a83a3cdb 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -234,6 +234,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) break; case AFI_UNSPEC: case AFI_L2VPN: + case AFI_LINKSTATE: case AFI_MAX: flog_warn(EC_ZEBRA_CONNECTED_AFI_UNKNOWN, "Received unknown AFI: %s", afi2str(afi)); @@ -424,6 +425,7 @@ void connected_down(struct interface *ifp, struct connected *ifc) break; case AFI_UNSPEC: case AFI_L2VPN: + case AFI_LINKSTATE: case AFI_MAX: zlog_warn("Unknown AFI: %s", afi2str(afi)); break; diff --git a/zebra/dpdk/zebra_dplane_dpdk.c b/zebra/dpdk/zebra_dplane_dpdk.c index fc140b07a34d..4c320442512e 100644 --- a/zebra/dpdk/zebra_dplane_dpdk.c +++ b/zebra/dpdk/zebra_dplane_dpdk.c @@ -611,11 +611,11 @@ static void zd_dpdk_port_init(void) if (rte_flow_isolate(port_id, 1, &error)) { if (IS_ZEBRA_DEBUG_DPLANE_DPDK) zlog_debug( - "Flow isolate on port %u failed %d\n", + "Flow isolate on port %u failed %d", port_id, error.type); } else { if (IS_ZEBRA_DEBUG_DPLANE_DPDK) - zlog_debug("Flow isolate on port %u\n", + zlog_debug("Flow isolate on port %u", port_id); } rc = rte_eth_dev_start(port_id); diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 02881a644705..2a8792523188 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -65,6 +65,7 @@ struct fpm_nl_ctx { bool disabled; bool connecting; bool use_nhg; + bool use_route_replace; struct sockaddr_storage addr; /* data plane buffers. */ @@ -282,6 +283,25 @@ DEFUN(no_fpm_use_nhg, no_fpm_use_nhg_cmd, return CMD_SUCCESS; } +DEFUN(fpm_use_route_replace, fpm_use_route_replace_cmd, + "fpm use-route-replace", + FPM_STR + "Use netlink route replace semantics\n") +{ + gfnc->use_route_replace = true; + return CMD_SUCCESS; +} + +DEFUN(no_fpm_use_route_replace, no_fpm_use_route_replace_cmd, + "no fpm use-route-replace", + NO_STR + FPM_STR + "Use netlink route replace semantics\n") +{ + gfnc->use_route_replace = false; + return CMD_SUCCESS; +} + DEFUN(fpm_reset_counters, fpm_reset_counters_cmd, "clear fpm counters", CLEAR_STR @@ -396,6 +416,11 @@ static int fpm_write_config(struct vty *vty) written = 1; } + if (!gfnc->use_route_replace) { + vty_out(vty, "no fpm use-route-replace\n"); + written = 1; + } + return written; } @@ -807,12 +832,20 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) frr_mutex_lock_autounlock(&fnc->obuf_mutex); + /* + * If route replace is enabled then directly encode the install which + * is going to use `NLM_F_REPLACE` (instead of delete/add operations). + */ + if (fnc->use_route_replace && op == DPLANE_OP_ROUTE_UPDATE) + op = DPLANE_OP_ROUTE_INSTALL; + switch (op) { case DPLANE_OP_ROUTE_UPDATE: case DPLANE_OP_ROUTE_DELETE: rv = netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx, nl_buf, sizeof(nl_buf), - true, fnc->use_nhg); + true, fnc->use_nhg, + false); if (rv <= 0) { zlog_err( "%s: netlink_route_multipath_msg_encode failed", @@ -828,9 +861,12 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) /* FALL THROUGH */ case DPLANE_OP_ROUTE_INSTALL: - rv = netlink_route_multipath_msg_encode( - RTM_NEWROUTE, ctx, &nl_buf[nl_buf_len], - sizeof(nl_buf) - nl_buf_len, true, fnc->use_nhg); + rv = netlink_route_multipath_msg_encode(RTM_NEWROUTE, ctx, + &nl_buf[nl_buf_len], + sizeof(nl_buf) - + nl_buf_len, + true, fnc->use_nhg, + fnc->use_route_replace); if (rv <= 0) { zlog_err( "%s: netlink_route_multipath_msg_encode failed", @@ -1469,6 +1505,7 @@ static int fpm_nl_start(struct zebra_dplane_provider *prov) /* Set default values. */ fnc->use_nhg = true; + fnc->use_route_replace = true; return 0; } @@ -1609,6 +1646,8 @@ static int fpm_nl_new(struct event_loop *tm) install_element(CONFIG_NODE, &no_fpm_set_address_cmd); install_element(CONFIG_NODE, &fpm_use_nhg_cmd); install_element(CONFIG_NODE, &no_fpm_use_nhg_cmd); + install_element(CONFIG_NODE, &fpm_use_route_replace_cmd); + install_element(CONFIG_NODE, &no_fpm_use_route_replace_cmd); return 0; } diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index ca0a354afdc0..61a8c6a78a0e 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1508,6 +1508,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) ns_id_t link_nsid = ns_id; ifindex_t master_infindex = IFINDEX_INTERNAL; uint8_t bypass = 0; + uint32_t txqlen = 0; frrtrace(3, frr_zebra, netlink_interface, h, ns_id, startup); @@ -1586,6 +1587,9 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) link_nsid = ns_id_get_absolute(ns_id, link_nsid); } + if (tb[IFLA_TXQLEN]) + txqlen = *(uint32_t *)RTA_DATA(tb[IFLA_TXQLEN]); + struct zebra_dplane_ctx *ctx = dplane_ctx_alloc(); dplane_ctx_set_ns_id(ctx, ns_id); dplane_ctx_set_ifp_link_nsid(ctx, link_nsid); @@ -1594,6 +1598,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) dplane_ctx_set_ifname(ctx, name); dplane_ctx_set_ifp_startup(ctx, startup); dplane_ctx_set_ifp_family(ctx, ifi->ifi_family); + dplane_ctx_set_intf_txqlen(ctx, txqlen); /* We are interested in some AF_BRIDGE notifications. */ #ifndef AF_BRIDGE diff --git a/zebra/interface.c b/zebra/interface.c index 9ca330571f4d..919cd11bc842 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -853,7 +853,7 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) if_down_del_nbr_connected(ifp); /* Send out notification on interface VRF change. */ - /* This is to issue an UPDATE or a DELETE, as appropriate. */ + /* This is to issue a DELETE, as appropriate. */ zebra_interface_vrf_update_del(ifp, vrf_id); if (if_is_vrf(ifp)) @@ -1131,8 +1131,6 @@ void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex, { struct zebra_if *zif; - if (IS_ZEBRA_IF_VETH(ifp)) - return; zif = (struct zebra_if *)ifp->info; zif->link_nsid = ns_id; zif->link_ifindex = link_ifindex; @@ -2053,6 +2051,8 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) if_update_to_new_vrf(ifp, vrf_id); } + zif = ifp->info; + /* Update interface information. */ set_ifindex(ifp, ifindex, zns); ifp->flags = flags; @@ -2060,6 +2060,7 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) ifp->metric = 0; ifp->speed = kernel_get_speed(ifp, NULL); ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; + ifp->txqlen = dplane_ctx_get_intf_txqlen(ctx); /* Set interface type */ zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); @@ -2070,16 +2071,6 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) /* Update link. */ zebra_if_update_link(ifp, link_ifindex, link_nsid); - /* - * Just set the @link/lower-device ifindex. During - * nldump interfaces are not ordered in any fashion so - * we may end up getting upper devices before lower - * devices. We will setup the real linkage once the dump - * is complete. - */ - zif = (struct zebra_if *)ifp->info; - zif->link_ifindex = link_ifindex; - ifp->ll_type = dplane_ctx_get_ifp_zltype(ctx); interface_update_hw_addr(ctx, ifp); @@ -2142,6 +2133,7 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) set_ifindex(ifp, ifindex, zns); ifp->mtu6 = ifp->mtu = mtu; ifp->metric = 0; + ifp->txqlen = dplane_ctx_get_intf_txqlen(ctx); /* * Update interface type - NOTE: Only slave_type can @@ -2786,8 +2778,8 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) return; } - vty_out(vty, " index %d metric %d mtu %d speed %u ", ifp->ifindex, - ifp->metric, ifp->mtu, ifp->speed); + vty_out(vty, " index %d metric %d mtu %d speed %u txqlen %u", + ifp->ifindex, ifp->metric, ifp->mtu, ifp->speed, ifp->txqlen); if (ifp->mtu6 != ifp->mtu) vty_out(vty, "mtu6 %d ", ifp->mtu6); vty_out(vty, "\n flags: %s\n", if_flag_dump(ifp->flags)); @@ -3174,6 +3166,7 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, if (ifp->mtu6 != ifp->mtu) json_object_int_add(json_if, "mtu6", ifp->mtu6); json_object_int_add(json_if, "speed", ifp->speed); + json_object_int_add(json_if, "txqlen", ifp->txqlen); json_object_string_add(json_if, "flags", if_flag_dump(ifp->flags)); /* Hardware address. */ diff --git a/zebra/label_manager.c b/zebra/label_manager.c index c77470a70109..0be0b4e732fa 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -28,6 +28,8 @@ #include "zebra/zapi_msg.h" #include "zebra/debug.h" +#include "zebra/label_manager_clippy.c" + #define CONNECTION_DELAY 5 struct label_manager lbl_mgr; @@ -96,7 +98,7 @@ void delete_label_chunk(void *val) */ int release_daemon_label_chunks(struct zserv *client) { - struct listnode *node; + struct listnode *node, *nnode; struct label_manager_chunk *lmc; int count = 0; int ret; @@ -106,7 +108,7 @@ int release_daemon_label_chunks(struct zserv *client) __func__, zebra_route_string(client->proto), client->instance, client->session_id); - for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { + for (ALL_LIST_ELEMENTS(lbl_mgr.lc_list, node, nnode, lmc)) { if (lmc->proto == client->proto && lmc->instance == client->instance && lmc->session_id == client->session_id && lmc->keep == 0) { @@ -145,6 +147,22 @@ void lm_hooks_unregister(void) hook_unregister(lm_release_chunk, label_manager_release_label_chunk); } +DEFPY(show_label_table, show_label_table_cmd, "show debugging label-table", + SHOW_STR + DEBUG_STR + "Display allocated label chunks\n") +{ + struct label_manager_chunk *lmc; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { + vty_out(vty, "Proto %s: [%u/%u]\n", + zebra_route_string(lmc->proto), lmc->start, lmc->end); + } + + return CMD_SUCCESS; +} + /** * Init label manager (or proxy to an external one) */ @@ -159,6 +177,8 @@ void label_manager_init(void) /* notify any external module that we are done */ hook_call(lm_cbs_inited); + + install_element(VIEW_NODE, &show_label_table_cmd); } /* alloc and fill a label chunk */ @@ -399,13 +419,14 @@ int release_label_chunk(uint8_t proto, unsigned short instance, "%s: Daemon mismatch!!", __func__); continue; } - lmc->proto = NO_PROTO; - lmc->instance = 0; - lmc->session_id = 0; - lmc->keep = 0; ret = 0; break; } + if (lmc) { + list_delete_node(lbl_mgr.lc_list, node); + delete_label_chunk(lmc); + } + if (ret != 0) flog_err(EC_ZEBRA_LM_UNRELEASED_CHUNK, "%s: Label chunk not released!!", __func__); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 7aa254b1cb20..463c903dafdf 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -592,9 +592,8 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id) struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug( - "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/DEL %s VRF Id %u -> %u", - ifp->name, ifp->vrf->vrf_id, new_vrf_id); + zlog_debug("MESSAGE: ZEBRA_INTERFACE_DELETE %s VRF Id %u -> %u", + ifp->name, ifp->vrf->vrf_id, new_vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ @@ -606,7 +605,6 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id) zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); client->ifdel_cnt++; zsend_interface_delete(client, ifp); - zsend_interface_vrf_update(client, ifp, new_vrf_id); } } @@ -619,9 +617,8 @@ void zebra_interface_vrf_update_add(struct interface *ifp, vrf_id_t old_vrf_id) struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug( - "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/ADD %s VRF Id %u -> %u", - ifp->name, old_vrf_id, ifp->vrf->vrf_id); + zlog_debug("MESSAGE: ZEBRA_INTERFACE_ADD %s VRF Id %u -> %u", + ifp->name, old_vrf_id, ifp->vrf->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ diff --git a/zebra/rib.h b/zebra/rib.h index e20084f8cf2e..e70b5c142363 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -337,8 +337,8 @@ int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new_nhghe); /* NHG replace has happend, we have to update route_entry pointers to new one */ -void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry, - struct nhg_hash_entry *new_entry); +int rib_handle_nhg_replace(struct nhg_hash_entry *old_entry, + struct nhg_hash_entry *new_entry); #define route_entry_dump(prefix, src, re) _route_entry_dump(__func__, prefix, src, re) extern void _route_entry_dump(const char *func, union prefixconstptr pp, diff --git a/zebra/router-id.c b/zebra/router-id.c index ef87d924fe54..45edf45336a2 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -102,6 +102,7 @@ int router_id_get(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf) return 0; case AFI_UNSPEC: case AFI_L2VPN: + case AFI_LINKSTATE: case AFI_MAX: return -1; } @@ -126,6 +127,7 @@ static int router_id_set(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf) break; case AFI_UNSPEC: case AFI_L2VPN: + case AFI_LINKSTATE: case AFI_MAX: return -1; } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 2318cd637459..bfe1910a5805 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -66,6 +66,7 @@ #include "zebra/zebra_evpn_mh.h" #include "zebra/zebra_trace.h" #include "zebra/zebra_neigh.h" +#include "lib/srv6.h" #ifndef AF_MPLS #define AF_MPLS 28 @@ -77,6 +78,8 @@ #define BR_SPH_LIST_SIZE 10 #endif +DEFINE_MTYPE_STATIC(LIB, NH_SRV6, "Nexthop srv6"); + static vlanid_t filter_vlan = 0; /* We capture whether the current kernel supports nexthop ids; by @@ -407,6 +410,36 @@ static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels) return num_labels; } +/** + * @parse_encap_seg6local_flavors() - Parses encapsulated SRv6 flavors + * attributes + * @tb: Pointer to rtattr to look for nested items in. + * @flv: Pointer to store SRv6 flavors info in. + * + * Return: 0 on success, non-zero on error + */ +static int parse_encap_seg6local_flavors(struct rtattr *tb, + struct seg6local_flavors_info *flv) +{ + struct rtattr *tb_encap[SEG6_LOCAL_FLV_MAX + 1] = {}; + + netlink_parse_rtattr_nested(tb_encap, SEG6_LOCAL_FLV_MAX, tb); + + if (tb_encap[SEG6_LOCAL_FLV_OPERATION]) + flv->flv_ops = *(uint32_t *)RTA_DATA( + tb_encap[SEG6_LOCAL_FLV_OPERATION]); + + if (tb_encap[SEG6_LOCAL_FLV_LCBLOCK_BITS]) + flv->lcblock_len = *(uint8_t *)RTA_DATA( + tb_encap[SEG6_LOCAL_FLV_LCBLOCK_BITS]); + + if (tb_encap[SEG6_LOCAL_FLV_LCNODE_FN_BITS]) + flv->lcnode_func_len = *(uint8_t *)RTA_DATA( + tb_encap[SEG6_LOCAL_FLV_LCNODE_FN_BITS]); + + return 0; +} + static enum seg6local_action_t parse_encap_seg6local(struct rtattr *tb, struct seg6local_context *ctx) @@ -434,6 +467,11 @@ parse_encap_seg6local(struct rtattr *tb, ctx->table = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_VRFTABLE]); + if (tb_encap[SEG6_LOCAL_FLAVORS]) { + parse_encap_seg6local_flavors(tb_encap[SEG6_LOCAL_FLAVORS], + &ctx->flv); + } + return act; } @@ -441,19 +479,19 @@ static int parse_encap_seg6(struct rtattr *tb, struct in6_addr *segs) { struct rtattr *tb_encap[SEG6_IPTUNNEL_MAX + 1] = {}; struct seg6_iptunnel_encap *ipt = NULL; - struct in6_addr *segments = NULL; + int i; netlink_parse_rtattr_nested(tb_encap, SEG6_IPTUNNEL_MAX, tb); - /* - * TODO: It's not support multiple SID list. - */ if (tb_encap[SEG6_IPTUNNEL_SRH]) { ipt = (struct seg6_iptunnel_encap *) RTA_DATA(tb_encap[SEG6_IPTUNNEL_SRH]); - segments = ipt->srh[0].segments; - *segs = segments[0]; - return 1; + + for (i = ipt->srh[0].first_segment; i >= 0; i--) + memcpy(&segs[i], &ipt->srh[0].segments[i], + sizeof(struct in6_addr)); + + return ipt->srh[0].first_segment + 1; } return 0; @@ -471,7 +509,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, int num_labels = 0; enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; struct seg6local_context seg6l_ctx = {}; - struct in6_addr seg6_segs = {}; + struct in6_addr segs[SRV6_MAX_SIDS] = {}; int num_segs = 0; vrf_id_t nh_vrf_id = vrf_id; @@ -520,7 +558,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE] && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE]) == LWTUNNEL_ENCAP_SEG6) { - num_segs = parse_encap_seg6(tb[RTA_ENCAP], &seg6_segs); + num_segs = parse_encap_seg6(tb[RTA_ENCAP], segs); } if (rtm->rtm_flags & RTNH_F_ONLINK) @@ -532,11 +570,21 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, if (num_labels) nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels); + /* Resolve default values for SRv6 flavors */ + if (seg6l_ctx.flv.flv_ops != ZEBRA_SEG6_LOCAL_FLV_OP_UNSPEC) { + if (seg6l_ctx.flv.lcblock_len == 0) + seg6l_ctx.flv.lcblock_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCBLOCK_LEN; + if (seg6l_ctx.flv.lcnode_func_len == 0) + seg6l_ctx.flv.lcnode_func_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCNODE_FN_LEN; + } + if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) nexthop_add_srv6_seg6local(&nh, seg6l_act, &seg6l_ctx); if (num_segs) - nexthop_add_srv6_seg6(&nh, &seg6_segs); + nexthop_add_srv6_seg6(&nh, segs, num_segs); return nh; } @@ -556,7 +604,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, int num_labels = 0; enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; struct seg6local_context seg6l_ctx = {}; - struct in6_addr seg6_segs = {}; + struct in6_addr segs[SRV6_MAX_SIDS] = {}; int num_segs = 0; struct rtattr *rtnh_tb[RTA_MAX + 1] = {}; @@ -612,7 +660,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE]) == LWTUNNEL_ENCAP_SEG6) { num_segs = parse_encap_seg6(rtnh_tb[RTA_ENCAP], - &seg6_segs); + segs); } } @@ -639,12 +687,23 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, nexthop_add_labels(nh, ZEBRA_LSP_STATIC, num_labels, labels); + /* Resolve default values for SRv6 flavors */ + if (seg6l_ctx.flv.flv_ops != + ZEBRA_SEG6_LOCAL_FLV_OP_UNSPEC) { + if (seg6l_ctx.flv.lcblock_len == 0) + seg6l_ctx.flv.lcblock_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCBLOCK_LEN; + if (seg6l_ctx.flv.lcnode_func_len == 0) + seg6l_ctx.flv.lcnode_func_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCNODE_FN_LEN; + } + if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) nexthop_add_srv6_seg6local(nh, seg6l_act, &seg6l_ctx); if (num_segs) - nexthop_add_srv6_seg6(nh, &seg6_segs); + nexthop_add_srv6_seg6(nh, segs, num_segs); if (rtnh->rtnh_flags & RTNH_F_ONLINK) SET_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK); @@ -1458,37 +1517,80 @@ static bool _netlink_route_encode_nexthop_src(const struct nexthop *nexthop, } static ssize_t fill_seg6ipt_encap(char *buffer, size_t buflen, - const struct in6_addr *seg) + struct seg6_seg_stack *segs) { struct seg6_iptunnel_encap *ipt; struct ipv6_sr_hdr *srh; - const size_t srhlen = 24; + size_t srhlen; + int i; - /* - * Caution: Support only SINGLE-SID, not MULTI-SID - * This function only supports the case where segs represents - * a single SID. If you want to extend the SRv6 functionality, - * you should improve the Boundary Check. - * Ex. In case of set a SID-List include multiple-SIDs as an - * argument of the Transit Behavior, we must support variable - * boundary check for buflen. - */ - if (buflen < (sizeof(struct seg6_iptunnel_encap) + - sizeof(struct ipv6_sr_hdr) + 16)) + if (segs->num_segs > SRV6_MAX_SEGS) { + /* Exceeding maximum supported SIDs */ + return -1; + } + + srhlen = SRH_BASE_HEADER_LENGTH + SRH_SEGMENT_LENGTH * segs->num_segs; + + if (buflen < (sizeof(struct seg6_iptunnel_encap) + srhlen)) return -1; memset(buffer, 0, buflen); ipt = (struct seg6_iptunnel_encap *)buffer; ipt->mode = SEG6_IPTUN_MODE_ENCAP; - srh = ipt->srh; + + srh = (struct ipv6_sr_hdr *)&ipt->srh; srh->hdrlen = (srhlen >> 3) - 1; srh->type = 4; - srh->segments_left = 0; - srh->first_segment = 0; - memcpy(&srh->segments[0], seg, sizeof(struct in6_addr)); + srh->segments_left = segs->num_segs - 1; + srh->first_segment = segs->num_segs - 1; + + for (i = 0; i < segs->num_segs; i++) { + memcpy(&srh->segments[i], &segs->seg[i], + sizeof(struct in6_addr)); + } + + return sizeof(struct seg6_iptunnel_encap) + srhlen; +} + +static bool +_netlink_nexthop_encode_seg6local_flavor(const struct nexthop *nexthop, + struct nlmsghdr *nlmsg, size_t buflen) +{ + struct rtattr *nest; + struct seg6local_flavors_info *flv; + + assert(nexthop); + + if (!nexthop->nh_srv6) + return false; + + flv = &nexthop->nh_srv6->seg6local_ctx.flv; + + if (flv->flv_ops == ZEBRA_SEG6_LOCAL_FLV_OP_UNSPEC) + return true; - return srhlen + 4; + nest = nl_attr_nest(nlmsg, buflen, SEG6_LOCAL_FLAVORS); + if (!nest) + return false; + + if (!nl_attr_put32(nlmsg, buflen, SEG6_LOCAL_FLV_OPERATION, + flv->flv_ops)) + return false; + + if (flv->lcblock_len) + if (!nl_attr_put8(nlmsg, buflen, SEG6_LOCAL_FLV_LCBLOCK_BITS, + flv->lcblock_len)) + return false; + + if (flv->lcnode_func_len) + if (!nl_attr_put8(nlmsg, buflen, SEG6_LOCAL_FLV_LCNODE_FN_BITS, + flv->lcnode_func_len)) + return false; + + nl_attr_nest_end(nlmsg, nest); + + return true; } /* This function takes a nexthop as argument and adds @@ -1622,10 +1724,17 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, nexthop->nh_srv6->seg6local_action); return false; } + + if (!_netlink_nexthop_encode_seg6local_flavor( + nexthop, nlmsg, req_size)) + return false; + nl_attr_nest_end(nlmsg, nest); } - if (!sid_zero(&nexthop->nh_srv6->seg6_segs)) { + if (nexthop->nh_srv6->seg6_segs && + nexthop->nh_srv6->seg6_segs->num_segs && + !sid_zero(nexthop->nh_srv6->seg6_segs)) { char tun_buf[4096]; ssize_t tun_len; struct rtattr *nest; @@ -1636,8 +1745,9 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP); if (!nest) return false; - tun_len = fill_seg6ipt_encap(tun_buf, sizeof(tun_buf), - &nexthop->nh_srv6->seg6_segs); + tun_len = + fill_seg6ipt_encap(tun_buf, sizeof(tun_buf), + nexthop->nh_srv6->seg6_segs); if (tun_len < 0) return false; if (!nl_attr_put(nlmsg, req_size, SEG6_IPTUNNEL_SRH, @@ -2060,10 +2170,10 @@ static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen, * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer * otherwise the number of bytes written to buf. */ -ssize_t netlink_route_multipath_msg_encode(int cmd, - struct zebra_dplane_ctx *ctx, +ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, uint8_t *data, size_t datalen, - bool fpm, bool force_nhg) + bool fpm, bool force_nhg, + bool force_rr) { int bytelen; struct nexthop *nexthop = NULL; @@ -2097,8 +2207,9 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - if ((cmd == RTM_NEWROUTE) && - ((p->family == AF_INET) || v6_rr_semantics)) + if (((cmd == RTM_NEWROUTE) && + ((p->family == AF_INET) || v6_rr_semantics)) || + force_rr) req->n.nlmsg_flags |= NLM_F_REPLACE; req->n.nlmsg_type = cmd; @@ -2861,10 +2972,17 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, __func__, action); return 0; } + + if (!_netlink_nexthop_encode_seg6local_flavor( + nh, &req->n, buflen)) + return false; + nl_attr_nest_end(&req->n, nest); } - if (!sid_zero(&nh->nh_srv6->seg6_segs)) { + if (nh->nh_srv6->seg6_segs && + nh->nh_srv6->seg6_segs->num_segs && + !sid_zero(nh->nh_srv6->seg6_segs)) { char tun_buf[4096]; ssize_t tun_len; struct rtattr *nest; @@ -2877,9 +2995,9 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, NHA_ENCAP | NLA_F_NESTED); if (!nest) return 0; - tun_len = fill_seg6ipt_encap(tun_buf, - sizeof(tun_buf), - &nh->nh_srv6->seg6_segs); + tun_len = fill_seg6ipt_encap( + tun_buf, sizeof(tun_buf), + nh->nh_srv6->seg6_segs); if (tun_len < 0) return 0; if (!nl_attr_put(&req->n, buflen, @@ -2953,14 +3071,14 @@ static ssize_t netlink_newroute_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, size_t buflen) { return netlink_route_multipath_msg_encode(RTM_NEWROUTE, ctx, buf, - buflen, false, false); + buflen, false, false, false); } static ssize_t netlink_delroute_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, size_t buflen) { return netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx, buf, - buflen, false, false); + buflen, false, false, false); } enum netlink_msg_status diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index d9d0ee76249a..d51944f1a462 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -56,7 +56,8 @@ extern ssize_t netlink_mpls_multipath_msg_encode(int cmd, extern ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, uint8_t *data, size_t datalen, - bool fpm, bool force_nhg); + bool fpm, bool force_nhg, + bool force_rr); extern ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data, size_t datalen); diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index bc96e12902cf..f00aef52c07a 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -174,6 +174,17 @@ static ssize_t netlink_oldrule_msg_encoder(struct zebra_dplane_ctx *ctx, dplane_ctx_rule_get_old_ipproto(ctx), buf, buflen); } +/* + * Identify valid rule actions for netlink - other actions can't be installed + */ +static bool nl_rule_valid_action(uint32_t action) +{ + if (action == PBR_ACTION_TABLE) + return true; + else + return false; +} + /* Public functions */ enum netlink_msg_status @@ -181,6 +192,7 @@ netlink_put_rule_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) { enum dplane_op_e op; enum netlink_msg_status ret; + struct pbr_rule rule = {}; op = dplane_ctx_get_op(ctx); if (!(op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE @@ -192,6 +204,18 @@ netlink_put_rule_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) return FRR_NETLINK_ERROR; } + /* TODO -- special handling for rules that include actions that + * netlink cannot install. Some of the rule attributes are not + * available in netlink: only try to install valid actions. + */ + dplane_ctx_rule_get(ctx, &rule, NULL); + if (!nl_rule_valid_action(rule.action.flags)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: skip invalid action %#x", __func__, + rule.action.flags); + return 0; + } + ret = netlink_batch_add_msg(bth, ctx, netlink_rule_msg_encoder, false); /** diff --git a/zebra/subdir.am b/zebra/subdir.am index 1060e3878532..b3bd9be9c274 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -124,6 +124,7 @@ clippy_scan += \ zebra/zebra_srv6_vty.c \ zebra/zebra_vrf.c \ zebra/dpdk/zebra_dplane_dpdk_vty.c \ + zebra/label_manager.c \ # end noinst_HEADERS += \ diff --git a/zebra/tc_netlink.c b/zebra/tc_netlink.c index 679dc80a583e..d633c07770cf 100644 --- a/zebra/tc_netlink.c +++ b/zebra/tc_netlink.c @@ -160,7 +160,7 @@ static ssize_t netlink_qdisc_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, struct nlmsghdr n; struct tcmsg t; char buf[0]; - } *req = (void *)data; + } *req = data; if (datalen < sizeof(*req)) return 0; @@ -236,7 +236,7 @@ static ssize_t netlink_tclass_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, struct nlmsghdr n; struct tcmsg t; char buf[0]; - } *req = (void *)data; + } *req = data; if (datalen < sizeof(*req)) return 0; @@ -486,7 +486,7 @@ static ssize_t netlink_tfilter_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, struct nlmsghdr n; struct tcmsg t; char buf[0]; - } *req = (void *)data; + } *req = data; if (datalen < sizeof(*req)) return 0; @@ -703,6 +703,8 @@ int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) { struct tcmsg *tcm; struct zebra_tc_qdisc qdisc = {}; + enum tc_qdisc_kind kind = TC_QDISC_UNSPEC; + const char *kind_str = "Unknown"; int len; struct rtattr *tb[TCA_MAX + 1]; @@ -722,9 +724,11 @@ int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) tcm = NLMSG_DATA(h); netlink_parse_rtattr(tb, TCA_MAX, TCA_RTA(tcm), len); - const char *kind_str = (const char *)RTA_DATA(tb[TCA_KIND]); + if (RTA_DATA(tb[TCA_KIND])) { + kind_str = (const char *)RTA_DATA(tb[TCA_KIND]); - enum tc_qdisc_kind kind = tc_qdisc_str2kind(kind_str); + kind = tc_qdisc_str2kind(kind_str); + } qdisc.qdisc.ifindex = tcm->tcm_ifindex; diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index f6afb006b720..b73511f02775 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -71,6 +71,7 @@ static void zserv_encode_interface(struct stream *s, struct interface *ifp) stream_putc(s, ifp->ptm_status); stream_putl(s, ifp->metric); stream_putl(s, ifp->speed); + stream_putl(s, ifp->txqlen); stream_putl(s, ifp->mtu); stream_putl(s, ifp->mtu6); stream_putl(s, ifp->bandwidth); @@ -434,27 +435,6 @@ int zsend_interface_addresses(struct zserv *client, struct interface *ifp) return 0; } -/* Notify client about interface moving from one VRF to another. - * Whether client is interested in old and new VRF is checked by caller. - */ -int zsend_interface_vrf_update(struct zserv *client, struct interface *ifp, - vrf_id_t vrf_id) -{ - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - - zclient_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf->vrf_id); - - /* Fill in the name of the interface and its new VRF (id) */ - stream_put(s, ifp->name, INTERFACE_NAMSIZ); - stream_putl(s, vrf_id); - - /* Write packet size. */ - stream_putw_at(s, 0, stream_get_endp(s)); - - client->if_vrfchg_cnt++; - return zserv_send_message(client, s); -} - /* Add new nbr connected IPv6 address */ void nbr_connected_add_ipv6(struct interface *ifp, struct in6_addr *address) { @@ -564,6 +544,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, client->redist_v6_del_cnt++; break; case AFI_L2VPN: + case AFI_LINKSTATE: case AFI_MAX: case AFI_UNSPEC: break; @@ -847,7 +828,9 @@ void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, VRF_DEFAULT); + zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, + dplane_ctx_rule_get_vrfid(ctx)); + stream_put(s, ¬e, sizeof(note)); stream_putl(s, dplane_ctx_rule_get_seq(ctx)); stream_putl(s, dplane_ctx_rule_get_priority(ctx)); @@ -1793,7 +1776,8 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, if (IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: adding seg6", __func__); - nexthop_add_srv6_seg6(nexthop, &api_nh->seg6_segs); + nexthop_add_srv6_seg6(nexthop, &api_nh->seg6_segs[0], + api_nh->seg_num); } if (IS_ZEBRA_DEBUG_RECV) { diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index ce8e154465ff..a01cbf675d51 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -57,8 +57,6 @@ extern int zsend_redistribute_route(int cmd, struct zserv *zclient, extern int zsend_router_id_update(struct zserv *zclient, afi_t afi, struct prefix *p, vrf_id_t vrf_id); -extern int zsend_interface_vrf_update(struct zserv *zclient, - struct interface *ifp, vrf_id_t vrf_id); extern int zsend_interface_link_params(struct zserv *zclient, struct interface *ifp); extern int zsend_pw_update(struct zserv *client, struct zebra_pw *pw); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 7b2f6430804f..099a6e2725c1 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -216,6 +216,8 @@ struct dplane_intf_info { uint32_t rc_bitfield; + uint32_t txqlen; + uint32_t metric; uint32_t flags; @@ -2656,6 +2658,20 @@ void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label) } } +void dplane_ctx_set_intf_txqlen(struct zebra_dplane_ctx *ctx, uint32_t txqlen) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.txqlen = txqlen; +} + +uint32_t dplane_ctx_get_intf_txqlen(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.txqlen; +} + /* Accessors for MAC information */ vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx) { @@ -3015,6 +3031,13 @@ void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx, ctx->u.rule.new.dp_flow_ptr = dp_flow_ptr; } +vrf_id_t dplane_ctx_rule_get_vrfid(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rule.new.prule.vrf_id; +} + /*********************************************************************** * PBR RULE ACCESSORS - end **********************************************************************/ diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index c006522e0177..87c2e0365677 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -672,6 +672,8 @@ void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx, bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx); const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label); +void dplane_ctx_set_intf_txqlen(struct zebra_dplane_ctx *ctx, uint32_t txqlen); +uint32_t dplane_ctx_get_intf_txqlen(const struct zebra_dplane_ctx *ctx); /* Accessors for MAC information */ vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx); @@ -738,6 +740,8 @@ intptr_t dplane_ctx_rule_get_old_dp_flow_ptr(const struct zebra_dplane_ctx *ctx); void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx, intptr_t dp_flow_ptr); +vrf_id_t dplane_ctx_rule_get_vrfid(const struct zebra_dplane_ctx *ctx); + /* Accessors for policy based routing iptable information */ struct zebra_pbr_iptable; void dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c index a0ef08273c50..a93dbbb008cc 100644 --- a/zebra/zebra_nb.c +++ b/zebra/zebra_nb.c @@ -598,6 +598,28 @@ const struct frr_yang_module_info frr_zebra_info = { .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_color_get_elem, } }, + + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry", + .cbs = { + .get_next = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_next, + .get_keys = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_keys, + .lookup_entry = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_lookup_entry, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry/id", + .cbs = { + .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_id_get_elem, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry/seg", + .cbs = { + .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_seg_get_elem, + } + }, + { .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/mpls-label-stack/entry", .cbs = { diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index a066a7f9dcce..80d2aaa6fee5 100644 --- a/zebra/zebra_nb.h +++ b/zebra/zebra_nb.h @@ -240,6 +240,20 @@ struct yang_data * lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_color_get_elem( struct nb_cb_get_elem_args *args); const void * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_next( + struct nb_cb_get_next_args *args); +int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_keys( + struct nb_cb_get_keys_args *args); +const void * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_lookup_entry( + struct nb_cb_lookup_entry_args *args); +struct yang_data * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_id_get_elem( + struct nb_cb_get_elem_args *args); +struct yang_data * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_seg_get_elem( + struct nb_cb_get_elem_args *args); +const void * lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_mpls_label_stack_entry_get_next( struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_mpls_label_stack_entry_get_keys( diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c index acf0b80aca68..ba537475cbcc 100644 --- a/zebra/zebra_nb_state.c +++ b/zebra/zebra_nb_state.c @@ -840,6 +840,58 @@ lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_color_get_elem( return NULL; } +/* + * XPath: + * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry + */ +const void * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_next( + struct nb_cb_get_next_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + +int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_keys( + struct nb_cb_get_keys_args *args) +{ + /* TODO: implement me. */ + return NB_OK; +} + +const void * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_lookup_entry( + struct nb_cb_lookup_entry_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: + * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry/id + */ +struct yang_data * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_id_get_elem( + struct nb_cb_get_elem_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: + * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry/seg + */ +struct yang_data * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_seg_get_elem( + struct nb_cb_get_elem_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + + /* * XPath: * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/mpls-label-stack/entry diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index d3c86e2a3723..d1a84491aa0a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1868,11 +1868,18 @@ static struct nexthop *nexthop_set_resolved(afi_t afi, labels); if (nexthop->nh_srv6) { - nexthop_add_srv6_seg6local(resolved_hop, - nexthop->nh_srv6->seg6local_action, - &nexthop->nh_srv6->seg6local_ctx); - nexthop_add_srv6_seg6(resolved_hop, - &nexthop->nh_srv6->seg6_segs); + if (nexthop->nh_srv6->seg6local_action != + ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + nexthop_add_srv6_seg6local(resolved_hop, + nexthop->nh_srv6 + ->seg6local_action, + &nexthop->nh_srv6 + ->seg6local_ctx); + if (nexthop->nh_srv6->seg6_segs) + nexthop_add_srv6_seg6(resolved_hop, + &nexthop->nh_srv6->seg6_segs->seg[0], + nexthop->nh_srv6->seg6_segs + ->num_segs); } resolved_hop->rparent = nexthop; @@ -2281,6 +2288,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, break; case AFI_UNSPEC: case AFI_L2VPN: + case AFI_LINKSTATE: case AFI_MAX: flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u", __func__, @@ -2324,6 +2332,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, break; case AFI_UNSPEC: case AFI_L2VPN: + case AFI_LINKSTATE: case AFI_MAX: assert(afi != AFI_IP && afi != AFI_IP6); break; @@ -3420,6 +3429,7 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type, struct nhg_connected *rb_node_dep = NULL; struct nexthop *newhop; bool replace = false; + int ret = 0; if (!nhg->nexthop) { if (IS_ZEBRA_DEBUG_NHG) @@ -3517,22 +3527,31 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type, if (CHECK_FLAG(old->flags, NEXTHOP_GROUP_PROTO_RELEASED)) zebra_nhg_increment_ref(old); - rib_handle_nhg_replace(old, new); + ret = rib_handle_nhg_replace(old, new); + if (ret) + /* + * if ret > 0, some previous re->nhe has freed the + * address to which old_entry is pointing. Hence mark + * the old NHE as NULL + */ + old = NULL; + else { + /* We have to decrement its singletons + * because some might not exist in NEW. + */ + if (!zebra_nhg_depends_is_empty(old)) { + frr_each (nhg_connected_tree, &old->nhg_depends, + rb_node_dep) + zebra_nhg_decrement_ref( + rb_node_dep->nhe); + } - /* We have to decrement its singletons - * because some might not exist in NEW. - */ - if (!zebra_nhg_depends_is_empty(old)) { - frr_each (nhg_connected_tree, &old->nhg_depends, - rb_node_dep) - zebra_nhg_decrement_ref(rb_node_dep->nhe); + /* Dont call the dec API, we dont want to uninstall the ID */ + old->refcnt = 0; + EVENT_OFF(old->timer); + zebra_nhg_free(old); + old = NULL; } - - /* Dont call the dec API, we dont want to uninstall the ID */ - old->refcnt = 0; - EVENT_OFF(old->timer); - zebra_nhg_free(old); - old = NULL; } if (IS_ZEBRA_DEBUG_NHG_DETAIL) diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 5124768a7c50..c04c5f558057 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -172,10 +172,13 @@ uint32_t zebra_pbr_rules_hash_key(const void *arg) key = jhash_3words(rule->rule.filter.pcp, rule->rule.filter.vlan_id, rule->rule.filter.vlan_flags, key); - return jhash_3words(rule->rule.filter.src_port, - rule->rule.filter.dst_port, - prefix_hash_key(&rule->rule.filter.dst_ip), - jhash_1word(rule->rule.unique, key)); + key = jhash_3words(rule->rule.filter.src_port, + rule->rule.filter.dst_port, + prefix_hash_key(&rule->rule.filter.dst_ip), key); + + key = jhash_2words(rule->rule.unique, rule->sock, key); + + return key; } bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) @@ -191,6 +194,9 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) if (r1->rule.priority != r2->rule.priority) return false; + if (r1->sock != r2->sock) + return false; + if (r1->rule.unique != r2->rule.unique) return false; @@ -226,6 +232,7 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) struct pbr_rule_unique_lookup { struct zebra_pbr_rule *rule; + int sock; uint32_t unique; char ifname[INTERFACE_NAMSIZ + 1]; vrf_id_t vrf_id; @@ -236,9 +243,9 @@ static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data) struct pbr_rule_unique_lookup *pul = data; struct zebra_pbr_rule *rule = b->data; - if (pul->unique == rule->rule.unique - && strncmp(pul->ifname, rule->rule.ifname, INTERFACE_NAMSIZ) == 0 - && pul->vrf_id == rule->vrf_id) { + if (pul->sock == rule->sock && pul->unique == rule->rule.unique && + strmatch(pul->ifname, rule->rule.ifname) && + pul->vrf_id == rule->vrf_id) { pul->rule = rule; return HASHWALK_ABORT; } @@ -255,6 +262,7 @@ pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule) strlcpy(pul.ifname, zrule->rule.ifname, INTERFACE_NAMSIZ); pul.rule = NULL; pul.vrf_id = zrule->vrf_id; + pul.sock = zrule->sock; hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul); return pul.rule; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5a32cf6bb9f8..c05d69a2dd39 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -428,18 +428,29 @@ int route_entry_update_nhe(struct route_entry *re, done: /* Detach / deref previous nhg */ - if (old_nhg) + + if (old_nhg) { + /* + * Return true if we are deleting the previous NHE + * Note: we dont check the return value of the function anywhere + * except at rib_handle_nhg_replace(). + */ + if (old_nhg->refcnt == 1) + ret = 1; + zebra_nhg_decrement_ref(old_nhg); + } return ret; } -void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry, - struct nhg_hash_entry *new_entry) +int rib_handle_nhg_replace(struct nhg_hash_entry *old_entry, + struct nhg_hash_entry *new_entry) { struct zebra_router_table *zrt; struct route_node *rn; struct route_entry *re, *next; + int ret = 0; if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: replacing routes nhe (%u) OLD %p NEW %p", @@ -451,10 +462,17 @@ void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry, rn = srcdest_route_next(rn)) { RNODE_FOREACH_RE_SAFE (rn, re, next) { if (re->nhe && re->nhe == old_entry) - route_entry_update_nhe(re, new_entry); + ret += route_entry_update_nhe(re, + new_entry); } } } + + /* + * if ret > 0, some previous re->nhe has freed the address to which + * old_entry is pointing. + */ + return ret; } struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 28b83ce8b6f6..30d92c30f4d5 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -1268,6 +1268,7 @@ void show_nexthop_json_helper(json_object *json_nexthop, json_object *json_backups = NULL; json_object *json_seg6local = NULL; json_object *json_seg6 = NULL; + json_object *json_segs = NULL; int i; json_object_int_add(json_nexthop, "flags", nexthop->flags); @@ -1425,11 +1426,31 @@ void show_nexthop_json_helper(json_object *json_nexthop, nexthop->nh_srv6->seg6local_action)); json_object_object_add(json_nexthop, "seg6local", json_seg6local); - - json_seg6 = json_object_new_object(); - json_object_string_addf(json_seg6, "segs", "%pI6", - &nexthop->nh_srv6->seg6_segs); - json_object_object_add(json_nexthop, "seg6", json_seg6); + if (nexthop->nh_srv6->seg6_segs && + nexthop->nh_srv6->seg6_segs->num_segs == 1) { + json_seg6 = json_object_new_object(); + json_object_string_addf(json_seg6, "segs", "%pI6", + &nexthop->nh_srv6->seg6_segs + ->seg[0]); + json_object_object_add(json_nexthop, "seg6", json_seg6); + } else { + json_segs = json_object_new_array(); + if (nexthop->nh_srv6->seg6_segs) { + for (int seg_idx = 0; + seg_idx < + nexthop->nh_srv6->seg6_segs->num_segs; + seg_idx++) + json_object_array_add( + json_segs, + json_object_new_stringf( + "%pI6", + &nexthop->nh_srv6 + ->seg6_segs + ->seg[seg_idx])); + json_object_object_add(json_nexthop, "seg6", + json_segs); + } + } } } @@ -1440,7 +1461,9 @@ void show_route_nexthop_helper(struct vty *vty, const struct route_entry *re, const struct nexthop *nexthop) { char buf[MPLS_LABEL_STRLEN]; - int i; + char seg_buf[SRV6_SEG_STRLEN]; + struct seg6_segs segs; + uint8_t i; switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: @@ -1538,9 +1561,17 @@ void show_route_nexthop_helper(struct vty *vty, const struct route_entry *re, seg6local_action2str( nexthop->nh_srv6->seg6local_action), buf); - if (IPV6_ADDR_CMP(&nexthop->nh_srv6->seg6_segs, &in6addr_any)) - vty_out(vty, ", seg6 %pI6", - &nexthop->nh_srv6->seg6_segs); + if (nexthop->nh_srv6->seg6_segs && + IPV6_ADDR_CMP(&nexthop->nh_srv6->seg6_segs->seg[0], + &in6addr_any)) { + segs.num_segs = nexthop->nh_srv6->seg6_segs->num_segs; + for (i = 0; i < segs.num_segs; i++) + memcpy(&segs.segs[i], + &nexthop->nh_srv6->seg6_segs->seg[i], + sizeof(struct in6_addr)); + snprintf_seg6_segs(seg_buf, SRV6_SEG_STRLEN, &segs); + vty_out(vty, ", seg6 %s", seg_buf); + } } if (nexthop->weight) diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index e06733cb8c68..8cab1849535b 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -353,7 +353,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], if (policy) /* Not supported (yet?) */ return; for (*np = route_top(table); *np; *np = route_next(*np)) { - if (!in_addr_cmp(&(*np)->p.u.prefix, + if (!in_addr_cmp((uint8_t *)&(*np)->p.u.prefix4, (uint8_t *)&dest)) { RNODE_FOREACH_RE (*np, *re) { if (!in_addr_cmp((uint8_t *)&(*re)->nhe @@ -374,13 +374,14 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], for (np2 = route_top(table); np2; np2 = route_next(np2)) { /* Check destination first */ - if (in_addr_cmp(&np2->p.u.prefix, (uint8_t *)&dest) > 0) + if (in_addr_cmp((uint8_t *)&np2->p.u.prefix4, + (uint8_t *)&dest) > 0) RNODE_FOREACH_RE (np2, re2) { check_replace(np2, re2, np, re); } - if (in_addr_cmp(&np2->p.u.prefix, (uint8_t *)&dest) - == 0) { /* have to look at each re individually */ + if (in_addr_cmp((uint8_t *)&np2->p.u.prefix4, (uint8_t *)&dest) == + 0) { /* have to look at each re individually */ RNODE_FOREACH_RE (np2, re2) { int proto2, policy2; diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 0c063830d305..25e65139894f 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -373,6 +373,12 @@ struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf) zebra_pw_init(zvrf); zvrf->table_id = rt_table_main_id; /* by default table ID is default one */ + + if (DFLT_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) { + zvrf->zebra_rnh_ip_default_route = true; + zvrf->zebra_rnh_ipv6_default_route = true; + } + return zvrf; } @@ -456,11 +462,20 @@ static int vrf_config_write(struct vty *vty) zvrf->l3vni) ? " prefix-routes-only" : ""); - if (zvrf->zebra_rnh_ip_default_route) - vty_out(vty, "ip nht resolve-via-default\n"); - if (zvrf->zebra_rnh_ipv6_default_route) - vty_out(vty, "ipv6 nht resolve-via-default\n"); + if (zvrf->zebra_rnh_ip_default_route != + SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) + vty_out(vty, "%sip nht resolve-via-default\n", + zvrf->zebra_rnh_ip_default_route + ? "" + : "no "); + + if (zvrf->zebra_rnh_ipv6_default_route != + SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) + vty_out(vty, "%sipv6 nht resolve-via-default\n", + zvrf->zebra_rnh_ipv6_default_route + ? "" + : "no "); if (zvrf->tbl_mgr && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)) @@ -476,11 +491,19 @@ static int vrf_config_write(struct vty *vty) ? " prefix-routes-only" : ""); zebra_ns_config_write(vty, (struct ns *)vrf->ns_ctxt); - if (zvrf->zebra_rnh_ip_default_route) - vty_out(vty, " ip nht resolve-via-default\n"); - - if (zvrf->zebra_rnh_ipv6_default_route) - vty_out(vty, " ipv6 nht resolve-via-default\n"); + if (zvrf->zebra_rnh_ip_default_route != + SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) + vty_out(vty, " %sip nht resolve-via-default\n", + zvrf->zebra_rnh_ip_default_route + ? "" + : "no "); + + if (zvrf->zebra_rnh_ipv6_default_route != + SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) + vty_out(vty, " %sipv6 nht resolve-via-default\n", + zvrf->zebra_rnh_ipv6_default_route + ? "" + : "no "); if (zvrf->tbl_mgr && vrf_is_backend_netns() && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)) diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index aef83cd8f172..5cbfab1ddc0f 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -13,11 +13,17 @@ #include #include #include +#include "defaults.h" #ifdef __cplusplus extern "C" { #endif +FRR_CFG_DEFAULT_BOOL(ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT, + { .val_bool = true, .match_profile = "traditional", }, + { .val_bool = false }, +); + /* MPLS (Segment Routing) global block */ struct mpls_srgb { uint32_t start_label; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 1a123ba5c268..d36c2f81c789 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1067,16 +1067,22 @@ DEFPY (show_ip_nht, json_object *json = NULL; json_object *json_vrf = NULL; json_object *json_nexthop = NULL; + struct zebra_vrf *zvrf; + bool resolve_via_default = false; if (uj) json = json_object_new_object(); if (vrf_all) { struct vrf *vrf; - struct zebra_vrf *zvrf; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { if ((zvrf = vrf->info) != NULL) { + resolve_via_default = + (afi == AFI_IP) + ? zvrf->zebra_rnh_ip_default_route + : zvrf->zebra_rnh_ipv6_default_route; + if (uj) { json_vrf = json_object_new_object(); json_nexthop = json_object_new_object(); @@ -1088,9 +1094,16 @@ DEFPY (show_ip_nht, ? "ipv4" : "ipv6", json_nexthop); + json_object_boolean_add(json_nexthop, + "resolveViaDefault", + resolve_via_default); } else { vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf)); + vty_out(vty, + " Resolve via default: %s\n", + resolve_via_default ? "on" + : "off"); } zebra_print_rnh_table(zvrf_id(zvrf), afi, safi, vty, NULL, json_nexthop); @@ -1115,6 +1128,11 @@ DEFPY (show_ip_nht, } } + zvrf = zebra_vrf_lookup_by_id(vrf_id); + resolve_via_default = (afi == AFI_IP) + ? zvrf->zebra_rnh_ip_default_route + : zvrf->zebra_rnh_ipv6_default_route; + if (uj) { json_vrf = json_object_new_object(); json_nexthop = json_object_new_object(); @@ -1126,6 +1144,13 @@ DEFPY (show_ip_nht, json_object_object_add(json_vrf, (afi == AFI_IP) ? "ipv4" : "ipv6", json_nexthop); + + json_object_boolean_add(json_nexthop, "resolveViaDefault", + resolve_via_default); + } else { + vty_out(vty, "VRF %s:\n", zvrf_name(zvrf)); + vty_out(vty, " Resolve via default: %s\n", + resolve_via_default ? "on" : "off"); } zebra_print_rnh_table(vrf_id, afi, safi, vty, p, json_nexthop);