diff options
210 files changed, 7985 insertions, 5432 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index 2cb3feec15..855b585903 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -33,6 +33,8 @@ _libdir=/usr/lib _user=frr build() { + export ABUILD_APK_INDEX_OPTS="--allow-untrusted" + cd "$builddir" ./configure \ diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 9dcd0ad1d6..4c1615a5c6 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -77,6 +77,9 @@ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; +/* as-path orphan exclude list */ +static struct as_list_list_head as_exclude_list_orphan; + /* Callers are required to initialize the memory */ static as_t *assegment_data_new(int num) { @@ -1558,6 +1561,38 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) /* Not reached */ } +/* insert aspath exclude in head of orphan exclude list*/ +void as_exclude_set_orphan(struct aspath_exclude *ase) +{ + ase->exclude_aspath_acl = NULL; + as_list_list_add_head(&as_exclude_list_orphan, ase); +} + +void as_exclude_remove_orphan(struct aspath_exclude *ase) +{ + if (as_list_list_count(&as_exclude_list_orphan)) + as_list_list_del(&as_exclude_list_orphan, ase); +} + +/* currently provide only one exclude, not a list */ +struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name) +{ + struct aspath_exclude *ase = NULL; + char *name = NULL; + + frr_each (as_list_list, &as_exclude_list_orphan, ase) { + if (ase->exclude_aspath_acl_name) { + name = ase->exclude_aspath_acl_name; + if (!strcmp(name, acl_name)) + break; + } + } + if (ase) + as_exclude_remove_orphan(ase); + + return ase; +} + /* Iterate over AS_PATH segments and wipe all occurrences of the * listed AS numbers. Hence some segments may lose some or even * all data on the way, the operation is implemented as a smarter @@ -2236,14 +2271,26 @@ void aspath_init(void) { ashash = hash_create_size(32768, aspath_key_make, aspath_cmp, "BGP AS Path"); + + as_list_list_init(&as_exclude_list_orphan); } void aspath_finish(void) { + struct aspath_exclude *ase; + hash_clean_and_free(&ashash, (void (*)(void *))aspath_free); if (snmp_stream) stream_free(snmp_stream); + + while ((ase = as_list_list_pop(&as_exclude_list_orphan))) { + aspath_free(ase->aspath); + if (ase->exclude_aspath_acl_name) + XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name); + XFREE(MTYPE_ROUTE_MAP_COMPILED, ase); + } + as_list_list_fini(&as_exclude_list_orphan); } /* return and as path value */ diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 2a831c3a55..f7e57fd66d 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -9,6 +9,7 @@ #include "lib/json.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_filter.h" +#include <typesafe.h> /* AS path segment type. */ #define AS_SET 1 @@ -67,11 +68,14 @@ struct aspath { /* `set as-path exclude ASn' */ struct aspath_exclude { + struct as_list_list_item exclude_list; struct aspath *aspath; bool exclude_all; char *exclude_aspath_acl_name; struct as_list *exclude_aspath_acl; }; +DECLARE_DLIST(as_list_list, struct aspath_exclude, exclude_list); + /* Prototypes. */ extern void aspath_init(void); @@ -83,6 +87,9 @@ extern struct aspath *aspath_parse(struct stream *s, size_t length, extern struct aspath *aspath_dup(struct aspath *aspath); extern struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2); extern struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2); +extern void as_exclude_set_orphan(struct aspath_exclude *ase); +extern void as_exclude_remove_orphan(struct aspath_exclude *ase); +extern struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name); extern struct aspath *aspath_filter_exclude(struct aspath *source, struct aspath *exclude_list); extern struct aspath *aspath_filter_exclude_all(struct aspath *source); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index da4701d069..2ed49935e5 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2575,7 +2575,6 @@ bgp_attr_ext_communities(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; - uint8_t sticky = 0; bool proxy = false; struct ecommunity *ecomm; @@ -2605,21 +2604,20 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) attr->df_pref = bgp_attr_df_pref_from_ec(attr, &attr->df_alg); /* Extract MAC mobility sequence number, if any. */ - attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky); - attr->sticky = sticky; + attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr); /* Check if this is a Gateway MAC-IP advertisement */ - attr->default_gw = bgp_attr_default_gw(attr); + bgp_attr_default_gw(attr); /* Handle scenario where router flag ecommunity is not * set but default gw ext community is present. * Use default gateway, set and propogate R-bit. */ - if (attr->default_gw) - attr->router_flag = 1; + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER); /* Check EVPN Neighbor advertisement flags, R-bit */ - bgp_attr_evpn_na_flag(attr, &attr->router_flag, &proxy); + bgp_attr_evpn_na_flag(attr, &proxy); if (proxy) attr->es_flags |= ATTR_ES_PROXY_ADVERT; @@ -2721,17 +2719,20 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args) } } - while (length >= 4) { + while (STREAM_READABLE(BGP_INPUT(peer)) >= 4) { uint16_t subtype = 0; uint16_t sublength = 0; struct bgp_attr_encap_subtlv *tlv; if (BGP_ATTR_ENCAP == type) { subtype = stream_getc(BGP_INPUT(peer)); - sublength = (subtype < 128) - ? stream_getc(BGP_INPUT(peer)) - : stream_getw(BGP_INPUT(peer)); - length -= 2; + if (subtype < 128) { + sublength = stream_getc(BGP_INPUT(peer)); + length -= 2; + } else { + sublength = stream_getw(BGP_INPUT(peer)); + length -= 3; + } #ifdef ENABLE_BGP_VNC } else { subtype = stream_getw(BGP_INPUT(peer)); @@ -4465,6 +4466,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, bgp_packet_mpattr_end(s, mpattrlen_pos); } + (void)peer_sort(peer); + /* Origin attribute. */ stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_ORIGIN); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index f353e76913..3519dc3401 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -197,9 +197,6 @@ struct attr { #define ATTR_ES_L3_NHG_ACTIVE (1 << 6) #define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE) - /* NA router flag (R-bit) support in EVPN */ - uint8_t router_flag; - /* Distance as applied by Route map */ uint8_t distance; @@ -256,11 +253,12 @@ struct attr { /* MP Nexthop length */ uint8_t mp_nexthop_len; - /* Static MAC for EVPN */ - uint8_t sticky; - - /* Flag for default gateway extended community in EVPN */ - uint8_t default_gw; + /* EVPN flags */ + uint8_t evpn_flags; +#define ATTR_EVPN_FLAG_STICKY (1 << 0) +#define ATTR_EVPN_FLAG_DEFAULT_GW (1 << 1) +/* NA router flag (R-bit) support in EVPN */ +#define ATTR_EVPN_FLAG_ROUTER (1 << 2) /* route tag */ route_tag_t tag; diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index bbc4ba9525..086c36f36c 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -115,14 +115,14 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) /* * return true if attr contains default gw extended community */ -uint8_t bgp_attr_default_gw(struct attr *attr) +void bgp_attr_default_gw(struct attr *attr) { struct ecommunity *ecom; uint32_t i; ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) - return 0; + return; /* If there is a default gw extendd community return true otherwise * return 0 */ @@ -136,10 +136,9 @@ uint8_t bgp_attr_default_gw(struct attr *attr) if ((type == ECOMMUNITY_ENCODE_OPAQUE && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW)) - return 1; + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); } - - return 0; + UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); } /* @@ -183,7 +182,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg) * Fetch and return the sequence number from MAC Mobility extended * community, if present, else 0. */ -uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) +uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr) { struct ecommunity *ecom; uint32_t i; @@ -213,9 +212,9 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) flags = *pnt++; if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY) - *sticky = 1; + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); else - *sticky = 0; + UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); pnt++; pnt = ptr_get_be32(pnt, &seq_num); @@ -229,8 +228,7 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) /* * return true if attr contains router flag extended community */ -void bgp_attr_evpn_na_flag(struct attr *attr, - uint8_t *router_flag, bool *proxy) +void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy) { struct ecommunity *ecom; uint32_t i; @@ -254,7 +252,8 @@ void bgp_attr_evpn_na_flag(struct attr *attr, val = *pnt++; if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG) - *router_flag = 1; + SET_FLAG(attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER); if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG) *proxy = true; diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index f8d3978b96..e12fc3a86c 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -36,12 +36,10 @@ extern void bgp_add_routermac_ecom(struct attr *attr, extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, struct prefix *dst); extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); -extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, - uint8_t *sticky); -extern uint8_t bgp_attr_default_gw(struct attr *attr); +extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr); +extern void bgp_attr_default_gw(struct attr *attr); -extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag, - bool *proxy); +extern void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy); extern uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 5ce5b19b18..75a7d85e88 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1159,9 +1159,8 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } /* Add MAC mobility (sticky) if needed. */ - if (attr->sticky) { + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY)) { seqnum = 0; - memset(&ecom_sticky, 0, sizeof(ecom_sticky)); encode_mac_mobility_extcomm(1, seqnum, &eval_sticky); ecom_sticky.size = 1; ecom_sticky.unit_size = ECOMMUNITY_SIZE; @@ -1179,8 +1178,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } /* Add default gateway, if needed. */ - if (attr->default_gw) { - memset(&ecom_default_gw, 0, sizeof(ecom_default_gw)); + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) { encode_default_gw_extcomm(&eval_default_gw); ecom_default_gw.size = 1; ecom_default_gw.unit_size = ECOMMUNITY_SIZE; @@ -1191,9 +1189,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } proxy = !!(attr->es_flags & ATTR_ES_PROXY_ADVERT); - if (attr->router_flag || proxy) { - memset(&ecom_na, 0, sizeof(ecom_na)); - encode_na_flag_extcomm(&eval_na, attr->router_flag, proxy); + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER) || proxy) { + encode_na_flag_extcomm(&eval_na, + CHECK_FLAG(attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER), + proxy); ecom_na.size = 1; ecom_na.unit_size = ECOMMUNITY_SIZE; ecom_na.val = (uint8_t *)eval_na.val; @@ -1278,12 +1278,15 @@ enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn flags = 0; if (pi->sub_type == BGP_ROUTE_IMPORTED) { - if (pi->attr->sticky) + if (CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_STICKY)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); - if (pi->attr->default_gw) + if (CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_DEFAULT_GW)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); if (is_evpn_prefix_ipaddr_v6(p) && - pi->attr->router_flag) + CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); seq = mac_mobility_seqnum(pi->attr); @@ -1837,7 +1840,8 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi, *active_on_peer = true; } - if (second_best_path->attr->router_flag) + if (CHECK_FLAG(second_best_path->attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER)) *peer_router = true; /* we use both proxy and non-proxy imports to @@ -1937,7 +1941,6 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct attr local_attr; struct bgp_labels bgp_labels = {}; int route_change = 1; - uint8_t sticky = 0; const struct prefix_evpn *evp; *pi = NULL; @@ -1969,9 +1972,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, local_attr = *attr; /* Extract MAC mobility sequence number, if any. */ - local_attr.mm_seqnum = - bgp_attr_mac_mobility_seqnum(&local_attr, &sticky); - local_attr.sticky = sticky; + local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum(&local_attr); /* Add (or update) attribute to hash. */ attr_new = bgp_attr_intern(&local_attr); @@ -2066,9 +2067,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, BGP_PATH_ATTR_CHANGED); /* Extract MAC mobility sequence number, if any. */ - local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum( - &local_attr, &sticky); - local_attr.sticky = sticky; + local_attr.mm_seqnum = + bgp_attr_mac_mobility_seqnum(&local_attr); attr_new = bgp_attr_intern(&local_attr); @@ -2201,10 +2201,12 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0; - attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0; - attr.router_flag = CHECK_FLAG(flags, - ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0; + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_STICKY); + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER); if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) attr.es_flags |= ATTR_ES_PROXY_ADVERT; @@ -2506,13 +2508,12 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = (local_pi->attr->sticky) ? 1 : 0; - attr.router_flag = (local_pi->attr->router_flag) ? 1 : 0; + attr.evpn_flags = local_pi->attr->evpn_flags; attr.es_flags = local_pi->attr->es_flags; - if (local_pi->attr->default_gw) { - attr.default_gw = 1; + if (CHECK_FLAG(local_pi->attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) { + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); if (is_evpn_prefix_ipaddr_v6(&evp)) - attr.router_flag = 1; + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER); } memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t)); bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr, @@ -3037,6 +3038,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, vrf_id_to_name(bgp_vrf->vrf_id), evp, parent_pi, parent_pi->flags); + if (bgp_vrf->vrf_id == VRF_UNKNOWN) + return -1; + /* Create (or fetch) route within the VRF. */ /* NOTE: There is no RD here. */ if (is_evpn_prefix_ipaddr_v4(evp)) { @@ -6984,6 +6988,17 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id) } /* + * When bgp instance goes down also clean up what might have been left over + * from evpn. + */ +void bgp_evpn_instance_down(struct bgp *bgp) +{ + /* If we have a stale local vni, delete it */ + if (bgp->l3vni) + bgp_evpn_local_l3vni_del(bgp->l3vni, bgp->vrf_id); +} + +/* * Handle del of a local VNI. */ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni) diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 223f18a177..dc82bcfba9 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -153,6 +153,7 @@ extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id, struct in_addr originator_ip, int filter, ifindex_t svi_ifindex, bool is_anycast_mac); extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id); +extern void bgp_evpn_instance_down(struct bgp *bgp); extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni); extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, struct in_addr originator_ip, diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 07bba9b426..b05df3d82a 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -382,7 +382,7 @@ static inline void encode_mac_mobility_extcomm(int static_mac, uint32_t seq, } static inline void encode_na_flag_extcomm(struct ecommunity_val *eval, - uint8_t na_flag, bool proxy) + bool na_flag, bool proxy) { memset(eval, 0, sizeof(*eval)); eval->val[0] = ECOMMUNITY_ENCODE_EVPN; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 846a82ba90..c28cdb4a65 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -4840,7 +4840,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd, char *vrf = NULL; char *neighbor = NULL; as_t as = 0; /* 0 means AS filter not set */ - int as_type = AS_UNSPECIFIED; + enum peer_asn_type as_type = AS_UNSPECIFIED; uint16_t show_flags = 0; if (argv_find(argv, argc, "vrf", &idx_vrf)) diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index a85117965a..002f054f5e 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -16,7 +16,7 @@ #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" -/* List of AS filter list. */ +/* List of AS list. */ struct as_list_list { struct as_list *head; struct as_list *tail; @@ -205,14 +205,6 @@ static struct as_list *as_list_new(void) static void as_list_free(struct as_list *aslist) { - struct aspath_exclude_list *cur_bp = aslist->exclude_list; - struct aspath_exclude_list *next_bp = NULL; - - while (cur_bp) { - next_bp = cur_bp->next; - XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_bp); - cur_bp = next_bp; - } XFREE (MTYPE_AS_STR, aslist->name); XFREE (MTYPE_AS_LIST, aslist); @@ -299,7 +291,6 @@ static void as_list_delete(struct as_list *aslist) { struct as_list_list *list; struct as_filter *filter, *next; - struct aspath_exclude_list *cur_bp; for (filter = aslist->head; filter; filter = next) { next = filter->next; @@ -318,12 +309,6 @@ static void as_list_delete(struct as_list *aslist) else list->head = aslist->next; - cur_bp = aslist->exclude_list; - while (cur_bp) { - cur_bp->bp_as_excl->exclude_aspath_acl = NULL; - cur_bp = cur_bp->next; - } - as_list_free(aslist); } @@ -431,6 +416,7 @@ DEFUN(as_path, bgp_as_path_cmd, enum as_filter_type type; struct as_filter *asfilter; struct as_list *aslist; + struct aspath_exclude *ase; regex_t *regex; char *regstr; int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO; @@ -482,6 +468,22 @@ DEFUN(as_path, bgp_as_path_cmd, else as_list_filter_add(aslist, asfilter); + /* init the exclude rule list*/ + as_list_list_init(&aslist->exclude_rule); + + /* get aspath orphan exclude that are using this acl */ + ase = as_exclude_lookup_orphan(alname); + if (ase) { + as_list_list_add_head(&aslist->exclude_rule, ase); + /* set reverse pointer */ + ase->exclude_aspath_acl = aslist; + /* set list of aspath excludes using that acl */ + while ((ase = as_exclude_lookup_orphan(alname))) { + as_list_list_add_head(&aslist->exclude_rule, ase); + ase->exclude_aspath_acl = aslist; + } + } + return CMD_SUCCESS; } @@ -502,6 +504,7 @@ DEFUN(no_as_path, no_bgp_as_path_cmd, enum as_filter_type type; struct as_filter *asfilter; struct as_list *aslist; + struct aspath_exclude *ase; char *regstr; regex_t *regex; @@ -556,6 +559,12 @@ DEFUN(no_as_path, no_bgp_as_path_cmd, XFREE(MTYPE_TMP, regstr); + /* put aspath exclude list into orphan */ + if (as_list_list_count(&aslist->exclude_rule)) + while ((ase = as_list_list_pop(&aslist->exclude_rule))) + as_exclude_set_orphan(ase); + + as_list_list_fini(&aslist->exclude_rule); as_list_filter_delete(aslist, asfilter); return CMD_SUCCESS; diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h index 2d9f07ce84..77a3f3c2f7 100644 --- a/bgpd/bgp_filter.h +++ b/bgpd/bgp_filter.h @@ -6,11 +6,12 @@ #ifndef _QUAGGA_BGP_FILTER_H #define _QUAGGA_BGP_FILTER_H +#include <typesafe.h> + #define ASPATH_SEQ_NUMBER_AUTO -1 enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT }; - /* Element of AS path filter. */ struct as_filter { struct as_filter *next; @@ -25,11 +26,7 @@ struct as_filter { int64_t seq; }; -struct aspath_exclude_list { - struct aspath_exclude_list *next; - struct aspath_exclude *bp_as_excl; -}; - +PREDECL_DLIST(as_list_list); /* AS path filter list. */ struct as_list { char *name; @@ -39,7 +36,9 @@ struct as_list { struct as_filter *head; struct as_filter *tail; - struct aspath_exclude_list *exclude_list; + + /* Changes in AS path */ + struct as_list_list_head exclude_rule; }; diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 15cc5dbe2e..76624fee9e 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1241,7 +1241,7 @@ void bgp_fsm_change_status(struct peer_connection *connection, /* Transition into Clearing or Deleted must /always/ clear all routes.. * (and must do so before actually changing into Deleted.. */ - if (status >= Clearing) { + if (status >= Clearing && (peer->established || peer == bgp->peer_self)) { bgp_clear_route_all(peer); /* If no route was queued for the clear-node processing, @@ -2046,9 +2046,10 @@ static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi, } gr_info->eor_required++; /* Send message to RIB indicating route update pending */ - if (gr_info->af_enabled[afi][safi] == false) { - gr_info->af_enabled[afi][safi] = true; - /* Send message to RIB */ + if (gr_info->af_enabled == false) { + gr_info->af_enabled = true; + gr_info->route_sync = false; + bgp->gr_route_sync_pending = true; bgp_zebra_update(bgp, afi, safi, ZEBRA_CLIENT_ROUTE_UPDATE_PENDING); } @@ -2082,7 +2083,7 @@ static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi) if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && BGP_PEER_RESTARTING_MODE(peer)) { /* Check if the forwarding state is preserved */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) { + if (bgp_gr_is_forwarding_preserved(bgp)) { gr_info = &(bgp->gr_info[afi][safi]); ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info); } @@ -2199,8 +2200,7 @@ bgp_establish(struct peer_connection *connection) } else { if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && BGP_PEER_RESTARTING_MODE(peer) && - CHECK_FLAG(peer->bgp->flags, - BGP_FLAG_GR_PRESERVE_FWD)) + bgp_gr_is_forwarding_preserved(peer->bgp)) peer->bgp->gr_info[afi][safi] .eor_required++; } @@ -2695,53 +2695,60 @@ int bgp_event_update(struct peer_connection *connection, } /* BGP GR Code */ -int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, - enum global_mode global_new_state, - enum global_mode global_old_state) +static inline void +bgp_peer_inherit_global_gr_mode(struct peer *peer, + enum global_mode global_gr_mode) +{ + switch (global_gr_mode) { + case GLOBAL_HELPER: + BGP_PEER_GR_HELPER_ENABLE(peer); + break; + case GLOBAL_GR: + BGP_PEER_GR_ENABLE(peer); + break; + case GLOBAL_DISABLE: + BGP_PEER_GR_DISABLE(peer); + break; + case GLOBAL_INVALID: + default: + zlog_err("Unexpected Global GR mode %d", global_gr_mode); + } +} + +static void bgp_gr_update_mode_of_all_peers(struct bgp *bgp, + enum global_mode global_new_state) { struct peer *peer = {0}; struct listnode *node = {0}; struct listnode *nnode = {0}; enum peer_mode peer_old_state = PEER_INVALID; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] Peer: (%s) :", __func__, - peer->host); + /* TODO: Need to handle peer-groups. */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { peer_old_state = bgp_peer_gr_mode_get(peer); + if (peer_old_state != PEER_GLOBAL_INHERIT) + continue; - if (peer_old_state == PEER_GLOBAL_INHERIT) { + bgp_peer_inherit_global_gr_mode(peer, global_new_state); + bgp_peer_gr_flags_update(peer); - /* - *Reset only these peers and send a - *new open message with the change capabilities. - *Considering the mode to be "global_new_state" and - *do all operation accordingly - */ + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64 + "...resetting session", + peer, peer->peer_gr_new_status_flag, + peer->flags); - switch (global_new_state) { - case GLOBAL_HELPER: - BGP_PEER_GR_HELPER_ENABLE(peer); - break; - case GLOBAL_GR: - BGP_PEER_GR_ENABLE(peer); - break; - case GLOBAL_DISABLE: - BGP_PEER_GR_DISABLE(peer); - break; - case GLOBAL_INVALID: - zlog_debug("%s [BGP_GR] GLOBAL_INVALID", - __func__); - return BGP_ERR_GR_OPERATION_FAILED; - } - } + /* Reset session to match with behavior for other peer + * configs that require the session to be re-setup. + */ + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } else + bgp_session_reset(peer); } - - bgp->global_gr_present_state = global_new_state; - - return BGP_GR_SUCCESS; } int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) @@ -2749,46 +2756,27 @@ int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) enum global_mode global_new_state = GLOBAL_INVALID; enum global_mode global_old_state = GLOBAL_INVALID; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR]START: global_gr_cmd :%s:", __func__, - print_global_gr_cmd(global_gr_cmd)); - global_old_state = bgp_global_gr_mode_get(bgp); + global_new_state = bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd]; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] global_old_gr_state :%s:", - print_global_gr_mode(global_old_state)); - - if (global_old_state != GLOBAL_INVALID) { - global_new_state = - bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd]; + zlog_debug("%s: Handle GR command %s, current GR state %s, new GR state %s", + bgp->name_pretty, print_global_gr_cmd(global_gr_cmd), + print_global_gr_mode(global_old_state), + print_global_gr_mode(global_new_state)); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] global_new_gr_state :%s:", - print_global_gr_mode(global_new_state)); - } else { - zlog_err("%s [BGP_GR] global_old_state == GLOBAL_INVALID", - __func__); + if (global_old_state == GLOBAL_INVALID) return BGP_ERR_GR_OPERATION_FAILED; - } - - if (global_new_state == GLOBAL_INVALID) { - zlog_err("%s [BGP_GR] global_new_state == GLOBAL_INVALID", - __func__); + if (global_new_state == GLOBAL_INVALID) return BGP_ERR_GR_INVALID_CMD; - } - if (global_new_state == global_old_state) { - /* Trace msg */ - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "%s [BGP_GR] global_new_state == global_old_state :%s", - __func__, - print_global_gr_mode(global_new_state)); + if (global_new_state == global_old_state) return BGP_GR_NO_OPERATION; - } - return bgp_gr_lookup_n_update_all_peer(bgp, global_new_state, - global_old_state); + /* Update global GR mode and process all peers in instance. */ + bgp->global_gr_present_state = global_new_state; + bgp_gr_update_mode_of_all_peers(bgp, global_new_state); + + return BGP_GR_SUCCESS; } const char *print_peer_gr_mode(enum peer_mode pr_mode) @@ -2903,179 +2891,101 @@ int bgp_neighbor_graceful_restart(struct peer *peer, { enum peer_mode peer_new_state = PEER_INVALID; enum peer_mode peer_old_state = PEER_INVALID; - struct bgp_peer_gr peer_state; + struct bgp_peer_gr gr_fsm; int result = BGP_GR_FAILURE; - /* - * fetch peer_old_state from peer structure also - * fetch global_old_state from bgp structure, - * peer had a back pointer to bgpo struct ; - */ - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] START:Peer: (%s) : peer_gr_cmd :%s:", - __func__, peer->host, - print_peer_gr_cmd(peer_gr_cmd)); - peer_old_state = bgp_peer_gr_mode_get(peer); + gr_fsm = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd]; + peer_new_state = gr_fsm.next_state; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] peer_old_state: %d", __func__, - peer_old_state); + zlog_debug("%pBP: Handle GR command %s, current GR state %s, new GR state %s", + peer, print_peer_gr_cmd(peer_gr_cmd), + print_peer_gr_mode(peer_old_state), + print_peer_gr_mode(peer_new_state)); if (peer_old_state == PEER_INVALID) return BGP_ERR_GR_OPERATION_FAILED; - peer_state = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd]; - peer_new_state = peer_state.next_state; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] peer_new_state: %d", __func__, - peer_new_state); - if (peer_new_state == PEER_INVALID) return BGP_ERR_GR_INVALID_CMD; - if (peer_new_state != peer_old_state) { - result = peer_state.action_fun(peer, peer_old_state, - peer_new_state); - } else { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] peer_old_state == peer_new_state !"); + if (peer_new_state == peer_old_state) return BGP_GR_NO_OPERATION; - } - if (result == BGP_GR_SUCCESS) { - - /* Update the mode i.e peer_new_state into the peer structure */ - peer->peer_gr_present_state = peer_new_state; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Successfully change the state of the peer to : %s : !", - print_peer_gr_mode(peer_new_state)); - - return BGP_GR_SUCCESS; - } + result = gr_fsm.action_fun(peer, peer_old_state, peer_new_state); return result; } -unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, - enum peer_mode new_peer_state) +static inline bool gr_mode_matches(enum peer_mode peer_gr_mode, + enum global_mode global_gr_mode) { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "%s [BGP_GR] Move peer from old_peer_state :%s: to new_peer_state :%s: !!!!", - __func__, print_peer_gr_mode(old_peer_state), - print_peer_gr_mode(new_peer_state)); + if ((peer_gr_mode == PEER_HELPER && global_gr_mode == GLOBAL_HELPER) || + (peer_gr_mode == PEER_GR && global_gr_mode == GLOBAL_GR) || + (peer_gr_mode == PEER_DISABLE && global_gr_mode == GLOBAL_DISABLE)) + return true; + return false; +} - enum global_mode bgp_gr_global_mode = GLOBAL_INVALID; - unsigned int ret = BGP_GR_FAILURE; +unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state, + enum peer_mode new_state) +{ + enum global_mode global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + bool session_reset = true; - if (old_peer_state == new_peer_state) { - /* Nothing to do over here as the present and old state is the - * same */ + if (old_state == new_state) return BGP_GR_NO_OPERATION; - } - if ((old_peer_state == PEER_INVALID) - || (new_peer_state == PEER_INVALID)) { - /* something bad happend , print error message */ + if ((old_state == PEER_INVALID) || (new_state == PEER_INVALID)) return BGP_ERR_GR_INVALID_CMD; - } - - bgp_gr_global_mode = bgp_global_gr_mode_get(peer->bgp); - - if ((old_peer_state == PEER_GLOBAL_INHERIT) - && (new_peer_state != PEER_GLOBAL_INHERIT)) { - - /* fetch the Mode running in the Global state machine - *from the bgp structure into a variable called - *bgp_gr_global_mode - */ - /* Here we are checking if the - *1. peer_new_state == global_mode == helper_mode - *2. peer_new_state == global_mode == GR_mode - *3. peer_new_state == global_mode == disabled_mode - */ + global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + if ((old_state == PEER_GLOBAL_INHERIT) && + (new_state != PEER_GLOBAL_INHERIT)) { BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer); - if ((int)new_peer_state == (int)bgp_gr_global_mode) { - /* This is incremental updates i.e no tear down - * of the existing session - * as the peer is already working in the same mode. + if (gr_mode_matches(new_state, global_gr_mode)) + /* Peer was inheriting the global state and + * its new state still is the same, so a + * session reset is not needed. */ - ret = BGP_GR_SUCCESS; - } else { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer state changed from :%s ", - print_peer_gr_mode(old_peer_state)); - - bgp_peer_move_to_gr_mode(peer, new_peer_state); - - ret = BGP_GR_SUCCESS; - } - } - /* In the case below peer is going into Global inherit mode i.e. - * the peer would work as the mode configured at the global level - */ - else if ((new_peer_state == PEER_GLOBAL_INHERIT) - && (old_peer_state != PEER_GLOBAL_INHERIT)) { - /* Here in this case it would be destructive - * in all the cases except one case when, - * Global GR is configured Disabled - * and present_peer_state is not disable - */ - + session_reset = false; + } else if ((new_state == PEER_GLOBAL_INHERIT) && + (old_state != PEER_GLOBAL_INHERIT)) { BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); - if ((int)old_peer_state == (int)bgp_gr_global_mode) { - /* This is incremental updates - *i.e no tear down of the existing session - *as the peer is already working in the same mode. + if (gr_mode_matches(old_state, global_gr_mode)) + /* Peer is inheriting the global state and + * its old state was also the same, so a + * session reset is not needed. */ - ret = BGP_GR_SUCCESS; - } else { - /* Destructive always */ - /* Tear down the old session - * and send the new capability - * as per the bgp_gr_global_mode - */ - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer state changed from :%s", - print_peer_gr_mode(old_peer_state)); + session_reset = false; + } - bgp_peer_move_to_gr_mode(peer, bgp_gr_global_mode); + /* Ensure we move to the new state and update flags */ + bgp_peer_move_to_gr_mode(peer, new_state); - ret = BGP_GR_SUCCESS; - } - } else { - /* - *This else case, it include all the cases except --> - *(new_peer_state != Peer_Global) && - *( old_peer_state != Peer_Global ) + if (session_reset) { + /* Reset session to match with behavior for other peer + * configs that require the session to be re-setup. */ - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Peer state changed from :%s", - print_peer_gr_mode(old_peer_state)); - - bgp_peer_move_to_gr_mode(peer, new_peer_state); - - ret = BGP_GR_SUCCESS; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } else + bgp_session_reset(peer); } - return ret; + return BGP_GR_SUCCESS; } -inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) +void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state) { - int bgp_global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + enum global_mode global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + enum peer_mode old_state = bgp_peer_gr_mode_get(peer); switch (new_state) { case PEER_HELPER: @@ -3089,57 +2999,38 @@ inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) break; case PEER_GLOBAL_INHERIT: BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); - - if (bgp_global_gr_mode == GLOBAL_HELPER) { - BGP_PEER_GR_HELPER_ENABLE(peer); - } else if (bgp_global_gr_mode == GLOBAL_GR) { - BGP_PEER_GR_ENABLE(peer); - } else if (bgp_global_gr_mode == GLOBAL_DISABLE) { - BGP_PEER_GR_DISABLE(peer); - } else { - zlog_err( - "[BGP_GR] Default switch inherit mode ::: SOMETHING IS WRONG !!!"); - } + bgp_peer_inherit_global_gr_mode(peer, global_gr_mode); break; + case PEER_INVALID: default: zlog_err( "[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!"); break; } + bgp_peer_gr_flags_update(peer); + peer->peer_gr_present_state = new_state; + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Peer state changed --to--> : %d : !", - new_state); + zlog_debug("%pBP: Peer GR mode changed from %s to %s, GR flags 0x%x peer flags 0x%" PRIx64, + peer, print_peer_gr_mode(old_state), + print_peer_gr_mode(new_state), + peer->peer_gr_new_status_flag, peer->flags); } void bgp_peer_gr_flags_update(struct peer *peer) { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] called !", __func__); if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_HELPER : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_HELPER) - ? "Set" - : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - ? "Set" - : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) SET_FLAG(peer->flags, @@ -3147,28 +3038,28 @@ void bgp_peer_gr_flags_update(struct peer *peer) else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT) - ? "Set" - : "UnSet")); - - if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) { - zlog_debug("[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_MODE!", - peer->host); + zlog_debug("%pBP: Peer flags updated to 0x%" PRIx64 + ", GR flags 0x%x, GR mode %s", + peer, peer->flags, peer->peer_gr_new_status_flag, + print_peer_gr_mode(bgp_peer_gr_mode_get(peer))); + /* + * If GR has been completely disabled for the peer and we were + * acting as the Helper for the peer (i.e., keeping stale routes + * and running the restart timer or stalepath timer), clear those + * states. + */ + if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) { UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { - + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP: GR disabled, stopping NSF and clearing stale routes", + peer); peer_nsf_stop(peer); - zlog_debug( - "[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_WAIT!", - peer->host); } } } diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index bcdd49193f..85c488962f 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -151,7 +151,7 @@ int bgp_neighbor_graceful_restart(struct peer *peer, enum peer_gr_command peer_gr_cmd); unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, enum peer_mode new_peer_state); -void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state); +void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state); unsigned int bgp_peer_gr_helper_enable(struct peer *peer); unsigned int bgp_peer_gr_enable(struct peer *peer); unsigned int bgp_peer_gr_global_inherit(struct peer *peer); @@ -160,9 +160,6 @@ enum peer_mode bgp_peer_gr_mode_get(struct peer *peer); enum global_mode bgp_global_gr_mode_get(struct bgp *bgp); enum peer_mode bgp_get_peer_gr_mode_from_flags(struct peer *peer); unsigned int bgp_peer_gr_global_inherit_unset(struct peer *peer); -int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, - enum global_mode global_new_state, - enum global_mode global_old_state); void bgp_peer_gr_flags_update(struct peer *peer); const char *print_peer_gr_mode(enum peer_mode pr_mode); const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd); diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 97658d340b..5e6a62c9b9 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -511,6 +511,7 @@ int main(int argc, char **argv) /* BGP master init. */ bgp_master_init(frr_init(), buffer_size, addresses); + bm->startup_time = monotime(NULL); bm->port = bgp_port; if (bgp_port == 0) bgp_option_set(BGP_OPT_NO_LISTEN); @@ -518,6 +519,9 @@ int main(int argc, char **argv) bgp_option_set(BGP_OPT_NO_FIB); if (no_zebra_flag) bgp_option_set(BGP_OPT_NO_ZEBRA); + if (bgpd_di.graceful_restart) + SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART); + bgp_error_init(); /* Initializations. */ libagentx_init(); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 248d478fe1..945076709c 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -519,20 +519,17 @@ static int bgp_capability_restart(struct peer *peer, UNSET_FLAG(restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; - if (bgp_debug_neighbor_events(peer)) { - zlog_debug( - "%s Peer has%srestarted. Restart Time: %d, N-bit set: %s", - peer->host, - CHECK_FLAG(peer->cap, - PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) - ? " " - : " not ", - peer->v_gr_restart, - CHECK_FLAG(peer->cap, - PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) - ? "yes" - : "no"); - } + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP OPEN has GR capability, Restart time %d R-bit %s N-bit %s", + peer, peer->v_gr_restart, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) + ? "SET" + : "NOT-SET", + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) + ? "SET" + : "NOT-SET"); while (stream_get_getp(s) + 4 <= end) { afi_t afi; @@ -556,14 +553,12 @@ static int bgp_capability_restart(struct peer *peer, iana_safi2str(pkt_safi)); } else { if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s Address family %s is%spreserved", - peer->host, get_afi_safi_str(afi, safi, false), - CHECK_FLAG( - peer->af_cap[afi][safi], - PEER_CAP_RESTART_AF_PRESERVE_RCV) - ? " " - : " not "); + zlog_debug("%pBP F-bit %s for %s", peer, + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_PRESERVE_RCV) + ? "SET" + : "NOT-SET", + get_afi_safi_str(afi, safi, false)); SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV); @@ -1587,15 +1582,12 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, uint32_t restart_time; unsigned long capp = 0; unsigned long rcapp = 0; + struct bgp *bgp = peer->bgp; if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) return; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending helper Capability for Peer :%s :", - peer->host); - SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); capp = stream_get_endp(s); /* Set Capability Len Pointer */ @@ -1605,42 +1597,41 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, /* Set Restart Capability Len Pointer */ rcapp = stream_get_endp(s); stream_putc(s, 0); - restart_time = peer->bgp->restart_time; - if (peer->bgp->t_startup) { + restart_time = bgp->restart_time; + if (peer->bgp->t_startup || bgp_in_graceful_restart()) { SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending R-Bit for peer: %s", - peer->host); } - if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { SET_FLAG(restart_time, GRACEFUL_RESTART_N_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending N-Bit for peer: %s", - peer->host); } stream_putw(s, restart_time); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s: Sending GR Capability, Restart time %d R-bit %s, N-bit %s", + peer->host, bgp->restart_time, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV) + ? "SET" + : "NOT-SET", + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV) + ? "SET" + : "NOT-SET"); + /* Send address-family specific graceful-restart capability * only when GR config is present */ if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) { - if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD) - && BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] F bit Set"); - FOREACH_AFI_SAFI (afi, safi) { + bool f_bit = false; + if (!peer->afc[afi][safi]) continue; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Sending GR Capability for AFI :%d :, SAFI :%d:", - afi, safi); - /* Convert AFI, SAFI to values for * packet. */ @@ -1648,11 +1639,15 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, &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); + + f_bit = bgp_gr_is_forwarding_preserved(bgp); + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("... F-bit %s for %s", + f_bit ? "SET" : "NOT-SET", + get_afi_safi_str(afi, safi, false)); + + stream_putc(s, f_bit ? GRACEFUL_RESTART_F_BIT : 0); } } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 8a4453f124..4625f15778 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -696,10 +696,9 @@ void bgp_open_send(struct peer_connection *connection) bgp_packet_set_size(s); if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s sending OPEN, version %d, my as %u, holdtime %d, id %pI4", - peer->host, BGP_VERSION_4, local_as, send_holdtime, - &peer->local_id); + zlog_debug("%pBP fd %d sending OPEN, version %d, my as %u, holdtime %d, id %pI4", + peer, peer->connection->fd, BGP_VERSION_4, local_as, + send_holdtime, &peer->local_id); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ @@ -1296,7 +1295,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, stream_putc(s, 0); gr_restart_time = peer->bgp->restart_time; - if (peer->bgp->t_startup) { + if (peer->bgp->t_startup || bgp_in_graceful_restart()) { SET_FLAG(gr_restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); } @@ -1978,6 +1977,14 @@ static int bgp_open_receive(struct peer_connection *connection, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return BGP_Stop; + } else if (peer->as_type == AS_AUTO) { + if (remote_as == peer->bgp->as) { + peer->as = peer->local_as; + SET_FLAG(peer->as_type, AS_INTERNAL); + } else { + peer->as = remote_as; + SET_FLAG(peer->as_type, AS_EXTERNAL); + } } else if (peer->as_type == AS_INTERNAL) { if (remote_as != peer->bgp->as) { if (bgp_debug_neighbor_events(peer)) @@ -3438,7 +3445,7 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action, } len = *data; - if (data + len > end) { + if (data + len + 1 > end) { zlog_err("%pBP: Received invalid FQDN capability length (host name) %d", peer, hdr->length); return; @@ -3469,7 +3476,7 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action, /* domainname */ len = *data; - if (data + len > end) { + if (data + len + 1 > end) { zlog_err("%pBP: Received invalid FQDN capability length (domain name) %d", peer, len); return; @@ -3695,7 +3702,7 @@ static void bgp_dynamic_capability_software_version(uint8_t *pnt, int action, char soft_version[BGP_MAX_SOFT_VERSION + 1] = {}; if (action == CAPABILITY_ACTION_SET) { - if (data + len > end) { + if (data + len + 1 > end) { zlog_err("%pBP: Received invalid Software Version capability length %d", peer, len); return; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4dcb22234a..2a9fc6ce0d 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -851,8 +851,13 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, * with the * sticky flag. */ - if (newattr->sticky != existattr->sticky) { - if (newattr->sticky && !existattr->sticky) { + bool new_sticky = CHECK_FLAG(newattr->evpn_flags, + ATTR_EVPN_FLAG_STICKY); + bool exist_sticky = CHECK_FLAG(existattr->evpn_flags, + ATTR_EVPN_FLAG_STICKY); + + if (new_sticky != exist_sticky) { + if (new_sticky && !exist_sticky) { *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( @@ -861,7 +866,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, return 1; } - if (!newattr->sticky && existattr->sticky) { + if (!new_sticky && exist_sticky) { *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( @@ -3877,6 +3882,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) struct bgp_dest *dest; int cnt = 0; struct afi_safi_info *thread_info; + bool route_sync_pending = false; if (bgp->gr_info[afi][safi].t_route_select) { struct event *t = bgp->gr_info[afi][safi].t_route_select; @@ -3886,7 +3892,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) EVENT_OFF(bgp->gr_info[afi][safi].t_route_select); } - if (BGP_DEBUG(update, UPDATE_OUT)) { + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) { zlog_debug("%s: processing route for %s : cnt %d", __func__, get_afi_safi_str(afi, safi, false), bgp->gr_info[afi][safi].gr_deferred); @@ -3919,6 +3925,21 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) /* Send route processing complete message to RIB */ bgp_zebra_update(bgp, afi, safi, ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE); + bgp->gr_info[afi][safi].route_sync = true; + + /* If this instance is all done, check for GR completion overall */ + FOREACH_AFI_SAFI_NSF (afi, safi) { + if (bgp->gr_info[afi][safi].af_enabled && + !bgp->gr_info[afi][safi].route_sync) { + route_sync_pending = true; + break; + } + } + + if (!route_sync_pending) { + bgp->gr_route_sync_pending = false; + bgp_update_gr_completion(); + } return; } @@ -6333,7 +6354,8 @@ void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi) bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) { - if (peer->sort == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_CONFED || peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) return true; if (peer->sort == BGP_PEER_EBGP && @@ -6346,7 +6368,8 @@ bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) bool bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter) { - if (peer->sort == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_CONFED || peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) return true; if (peer->sort == BGP_PEER_EBGP diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 9b0ca72e4c..97ae92c899 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2322,7 +2322,7 @@ static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = { static void *route_aspath_exclude_compile(const char *arg) { struct aspath_exclude *ase; - struct aspath_exclude_list *ael; + struct as_list *aux_aslist; const char *str = arg; static const char asp_acl[] = "as-path-access-list"; @@ -2334,44 +2334,37 @@ static void *route_aspath_exclude_compile(const char *arg) while (*str == ' ') str++; ase->exclude_aspath_acl_name = XSTRDUP(MTYPE_TMP, str); - ase->exclude_aspath_acl = as_list_lookup(str); + aux_aslist = as_list_lookup(str); + if (!aux_aslist) + /* new orphan filter */ + as_exclude_set_orphan(ase); + else + as_list_list_add_head(&aux_aslist->exclude_rule, ase); + + ase->exclude_aspath_acl = aux_aslist; } else ase->aspath = aspath_str2aspath(str, bgp_get_asnotation(NULL)); - if (ase->exclude_aspath_acl) { - ael = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, - sizeof(struct aspath_exclude_list)); - ael->bp_as_excl = ase; - ael->next = ase->exclude_aspath_acl->exclude_list; - ase->exclude_aspath_acl->exclude_list = ael; - } - return ase; } static void route_aspath_exclude_free(void *rule) { struct aspath_exclude *ase = rule; - struct aspath_exclude_list *cur_ael = NULL; - struct aspath_exclude_list *prev_ael = NULL; + struct as_list *acl; + + /* manage references to that rule*/ + if (ase->exclude_aspath_acl) { + acl = ase->exclude_aspath_acl; + as_list_list_del(&acl->exclude_rule, ase); + } else { + /* no ref to acl, this aspath exclude is orphan */ + as_exclude_remove_orphan(ase); + } aspath_free(ase->aspath); if (ase->exclude_aspath_acl_name) XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name); - if (ase->exclude_aspath_acl) - cur_ael = ase->exclude_aspath_acl->exclude_list; - while (cur_ael) { - if (cur_ael->bp_as_excl == ase) { - if (prev_ael) - prev_ael->next = cur_ael->next; - else - ase->exclude_aspath_acl->exclude_list = NULL; - XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_ael); - break; - } - prev_ael = cur_ael; - cur_ael = cur_ael->next; - } XFREE(MTYPE_ROUTE_MAP_COMPILED, ase); } @@ -2406,16 +2399,10 @@ route_set_aspath_exclude(void *rule, const struct prefix *dummy, void *object) else if (ase->exclude_all) path->attr->aspath = aspath_filter_exclude_all(new_path); - else if (ase->exclude_aspath_acl_name) { - if (!ase->exclude_aspath_acl) - ase->exclude_aspath_acl = - as_list_lookup(ase->exclude_aspath_acl_name); - if (ase->exclude_aspath_acl) - path->attr->aspath = - aspath_filter_exclude_acl(new_path, - ase->exclude_aspath_acl); - } - + else if (ase->exclude_aspath_acl) + path->attr->aspath = + aspath_filter_exclude_acl(new_path, + ase->exclude_aspath_acl); return RMAP_OKAY; } diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 124e7a388b..b717793a45 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -343,7 +343,12 @@ static unsigned int updgrp_hash_key_make(const void *p) key = 0; - key = jhash_1word(peer->sort, key); /* EBGP or IBGP */ + /* `remote-as auto` technically uses identical peer->sort. + * After OPEN message is parsed, this is updated accordingly, but + * we need to call the peer_sort() here also to properly create + * separate subgroups. + */ + key = jhash_1word(peer_sort((struct peer *)peer), key); key = jhash_1word(peer->sub_sort, key); /* OAD */ key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key); key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index fbe1db9d2a..0ef1351835 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3019,6 +3019,98 @@ DEFUN (no_bgp_deterministic_med, return CMD_SUCCESS; } +static int bgp_inst_gr_config_vty(struct vty *vty, struct bgp *bgp, bool on, + bool disable) +{ + int ret = BGP_GR_FAILURE; + + /* + * Update the instance and all its peers, if appropriate. + * Then, inform zebra of BGP's GR capabilities, if needed. + */ + if (disable) + ret = bgp_gr_update_all(bgp, on ? GLOBAL_DISABLE_CMD + : NO_GLOBAL_DISABLE_CMD); + else + ret = bgp_gr_update_all(bgp, + on ? GLOBAL_GR_CMD : NO_GLOBAL_GR_CMD); + + VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, + ret); + return ret; +} + +static int bgp_global_gr_config_vty(struct vty *vty, bool on, bool disable) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + bool vrf_cfg = false; + int ret = BGP_GR_FAILURE; + + if (disable) { + if ((on && CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) || + (!on && !CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED))) + return CMD_SUCCESS; + } else { + if ((on && CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) || + (!on && !CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER))) + return CMD_SUCCESS; + } + + /* See if GR is set per-vrf and warn user to delete */ + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_CONFIGURED)) { + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + enum global_mode gr_mode = bgp_global_gr_mode_get(bgp); + + if (gr_mode != GLOBAL_HELPER) { + vty_out(vty, + "%% graceful-restart configuration found in %s, mode %d\n", + bgp->name_pretty, gr_mode); + vrf_cfg = true; + } + } + } + + if (vrf_cfg) { + vty_out(vty, + "%%Failed: global graceful-restart not permitted with per-vrf configuration\n"); + return CMD_WARNING; + } + + /* Set flag globally */ + if (on) { + if (disable) { + UNSET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + SET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + } else { + SET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + UNSET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + } + } else { + if (disable) + UNSET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + else + UNSET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + } + + /* Initiate processing for all BGP instances. */ + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + ret = bgp_inst_gr_config_vty(vty, bgp, on, disable); + if (ret != BGP_GR_SUCCESS) + vty_out(vty, + "%% Applying global graceful-restart %s config to vrf %s failed, error %d\n", + (disable) ? "disable" : "", + bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT + ? "Default" + : bgp->name, + ret); + } + + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); + return bgp_vty_return(vty, ret); +} + /* "bgp graceful-restart mode" configuration. */ DEFUN (bgp_graceful_restart, bgp_graceful_restart_cmd, @@ -3027,25 +3119,18 @@ DEFUN (bgp_graceful_restart, GR_CMD ) { - int ret = BGP_GR_FAILURE; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : START "); + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, true, false); + int ret = BGP_GR_FAILURE; VTY_DECLVAR_CONTEXT(bgp, bgp); - ret = bgp_gr_update_all(bgp, GLOBAL_GR_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, true, false); if (ret == BGP_GR_SUCCESS) { - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, - bgp->peer, - ret); vty_out(vty, "Graceful restart configuration changed, reset all peers to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3057,14 +3142,13 @@ DEFUN (no_bgp_graceful_restart, NO_GR_CMD ) { - VTY_DECLVAR_CONTEXT(bgp, bgp); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : START "); + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, false, false); + VTY_DECLVAR_CONTEXT(bgp, bgp); int ret = BGP_GR_FAILURE; - ret = bgp_gr_update_all(bgp, NO_GLOBAL_GR_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, false, false); if (ret == BGP_GR_SUCCESS) { VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, @@ -3073,9 +3157,6 @@ DEFUN (no_bgp_graceful_restart, "Graceful restart configuration changed, reset all peers to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3087,12 +3168,21 @@ DEFUN (bgp_graceful_restart_stalepath_time, "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t stalepath; stalepath = strtoul(argv[idx_number]->arg, NULL, 10); - bgp->stalepath_time = stalepath; + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + bm->stalepath_time = stalepath; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + bgp->stalepath_time = stalepath; + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->stalepath_time = stalepath; + } return CMD_SUCCESS; } @@ -3104,20 +3194,32 @@ DEFUN (bgp_graceful_restart_restart_time, "Set the time to wait to delete stale routes before a BGP open message is received\n" "Delay value (seconds)\n") { - 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); + if (vty->node == CONFIG_NODE) { + struct bgp *bgp; + bm->restart_time = restart; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + 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); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + 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; } @@ -3129,16 +3231,32 @@ DEFUN (bgp_graceful_restart_select_defer_time, "Set the time to defer the BGP route selection after restart\n" "Delay value (seconds, 0 - disable)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t defer_time; defer_time = strtoul(argv[idx_number]->arg, NULL, 10); - bgp->select_defer_time = defer_time; - if (defer_time == 0) - SET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); - else - UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + bm->select_defer_time = defer_time; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->select_defer_time = defer_time; + if (defer_time == 0) + SET_FLAG(bgp->flags, + BGP_FLAG_SELECT_DEFER_DISABLE); + else + UNSET_FLAG(bgp->flags, + BGP_FLAG_SELECT_DEFER_DISABLE); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->select_defer_time = defer_time; + if (defer_time == 0) + SET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + else + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } return CMD_SUCCESS; } @@ -3152,9 +3270,17 @@ DEFUN (no_bgp_graceful_restart_stalepath_time, "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; - bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + bm->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + } return CMD_SUCCESS; } @@ -3167,17 +3293,30 @@ DEFUN (no_bgp_graceful_restart_restart_time, "Set the time to wait to delete stale routes before a BGP open message is received\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); struct listnode *node, *nnode; struct peer *peer; - bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + if (vty->node == CONFIG_NODE) { + struct bgp *bgp; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) - bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, - CAPABILITY_CODE_RESTART, - CAPABILITY_ACTION_UNSET); + bm->restart_time = BGP_DEFAULT_RESTART_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + 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); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + 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; } @@ -3190,10 +3329,21 @@ DEFUN (no_bgp_graceful_restart_select_defer_time, "Set the time to defer the BGP route selection after restart\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; - bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; - UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + bm->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->select_defer_time = + BGP_DEFAULT_SELECT_DEFERRAL_TIME; + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } return CMD_SUCCESS; } @@ -3205,8 +3355,17 @@ DEFUN (bgp_graceful_restart_preserve_fw, "Graceful restart capability parameters\n" "Sets F-bit indication that fib is preserved while doing Graceful Restart\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); - SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + SET_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD); + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } return CMD_SUCCESS; } @@ -3218,8 +3377,17 @@ DEFUN (no_bgp_graceful_restart_preserve_fw, "Graceful restart capability parameters\n" "Unsets F-bit indication that fib is preserved while doing Graceful Restart\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); - UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + UNSET_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD); + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } return CMD_SUCCESS; } @@ -3271,21 +3439,17 @@ DEFUN (bgp_graceful_restart_disable, BGP_STR GR_DISABLE) { + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, true, true); + int ret = BGP_GR_FAILURE; struct listnode *node, *nnode; struct peer *peer; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_graceful_restart_disable_cmd : START "); - VTY_DECLVAR_CONTEXT(bgp, bgp); - ret = bgp_gr_update_all(bgp, GLOBAL_DISABLE_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, true, true); if (ret == BGP_GR_SUCCESS) { - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, - bgp->peer, - ret); vty_out(vty, "Graceful restart configuration changed, reset all peers to take effect\n"); @@ -3299,9 +3463,6 @@ DEFUN (bgp_graceful_restart_disable, } } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] bgp_graceful_restart_disable_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3313,27 +3474,18 @@ DEFUN (no_bgp_graceful_restart_disable, NO_GR_DISABLE ) { - VTY_DECLVAR_CONTEXT(bgp, bgp); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_graceful_restart_disable_cmd : START "); + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, false, true); + VTY_DECLVAR_CONTEXT(bgp, bgp); int ret = BGP_GR_FAILURE; - ret = bgp_gr_update_all(bgp, NO_GLOBAL_DISABLE_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, false, true); if (ret == BGP_GR_SUCCESS) { - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, - bgp->peer, - ret); vty_out(vty, "Graceful restart configuration changed, reset all peers to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_graceful_restart_disable_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3351,13 +3503,14 @@ DEFUN (bgp_neighbor_graceful_restart_set, VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } result = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD); if (result == BGP_GR_SUCCESS) { @@ -3367,15 +3520,7 @@ DEFUN (bgp_neighbor_graceful_restart_set, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : END "); - - if (ret != BGP_GR_SUCCESS) - vty_out(vty, - "As part of configuring graceful-restart, capability send to zebra failed\n"); - - return bgp_vty_return(vty, result); + return bgp_vty_return(vty, ret); } DEFUN (no_bgp_neighbor_graceful_restart, @@ -3396,10 +3541,11 @@ DEFUN (no_bgp_neighbor_graceful_restart, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : START "); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } result = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3409,14 +3555,6 @@ DEFUN (no_bgp_neighbor_graceful_restart, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : END "); - - if (ret != BGP_GR_SUCCESS) - vty_out(vty, - "As part of configuring graceful-restart, capability send to zebra failed\n"); - return bgp_vty_return(vty, result); } @@ -3434,15 +3572,14 @@ DEFUN (bgp_neighbor_graceful_restart_helper_set, VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); - if (!peer) return CMD_WARNING_CONFIG_FAILED; - + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3452,10 +3589,6 @@ DEFUN (bgp_neighbor_graceful_restart_helper_set, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3477,10 +3610,11 @@ DEFUN (no_bgp_neighbor_graceful_restart_helper, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : START "); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, NO_PEER_HELPER_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3490,10 +3624,6 @@ DEFUN (no_bgp_neighbor_graceful_restart_helper, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3511,29 +3641,24 @@ DEFUN (bgp_neighbor_graceful_restart_disable_set, VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_disable_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, PEER_DISABLE_CMD); if (ret == BGP_GR_SUCCESS) { - if (peer->bgp->t_startup) + if (peer->bgp->t_startup || bgp_in_graceful_restart()) bgp_peer_gr_flags_update(peer); VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR]bgp_neighbor_graceful_restart_disable_set_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3555,23 +3680,18 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : START "); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD); if (ret == BGP_GR_SUCCESS) { VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3586,9 +3706,10 @@ DEFPY (neighbor_graceful_shutdown, afi_t afi; safi_t safi; struct peer *peer; - VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; + VTY_DECLVAR_CONTEXT(bgp, bgp); + peer = peer_and_group_lookup_vty(vty, neighbor); if (!peer) return CMD_WARNING_CONFIG_FAILED; @@ -4741,7 +4862,7 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; as_t as; - int as_type = AS_SPECIFIED; + enum peer_asn_type as_type = AS_SPECIFIED; union sockunion su; if (as_str[0] == 'i') { @@ -4750,6 +4871,9 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, } else if (as_str[0] == 'e') { as = 0; as_type = AS_EXTERNAL; + } else if (as_str[0] == 'a') { + as = 0; + as_type = AS_AUTO; } else if (!asn_str2asn(as_str, &as)) as_type = AS_UNSPECIFIED; @@ -4855,13 +4979,14 @@ ALIAS(no_bgp_shutdown, no_bgp_shutdown_msg_cmd, DEFUN (neighbor_remote_as, neighbor_remote_as_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <ASNUM|internal|external>", + "neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <ASNUM|internal|external|auto>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_peer = 1; int idx_remote_as = 3; @@ -4916,7 +5041,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, { VTY_DECLVAR_CONTEXT(bgp, bgp); as_t as = 0; - int as_type = AS_UNSPECIFIED; + enum peer_asn_type as_type = AS_UNSPECIFIED; struct peer *peer; struct peer_group *group; int ret = 0; @@ -4933,6 +5058,8 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, as_type = AS_INTERNAL; } else if (as_str[0] == 'e') { as_type = AS_EXTERNAL; + } else if (as_str[0] == 'a') { + as_type = AS_AUTO; } else { /* Get AS number. */ if (asn_str2asn(as_str, &as)) @@ -5049,14 +5176,15 @@ DEFUN (neighbor_interface_config_v6only, DEFUN (neighbor_interface_config_remote_as, neighbor_interface_config_remote_as_cmd, - "neighbor WORD interface remote-as <ASNUM|internal|external>", + "neighbor WORD interface remote-as <ASNUM|internal|external|auto>", NEIGHBOR_STR "Interface name or neighbor tag\n" "Enable BGP on interface\n" "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_word = 1; int idx_remote_as = 4; @@ -5066,7 +5194,7 @@ DEFUN (neighbor_interface_config_remote_as, DEFUN (neighbor_interface_v6only_config_remote_as, neighbor_interface_v6only_config_remote_as_cmd, - "neighbor WORD interface v6only remote-as <ASNUM|internal|external>", + "neighbor WORD interface v6only remote-as <ASNUM|internal|external|auto>", NEIGHBOR_STR "Interface name or neighbor tag\n" "Enable BGP with v6 link-local only\n" @@ -5074,7 +5202,8 @@ DEFUN (neighbor_interface_v6only_config_remote_as, "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_word = 1; int idx_remote_as = 5; @@ -5111,14 +5240,15 @@ DEFUN (neighbor_peer_group, DEFUN (no_neighbor, no_neighbor_cmd, - "no neighbor <WORD|<A.B.C.D|X:X::X:X> [remote-as <(1-4294967295)|internal|external>]>", + "no neighbor <WORD|<A.B.C.D|X:X::X:X> [remote-as <(1-4294967295)|internal|external|auto>]>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_peer = 2; @@ -5189,7 +5319,7 @@ DEFUN (no_neighbor, DEFUN (no_neighbor_interface_config, no_neighbor_interface_config_cmd, - "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external>]", + "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external|auto>]", NO_STR NEIGHBOR_STR "Interface name\n" @@ -5200,7 +5330,8 @@ DEFUN (no_neighbor_interface_config, "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_word = 2; @@ -5257,14 +5388,15 @@ DEFUN (no_neighbor_peer_group, DEFUN (no_neighbor_interface_peer_group_remote_as, no_neighbor_interface_peer_group_remote_as_cmd, - "no neighbor WORD remote-as <ASNUM|internal|external>", + "no neighbor WORD remote-as <ASNUM|internal|external|auto>", NO_STR NEIGHBOR_STR "Interface name or neighbor tag\n" "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_word = 2; @@ -11661,10 +11793,9 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer, BGP_NOTIFY_CEASE_HARD_RESET) : ""); } else { - vty_out(vty, " %s (%s)\n", + vty_out(vty, " %s (%s)\n", peer_down_str[(int)peer->last_reset], - peer->soft_version ? peer->soft_version - : "n/a"); + peer->soft_version ? peer->soft_version : "n/a"); } } } @@ -11756,7 +11887,8 @@ static char *bgp_peer_description_stripped(char *desc, uint32_t size) /* Determine whether var peer should be filtered out of the summary. */ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, - struct peer *fpeer, int as_type, + struct peer *fpeer, + enum peer_asn_type as_type, as_t as) { @@ -11767,7 +11899,7 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, /* filter remote-as (internal|external) */ if (as_type != AS_UNSPECIFIED) { if (peer->as_type == AS_SPECIFIED) { - if (as_type == AS_INTERNAL) { + if (CHECK_FLAG(as_type, AS_INTERNAL)) { if (peer->as != peer->local_as) return true; } else if (peer->as == peer->local_as) @@ -11790,8 +11922,8 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, * whitespaces and the whole output will be tricky. */ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, - struct peer *fpeer, int as_type, as_t as, - uint16_t show_flags) + struct peer *fpeer, enum peer_asn_type as_type, + as_t as, uint16_t show_flags) { struct peer *peer; struct listnode *node, *nnode; @@ -12598,10 +12730,9 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, } static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, - safi_t safi, - const char *neighbor, - int as_type, as_t as, - uint16_t show_flags) + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, + as_t as, uint16_t show_flags) { struct listnode *node, *nnode; struct bgp *bgp; @@ -12643,8 +12774,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, } int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, const char *neighbor, int as_type, - as_t as, uint16_t show_flags) + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, as_t as, + uint16_t show_flags) { struct bgp *bgp; bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); @@ -12759,6 +12891,8 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd, as_type = AS_INTERNAL; else if (argv[idx + 1]->arg[0] == 'e') as_type = AS_EXTERNAL; + else if (argv[idx + 1]->arg[0] == 'a') + as_type = AS_AUTO; else if (!asn_str2asn(argv[idx + 1]->arg, &as)) { vty_out(vty, "%% Invalid neighbor remote-as value: %s\n", @@ -13882,9 +14016,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object_boolean_true_add(json_neigh, "localAsReplaceAs"); } else { - if ((p->as_type == AS_SPECIFIED) || - (p->as_type == AS_EXTERNAL) || - (p->as_type == AS_INTERNAL)) { + if (p->as_type == AS_SPECIFIED || + CHECK_FLAG(p->as_type, AS_AUTO) || + CHECK_FLAG(p->as_type, AS_EXTERNAL) || + CHECK_FLAG(p->as_type, AS_INTERNAL)) { vty_out(vty, "remote AS "); vty_out(vty, ASN_FORMAT(bgp->asnotation), &p->as); vty_out(vty, ", "); @@ -13903,7 +14038,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, : ""); } /* peer type internal or confed-internal */ - if ((p->as == p->local_as) || (p->as_type == AS_INTERNAL)) { + if ((p->as == p->local_as) || (CHECK_FLAG(p->as_type, AS_INTERNAL))) { if (use_json) { if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) json_object_boolean_true_add( @@ -16891,7 +17026,7 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group, &conf->as); vty_out(vty, "\n"); } - } else if (conf->as_type == AS_INTERNAL) { + } else if (CHECK_FLAG(conf->as_type, AS_INTERNAL)) { if (json) asn_asn2json(json, "remoteAs", group->bgp->as, group->bgp->asnotation); @@ -16903,7 +17038,8 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group, vty_out(vty, "\nBGP peer-group %s\n", group->name); } - if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) { + if ((group->bgp->as == conf->as) || + CHECK_FLAG(conf->as_type, AS_INTERNAL)) { if (json) json_object_string_add(json_peer_group, "type", "internal"); @@ -18405,6 +18541,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, } else if (peer->as_type == AS_EXTERNAL) { vty_out(vty, " remote-as external"); if_ras_printed = true; + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " remote-as auto"); + if_ras_printed = true; } vty_out(vty, "\n"); @@ -18427,6 +18566,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s remote-as external\n", addr); + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " neighbor %s remote-as auto\n", + addr); } } @@ -18456,6 +18598,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s remote-as external\n", addr); + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " neighbor %s remote-as auto\n", + addr); } } } @@ -19167,6 +19312,7 @@ int bgp_config_write(struct vty *vty) hook_call(bgp_snmp_traps_config_write, vty); + vty_out(vty, "!\n"); if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER) vty_out(vty, "bgp route-map delay-timer %u\n", bm->rmap_update_timer); @@ -19181,6 +19327,30 @@ int bgp_config_write(struct vty *vty) if (bm->wait_for_fib) vty_out(vty, "bgp suppress-fib-pending\n"); + if (bm->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + vty_out(vty, "bgp graceful-restart stalepath-time %u\n", + bm->stalepath_time); + + if (bm->restart_time != BGP_DEFAULT_RESTART_TIME) + vty_out(vty, "bgp graceful-restart restart-time %u\n", + bm->restart_time); + + if (bm->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) + vty_out(vty, "bgp graceful-restart select-defer-time %u\n", + bm->select_defer_time); + + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) + vty_out(vty, "bgp graceful-restart\n"); + else if (CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) + vty_out(vty, "bgp graceful-restart-disable\n"); + + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + vty_out(vty, "bgp graceful-restart preserve-fw-state\n"); + + if (bm->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + vty_out(vty, "bgp graceful-restart rib-stale-time %u\n", + bm->rib_stale_time); + if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)) vty_out(vty, "bgp graceful-shutdown\n"); @@ -19202,6 +19372,8 @@ int bgp_config_write(struct vty *vty) if (bm->outq_limit != BM_DEFAULT_Q_LIMIT) vty_out(vty, "bgp output-queue-limit %u\n", bm->outq_limit); + vty_out(vty, "!\n"); + /* BGP configuration. */ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { @@ -19443,15 +19615,21 @@ int bgp_config_write(struct vty *vty) " bgp long-lived-graceful-restart stale-time %u\n", bgp->llgr_stale_time); - /* BGP graceful-restart. */ - if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) - vty_out(vty, - " bgp graceful-restart stalepath-time %u\n", - bgp->stalepath_time); + /* BGP per-instance graceful-restart. */ + /* BGP-wide settings and per-instance settings are mutually + * exclusive. + */ + if (bm->stalepath_time == BGP_DEFAULT_STALEPATH_TIME) + if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + vty_out(vty, + " bgp graceful-restart stalepath-time %u\n", + bgp->stalepath_time); - if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) - vty_out(vty, " bgp graceful-restart restart-time %u\n", - bgp->restart_time); + if (bm->restart_time == BGP_DEFAULT_RESTART_TIME) + if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) + vty_out(vty, + " bgp graceful-restart restart-time %u\n", + bgp->restart_time); if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION) != SAVE_BGP_GRACEFUL_NOTIFICATION) @@ -19461,30 +19639,34 @@ int bgp_config_write(struct vty *vty) ? "" : "no "); - if (bgp->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) - vty_out(vty, - " bgp graceful-restart select-defer-time %u\n", - bgp->select_defer_time); + if (bm->select_defer_time == BGP_DEFAULT_SELECT_DEFERRAL_TIME) + if (bgp->select_defer_time != + BGP_DEFAULT_SELECT_DEFERRAL_TIME) + vty_out(vty, + " bgp graceful-restart select-defer-time %u\n", + bgp->select_defer_time); - if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR) - vty_out(vty, " bgp graceful-restart\n"); + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_CONFIGURED)) { + if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR) + vty_out(vty, " bgp graceful-restart\n"); - if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE) - vty_out(vty, " bgp graceful-restart-disable\n"); + if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE) + vty_out(vty, " bgp graceful-restart-disable\n"); + } - /* BGP graceful-restart Preserve State F bit. */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) - vty_out(vty, - " bgp graceful-restart preserve-fw-state\n"); + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) + vty_out(vty, + " bgp graceful-restart preserve-fw-state\n"); /* BGP TCP keepalive */ bgp_config_tcp_keepalive(vty, bgp); - /* Stale timer for RIB */ - if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) - vty_out(vty, - " bgp graceful-restart rib-stale-time %u\n", - bgp->rib_stale_time); + if (bm->rib_stale_time == BGP_DEFAULT_RIB_STALE_TIME) + if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + vty_out(vty, + " bgp graceful-restart rib-stale-time %u\n", + bgp->rib_stale_time); /* BGP bestpath method. */ if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE)) @@ -20143,6 +20325,26 @@ void bgp_vty_init(void) install_element(CONFIG_NODE, &bgp_graceful_shutdown_cmd); install_element(CONFIG_NODE, &no_bgp_graceful_shutdown_cmd); + /* BGP-wide graceful-restart commands. */ + install_element(CONFIG_NODE, &bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_disable_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_disable_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_stalepath_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_stalepath_time_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_restart_time_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_restart_time_cmd); + install_element(CONFIG_NODE, + &bgp_graceful_restart_select_defer_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_select_defer_time_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_preserve_fw_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_preserve_fw_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_rib_stale_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_rib_stale_time_cmd); + /* Dummy commands (Currently not supported) */ install_element(BGP_NODE, &no_synchronization_cmd); install_element(BGP_NODE, &no_auto_summary_cmd); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index addd71757d..f88f5c8125 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -60,8 +60,6 @@ struct bgp; #define VTY_BGP_GR_ROUTER_DETECT(_bgp, _peer, _peer_list) \ do { \ - if (_peer->bgp->t_startup) \ - bgp_peer_gr_flags_update(_peer); \ for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ if (CHECK_FLAG(peer_loop->flags, \ PEER_FLAG_GRACEFUL_RESTART)) \ @@ -84,30 +82,27 @@ struct bgp; } \ } while (0) -#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \ - _bgp, _peer_list, _ret) \ - do { \ - struct peer *peer_loop; \ - bool gr_router_detected = false; \ - struct listnode *node = {0}; \ - struct listnode *nnode = {0}; \ - for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ - if (peer_loop->bgp->t_startup) \ - bgp_peer_gr_flags_update(peer_loop); \ - if (CHECK_FLAG(peer_loop->flags, \ - PEER_FLAG_GRACEFUL_RESTART)) \ - gr_router_detected = true; \ - } \ - if (gr_router_detected \ - && _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \ - if (bgp_zebra_send_capabilities(_bgp, false)) \ - _ret = BGP_ERR_INVALID_VALUE; \ - } else if (!gr_router_detected \ - && _bgp->present_zebra_gr_state \ - == ZEBRA_GR_ENABLE) { \ - if (bgp_zebra_send_capabilities(_bgp, true)) \ - _ret = BGP_ERR_INVALID_VALUE; \ - } \ +#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(_bgp, \ + _peer_list, _ret) \ + do { \ + struct peer *peer_loop; \ + bool gr_router_detected = false; \ + struct listnode *node = { 0 }; \ + struct listnode *nnode = { 0 }; \ + for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ + if (CHECK_FLAG(peer_loop->flags, \ + PEER_FLAG_GRACEFUL_RESTART)) \ + gr_router_detected = true; \ + } \ + if (gr_router_detected && \ + _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \ + if (bgp_zebra_send_capabilities(_bgp, false)) \ + _ret = BGP_ERR_INVALID_VALUE; \ + } else if (!gr_router_detected && \ + _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \ + if (bgp_zebra_send_capabilities(_bgp, true)) \ + _ret = BGP_ERR_INVALID_VALUE; \ + } \ } while (0) @@ -166,8 +161,9 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty, int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv, int argc, struct bgp **bgp, bool use_json); extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, const char *neighbor, int as_type, - as_t as, uint16_t show_flags); + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, as_t as, + uint16_t show_flags); extern bool peergroup_flag_check(struct peer *peer, uint64_t flag); extern bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint64_t flag); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 4d18078a43..72620de7d9 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1331,10 +1331,7 @@ static void bgp_zebra_announce_parse_nexthop( &nh_weight)) continue; } - if (CHECK_FLAG(info->flags, BGP_PATH_SELECTED)) - api_nh = &api->nexthops[*valid_nh_count]; - else - api_nh = &api->backup_nexthops[*valid_nh_count]; + api_nh = &api->nexthops[*valid_nh_count]; api_nh->srte_color = bgp_attr_get_color(info->attr); @@ -1559,7 +1556,6 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, struct peer *peer; uint32_t metric; route_tag_t tag; - bool is_add; uint32_t nhg_id = 0; struct bgp_table *table = bgp_dest_table(dest); const struct prefix *p = bgp_dest_get_prefix(dest); @@ -1613,9 +1609,7 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, table->afi, table->safi, &nhg_id, &metric, &tag, &allow_recursion); - is_add = (valid_nh_count || nhg_id) ? true : false; - - if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { + if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { struct bgp_zebra_opaque bzo = {}; const char *reason = bgp_path_selection_reason2str(dest->reason); @@ -1671,18 +1665,17 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, } if (bgp_debug_zebra(p)) { - zlog_debug("Tx route %s %s %pFX metric %u tag %" ROUTE_TAG_PRI + zlog_debug("Tx route add %s (table id %u) %pFX metric %u tag %" ROUTE_TAG_PRI " count %d nhg %d", - is_add ? "add" : "delete", bgp->name_pretty, - &api.prefix, api.metric, api.tag, api.nexthop_num, - nhg_id); + bgp->name_pretty, api.tableid, &api.prefix, + api.metric, api.tag, api.nexthop_num, nhg_id); bgp_debug_zebra_nh(&api); zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)", __func__, p, (allow_recursion ? "" : "NOT ")); } - return zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, - zclient, &api); + + return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); } @@ -1764,8 +1757,8 @@ enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest, } if (bgp_debug_zebra(p)) - zlog_debug("Tx route delete %s %pFX", bgp->name_pretty, - &api.prefix); + zlog_debug("Tx route delete %s (table id %u) %pFX", + bgp->name_pretty, api.tableid, &api.prefix); return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); } @@ -1794,6 +1787,8 @@ static void bgp_handle_route_announcements_to_zebra(struct event *e) bool install; while (count < ZEBRA_ANNOUNCEMENTS_LIMIT) { + is_evpn = false; + dest = zebra_announce_pop(&bm->zebra_announce_head); if (!dest) @@ -3980,6 +3975,11 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) return BGP_GR_FAILURE; } + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s(%d): Sending GR capability %s to zebra", + bgp->name_pretty, bgp->vrf_id, + disable ? "disabled" : "enabled"); + /* Check if capability is already sent. If the flag force is set * send the capability since this can be initial bgp configuration */ @@ -3995,8 +3995,8 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api) == ZCLIENT_SEND_FAILURE) { - zlog_err("%s: %s error sending capability", __func__, - bgp->name_pretty); + zlog_err("%s(%d): Error sending GR capability to zebra", + bgp->name_pretty, bgp->vrf_id); ret = BGP_GR_FAILURE; } else { if (disable) @@ -4004,9 +4004,6 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) else bgp->present_zebra_gr_state = ZEBRA_GR_ENABLE; - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: %s send capabilty success", __func__, - bgp->name_pretty); ret = BGP_GR_SUCCESS; } return ret; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 869d2b4552..3810413adc 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1074,10 +1074,10 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer) /* Peer-group */ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (peer->as_type == AS_INTERNAL) + if (CHECK_FLAG(peer->as_type, AS_INTERNAL)) return BGP_PEER_IBGP; - else if (peer->as_type == AS_EXTERNAL) + if (CHECK_FLAG(peer->as_type, AS_EXTERNAL)) return BGP_PEER_EBGP; else if (peer->as_type == AS_SPECIFIED && peer->as) { @@ -1132,17 +1132,20 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer) return BGP_PEER_IBGP; else return BGP_PEER_EBGP; - } else if (peer->group->conf->as_type - == AS_INTERNAL) + } else if (CHECK_FLAG(peer->group->conf->as_type, + AS_INTERNAL)) return BGP_PEER_IBGP; else return BGP_PEER_EBGP; } /* no AS information anywhere, let caller know */ return BGP_PEER_UNSPECIFIED; - } else if (peer->as_type != AS_SPECIFIED) - return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP - : BGP_PEER_EBGP); + } else if (peer->as_type != AS_SPECIFIED) { + if (CHECK_FLAG(peer->as_type, AS_INTERNAL)) + return BGP_PEER_IBGP; + else if (CHECK_FLAG(peer->as_type, AS_EXTERNAL)) + return BGP_PEER_EBGP; + } return (local_as == 0 ? BGP_PEER_INTERNAL : local_as == peer->as ? BGP_PEER_IBGP @@ -1391,9 +1394,31 @@ int bgp_global_gr_init(struct bgp *bgp) memcpy(bgp->GLOBAL_GR_FSM, local_GLOBAL_GR_FSM, sizeof(local_GLOBAL_GR_FSM)); - bgp->global_gr_present_state = GLOBAL_HELPER; + /* Inherit any BGP-wide configuration. */ + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) + bgp->global_gr_present_state = GLOBAL_GR; + else if (CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) + bgp->global_gr_present_state = GLOBAL_DISABLE; + else + bgp->global_gr_present_state = GLOBAL_HELPER; + + if (bm->restart_time != BGP_DEFAULT_RESTART_TIME) + bgp->restart_time = bm->restart_time; + if (bm->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + bgp->stalepath_time = bm->stalepath_time; + if (bm->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) + bgp->select_defer_time = bm->select_defer_time; + if (bm->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + bgp->rib_stale_time = bm->rib_stale_time; + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE; + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s: Global GR state is %s", bgp->name_pretty, + print_global_gr_mode(bgp->global_gr_present_state)); + return BGP_GR_SUCCESS; } @@ -1453,9 +1478,7 @@ int bgp_peer_gr_init(struct peer *peer) { PEER_HELPER, bgp_peer_gr_action }, { PEER_GLOBAL_INHERIT, NULL } } }; - memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM, - sizeof(local_Peer_GR_FSM)); - peer->peer_gr_present_state = PEER_GLOBAL_INHERIT; + memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM, sizeof(local_Peer_GR_FSM)); bgp_peer_move_to_gr_mode(peer, PEER_GLOBAL_INHERIT); return BGP_GR_SUCCESS; @@ -1929,7 +1952,7 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp) */ struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, struct peer_group *group, + enum peer_asn_type as_type, struct peer_group *group, bool config_node, const char *as_str) { int active; @@ -2061,7 +2084,7 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi) } /* Change peer's AS number. */ -void peer_as_change(struct peer *peer, as_t as, int as_specified, +void peer_as_change(struct peer *peer, as_t as, enum peer_asn_type as_type, const char *as_str) { enum bgp_peer_sort origtype, newtype; @@ -2077,13 +2100,13 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, } origtype = peer_sort_lookup(peer); peer->as = as; - if (as_specified == AS_SPECIFIED && as_str) { + if (as_type == AS_SPECIFIED && as_str) { if (peer->as_pretty) XFREE(MTYPE_BGP_NAME, peer->as_pretty); peer->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); } else if (peer->as_type == AS_UNSPECIFIED && peer->as_pretty) XFREE(MTYPE_BGP_NAME, peer->as_pretty); - peer->as_type = as_specified; + peer->as_type = as_type; if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION) && !bgp_confederation_peers_check(peer->bgp, as) @@ -2140,7 +2163,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, /* If peer does not exist, create new one. If peer already exists, set AS number to the peer. */ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, - as_t *as, int as_type, const char *as_str) + as_t *as, enum peer_asn_type as_type, const char *as_str) { struct peer *peer; as_t local_as; @@ -2181,10 +2204,10 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, } } else { /* internal/external used, compare as-types */ - if (((peer_sort_type == BGP_PEER_IBGP) - && (as_type != AS_INTERNAL)) - || ((peer_sort_type == BGP_PEER_EBGP) - && (as_type != AS_EXTERNAL))) { + if (((peer_sort_type == BGP_PEER_IBGP) && + !CHECK_FLAG(as_type, AS_INTERNAL)) || + ((peer_sort_type == BGP_PEER_EBGP) && + !CHECK_FLAG(as_type, AS_EXTERNAL))) { *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } @@ -3005,7 +3028,7 @@ static void peer_group2peer_config_copy(struct peer_group *group, /* Peer group's remote AS configuration. */ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as, - int as_type, const char *as_str) + enum peer_asn_type as_type, const char *as_str) { struct peer_group *group; struct peer *peer; @@ -3875,6 +3898,9 @@ void bgp_instance_down(struct bgp *bgp) struct listnode *node; struct listnode *next; + /* Cleanup evpn instance state */ + bgp_evpn_instance_down(bgp); + /* Stop timers. */ if (bgp->t_rmap_def_originate_eval) EVENT_OFF(bgp->t_rmap_def_originate_eval); @@ -4829,6 +4855,8 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg) /* iterate through peers of BGP instance */ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_USER_SHUTDOWN; + /* continue, if peer is already in administrative shutdown. */ if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) continue; @@ -4883,8 +4911,10 @@ void bgp_shutdown_disable(struct bgp *bgp) /* clear the BGP instances shutdown flag */ UNSET_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN); - for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { bgp_timer_set(peer->connection); + peer->last_reset = PEER_DOWN_WAITING_OPEN; + } } /* Change specified peer flag. */ @@ -4956,6 +4986,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set) bgp_zebra_terminate_radv(peer->bgp, peer); } + if (flag == PEER_FLAG_SHUTDOWN) + peer->last_reset = set ? PEER_DOWN_USER_SHUTDOWN + : PEER_DOWN_WAITING_OPEN; + /* Execute flag action on peer. */ if (action.type == peer_change_reset) peer_flag_modify_action(peer, flag); @@ -4991,6 +5025,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set) set ? bgp_zebra_initiate_radv(member->bgp, member) : bgp_zebra_terminate_radv(member->bgp, member); + if (flag == PEER_FLAG_SHUTDOWN) + member->last_reset = set ? PEER_DOWN_USER_SHUTDOWN + : PEER_DOWN_WAITING_OPEN; + /* Execute flag action on peer-group member. */ if (action.type == peer_change_reset) peer_flag_modify_action(member, flag); @@ -8390,6 +8428,10 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, bm->t_bgp_sync_label_manager = NULL; bm->t_bgp_start_label_manager = NULL; bm->t_bgp_zebra_route = NULL; + bm->restart_time = BGP_DEFAULT_RESTART_TIME; + bm->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + bm->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + bm->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME; bgp_mac_init(); /* init the rd id space. diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 1f8cc53349..95ddba4cdd 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -56,10 +56,12 @@ struct bgp_pbr_config; * behavior * in the system. */ -enum { AS_UNSPECIFIED = 0, - AS_SPECIFIED, - AS_INTERNAL, - AS_EXTERNAL, +enum peer_asn_type { + AS_UNSPECIFIED = 1, + AS_SPECIFIED = 2, + AS_INTERNAL = 4, + AS_EXTERNAL = 8, + AS_AUTO = 16, }; /* Zebra Gracaful Restart states */ @@ -163,6 +165,23 @@ struct bgp_master { uint32_t flags; #define BM_FLAG_GRACEFUL_SHUTDOWN (1 << 0) #define BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA (1 << 1) +#define BM_FLAG_MAINTENANCE_MODE (1 << 2) +#define BM_FLAG_GR_RESTARTER (1 << 3) +#define BM_FLAG_GR_DISABLED (1 << 4) +#define BM_FLAG_GR_PRESERVE_FWD (1 << 5) +#define BM_FLAG_GRACEFUL_RESTART (1 << 6) +#define BM_FLAG_GR_COMPLETE (1 << 7) + +#define BM_FLAG_GR_CONFIGURED (BM_FLAG_GR_RESTARTER | BM_FLAG_GR_DISABLED) + + /* BGP-wide graceful restart config params */ + uint32_t restart_time; + uint32_t stalepath_time; + uint32_t select_defer_time; + uint32_t rib_stale_time; + + time_t startup_time; + time_t gr_completion_time; bool terminating; /* global flag that sigint terminate seen */ @@ -293,9 +312,9 @@ struct graceful_restart_info { /* Best route select */ struct event *t_route_select; /* AFI, SAFI enabled */ - bool af_enabled[AFI_MAX][SAFI_MAX]; + bool af_enabled; /* Route update completed */ - bool route_sync[AFI_MAX][SAFI_MAX]; + bool route_sync; }; enum global_mode { @@ -547,6 +566,9 @@ struct bgp { */ enum zebra_gr_mode present_zebra_gr_state; + /* Is deferred path selection still not complete? */ + bool gr_route_sync_pending; + /* BGP Per AF flags */ uint16_t af_flags[AFI_MAX][SAFI_MAX]; #define BGP_CONFIG_DAMPENING (1 << 0) @@ -1226,7 +1248,7 @@ struct peer { struct peer_af *peer_af_array[BGP_AF_MAX]; /* Peer's remote AS number. */ - int as_type; + enum peer_asn_type as_type; as_t as; /* for vty as format */ char *as_pretty; @@ -2261,8 +2283,9 @@ extern bool peer_afc_advertised(struct peer *peer); extern void bgp_recalculate_all_bestpaths(struct bgp *bgp); extern struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, struct peer_group *group, - bool config_node, const char *as_str); + enum peer_asn_type as_type, + struct peer_group *group, bool config_node, + const char *as_str); extern struct peer *peer_create_accept(struct bgp *); extern void peer_xfer_config(struct peer *dst, struct peer *src); extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json, @@ -2335,13 +2358,13 @@ extern void bgp_listen_limit_unset(struct bgp *bgp); extern bool bgp_update_delay_active(struct bgp *); extern bool bgp_update_delay_configured(struct bgp *); extern bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi); -extern void peer_as_change(struct peer *peer, as_t as, int as_type, - const char *as_str); +extern void peer_as_change(struct peer *peer, as_t as, + enum peer_asn_type as_type, const char *as_str); extern int peer_remote_as(struct bgp *bgp, union sockunion *su, - const char *conf_if, as_t *as, int as_type, - const char *as_str); + const char *conf_if, as_t *as, + enum peer_asn_type as_type, const char *as_str); extern int peer_group_remote_as(struct bgp *bgp, const char *peer_str, as_t *as, - int as_type, const char *as_str); + enum peer_asn_type as_type, const char *as_str); extern int peer_delete(struct peer *peer); extern void peer_notify_unconfig(struct peer *peer); extern int peer_group_delete(struct peer_group *); @@ -2742,6 +2765,59 @@ static inline bool bgp_in_graceful_shutdown(struct bgp *bgp) !!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)); } +static inline bool bgp_in_graceful_restart(void) +{ + /* True if BGP has (re)started gracefully (based on flags + * noted at startup) and GR is not complete. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)); +} + +static inline bool bgp_is_graceful_restart_complete(void) +{ + /* True if BGP has (re)started gracefully (based on flags + * noted at startup) and GR is marked as complete. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) && + CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)); +} + +static inline void bgp_update_gr_completion(void) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + + /* + * Check and mark GR complete. This is done when deferred + * path selection has been completed for all instances and + * route-advertisement/EOR and route-sync with zebra has + * been invoked. + */ + if (!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)) + return; + + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (bgp->gr_route_sync_pending) + return; + } + + SET_FLAG(bm->flags, BM_FLAG_GR_COMPLETE); + bm->gr_completion_time = monotime(NULL); +} + +static inline bool bgp_gr_is_forwarding_preserved(struct bgp *bgp) +{ + /* + * Is forwarding state preserved? Based either on config + * or if BGP restarted gracefully. + * TBD: Additional AFI/SAFI based checks etc. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)); +} + /* For benefit of rfapi */ extern struct peer *peer_new(struct bgp *bgp); diff --git a/debian/control b/debian/control index 12b80a77f3..4a02a36b71 100644 --- a/debian/control +++ b/debian/control @@ -33,7 +33,11 @@ Build-Depends: bison, python3-sphinx:native, texinfo (>= 4.7), lua5.3 <pkg.frr.lua>, - liblua5.3-dev <pkg.frr.lua> + liblua5.3-dev <pkg.frr.lua>, + libgrpc-dev (>=1.16.1) <pkg.frr.grpc>, + libgrpc++-dev (>=1.16.1) <pkg.frr.grpc>, + protobuf-compiler (>=3.6.1) <pkg.frr.grpc>, + protobuf-compiler-grpc (>=1.16.1) <pkg.frr.grpc> Standards-Version: 4.5.0.3 Homepage: https://www.frrouting.org/ Vcs-Browser: https://github.com/FRRouting/frr/tree/debian/master @@ -136,3 +140,13 @@ Description: FRRouting suite - Python tools . Without this package installed, "reload" (as a systemd or init script invocation) will not work for the FRR daemons. + +Package: frr-grpc +Architecture: linux-any +Depends: frr (= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} +Description: FRRouting suite - GRPC interface + This provides the GRPC interface to the daemons. +Build-Profiles: <pkg.frr.grpc> + diff --git a/debian/copyright b/debian/copyright index edd73020bd..e1a944b338 100644 --- a/debian/copyright +++ b/debian/copyright @@ -4,6 +4,13 @@ Upstream-Contact: maintainers@frrouting.org, security@frrouting.org Source: https://www.frrouting.org/ Files: * +Comment: Note: GPL Versions of FRR binaries + If GRPC module is installed then please be aware that the + combination of the GRPC (licensed under Apache License) and + FRR (Licensed under GPLv2+) will force the resulting grpc + modules and related binaries to GPLv3 + Impacted binary files: frr/libfrrgrpc_pb.* frr/modules/grpc.so + FRR built or used without GRPC is not impacted Copyright: 1996-2003 by the original Zebra authors: Kunihiro Ishiguro <kunihiro@zebra.org> Toshiaki Takada <takada@zebra.org> @@ -377,6 +384,24 @@ License: LGPL-2.1+ License version 2.1 can be found in the file `/usr/share/common-licenses/LGPL-2.1'. +License: GPL-3 + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL-3'. + License: BSD-0-clause Redistribution and use in source and binary forms, with or without modification, are permitted. diff --git a/debian/frr-grpc.install b/debian/frr-grpc.install new file mode 100644 index 0000000000..d006439e6f --- /dev/null +++ b/debian/frr-grpc.install @@ -0,0 +1,2 @@ +usr/lib/*/frr/libfrrgrpc_pb.* +usr/lib/*/frr/modules/grpc.so diff --git a/debian/rules b/debian/rules index 0f84145718..ec8f92f755 100755 --- a/debian/rules +++ b/debian/rules @@ -33,6 +33,12 @@ else CONF_PIM6=--disable-pim6d endif +ifeq ($(filter pkg.frr.grpc,$(DEB_BUILD_PROFILES)),) + CONF_GRPC=--disable-grpc +else + CONF_GRPC=--enable-grpc +endif + export PYTHON=python3 %: @@ -51,6 +57,7 @@ override_dh_auto_configure: $(CONF_RPKI) \ $(CONF_LUA) \ $(CONF_PIM6) \ + $(CONF_GRPC) \ --with-libpam \ --enable-doc \ --enable-doc-html \ diff --git a/doc/developer/conf.py b/doc/developer/conf.py index 495c604ae0..6a3ffe1638 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -18,6 +18,7 @@ import re import pygments from sphinx.highlighting import lexers from sphinx.util import logging + logger = logging.getLogger(__name__) # If extensions (or modules to document with autodoc) are in another directory, @@ -53,18 +54,18 @@ source_suffix = ".rst" master_doc = "index" # General information about the project. -project = u"FRR" -copyright = u"2017, FRR" -author = u"FRR authors" +project = "FRR" +copyright = "2017, FRR" +author = "FRR authors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The short X.Y version. -version = u"?.?" +version = "?.?" # The full version, including alpha/beta/rc tags. -release = u"?.?-?" +release = "?.?-?" # ----------------------------------------------------------------------------- @@ -287,7 +288,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "FRR.tex", u"FRR Developer's Manual", u"FRR", "manual"), + (master_doc, "FRR.tex", "FRR Developer's Manual", "FRR", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -315,7 +316,7 @@ latex_logo = "../figures/frr-logo-medium.png" # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "frr", u"FRR Developer's Manual", [author], 1)] +man_pages = [(master_doc, "frr", "FRR Developer's Manual", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -330,7 +331,7 @@ texinfo_documents = [ ( master_doc, "frr", - u"FRR Developer's Manual", + "FRR Developer's Manual", author, "FRR", "One line description of project.", @@ -358,27 +359,29 @@ texinfo_documents = [ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() -frrfmt_re = re.compile(r'^\s*%(?P<spec>[^\s]+)\s+\((?P<types>.*)\)\s*$') +frrfmt_re = re.compile(r"^\s*%(?P<spec>[^\s]+)\s+\((?P<types>.*)\)\s*$") + def parse_frrfmt(env, text, node): from sphinx import addnodes m = frrfmt_re.match(text) if not m: - logger.warning('could not parse frrfmt:: %r' % (text), location=node) + logger.warning("could not parse frrfmt:: %r" % (text), location=node) node += addnodes.desc_name(text, text) return text - spec, types = m.group('spec'), m.group('types') + spec, types = m.group("spec"), m.group("types") - node += addnodes.desc_sig_operator('%', '%') - node += addnodes.desc_name(spec + ' ', spec + ' ') + node += addnodes.desc_sig_operator("%", "%") + node += addnodes.desc_name(spec + " ", spec + " ") plist = addnodes.desc_parameterlist() - for typ in types.split(','): + for typ in types.split(","): typ = typ.strip() plist += addnodes.desc_parameter(typ, typ) node += plist - return '%' + spec + return "%" + spec + # custom extensions here def setup(app): diff --git a/doc/developer/ospf-ls-retrans.rst b/doc/developer/ospf-ls-retrans.rst new file mode 100644 index 0000000000..230d7a1c5d --- /dev/null +++ b/doc/developer/ospf-ls-retrans.rst @@ -0,0 +1,69 @@ +OSPF Neighor Retransmission List +================================ + +Overview +-------- + +OSPF neighbor link-state retransmission lists are implemented using +both a sparse Link State Database (LSDB) and a doubly-linked list. +Rather than previous per-neighbor periodic timer, a per-neighbor +timer is set to the expiration time of the next scheduled LSA +retransmission. + +Sparse Link State Database (LSDB) +--------------------------------- + +When an explicit or implied acknowledgment is recieved from a +neighbor in 2-way state or higher, the acknowledge LSA must be +removed from the neighbor's link state retransmission list. In order +to do this efficiently, a sparse LSDB is utilized. LSDB entries also +include a pointer to the corresponding list entry so that it may be +efficiently removed from the doubly-linked list. + +The sparse LSDB is implemented using the OSPF functions is +ospf_lsdb.[c,h]. OSPF LSDBs are implemented as an array of route +tables (lib/table.[c,h]). What is unique of the LS Retransmission +list LSDB is that each entry also has a pointer into the doubly-linked +list to facilitate fast deletions. + +Doubly-Linked List +------------------ + +In addition to the sparse LSDB, LSAs on a neighbor LS retransmission +list are also maintained in a linked-list order chronologically +with the LSA scheduled for the next retransmission at the head of +the list. + +The doubly-link list is implemented using the dlist macros in +lib/typesafe.h. + +LSA LS Retransmission List Addition +------------------------------------ + +When an LSA is added to a neighbor retransmission list, it is +added to both the sparse LSDB and the doubly-linked list with a pointer +in the LSDB route-table node to the list entry. The LSA is added to +the tail of the list with the expiration time set to the current time +with the retransmission interval added. If the neighbor retransmission +timer is not set, it is set to expire at the time of the newly added +LSA. + +LSA LS Retransmission List Deletion +----------------------------------- + +When an LSA is deleted from a neighbor retransmission list, it is +deleted from eboth the sparse LSDB and the doubly-linked list with the +pointer the LSDB route-table node used to efficiently delete the entry +from the list. If the LSA at the head of the list was removed, then +the neighbor retransmission timer is reset to the expiration of the +LSA at the head of the list or canceled if the list is empty. + +Neighbor LS Retransmission List Expiration +------------------------------------------ + +When the neighbor retransmission timer expires, the LSA at the top of +list and any in a configured window (e.g., 50 milliseconds) are +retransmitted. The LSAs that have been retransmitted are removed from +the list and readded to the tail of the list with a new expiration time +which is retransmit-interval seconds in the future. + diff --git a/doc/developer/ospf.rst b/doc/developer/ospf.rst index 837a0bd185..da4802533c 100644 --- a/doc/developer/ospf.rst +++ b/doc/developer/ospf.rst @@ -8,6 +8,7 @@ OSPFD :maxdepth: 2 ospf-api + ospf-ls-retrans ospf-sr cspf diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst index c2c3b7e7e1..4109057ee5 100644 --- a/doc/developer/packaging-debian.rst +++ b/doc/developer/packaging-debian.rst @@ -68,6 +68,8 @@ buster.) +----------------+-------------------+-----------------------------------------+ | pkg.frr.pim6d | pkg.frr.nopim6d | builds pim6d (default enabled) | +----------------+-------------------+-----------------------------------------+ + | pkg.frr.grpc | pkg.frr.nogrpc | builds with grpc support (default: no) | + +----------------+-------------------+-----------------------------------------+ * the ``-uc -us`` options to disable signing the packages with your GPG key diff --git a/doc/developer/packaging-redhat.rst b/doc/developer/packaging-redhat.rst index d88f449926..8037873461 100644 --- a/doc/developer/packaging-redhat.rst +++ b/doc/developer/packaging-redhat.rst @@ -67,24 +67,27 @@ Tested on CentOS 6, CentOS 7, CentOS 8 and Fedora 24. ############### FRRouting (FRR) configure options ################# # with-feature options - %{!?with_pam: %global with_pam 0 } - %{!?with_ospfclient: %global with_ospfclient 1 } - %{!?with_ospfapi: %global with_ospfapi 1 } - %{!?with_irdp: %global with_irdp 1 } - %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_babeld: %global with_babeld 1 } + %{!?with_bfdd: %global with_bfdd 1 } + %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_cumulus: %global with_cumulus 0 } + %{!?with_eigrpd: %global with_eigrpd 1 } + %{!?with_fpm: %global with_fpm 1 } + %{!?with_mgmtd_test_be_client: %global with_mgmtd_test_be_client 0 } %{!?with_ldpd: %global with_ldpd 1 } - %{!?with_nhrpd: %global with_nhrpd 1 } - %{!?with_eigrp: %global with_eigrpd 1 } - %{!?with_shared: %global with_shared 1 } %{!?with_multipath: %global with_multipath 256 } - %{!?frr_user: %global frr_user frr } - %{!?vty_group: %global vty_group frrvty } - %{!?with_fpm: %global with_fpm 0 } - %{!?with_watchfrr: %global with_watchfrr 1 } - %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_nhrpd: %global with_nhrpd 1 } + %{!?with_ospfapi: %global with_ospfapi 1 } + %{!?with_ospfclient: %global with_ospfclient 1 } + %{!?with_pam: %global with_pam 0 } + %{!?with_pbrd: %global with_pbrd 1 } %{!?with_pimd: %global with_pimd 1 } %{!?with_pim6d: %global with_pim6d 1 } - %{!?with_rpki: %global with_rpki 0 } + %{!?with_vrrpd: %global with_vrrpd 1 } + %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_watchfrr: %global with_watchfrr 1 } + %{!?with_pathd: %global with_pathd 1 } + %{!?with_grpc: %global with_grpc 0 } 8. Build the RPM:: diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index f720f6279e..166c96da33 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -1306,6 +1306,16 @@ MemorySanitizer to ``configure``. +UndefinedSanitizer + Similar to AddressSanitizer, this tool provides runtime instrumentation for + detecting use of undefined behavior in C. Testing your own code with this + tool before submission is encouraged. You can enable it by passing:: + + --enable-undefined-sanitizer + + to ``configure``. If you run FRR with this you will probably also have + to set ``sudo sysctl vm.mmap_rnd_bits=28`` + All of the above tools are available in the Clang/LLVM toolchain since 3.4. AddressSanitizer and ThreadSanitizer are available in recent versions of GCC, but are no longer actively maintained. MemorySanitizer is not available in GCC. diff --git a/doc/user/overview.rst b/doc/user/about.rst index 2ef88acd7a..7d30a86154 100644 --- a/doc/user/overview.rst +++ b/doc/user/about.rst @@ -1,47 +1,8 @@ .. _overview: -******** -Overview -******** - -`FRR`_ is a fully featured, high performance, free software IP routing suite. - -FRR implements all standard routing protocols such as BGP, RIP, OSPF, IS-IS and -more (see :ref:`feature-matrix`), as well as many of their extensions. - -FRR is a high performance suite written primarily in C. It can easily handle -full Internet routing tables and is suitable for use on hardware ranging from -cheap SBCs to commercial grade routers. It is actively used in production by -hundreds of companies, universities, research labs and governments. - -FRR is distributed under GPLv2, with development modeled after the Linux -kernel. Anyone may contribute features, bug fixes, tools, documentation -updates, or anything else. - -FRR is a fork of `Quagga <http://www.quagga.net/>`_. - -.. _how-to-get-frr: - -How to get FRR -============== - -The official FRR website is located at |PACKAGE_URL| and contains further -information, as well as links to additional resources. - -Several distributions provide packages for FRR. Check your distribution's -repositories to find out if a suitable version is available. - -Up-to-date Debian & Redhat packages are available at https://deb.frrouting.org/ -& https://rpm.frrouting.org/ respectively. - -For instructions on installing from source, refer to the -`developer documentation <http://docs.frrouting.org/projects/dev-guide/en/latest/>`_. - - -.. _about-frr: - +********* About FRR -========= +********* FRR provides IP routing services. Its role in a networking stack is to exchange routing information with other routers, make routing and policy decisions, and @@ -55,11 +16,8 @@ light L2 functionality as well, but this is mostly left to the platform. This makes it suitable for deployments ranging from small home networks with static routes to Internet exchanges running full Internet tables. -FRR runs on all modern \*NIX operating systems, including Linux and the BSDs. -Feature support varies by platform; see the :ref:`feature-matrix`. - System Requirements -------------------- +=================== System resources needed by FRR are highly dependent on workload. Routing software performance is particularly susceptible to external factors such as: @@ -86,8 +44,8 @@ information with peers about how to forward packets. Forwarding plane performance largely depends on choice of NIC / ASIC. -System Architecture -------------------- +Architecture +============ .. index:: pair: architecture; FRR @@ -146,9 +104,8 @@ routing stack. .. _supported-platforms: -Supported Platforms -------------------- - +Platform Support +================ Currently FRR supports GNU/Linux and BSD. Porting FRR to other platforms is not too difficult as platform dependent code should be mostly limited to the diff --git a/doc/user/basics.rst b/doc/user/basics.rst new file mode 100644 index 0000000000..4504e9893c --- /dev/null +++ b/doc/user/basics.rst @@ -0,0 +1,23 @@ +.. _basics: + +###### +Basics +###### + +.. toctree:: + :maxdepth: 2 + + basic + extlog + vtysh + grpc + filter + routemap + affinitymap + ipv6 + kernel + snmp + scripting + nexthop_groups + + diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 3ca104a3a9..b2127e8955 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -1,12 +1,19 @@ .. _bfd: -********************************** -Bidirectional Forwarding Detection -********************************** +*** +BFD +*** -:abbr:`BFD (Bidirectional Forwarding Detection)` stands for -Bidirectional Forwarding Detection and it is described and extended by -the following RFCs: +:abbr:`BFD (Bidirectional Forwarding Detection)` is: + + a protocol intended to detect faults in the bidirectional path between two + forwarding engines, including interfaces, data link(s), and to the extent + possible the forwarding engines themselves, with potentially very low + latency. + + -- :rfc:`5880` + +It is described and extended by the following RFCs: * :rfc:`5880` * :rfc:`5881` diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 150a915e3a..a569a9af28 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -92,6 +92,12 @@ be specified (:ref:`common-invocation-options`). the operator has turned off communication to zebra and is running bgpd as a complete standalone process. +.. option:: -K, --graceful_restart + + Bgpd will use this option to denote either a planned FRR graceful + restart or a bgpd-only graceful restart, and this will drive the BGP + GR restarting router procedures. + LABEL MANAGER ------------- @@ -1080,6 +1086,52 @@ Default global mode is helper and default peer per mode is inherit from global. If per peer mode is configured, the GR mode of this particular peer will override the global mode. +.. _bgp-GR-config-mode-cmd: + +BGP GR Config Mode Commands +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. clicmd:: bgp graceful-restart + + This command will enable BGP graceful restart functionality for all BGP instances. + +.. clicmd:: bgp graceful-restart-disable + + This command will disable both the functionality graceful restart and helper + mode for all BGP instances + +.. clicmd:: bgp graceful-restart select-defer-time (0-3600) + + This is command, will set deferral time to value specified. + +.. clicmd:: bgp graceful-restart rib-stale-time (1-3600) + + This is command, will set the time for which stale routes are kept in RIB. + +.. clicmd:: bgp graceful-restart restart-time (0-4095) + + Set the time to wait to delete stale routes before a BGP open message + is received. + + Using with Long-lived Graceful Restart capability, this is recommended + setting this timer to 0 and control stale routes with + ``bgp long-lived-graceful-restart stale-time``. + + Default value is 120. + +.. clicmd:: bgp graceful-restart stalepath-time (1-4095) + + This is command, will set the max time (in seconds) to hold onto + restarting peer's stale paths. + + It also controls Enhanced Route-Refresh timer. + + If this command is configured and the router does not receive a Route-Refresh EoRR + message, the router removes the stale routes from the BGP table after the timer + expires. The stale path timer is started when the router receives a Route-Refresh + BoRR message + + .. _bgp-GR-global-mode-cmd: BGP GR Global Mode Commands @@ -1509,6 +1561,10 @@ Defining Peers peers ASN is the same as mine as specified under the :clicmd:`router bgp ASN` command the connection will be denied. +.. clicmd:: neighbor PEER remote-as auto + + The neighbor's ASN is detected automatically from the OPEN message. + .. clicmd:: neighbor PEER oad Mark a peer belonging to the One Administrative Domain. @@ -1647,7 +1703,7 @@ Configuring Peers IPv4 session addresses, see the ``neighbor PEER update-source`` command below. -.. clicmd:: neighbor PEER interface remote-as <internal|external|ASN> +.. clicmd:: neighbor PEER interface remote-as <internal|external|auto|ASN> Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The session will be established via IPv6 link locals. Use ``internal`` for iBGP diff --git a/doc/user/conf.py b/doc/user/conf.py index 728f9c9364..395875520d 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -18,6 +18,8 @@ import re import pygments import sphinx from sphinx.highlighting import lexers +from sphinx.domains.std import GenericObject +from docutils.parsers.rst import directives # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -52,18 +54,18 @@ source_suffix = ".rst" master_doc = "index" # General information about the project. -project = u"FRR" -copyright = u"2017, FRR" -author = u"FRR authors" +project = "FRR" +copyright = "2017, FRR" +author = "FRR authors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The short X.Y version. -version = u"?.?" +version = "?.?" # The full version, including alpha/beta/rc tags. -release = u"?.?-?" +release = "?.?-?" # ----------------------------------------------------------------------------- @@ -287,7 +289,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "FRR.tex", u"FRR User Manual", u"FRR", "manual"), + (master_doc, "FRR.tex", "FRR User Manual", "FRR", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -315,7 +317,7 @@ latex_logo = "../figures/frr-logo-medium.png" # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "frr", u"FRR User Manual", [author], 1)] +man_pages = [(master_doc, "frr", "FRR User Manual", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -330,7 +332,7 @@ texinfo_documents = [ ( master_doc, "frr", - u"FRR User Manual", + "FRR User Manual", author, "FRR", "One line description of project.", @@ -358,6 +360,7 @@ texinfo_documents = [ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() + # Parse version string into int array def vparse(s): a = [] @@ -372,11 +375,54 @@ def vparse(s): return a[:3] -# custom extensions here +class ClicmdDirective(GenericObject): + """ + Directive for documenting CLI commands. + + The xref string, if no option is provided, will be the verbatim command + string. If the :daemon: option is provided, then it's + "(<daemon>) <command string>)". + + Options: + :daemon: - specify the daemon this command belongs to. Useful for + disambiguating multiple definitions of the same command. + """ + + has_content = True + required_arguments = 1 + optional_arguments = 0 + option_spec = { + **GenericObject.option_spec, + "daemon": directives.unchanged, + } + + def handle_signature(self, sig, signode): + name = super().handle_signature(sig, signode) + daemon = self.options["daemon"] if "daemon" in self.options else "" + prefix = f"({daemon}) " if daemon else "" + return prefix + name + + def run(self): + daemon = self.options["daemon"] if "daemon" in self.options else "" + if daemon: + self.indextemplate = f"pair: ({daemon}) %s; configuration command" + else: + self.indextemplate = f"pair: %s; configuration command" + + nodes = super().run() + + return nodes + + def setup(app): - # object type for FRR CLI commands, can be extended to document parent CLI - # node later on - app.add_object_type("clicmd", "clicmd", indextemplate="pair: %s; configuration command") + # Override the directive that was just created for us + if int(sphinx.__version__.split(".")[0]) >= 2: + app.add_object_type("clicmd", "clicmd", objname="CLI command") + app.add_directive_to_domain("std", "clicmd", ClicmdDirective, override=True) + else: + app.add_object_type( + "clicmd", "clicmd", indextemplate="pair: %s; configuration command" + ) # I dont care how stupid this is if "add_js_file" in dir(app): @@ -389,7 +435,6 @@ def setup(app): else: app.add_stylesheet("overrides.css") - # load Pygments lexer for FRR config syntax # # NB: in Pygments 2.2+ this can be done with `load_lexer_from_file`, but we diff --git a/doc/user/index.rst b/doc/user/index.rst index 4789677a9a..d3b632a8de 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -1,80 +1,31 @@ FRRouting User Guide ==================== -############ -Introduction -############ +FRR is a fully featured, high performance, free software IP routing suite. It +implements all standard routing protocols such as BGP, RIP, OSPF, IS-IS and +more (see :ref:`feature-matrix`), as well as many of their extensions. It can +handle full Internet routing tables and is suitable for use on hardware ranging +from cheap SBCs to commercial grade routers, and is actively used in production +by hundreds of companies, universities, research labs and governments. -.. _introduction: -.. toctree:: - :maxdepth: 2 - - overview - installation - setup - -###### -Basics -###### +FRR runs on all modern \*NIX operating systems, including Linux and the BSDs. +Feature support varies by platform; see the :ref:`feature-matrix`. -.. _basics: -.. toctree:: - :maxdepth: 2 +FRR is distributed under GPLv2, with development modeled after the Linux +kernel. Anyone may contribute features, bug fixes, tools, documentation +updates, or anything else. - basic - extlog - vtysh - grpc - filter - routemap - affinitymap - ipv6 - kernel - snmp - scripting - nexthop_groups -.. modules +FRR is a fork of `Quagga <http://www.quagga.net/>`_. -######### -Protocols -######### - -.. _protocols: .. toctree:: :maxdepth: 2 - zebra - bfd - bgp - babeld - fabricd - ldpd - eigrpd - evpn - isisd - nhrpd - ospfd - ospf6d - pathd - pim - pimv6 - pbr - ripd - ripngd - sharp - static - vnc - vrrp - bmp - watchfrr - mgmtd - -######## -Appendix -######## + introduction + basics + protocols -.. _appendix: .. toctree:: + :caption: Appendix :maxdepth: 2 bugs diff --git a/doc/user/installation.rst b/doc/user/installation.rst index e49f10491e..4d2017c0f8 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -3,22 +3,25 @@ single: Installing FRR single: Building FRR -.. _installation: - Installation ============ -This section covers the basics of building, installing and setting up FRR. +This section covers the basics of building, installing and setting up +FRR. +The official FRR website is located at |PACKAGE_URL| and contains further +information, as well as links to additional resources. From Packages ------------- -The project publishes packages for Red Hat, Centos, Debian and Ubuntu on the -`GitHub releases <https://github.com/FRRouting/frr/releases>`_. page. External -contributors offer packages for many other platforms including \*BSD, Alpine, -Gentoo, Docker, and others. There is currently no documentation on how to use -those but we hope to add it soon. +Up-to-date Debian & Redhat packages are available at +https://deb.frrouting.org/ & https://rpm.frrouting.org/ respectively. + +Several distributions also provide packages for FRR. Check your +distribution's repositories to find out if a suitable version is +available. + From Snapcraft -------------- @@ -29,12 +32,12 @@ universal Snap images, available at https://snapcraft.io/frr. From Source ----------- -Building FRR from source is the best way to ensure you have the latest features -and bug fixes. Details for each supported platform, including dependency -package listings, permissions, and other gotchas, are in the `developer's -documentation -<http://docs.frrouting.org/projects/dev-guide/en/latest/building.html>`_. This -section provides a brief overview on the process. +Building FRR from source is the best way to ensure you have the latest +features and bug fixes. Details for each supported platform, including +dependency package listings, permissions, and other gotchas, are in the +`developer's documentation +<http://docs.frrouting.org/projects/dev-guide/en/latest/building.html>`_. +This section provides a brief overview on the process. Getting the Source diff --git a/doc/user/introduction.rst b/doc/user/introduction.rst new file mode 100644 index 0000000000..89866b9c29 --- /dev/null +++ b/doc/user/introduction.rst @@ -0,0 +1,13 @@ +.. _introduction: + +############ +Introduction +############ + +.. toctree:: + :maxdepth: 2 + + about + installation + setup + diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 70c15e73de..b80adba7f0 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -738,7 +738,17 @@ Interfaces retransmitting Database Description and Link State Request packets. The default value is 5 seconds. -.. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D] +.. clicmd:: ip ospf retransmit-window (20-1000) + + + Set number of milliseconds in the window for neighbor LSA retransmission. + When a neighbor Link State (LS) retransmission timer expires, LSAs scheduled + to be retransmitted within the number of milliseconds configured are + retransmitted to the neighbor. Any expiring after the window will be + retransmitted the next time the neighbor LS retransmission timer expires. + The default is 50 milliseconds. + + .. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D] Set number of seconds for InfTransDelay value. LSAs' age should be diff --git a/doc/user/protocols.rst b/doc/user/protocols.rst new file mode 100644 index 0000000000..e571cd66fc --- /dev/null +++ b/doc/user/protocols.rst @@ -0,0 +1,35 @@ +.. _protocols: + +######### +Protocols +######### + +.. toctree:: + :maxdepth: 2 + + zebra + bfd + bgp + babeld + fabricd + ldpd + eigrpd + evpn + isisd + nhrpd + ospfd + ospf6d + pathd + pim + pimv6 + pbr + ripd + ripngd + sharp + static + vnc + vrrp + bmp + watchfrr + mgmtd + diff --git a/doc/user/subdir.am b/doc/user/subdir.am index 4879f7f7ef..395ce305fe 100644 --- a/doc/user/subdir.am +++ b/doc/user/subdir.am @@ -29,7 +29,7 @@ user_RSTFILES = \ doc/user/ospf6d.rst \ doc/user/ospfd.rst \ doc/user/ospf_fundamentals.rst \ - doc/user/overview.rst \ + doc/user/about.rst \ doc/user/packet-dumps.rst \ doc/user/pathd.rst \ doc/user/pim.rst \ diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 1cff06feee..3f811455b3 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # Create a basic stage set up to build APKs -FROM alpine:3.19 as alpine-builder +FROM alpine:3.20 as alpine-builder RUN apk add \ --update-cache \ abuild \ @@ -24,7 +24,7 @@ RUN cd /src/libyang \ && abuild -r -P /pkgs/apk # This stage builds a dist tarball from the source -FROM alpine:3.19 as source-builder +FROM alpine:3.20 as source-builder RUN mkdir -p /src/alpine /pkgs/apk COPY alpine/APKBUILD.in /src/alpine COPY --from=alpine-apk-builder-libyang /pkgs/apk/src /pkgs/apk @@ -57,7 +57,7 @@ RUN cd /dist \ && abuild -r -P /pkgs/apk # This stage installs frr from the apk -FROM alpine:3.19 +FROM alpine:3.20 RUN mkdir -p /pkgs/apk COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/ RUN apk add \ diff --git a/docker/alpine/libyang/APKBUILD b/docker/alpine/libyang/APKBUILD index 6973fd62d8..d8cd4d918a 100755 --- a/docker/alpine/libyang/APKBUILD +++ b/docker/alpine/libyang/APKBUILD @@ -11,6 +11,7 @@ makedepends="bison cmake cmocka-dev flex pcre2-dev" checkdepends="expect grep shunit2" subpackages="$pkgname-dev $pkgname-doc" source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkgver.tar.gz" +options="!check" # secfixes: # 1.0.215-r1: @@ -21,6 +22,7 @@ source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkg # - CVE-2021-28906 build() { + export ABUILD_APK_INDEX_OPTS="--allow-untrusted" if [ "$CBUILD" != "$CHOST" ]; then CMAKE_CROSSOPTS="-DCMAKE_SYSTEM_NAME=Linux -DCMAKE_HOST_SYSTEM_NAME=Linux" fi diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 430bee92bf..3ed6fe95f5 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -293,7 +293,7 @@ const char *isis_adj_name(const struct isis_adjacency *adj) struct isis_dynhn *dyn; dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid); - if (dyn) + if (adj->circuit->area->dynhostname && dyn) return dyn->hostname; snprintfrr(buf, sizeof(buf), "%pSY", adj->sysid); @@ -358,12 +358,15 @@ void isis_adj_state_change(struct isis_adjacency **padj, * purposes */ adj->last_flap = time(NULL); adj->flaps++; - } else if (old_state == ISIS_ADJ_UP) { - circuit->adj_state_changes++; + } else { + if (old_state == ISIS_ADJ_UP) { + circuit->adj_state_changes++; - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - isis_tx_queue_clean(circuit->tx_queue); + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + isis_tx_queue_clean( + circuit->tx_queue); + } if (new_state == ISIS_ADJ_DOWN) { listnode_delete( @@ -409,10 +412,13 @@ void isis_adj_state_change(struct isis_adjacency **padj, master, send_l2_csnp, circuit, 0, &circuit->t_send_csnp[1]); } - } else if (old_state == ISIS_ADJ_UP) { - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - isis_tx_queue_clean(circuit->tx_queue); + } else { + if (old_state == ISIS_ADJ_UP) { + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + isis_tx_queue_clean( + circuit->tx_queue); + } if (new_state == ISIS_ADJ_DOWN) { if (adj->circuit->u.p2p.neighbor == adj) diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index 4eb57aefb0..dc8f0b96c0 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -2126,9 +2126,16 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit, } vadj_primary = listnode_head(vertex->Adj_N); + if (!vadj_primary) { + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: skipping computing LFAs due to no adjacencies"); + continue; + } sadj_primary = vadj_primary->sadj; parent_vertex = listnode_head(vertex->parents); + assert(parent_vertex); prefix_metric = vertex->d_N - parent_vertex->d_N; /* diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index c98cee06a5..bda7ed89a4 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -482,13 +482,19 @@ static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, lsp->tlvs = tlvs; - if (area->dynhostname && lsp->tlvs->hostname - && lsp->hdr.rem_lifetime) { - isis_dynhn_insert( - area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname, - (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2 - ? IS_LEVEL_2 - : IS_LEVEL_1); + if (area->dynhostname && lsp->hdr.rem_lifetime) { + if (lsp->tlvs->hostname) { + isis_dynhn_insert(area->isis, lsp->hdr.lsp_id, + lsp->tlvs->hostname, + (lsp->hdr.lsp_bits & LSPBIT_IST) == + IS_LEVEL_1_AND_2 + ? IS_LEVEL_2 + : IS_LEVEL_1); + } else { + if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id) && + !LSP_FRAGMENT(lsp->hdr.lsp_id)) + isis_dynhn_remove(area->isis, lsp->hdr.lsp_id); + } } return; @@ -1222,17 +1228,11 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) } /* Add SRv6 Locator TLV. */ - if (area->srv6db.config.enabled && - !list_isempty(area->srv6db.srv6_locator_chunks)) { + if (area->srv6db.config.enabled && area->srv6db.srv6_locator) { 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.prefix = area->srv6db.srv6_locator->prefix; locator.flags = 0; locator.algorithm = 0; @@ -1252,7 +1252,8 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) isis_tlvs_add_ipv6_reach(lsp->tlvs, isis_area_ipv6_topology(area), - &chunk->prefix, 0, false, NULL); + &area->srv6db.srv6_locator->prefix, 0, + false, NULL); } /* IPv4 address and TE router ID TLVs. @@ -2225,6 +2226,10 @@ void lsp_tick(struct event *thread) &area->lspdb[level], next); + if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id)) + isis_dynhn_remove(area->isis, + lsp->hdr.lsp_id); + lspdb_del(&area->lspdb[level], lsp); lsp_destroy(lsp); lsp = NULL; diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 763b8b73d2..8926b624ea 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -252,11 +252,12 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args) return NB_ERR_INCONSISTENCY; listnode_delete(area->area_addrs, addrp); - XFREE(MTYPE_ISIS_AREA_ADDR, addrp); /* * Last area address - reset the SystemID for this router */ - if (listcount(area->area_addrs) == 0) { + if (!memcmp(addrp->area_addr + addrp->addr_len, area->isis->sysid, + ISIS_SYS_ID_LEN) && + listcount(area->area_addrs) == 0) { for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (circuit->u.bc.is_dr[lvl - 1]) @@ -268,6 +269,8 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args) zlog_debug("Router has no SystemID"); } + XFREE(MTYPE_ISIS_AREA_ADDR, addrp); + return NB_OK; } @@ -3518,10 +3521,10 @@ int isis_instance_segment_routing_srv6_locator_modify( 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); + sr_debug("Trying to get locator %s for IS-IS area %s", loc_name, + area->area_tag); - if (isis_zebra_srv6_manager_get_locator_chunk(loc_name) < 0) + if (isis_zebra_srv6_manager_get_locator(loc_name) < 0) return NB_ERR; return NB_OK; diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 81201023d6..7aa9147e71 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -2227,21 +2227,35 @@ int _isis_spf_schedule(struct isis_area *area, int level, } static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, - uint8_t *root_sysid) + uint8_t *root_sysid, struct json_object **json) { struct listnode *node; struct isis_vertex *vertex; char buff[VID2STR_BUFFER]; + char vertex_name[VID2STR_BUFFER]; + char vertex_typestr[VID2STR_BUFFER]; + char vertex_interface[VID2STR_BUFFER]; + char vertex_parent[VID2STR_BUFFER + 11]; + char vertex_nexthop[VID2STR_BUFFER]; + char vertex_metricstr[20]; + struct ttable *tt; + char *table; - vty_out(vty, - "Vertex Type Metric Next-Hop Interface Parent\n"); + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Vertex|Type|Metric|Next-Hop|Interface|Parent"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) { if (VTYPE_IS(vertex->type) && memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { - vty_out(vty, "%-20s %-12s %-6s", - print_sys_hostname(root_sysid), "", ""); - vty_out(vty, "%-30s\n", ""); + /* display here */ + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", + print_sys_hostname(root_sysid), "", "", + "", "", ""); continue; } @@ -2251,9 +2265,12 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, struct isis_vertex_adj *vadj; struct isis_vertex *pvertex; - vty_out(vty, "%-20s %-12s %-6u ", - vid2string(vertex, buff, sizeof(buff)), - vtype2string(vertex->type), vertex->d_N); + snprintf(vertex_name, sizeof(vertex_name), "%s", + vid2string(vertex, buff, sizeof(buff))); + snprintf(vertex_typestr, sizeof(vertex_typestr), "%s", + vtype2string(vertex->type)); + snprintf(vertex_metricstr, sizeof(vertex_metricstr), "%u", + vertex->d_N); for (unsigned int i = 0; i < MAX(vertex->Adj_N ? listcount(vertex->Adj_N) : 0, vertex->parents ? listcount(vertex->parents) : 0); @@ -2273,36 +2290,60 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, } if (rows) { - vty_out(vty, "\n"); - vty_out(vty, "%-20s %-12s %-6s ", "", "", ""); + /* display here */ + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", + vertex_name, vertex_typestr, + vertex_metricstr, vertex_nexthop, + vertex_interface, vertex_parent); + + /* store the first 3 elements */ + vertex_name[0] = '\0'; + vertex_typestr[0] = '\0'; + vertex_metricstr[0] = '\0'; } if (vadj) { struct isis_spf_adj *sadj = vadj->sadj; - vty_out(vty, "%-20s %-9s ", - print_sys_hostname(sadj->id), - sadj->adj ? sadj->adj->circuit - ->interface->name - : "-"); + snprintf(vertex_nexthop, sizeof(vertex_nexthop), + "%s", print_sys_hostname(sadj->id)); + snprintf(vertex_interface, + sizeof(vertex_interface), "%s", + sadj->adj ? sadj->adj->circuit + ->interface->name + : "-"); } if (pvertex) { - if (!vadj) - vty_out(vty, "%-20s %-9s ", "", ""); - - vty_out(vty, "%s(%d)", - vid2string(pvertex, buff, sizeof(buff)), - pvertex->type); + if (!vadj) { + vertex_nexthop[0] = '\0'; + vertex_interface[0] = '\0'; + } + snprintf(vertex_parent, sizeof(vertex_parent), + "%s(%d)", + vid2string(pvertex, buff, sizeof(buff)), + pvertex->type); } ++rows; } - vty_out(vty, "\n"); + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", vertex_name, + vertex_typestr, vertex_metricstr, vertex_nexthop, + vertex_interface, vertex_parent); } + if (json == NULL) { + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + } else + *json = ttable_json_with_json_text( + tt, "ssdsss", + "vertex|type|metric|nextHop|interface|parent"); + ttable_del(tt); } -void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) +void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree, + struct json_object **json) { const char *tree_id_text = NULL; @@ -2324,14 +2365,18 @@ void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) return; } - vty_out(vty, "IS-IS paths to level-%d routers %s\n", spftree->level, - tree_id_text); - isis_print_paths(vty, &spftree->paths, spftree->sysid); - vty_out(vty, "\n"); + if (!json) + vty_out(vty, "IS-IS paths to level-%d routers %s\n", + spftree->level, tree_id_text); + + isis_print_paths(vty, &spftree->paths, spftree->sysid, json); + if (!json) + vty_out(vty, "\n"); } static void show_isis_topology_common(struct vty *vty, int levels, - struct isis *isis, uint8_t algo) + struct isis *isis, uint8_t algo, + json_object **json) { #ifndef FABRICD struct isis_flex_algo_data *fa_data; @@ -2340,10 +2385,15 @@ static void show_isis_topology_common(struct vty *vty, int levels, struct isis_spftree *spftree; struct listnode *node; struct isis_area *area; + json_object *json_level = NULL, *jstr = NULL, *json_val; + char key[18]; if (!isis->area_list || isis->area_list->count == 0) return; + if (json) + *json = json_object_new_object(); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { #ifndef FABRICD /* @@ -2361,21 +2411,37 @@ static void show_isis_topology_common(struct vty *vty, int levels, fa_data = NULL; #endif /* ifndef FABRICD */ - vty_out(vty, - "Area %s:", area->area_tag ? area->area_tag : "null"); + if (json) { + jstr = json_object_new_string( + area->area_tag ? area->area_tag : "null"); + json_object_object_add(*json, "area", jstr); + json_object_int_add(*json, "algorithm", algo); + } else { + vty_out(vty, "Area %s:", + area->area_tag ? area->area_tag : "null"); #ifndef FABRICD - if (algo != SR_ALGORITHM_SPF) - vty_out(vty, " Algorithm %hhu\n", algo); - else + if (algo != SR_ALGORITHM_SPF) + vty_out(vty, " Algorithm %hhu\n", algo); + else #endif /* ifndef FABRICD */ - vty_out(vty, "\n"); + vty_out(vty, "\n"); + } for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { if ((level & levels) == 0) continue; + if (json) { + json_level = json_object_new_object(); + jstr = json_object_new_string( + area->area_tag ? area->area_tag + : "null"); + json_object_object_add(json_level, "area", jstr); + } + if (area->ip_circuits > 0) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = fa_data->spftree[SPFTREE_IPV4] @@ -2385,9 +2451,16 @@ static void show_isis_topology_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV4] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv4-paths", + json_val); + } } if (area->ipv6_circuits > 0) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = fa_data->spftree[SPFTREE_IPV6] @@ -2396,9 +2469,16 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_IPV6] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-paths", + json_val); + } } if (isis_area_ipv6_dstsrc_enabled(area)) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = @@ -2408,18 +2488,36 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_DSTSRC] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-dstsrc-paths", + json_val); + } + } + if (json) { + snprintf(key, sizeof(key), "level-%d", level); + json_object_object_add(*json, key, json_level); } } if (fabricd_spftree(area)) { + json_val = NULL; + vty_out(vty, "IS-IS paths to level-2 routers with hop-by-hop metric\n"); - isis_print_paths(vty, &fabricd_spftree(area)->paths, isis->sysid); - vty_out(vty, "\n"); + isis_print_paths(vty, &fabricd_spftree(area)->paths, + isis->sysid, json ? &json_val : NULL); + if (json && json_val) + json_object_object_add(json_level, + "fabricd-paths", + json_val); + else + vty_out(vty, "\n"); } - - vty_out(vty, "\n"); + if (!json) + vty_out(vty, "\n"); } } @@ -2430,6 +2528,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, " [<level-1|level-2>]" " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ + " [json$uj]" , SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" @@ -2440,6 +2539,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, "Show Flex-algo routes\n" "Algorithm number\n" #endif /* ifndef FABRICD */ + JSON_STR ) { int levels = ISIS_LEVELS; @@ -2450,6 +2550,8 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, bool all_algorithm = false; int idx_vrf = 0; uint16_t algorithm = SR_ALGORITHM_SPF; + bool uj = use_json(argc, argv); + json_object *json = NULL, *json_vrf = NULL; #ifndef FABRICD int idx = 0; @@ -2473,21 +2575,33 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, } ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (uj) + json = json_object_new_array(); + if (all_vrf) { for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { if (all_algorithm) { for (algorithm = SR_ALGORITHM_FLEX_MIN; algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) - show_isis_topology_common( - vty, levels, isis, - (uint8_t)algorithm); + show_isis_topology_common(vty, levels, + isis, + (uint8_t)algorithm, + uj ? &json_vrf + : NULL); } else { show_isis_topology_common(vty, levels, isis, - (uint8_t)algorithm); + (uint8_t)algorithm, + uj ? &json_vrf : NULL); + } + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int( + isis->vrf_id)); + json_object_array_add(json, json_vrf); } } - return CMD_SUCCESS; + goto out; } isis = isis_lookup_by_vrfname(vrf_name); if (isis == NULL) @@ -2496,10 +2610,24 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, for (algorithm = SR_ALGORITHM_FLEX_MIN; algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) { show_isis_topology_common(vty, levels, isis, - (uint8_t)algorithm); + (uint8_t)algorithm, + uj ? &json_vrf : NULL); } } else - show_isis_topology_common(vty, levels, isis, (uint8_t)algorithm); + show_isis_topology_common(vty, levels, isis, (uint8_t)algorithm, + uj ? &json_vrf : NULL); + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int(isis->vrf_id)); + json_object_array_add(json, json_vrf); + } +out: + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } @@ -2887,7 +3015,11 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree, vty_out(vty, "%s\n", table); XFREE(MTYPE_TMP, table); } else if (json) { - *json = ttable_json(tt, prefix_sid ? "sdssdsdd" : "sdsss"); + *json = ttable_json_with_json_text( + tt, prefix_sid ? "sdssdsdd" : "sdsss", + prefix_sid + ? "prefix|metric|interface|nextHop|segmentIdentifier|labelOperation|Algorithm" + : "prefix|metric|interface|nextHop|label(s)"); } ttable_del(tt); } @@ -2971,8 +3103,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV4] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv4-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, @@ -2993,8 +3131,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV6] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, @@ -3016,8 +3160,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_DSTSRC] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-dstsrc-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, prefix_sid, backup); diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 7e9754d9bf..ee2d29abe3 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -61,7 +61,8 @@ struct isis_lsp *isis_root_system_lsp(struct lspdb_head *lspdb, __FILE__, __LINE__) int _isis_spf_schedule(struct isis_area *area, int level, const char *func, const char *file, int line); -void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree); +void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree, + struct json_object **json); void isis_print_routes(struct vty *vty, struct isis_spftree *spftree, json_object **json, bool prefix_sid, bool backup); void isis_spf_init(void); diff --git a/isisd/isis_srv6.c b/isisd/isis_srv6.c index 44fd599cbb..b5974b1a62 100644 --- a/isisd/isis_srv6.c +++ b/isisd/isis_srv6.c @@ -102,6 +102,7 @@ bool isis_srv6_locator_unset(struct isis_area *area) struct srv6_locator_chunk *chunk; struct isis_srv6_sid *sid; struct srv6_adjacency *sra; + struct srv6_sid_ctx ctx = {}; if (strncmp(area->srv6db.config.srv6_locator_name, "", sizeof(area->srv6db.config.srv6_locator_name)) == 0) { @@ -120,13 +121,31 @@ bool isis_srv6_locator_unset(struct isis_area *area) * Zebra */ isis_zebra_srv6_sid_uninstall(area, sid); + /* + * Inform the SID Manager that IS-IS will no longer use the SID, so + * that the SID Manager can remove the SID context ownership from IS-IS + * and release/free the SID context if it is not yes by other protocols. + */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; + isis_zebra_release_srv6_sid(&ctx); + 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)) + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) { + /* + * Inform the SID Manager that IS-IS will no longer use the SID, so + * that the SID Manager can remove the SID context ownership from IS-IS + * and release/free the SID context if it is not yes by other protocols. + */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = sra->nexthop; + isis_zebra_release_srv6_sid(&ctx); + srv6_endx_sid_del(sra); + } /* Inform Zebra that we are releasing the SRv6 locator */ ret = isis_zebra_srv6_manager_release_locator_chunk( @@ -146,6 +165,10 @@ bool isis_srv6_locator_unset(struct isis_area *area) srv6_locator_chunk_free(&chunk); } + /* Clear locator */ + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Clear locator name */ memset(area->srv6db.config.srv6_locator_name, 0, sizeof(area->srv6db.config.srv6_locator_name)); @@ -198,149 +221,35 @@ void isis_srv6_interface_set(struct isis_area *area, const char *ifname) } /** - * 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 locator SRv6 locator * @param behavior SRv6 Endpoint Behavior bound to the SID + * @param sid_value SRv6 SID value * * @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, +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, enum srv6_endpoint_behavior_codepoint behavior, - int sid_func) + struct in6_addr *sid_value) { struct isis_srv6_sid *sid = NULL; - if (!area || !chunk) + if (!area || !locator || !sid_value) 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->sid = *sid_value; 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->structure.loc_block_len = locator->block_bits_length; + sid->structure.loc_node_len = locator->node_bits_length; + sid->structure.func_len = locator->function_bits_length; + sid->structure.arg_len = locator->argument_bits_length; + sid->locator = locator; sid->area = area; return sid; @@ -376,9 +285,10 @@ void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level) * @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) + * @param sid_value SID value associated to be associated with the adjacency */ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, - struct list *nexthops) + struct list *nexthops, struct in6_addr *sid_value) { struct isis_circuit *circuit = adj->circuit; struct isis_area *area = circuit->area; @@ -387,11 +297,10 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, struct isis_srv6_lan_endx_sid_subtlv *ladj_sid; struct in6_addr nexthop; uint8_t flags = 0; - struct srv6_locator_chunk *chunk; + struct srv6_locator *locator; uint32_t behavior; - if (!area || !area->srv6db.srv6_locator_chunks || - list_isempty(area->srv6db.srv6_locator_chunks)) + if (!area || !area->srv6db.srv6_locator) return; sr_debug("ISIS-SRv6 (%s): Add %s End.X SID", area->area_tag, @@ -401,10 +310,7 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, if (!circuit->ipv6_router || !adj->ll_ipv6_count) return; - chunk = (struct srv6_locator_chunk *)listgetdata( - listhead(area->srv6db.srv6_locator_chunks)); - if (!chunk) - return; + locator = area->srv6db.srv6_locator; nexthop = adj->ll_ipv6_addrs[0]; @@ -415,25 +321,21 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, if (circuit->ext == NULL) circuit->ext = isis_alloc_ext_subtlvs(); - behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) + behavior = (CHECK_FLAG(locator->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_ADJ_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->locator = locator; + sra->structure.loc_block_len = locator->block_bits_length; + sra->structure.loc_node_len = locator->node_bits_length; + sra->structure.func_len = locator->function_bits_length; + sra->structure.arg_len = locator->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; - } + sra->sid = *sid_value; switch (circuit->circ_type) { /* SRv6 LAN End.X SID for Broadcast interface section #8.2 */ @@ -505,9 +407,9 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, * * @param adj IS-IS Adjacency */ -void srv6_endx_sid_add(struct isis_adjacency *adj) +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value) { - srv6_endx_sid_add_single(adj, false, NULL); + srv6_endx_sid_add_single(adj, false, NULL, sid_value); } /** @@ -610,7 +512,7 @@ static int srv6_adj_ip_enabled(struct isis_adjacency *adj, int family, family != AF_INET6) return 0; - srv6_endx_sid_add(adj); + isis_zebra_request_srv6_sid_endx(adj); return 0; } @@ -832,6 +734,9 @@ void isis_srv6_area_term(struct isis_area *area) srv6_locator_chunk_free(&chunk); list_delete(&srv6db->srv6_locator_chunks); + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Free SRv6 SIDs list */ list_delete(&srv6db->srv6_sids); list_delete(&srv6db->srv6_endx_sids); diff --git a/isisd/isis_srv6.h b/isisd/isis_srv6.h index 7f16712ae3..bde14965f6 100644 --- a/isisd/isis_srv6.h +++ b/isisd/isis_srv6.h @@ -44,7 +44,7 @@ struct isis_srv6_sid { struct isis_srv6_sid_structure structure; /* Parent SRv6 locator */ - struct srv6_locator_chunk *locator; + struct srv6_locator *locator; /* Backpointer to IS-IS area */ struct isis_area *area; @@ -89,7 +89,7 @@ struct srv6_adjacency { struct isis_srv6_sid_structure structure; /* Parent SRv6 locator */ - struct srv6_locator_chunk *locator; + struct srv6_locator *locator; /* Adjacency-SID nexthop information */ struct in6_addr nexthop; @@ -109,6 +109,8 @@ struct srv6_adjacency { /* Per-area IS-IS SRv6 Data Base (SRv6 DB) */ struct isis_srv6_db { + /* List of SRv6 Locator */ + struct srv6_locator *srv6_locator; /* List of SRv6 Locator chunks */ struct list *srv6_locator_chunks; @@ -149,9 +151,9 @@ 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, +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, enum srv6_endpoint_behavior_codepoint behavior, - int sid_func); + struct in6_addr *sid_value); extern void isis_srv6_sid_free(struct isis_srv6_sid *sid); extern void isis_srv6_area_init(struct isis_area *area); @@ -169,8 +171,8 @@ 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); + struct list *nexthops, struct in6_addr *sid_value); +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value); 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); diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 3bb8a48246..c7f45b2469 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -1010,7 +1010,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_adj_sid *adj; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *adj_sid_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1022,42 +1022,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", adj->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", + adj_sid_json = json_object_new_object(); + json_object_int_add(adj_sid_json, "sid", adj->sid); - json_object_int_add(flags_json, "weight", + json_object_int_add(adj_sid_json, "weight", adj->weight); - json_object_string_add( - flags_json, "flag-f", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-b", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-v", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-l", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); + json_object_string_add(adj_sid_json, "flag-f", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-b", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-v", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-l", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-s", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-p", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + adj_sid_json); } /* end old deprecated key format */ @@ -1067,35 +1062,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", adj->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", adj->sid); - json_object_int_add(flags_json, "weight", + adj_sid_json = json_object_new_object(); + json_object_int_add(adj_sid_json, "sid", + adj->sid); + json_object_int_add(adj_sid_json, "weight", adj->weight); - json_object_boolean_add(flags_json, "flagF", + json_object_boolean_add(adj_sid_json, "flagF", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? true : false); - json_object_boolean_add(flags_json, "flagB", + json_object_boolean_add(adj_sid_json, "flagB", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? true : false); - json_object_boolean_add(flags_json, "flagV", + json_object_boolean_add(adj_sid_json, "flagV", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? true : false); - json_object_boolean_add(flags_json, "flagL", + json_object_boolean_add(adj_sid_json, "flagL", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? true : false); - json_object_boolean_add(flags_json, "flagS", + json_object_boolean_add(adj_sid_json, "flagS", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? true : false); - json_object_boolean_add(flags_json, "flagP", + json_object_boolean_add(adj_sid_json, "flagP", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG ? true : false); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + adj_sid_json); } } else for (adj = (struct isis_adj_sid *)exts->adj_sid.head; @@ -1128,7 +1125,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) { struct isis_lan_adj_sid *lan; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *lan_adj_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1147,42 +1144,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, continue; snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", lan->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", + lan_adj_json = json_object_new_object(); + json_object_int_add(lan_adj_json, "sid", lan->sid); - json_object_int_add(flags_json, "weight", + json_object_int_add(lan_adj_json, "weight", lan->weight); - json_object_string_add( - flags_json, "flag-f", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-b", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-v", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-l", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); + json_object_string_add(lan_adj_json, "flag-f", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-b", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-v", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-l", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-s", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-p", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + lan_adj_json); } /* end old deprecated key format */ @@ -1197,35 +1189,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, continue; snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", lan->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", lan->sid); - json_object_int_add(flags_json, "weight", + lan_adj_json = json_object_new_object(); + json_object_int_add(lan_adj_json, "sid", + lan->sid); + json_object_int_add(lan_adj_json, "weight", lan->weight); - json_object_boolean_add(flags_json, "flagF", + json_object_boolean_add(lan_adj_json, "flagF", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? true : false); - json_object_boolean_add(flags_json, "flagB", + json_object_boolean_add(lan_adj_json, "flagB", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? true : false); - json_object_boolean_add(flags_json, "flagV", + json_object_boolean_add(lan_adj_json, "flagV", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? true : false); - json_object_boolean_add(flags_json, "flagL", + json_object_boolean_add(lan_adj_json, "flagL", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? true : false); - json_object_boolean_add(flags_json, "flagS", + json_object_boolean_add(lan_adj_json, "flagS", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? true : false); - json_object_boolean_add(flags_json, "flagP", + json_object_boolean_add(lan_adj_json, "flagP", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG ? true : false); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + lan_adj_json); } } else @@ -1268,7 +1262,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_srv6_endx_sid_subtlv *adj; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *srv6_endx_sid_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1282,76 +1276,85 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, 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); + srv6_endx_sid_json = json_object_new_object(); + json_object_string_addf(srv6_endx_sid_json, + "sid", "%pI6", + &adj->sid); + json_object_string_add(srv6_endx_sid_json, + "algorithm", + sr_algorithm_string( + adj->algorithm)); + json_object_int_add(srv6_endx_sid_json, + "weight", adj->weight); + json_object_string_add(srv6_endx_sid_json, + "behavior", + seg6local_action2str( + adj->behavior)); + json_object_string_add(srv6_endx_sid_json, + "flag-b", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? "1" + : "0"); + json_object_string_add(srv6_endx_sid_json, + "flag-s", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? "1" + : "0"); + json_object_string_add(srv6_endx_sid_json, + "flag-p", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + srv6_endx_sid_json); if (adj->subsubtlvs) isis_format_subsubtlvs(adj->subsubtlvs, NULL, - arr_adj_json, + srv6_endx_sid_json, indent + 4); } /* end old deprecated key format */ arr_adj_json = json_object_new_array(); - json_object_object_add(json, "srv6EndSID", arr_adj_json); + json_object_object_add(json, "srv6EndXSID", + 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", + srv6_endx_sid_json = json_object_new_object(); + json_object_string_addf(srv6_endx_sid_json, + "sid", "%pI6", + &adj->sid); + json_object_string_add(srv6_endx_sid_json, + "algorithm", sr_algorithm_string( adj->algorithm)); - json_object_int_add(flags_json, "weight", - adj->weight); - json_object_string_add(flags_json, "behavior", + json_object_int_add(srv6_endx_sid_json, + "weight", adj->weight); + json_object_string_add(srv6_endx_sid_json, + "behavior", seg6local_action2str( adj->behavior)); json_object_boolean_add( - flags_json, "flagB", + srv6_endx_sid_json, "flagB", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); json_object_boolean_add( - flags_json, "flagS", + srv6_endx_sid_json, "flagS", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); json_object_boolean_add( - flags_json, "flagP", + srv6_endx_sid_json, "flagP", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_endx_sid_json); if (adj->subsubtlvs) isis_format_subsubtlvs(adj->subsubtlvs, NULL, - arr_adj_json, + srv6_endx_sid_json, indent + 4); } } else @@ -1384,7 +1387,8 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, 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; + struct json_object *arr_adj_json, + *srv6_lan_endx_sid_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1398,42 +1402,47 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, 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, + srv6_lan_endx_sid_json = + json_object_new_object(); + json_object_string_addf(srv6_lan_endx_sid_json, + "sid", "%pI6", + &lan->sid); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "algorithm", + sr_algorithm_string( + lan->algorithm)); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "behavior", + seg6local_action2str( + lan->behavior)); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-b", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? "1" + : "0"); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-s", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? "1" + : "0"); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-p", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? "1" + : "0"); + json_object_string_addf(srv6_lan_endx_sid_json, "neighbor-id", "%pSY", lan->neighbor_id); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_lan_endx_sid_json); if (lan->subsubtlvs) isis_format_subsubtlvs(lan->subsubtlvs, NULL, - arr_adj_json, + srv6_lan_endx_sid_json, indent + 4); } /* end old deprecated key format */ @@ -1446,39 +1455,44 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, 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", + srv6_lan_endx_sid_json = + json_object_new_object(); + json_object_string_addf(srv6_lan_endx_sid_json, + "sid", "%pI6", + &lan->sid); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "algorithm", sr_algorithm_string( lan->algorithm)); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add(flags_json, "behavior", + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "behavior", seg6local_action2str( lan->behavior)); json_object_boolean_add( - flags_json, "flagB", + srv6_lan_endx_sid_json, "flagB", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); json_object_boolean_add( - flags_json, "flagS", + srv6_lan_endx_sid_json, "flagS", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); json_object_boolean_add( - flags_json, "flagP", + srv6_lan_endx_sid_json, "flagP", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); - json_object_string_addf(flags_json, - "neighbor-id", "%pSY", + json_object_string_addf(srv6_lan_endx_sid_json, + "neighborID", "%pSY", lan->neighbor_id); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_lan_endx_sid_json); if (lan->subsubtlvs) isis_format_subsubtlvs(lan->subsubtlvs, NULL, - arr_adj_json, + srv6_lan_endx_sid_json, indent + 4); } } else diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 2412ec5e84..ce4eb74ec6 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -645,6 +645,70 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size) } /** + * Request an End.X SID for an IS-IS adjacency. + * + * @param adj IS-IS Adjacency + */ +void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj) +{ + struct isis_circuit *circuit = adj->circuit; + struct isis_area *area = circuit->area; + struct in6_addr nexthop; + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + bool ret; + + if (!area || !area->srv6db.srv6_locator) + return; + + /* Determine nexthop IP address */ + if (!circuit->ipv6_router || !adj->ll_ipv6_count) + return; + + nexthop = adj->ll_ipv6_addrs[0]; + + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = nexthop; + ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, + area->srv6db.config.srv6_locator_name); + if (!ret) { + zlog_err("%s: not allocated new End.X SID for IS-IS area %s", + __func__, area->area_tag); + return; + } +} + +static void request_srv6_sids(struct isis_area *area) +{ + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + struct listnode *node; + struct isis_adjacency *adj; + bool ret; + + if (!area || !area->srv6db.config.enabled || !area->srv6db.srv6_locator) + return; + + sr_debug("Requesting SRv6 SIDs for IS-IS area %s", area->area_tag); + + /* Request new SRv6 End SID */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; + ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, + area->srv6db.config.srv6_locator_name); + if (!ret) { + zlog_err("%s: not allocated new End SID for IS-IS area %s", + __func__, area->area_tag); + return; + } + + /* 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) + isis_zebra_request_srv6_sid_endx(adj); + } +} + +/** * Release Label Range to the Label Manager. * * @param start start of label range to release @@ -1119,99 +1183,47 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra) } /** - * Callback to process an SRv6 locator chunk received from SRv6 Manager (zebra). + * Internal function to process an SRv6 locator * - * @result 0 on success, -1 otherwise + * @param locator The locator to be processed */ -static int isis_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) +static int isis_zebra_process_srv6_locator_internal(struct srv6_locator *locator) { 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; - } + struct listnode *node; - /* Decode the received zebra message */ - s = zclient->ibuf; - if (zapi_srv6_locator_chunk_decode(s, chunk) < 0) { - srv6_locator_chunk_free(&chunk); + if (!isis || !locator) 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); + zlog_info("%s: Received SRv6 locator %s %pFX, loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u", + __func__, locator->name, &locator->prefix, + locator->block_bits_length, locator->node_bits_length, + locator->function_bits_length, locator->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) + /* + * Check if the IS-IS area is configured to use the received + * locator + */ + if (strncmp(area->srv6db.config.srv6_locator_name, locator->name, + sizeof(area->srv6db.config.srv6_locator_name)) != 0) { + zlog_err("%s: SRv6 Locator name unmatch %s:%s", + __func__, area->srv6db.config.srv6_locator_name, + locator->name); 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); + sr_debug("SRv6 locator (locator %s, prefix %pFX) set for IS-IS area %s", + locator->name, &locator->prefix, area->area_tag); - allocated = true; - break; - } + /* Store the locator in the IS-IS area */ + area->srv6db.srv6_locator = srv6_locator_alloc(locator->name); + srv6_locator_copy(area->srv6db.srv6_locator, locator); - if (!allocated) { - sr_debug("No IS-IS area configured for the locator %s", - chunk->locator_name); - srv6_locator_chunk_free(&chunk); + /* Request SIDs from the locator */ + request_srv6_sids(area); } return 0; @@ -1226,8 +1238,6 @@ 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; @@ -1236,33 +1246,7 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) 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; + return isis_zebra_process_srv6_locator_internal(&loc); } /** @@ -1335,6 +1319,9 @@ static int isis_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) } } + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Regenerate LSPs to advertise that the locator no longer * exists */ lsp_regenerate_schedule(area, area->is_type, 0); @@ -1368,6 +1355,232 @@ int isis_zebra_srv6_manager_release_locator_chunk(const char *name) return srv6_manager_release_locator_chunk(zclient, name); } +/** + * Ask the SRv6 Manager (zebra) about a specific locator + * + * @param name Locator name + * @return 0 on success, -1 otherwise + */ +int isis_zebra_srv6_manager_get_locator(const char *name) +{ + if (!name) + return -1; + + /* + * Send the Get Locator request to the SRv6 Manager and return the + * result + */ + return srv6_manager_get_locator(zclient, name); +} + +/** + * Ask the SRv6 Manager (zebra) to allocate a SID. + * + * Optionally, it is possible to provide an IPv6 address (sid_value parameter). + * + * When sid_value is provided, the SRv6 Manager allocates the requested SID + * address, if the request can be satisfied (explicit allocation). + * + * When sid_value is not provided, the SRv6 Manager allocates any available SID + * from the provided locator (dynamic allocation). + * + * @param ctx Context to be associated with the request SID + * @param sid_value IPv6 address to be associated with the requested SID (optional) + * @param locator_name Name of the locator from which the SID must be allocated + */ +bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + int ret; + + if (!ctx || !locator_name) + return false; + + /* + * Send the Get SRv6 SID request to the SRv6 Manager and check the + * result + */ + ret = srv6_manager_get_sid(zclient, ctx, sid_value, locator_name, NULL); + if (ret < 0) { + zlog_warn("%s: error getting SRv6 SID!", __func__); + return false; + } + + return true; +} + +/** + * Ask the SRv6 Manager (zebra) to release a previously allocated SID. + * + * This function is used to tell the SRv6 Manager that IS-IS no longer intends + * to use the SID. + * + * @param ctx Context to be associated with the SID to be released + */ +void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx) +{ + int ret; + + if (!ctx) + return; + + /* + * Send the Release SRv6 SID request to the SRv6 Manager and check the + * result + */ + ret = srv6_manager_release_sid(zclient, ctx); + if (ret < 0) { + zlog_warn("%s: error releasing SRv6 SID!", __func__); + return; + } +} + +static int isis_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS) +{ + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + struct srv6_sid_ctx ctx; + struct in6_addr sid_addr; + enum zapi_srv6_sid_notify note; + uint32_t sid_func; + struct isis_area *area; + struct listnode *node, *nnode, *n; + char buf[256]; + struct srv6_locator *locator; + struct prefix_ipv6 tmp_prefix; + struct srv6_adjacency *sra; + enum srv6_endpoint_behavior_codepoint behavior; + struct isis_srv6_sid *sid; + struct isis_adjacency *adj; + + if (!isis) + return -1; + + /* Decode the received notification message */ + if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr, + &sid_func, NULL, ¬e, NULL)) { + zlog_err("%s : error in msg decode", __func__); + return -1; + } + + sr_debug("%s: received SRv6 SID notify: ctx %s sid_value %pI6 sid_func %u note %s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx), &sid_addr, + sid_func, zapi_srv6_sid_notify2str(note)); + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + if (!area->srv6db.config.enabled || !area->srv6db.srv6_locator) + continue; + + locator = area->srv6db.srv6_locator; + + /* Verify that the received SID belongs to the configured locator */ + if (note == ZAPI_SRV6_SID_ALLOCATED) { + tmp_prefix.family = AF_INET6; + tmp_prefix.prefixlen = IPV6_MAX_BITLEN; + tmp_prefix.prefix = sid_addr; + + if (!prefix_match((struct prefix *)&locator->prefix, + (struct prefix *)&tmp_prefix)) { + sr_debug("%s : ignoring SRv6 SID notify: locator (area %s) does not match", + __func__, area->area_tag); + continue; + } + } + + /* Handle notification */ + switch (note) { + case ZAPI_SRV6_SID_ALLOCATED: + sr_debug("SRv6 SID %pI6 %s ALLOCATED", &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* Remove old End SIDs, if any */ + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_sids, + node, nnode, sid)) { + isis_zebra_srv6_sid_uninstall(area, sid); + listnode_delete(area->srv6db.srv6_sids, + sid); + } + + /* Allocate new SRv6 End SID */ + behavior = + (CHECK_FLAG(locator->flags, + SRV6_LOCATOR_USID)) + ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID + : SRV6_ENDPOINT_BEHAVIOR_END; + sid = isis_srv6_sid_alloc(area, + area->srv6db + .srv6_locator, + behavior, &sid_addr); + if (!sid) { + zlog_warn("%s: isis_srv6_sid_alloc failed", + __func__); + 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); + + } else if (ctx.behavior == + ZEBRA_SEG6_LOCAL_ACTION_END_X) { + for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, + n, adj)) { + /* Check if the End.X SID is for this adjacecny */ + if (adj->ll_ipv6_count == 0 || + memcmp(&adj->ll_ipv6_addrs[0], + &ctx.nh6, + sizeof(struct in6_addr)) != 0) + continue; + + /* Remove old End.X SIDs, if any */ + for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids, + node, nnode, sra)) + srv6_endx_sid_del(sra); + + /* Allocate new End.X SID for the adjacency */ + srv6_endx_sid_add_single(adj, false, + NULL, + &sid_addr); + } + } else { + zlog_warn("%s: unsupported behavior %u", + __func__, ctx.behavior); + return -1; + } + break; + case ZAPI_SRV6_SID_RELEASED: + sr_debug("SRv6 SID %pI6 %s: RELEASED", &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + break; + case ZAPI_SRV6_SID_FAIL_ALLOC: + sr_debug("SRv6 SID %pI6 %s: Failed to allocate", + &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + /* Error will be logged by zebra module */ + break; + case ZAPI_SRV6_SID_FAIL_RELEASE: + zlog_warn("%s: SRv6 SID %pI6 %s failure to release", + __func__, &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + /* Error will be logged by zebra module */ + break; + } + + /* Regenerate LSPs to advertise the new locator and the SID */ + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return 0; +} + static zclient_handler *const isis_handlers[] = { [ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra, [ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add, @@ -1380,10 +1593,9 @@ static zclient_handler *const isis_handlers[] = { [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, + [ZEBRA_SRV6_SID_NOTIFY] = isis_zebra_srv6_sid_notify, }; void isis_zebra_init(struct event_loop *master, int instance) diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index f1684b7c25..79da16efac 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -68,4 +68,11 @@ 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); +extern int isis_zebra_srv6_manager_get_locator(const char *name); +extern void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj); +extern bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name); +extern void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx); + #endif /* _ZEBRA_ISIS_ZEBRA_H */ diff --git a/isisd/isisd.c b/isisd/isisd.c index 982df0839b..8db6295b66 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -496,6 +496,7 @@ void isis_area_destroy(struct isis_area *area) { struct listnode *node, *nnode; struct isis_circuit *circuit; + struct iso_address *addr; QOBJ_UNREG(area); @@ -545,6 +546,15 @@ void isis_area_destroy(struct isis_area *area) if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) isis_redist_area_finish(area); + if (listcount(area->area_addrs) > 0) { + addr = listgetdata(listhead(area->area_addrs)); + if (!memcmp(addr->area_addr + addr->addr_len, area->isis->sysid, + ISIS_SYS_ID_LEN)) { + memset(area->isis->sysid, 0, ISIS_SYS_ID_LEN); + area->isis->sysid_set = 0; + } + } + list_delete(&area->area_addrs); for (int i = SPF_PREFIX_PRIO_CRITICAL; i <= SPF_PREFIX_PRIO_MEDIUM; diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index d40728b043..2596c79481 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -681,6 +681,18 @@ nbr_gtsm_setup(int fd, int af, struct nbr_params *nbrp) if (nbrp && CHECK_FLAG(nbrp->flags, F_NBRP_GTSM_HOPS)) ttl = 256 - nbrp->gtsm_hops; + /* + * In linux networking stack, the received mpls packets + * will be processed by the host twice, one as mpls packet, + * the other as ip packet, so its ttl will be decreased 1. + * This behavior is based on the new kernel (5.10 and 6.1), + * and older versions may behave differently. + * + * Here, decrease 1 for IP_MINTTL if GTSM is enabled. + * And this workaround makes the GTSM mechanism a bit deviation. + */ + ttl -= 1; + switch (af) { case AF_INET: if (sock_set_ipv4_minttl(fd, ttl) == -1) diff --git a/lib/frrcu.h b/lib/frrcu.h index 9f07a69b52..81ab5528a9 100644 --- a/lib/frrcu.h +++ b/lib/frrcu.h @@ -156,7 +156,7 @@ extern void rcu_enqueue(struct rcu_head *head, const struct rcu_action *action); #define rcu_call(func, ptr, field) \ do { \ typeof(ptr) _ptr = (ptr); \ - void (*fptype)(typeof(ptr)); \ + void (*_fptype)(typeof(ptr)); \ struct rcu_head *_rcu_head = &_ptr->field; \ static const struct rcu_action _rcu_action = { \ .type = RCUA_CALL, \ diff --git a/lib/libfrr.c b/lib/libfrr.c index 876efe23a8..338a7d0340 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -102,23 +102,25 @@ static void opt_extend(const struct optspec *os) #define OPTION_SCRIPTDIR 1009 static const struct option lo_always[] = { - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'v'}, - {"daemon", no_argument, NULL, 'd'}, - {"module", no_argument, NULL, 'M'}, - {"profile", required_argument, NULL, 'F'}, - {"pathspace", required_argument, NULL, 'N'}, - {"vrfdefaultname", required_argument, NULL, 'o'}, - {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, - {"moduledir", required_argument, NULL, OPTION_MODULEDIR}, - {"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR}, - {"log", required_argument, NULL, OPTION_LOG}, - {"log-level", required_argument, NULL, OPTION_LOGLEVEL}, - {"command-log-always", no_argument, NULL, OPTION_LOGGING}, - {"limit-fds", required_argument, NULL, OPTION_LIMIT_FDS}, - {NULL}}; + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "daemon", no_argument, NULL, 'd' }, + { "module", no_argument, NULL, 'M' }, + { "profile", required_argument, NULL, 'F' }, + { "pathspace", required_argument, NULL, 'N' }, + { "vrfdefaultname", required_argument, NULL, 'o' }, + { "graceful_restart", optional_argument, NULL, 'K' }, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK }, + { "moduledir", required_argument, NULL, OPTION_MODULEDIR }, + { "scriptdir", required_argument, NULL, OPTION_SCRIPTDIR }, + { "log", required_argument, NULL, OPTION_LOG }, + { "log-level", required_argument, NULL, OPTION_LOGLEVEL }, + { "command-log-always", no_argument, NULL, OPTION_LOGGING }, + { "limit-fds", required_argument, NULL, OPTION_LIMIT_FDS }, + { NULL } +}; static const struct optspec os_always = { - "hvdM:F:N:o:", + "hvdM:F:N:o:K::", " -h, --help Display this help and exit\n" " -v, --version Print program version\n" " -d, --daemon Runs in daemon mode\n" @@ -126,13 +128,15 @@ static const struct optspec os_always = { " -F, --profile Use specified configuration profile\n" " -N, --pathspace Insert prefix into config & socket paths\n" " -o, --vrfdefaultname Set default VRF name.\n" + " -K, --graceful_restart FRR starting in Graceful Restart mode, with optional route-cleanup timer\n" " --vty_socket Override vty socket path\n" " --moduledir Override modules directory\n" " --scriptdir Override scripts directory\n" " --log Set Logging to stdout, syslog, or file:<name>\n" " --log-level Set Logging Level to use, debug, info, warn, etc\n" " --limit-fds Limit number of fds supported\n", - lo_always}; + lo_always +}; static bool logging_to_stdout = false; /* set when --log stdout specified */ @@ -358,6 +362,8 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) strlcpy(frr_protonameinst, di->logname, sizeof(frr_protonameinst)); di->cli_mode = FRR_CLI_CLASSIC; + di->graceful_restart = false; + di->gr_cleanup_time = 0; /* we may be starting with extra FDs open for whatever purpose, * e.g. logging, some module, etc. Recording them here allows later @@ -520,6 +526,11 @@ static int frr_opt(int opt) di->db_file = optarg; break; #endif + case 'K': + di->graceful_restart = true; + if (optarg) + di->gr_cleanup_time = atoi(optarg); + break; case 'C': if (di->flags & FRR_NO_SPLIT_CONFIG) return 1; diff --git a/lib/libfrr.h b/lib/libfrr.h index 77d70448a9..db9cfbcb1f 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -118,6 +118,8 @@ struct frr_daemon_info { bool dryrun; bool daemon_mode; bool terminal; + bool graceful_restart; + int gr_cleanup_time; enum frr_cli_mode cli_mode; struct event *read_in; diff --git a/lib/libospf.h b/lib/libospf.h index 0ac490a00e..8a208beb3c 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -58,8 +58,10 @@ extern "C" { #define OSPF_HELLO_DELAY_DEFAULT 10 #define OSPF_ROUTER_PRIORITY_DEFAULT 1 #define OSPF_RETRANSMIT_INTERVAL_DEFAULT 5 +#define OSPF_RETRANSMIT_WINDOW_DEFAULT 50 /* milliseconds */ #define OSPF_TRANSMIT_DELAY_DEFAULT 1 #define OSPF_DEFAULT_BANDWIDTH 10000 /* Mbps */ +#define OSPF_ACK_DELAY_DEFAULT 1 #define OSPF_DEFAULT_REF_BANDWIDTH 100000 /* Kbps */ diff --git a/lib/seqlock.c b/lib/seqlock.c index 62ce316920..e74e6718bf 100644 --- a/lib/seqlock.c +++ b/lib/seqlock.c @@ -26,6 +26,39 @@ * OS specific synchronization wrappers * ****************************************/ +#ifndef __has_feature /* not available on old GCC */ +#define __has_feature(x) 0 +#endif + +#if (defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)) +/* TSAN really does not understand what is going on with the low-level + * futex/umtx calls. This leads to a whole bunch of warnings, a lot of which + * also have _extremely_ misleading text - since TSAN does not understand that + * there is in fact a synchronization primitive involved, it can end up pulling + * in completely unrelated things. + * + * What does work is the "unsupported platform" seqlock implementation based + * on a pthread mutex + condvar, since TSAN of course suppports these. + * + * It may be possible to also fix this with TSAN annotations (__tsan_acquire + * and __tsan_release), but using those (correctly) is not easy either, and + * for now just get things rolling. + */ + +#ifdef HAVE_SYNC_LINUX_FUTEX +#undef HAVE_SYNC_LINUX_FUTEX +#endif + +#ifdef HAVE_SYNC_OPENBSD_FUTEX +#undef HAVE_SYNC_OPENBSD_FUTEX +#endif + +#ifdef HAVE_SYNC_UMTX_OP +#undef HAVE_SYNC_UMTX_OP +#endif + +#endif /* TSAN */ + /* * Linux: sys_futex() */ diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index e15871ac81..2af4ae3170 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -110,6 +110,9 @@ void ospf_area_update_fr_state(struct ospf_area *area) static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_interface *oi = inbr->oi; + /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgment sent. If interface is in Backup state @@ -122,12 +125,27 @@ static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr, worked out previously */ /* Deal with router as BDR */ - if (inbr->oi->state == ISM_Backup && !NBR_IS_DR(inbr)) + if (oi->state == ISM_Backup && !NBR_IS_DR(inbr)) return; - /* Schedule a delayed LSA Ack to be sent */ - listnode_add(inbr->oi->ls_ack, - ospf_lsa_lock(lsa)); /* delayed LSA Ack */ + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue", + __func__, lsa->data->type, &lsa->data->id, + &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), &inbr->router_id, + IF_NAME(inbr->oi)); + + /* Add the LSA to the interface delayed Ack list. */ + ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); + ls_ack_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&oi->ls_ack_delayed, ls_ack_list_entry); + + /* Set LS Ack timer if it is not already scheduled. */ + if (!oi->t_ls_ack_delayed) + OSPF_ISM_TIMER_ON(oi->t_ls_ack_delayed, + ospf_ls_ack_delayed_timer, + oi->v_ls_ack_delayed); } /* Check LSA is related to external info. */ @@ -1015,7 +1033,7 @@ void ospf_ls_request_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) ospf_lsdb_delete(&nbr->ls_req, lsa); } -/* Remove all LSA from neighbor's ls-requenst list. */ +/* Remove all LSAs from neighbor's ls-request list. */ void ospf_ls_request_delete_all(struct ospf_neighbor *nbr) { ospf_lsa_unlock(&nbr->ls_req_last); @@ -1061,58 +1079,114 @@ int ospf_ls_retransmit_isempty(struct ospf_neighbor *nbr) /* Add LSA to be retransmitted to neighbor's ls-retransmit list. */ void ospf_ls_retransmit_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { - struct ospf_lsa *old; + struct ospf_lsdb_linked_node *ls_rxmt_node; + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + struct ospf_lsa *old = NULL; + bool rxmt_head_replaced = false; - old = ospf_ls_retransmit_lookup(nbr, lsa); + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + if (ls_rxmt_node) + old = ls_rxmt_node->info; if (ospf_lsa_more_recent(old, lsa) < 0) { if (old) { old->retransmit_counter--; + if (ls_rxmt_node->lsa_list_entry == + ospf_lsa_list_first(&nbr->ls_rxmt_list)) + rxmt_head_replaced = true; + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_node->lsa_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry); + ospf_lsdb_delete(&nbr->ls_rxmt, old); if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]", + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Old Delete LSA[%s] on Add", ospf_ls_retransmit_count(nbr), &nbr->router_id, ospf_get_name(nbr->oi->ospf), - dump_lsa_key(old)); - ospf_lsdb_delete(&nbr->ls_rxmt, old); + dump_lsa_key(lsa)); + ospf_lsa_unlock(&old); } lsa->retransmit_counter++; + ls_rxmt_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); + /* + * Set the LSA retransmission time for the neighbor; + */ + monotime(&ls_rxmt_list_entry->list_entry_time); + ls_rxmt_list_entry->list_entry_time.tv_sec += nbr->v_ls_rxmt; + /* - * We cannot make use of the newly introduced callback function - * "lsdb->new_lsa_hook" to replace debug output below, just - * because - * it seems no simple and smart way to pass neighbor information - * to - * the common function "ospf_lsdb_add()" -- endo. + * Add the LSA to the neighbor retransmission list. */ + ls_rxmt_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&nbr->ls_rxmt_list, ls_rxmt_list_entry); + ospf_lsdb_add(&nbr->ls_rxmt, lsa); + + /* + * Look up the newly added node and set the list pointer. + */ + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + ls_rxmt_node->lsa_list_entry = ls_rxmt_list_entry; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RXmtL(%lu)++, NBR(%pI4(%s)), LSA[%s]", + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Add LSA[%s] retrans at (%ld/%ld)", ospf_ls_retransmit_count(nbr), - &nbr->router_id, - ospf_get_name(nbr->oi->ospf), - dump_lsa_key(lsa)); - ospf_lsdb_add(&nbr->ls_rxmt, lsa); + &nbr->router_id, ospf_get_name(nbr->oi->ospf), + dump_lsa_key(lsa), + (long)ls_rxmt_list_entry->list_entry_time + .tv_sec, + (long)ls_rxmt_list_entry->list_entry_time + .tv_usec); + /* + * Reset the neighbor LSA retransmission timer if isn't currently + * running or the LSA at the head of the list was updated. + */ + if (!nbr->t_ls_rxmt || rxmt_head_replaced) + ospf_ls_retransmit_set_timer(nbr); } } /* Remove LSA from neibghbor's ls-retransmit list. */ void ospf_ls_retransmit_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { - if (ospf_ls_retransmit_lookup(nbr, lsa)) { + struct ospf_lsdb_linked_node *ls_rxmt_node; + + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + + if (ls_rxmt_node) { + bool rxmt_timer_reset; + + if (ls_rxmt_node->lsa_list_entry == + ospf_lsa_list_first(&nbr->ls_rxmt_list)) + rxmt_timer_reset = true; + else + rxmt_timer_reset = false; + lsa->retransmit_counter--; - if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) /* -- endo. */ - zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]", + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_node->lsa_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry); + ospf_lsdb_delete(&nbr->ls_rxmt, lsa); + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Delete LSA[%s]", ospf_ls_retransmit_count(nbr), - &nbr->router_id, - ospf_get_name(nbr->oi->ospf), + &nbr->router_id, ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); - ospf_lsdb_delete(&nbr->ls_rxmt, lsa); + ospf_lsa_unlock(&lsa); + + /* + * If the LS retransmission entry at the head of the list was + * deleted, reset the timer. + */ + if (rxmt_timer_reset) + ospf_ls_retransmit_set_timer(nbr); } } /* Clear neighbor's ls-retransmit list. */ void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr) { + struct ospf_lsa_list_entry *ls_rxmt_list_entry; struct ospf_lsdb *lsdb; int i; @@ -1128,10 +1202,54 @@ void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr) ospf_ls_retransmit_delete(nbr, lsa); } + frr_each_safe (ospf_lsa_list, &nbr->ls_rxmt_list, ls_rxmt_list_entry) { + ospf_lsa_list_del(&nbr->ls_rxmt_list, ls_rxmt_list_entry); + ospf_lsa_unlock(&ls_rxmt_list_entry->lsa); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_list_entry); + } + ospf_lsa_unlock(&nbr->ls_req_last); nbr->ls_req_last = NULL; } +/* + * Set the neighbor's ls-retransmit timer based on the next + * LSA retransmit time. + */ +void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr) +{ + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + + if (nbr->t_ls_rxmt) + EVENT_OFF(nbr->t_ls_rxmt); + + ls_rxmt_list_entry = ospf_lsa_list_first(&nbr->ls_rxmt_list); + if (ls_rxmt_list_entry) { + struct timeval current_time, delay; + unsigned long delay_milliseconds; + + monotime(¤t_time); + if (timercmp(¤t_time, + &ls_rxmt_list_entry->list_entry_time, >=)) + delay_milliseconds = 10; + else { + timersub(&ls_rxmt_list_entry->list_entry_time, + ¤t_time, &delay); + delay_milliseconds = (delay.tv_sec * 1000) + + (delay.tv_usec / 1000); + } + + event_add_timer_msec(master, ospf_ls_rxmt_timer, nbr, + delay_milliseconds, &nbr->t_ls_rxmt); + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) retrans timer set in %ld msecs - Head LSA(%s)", + ospf_ls_retransmit_count(nbr), + &nbr->router_id, ospf_get_name(nbr->oi->ospf), + delay_milliseconds, + dump_lsa_key(ls_rxmt_list_entry->lsa)); + } +} + /* Lookup LSA from neighbor's ls-retransmit list. */ struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h index 3757400d0c..2412052970 100644 --- a/ospfd/ospf_flood.h +++ b/ospfd/ospf_flood.h @@ -7,6 +7,39 @@ #ifndef _ZEBRA_OSPF_FLOOD_H #define _ZEBRA_OSPF_FLOOD_H +#include "typesafe.h" + +/* + * OSPF Temporal LSA List + */ +PREDECL_DLIST(ospf_lsa_list); + +struct ospf_lsa_list_entry { + /* Linkage for LSA List */ + struct ospf_lsa_list_item list_linkage; + + union { + /* + * Time associated with the list entry. For example, for a + * neigbhor link retransmission list, this is the + * retransmission time. + */ + struct timeval list_entry_timeval; + + /* + * Destanation address specific to the LSA list. For example, + * the distination for an associated direct LS acknowledgment. + */ + struct in_addr list_entry_dst_addr; + } u; + + struct ospf_lsa *lsa; +}; +#define list_entry_time u.list_entry_timeval +#define list_entry_dst u.list_entry_dst_addr + +DECLARE_DLIST(ospf_lsa_list, struct ospf_lsa_list_entry, list_linkage); + extern int ospf_flood(struct ospf *, struct ospf_neighbor *, struct ospf_lsa *, struct ospf_lsa *); extern int ospf_flood_through(struct ospf *, struct ospf_neighbor *, @@ -36,6 +69,8 @@ extern void ospf_ls_retransmit_add(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_clear(struct ospf_neighbor *); +extern void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr); + extern struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete_nbr_area(struct ospf_area *, diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 11ac7af7c9..c4210eb70c 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -186,10 +186,12 @@ static void ospf_if_default_variables(struct ospf_interface *oi) oi->crypt_seqnum = 0; - /* This must be short, (less than RxmtInterval) - - RFC 2328 Section 13.5 para 3. Set to 1 second to avoid Acks being - held back for too long - MAG */ - oi->v_ls_ack = 1; + /* + * The OSPF LS ACK Delay timer must be less than the LS Retransmision + * timer. As per RFC 2328 Section 13.5 paragraph 3, Set to 1 second + * to avoid Acks being held back for too long + */ + oi->v_ls_ack_delayed = OSPF_ACK_DELAY_DEFAULT; } /* lookup oi for specified prefix/ifp */ @@ -272,9 +274,9 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, /* Initialize static neighbor list. */ oi->nbr_nbma = list_new(); - /* Initialize Link State Acknowledgment list. */ - oi->ls_ack = list_new(); - oi->ls_ack_direct.ls_ack = list_new(); + /* Initialize Link State Acknowledgment lists. */ + ospf_lsa_list_init(&oi->ls_ack_delayed); + ospf_lsa_list_init(&oi->ls_ack_direct); /* Set default values. */ ospf_if_default_variables(oi); @@ -306,6 +308,22 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, return oi; } +/* + * Cleanup Interface Ack List + */ +static void ospf_if_cleanup_ack_list(struct ospf_lsa_list_head *ls_ack_list) +{ + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *lsa; + + frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; + ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } +} + /* Restore an interface to its pre UP state Used from ism_interface_down only */ void ospf_if_cleanup(struct ospf_interface *oi) @@ -314,7 +332,6 @@ void ospf_if_cleanup(struct ospf_interface *oi) struct listnode *node, *nnode; struct ospf_neighbor *nbr; struct ospf_nbr_nbma *nbr_nbma; - struct ospf_lsa *lsa; /* oi->nbrs and oi->nbr_nbma should be deleted on InterfaceDown event */ /* delete all static neighbors attached to this interface */ @@ -338,10 +355,9 @@ void ospf_if_cleanup(struct ospf_interface *oi) OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); } - /* Cleanup Link State Acknowlegdment list. */ - for (ALL_LIST_ELEMENTS(oi->ls_ack, node, nnode, lsa)) - ospf_lsa_unlock(&lsa); /* oi->ls_ack */ - list_delete_all_node(oi->ls_ack); + /* Cleanup Link State Delayed Acknowlegdment list. */ + ospf_if_cleanup_ack_list(&oi->ls_ack_delayed); + ospf_if_cleanup_ack_list(&oi->ls_ack_direct); oi->crypt_seqnum = 0; @@ -377,8 +393,8 @@ void ospf_if_free(struct ospf_interface *oi) /* Free any lists that should be freed */ list_delete(&oi->nbr_nbma); - list_delete(&oi->ls_ack); - list_delete(&oi->ls_ack_direct.ls_ack); + ospf_if_cleanup_ack_list(&oi->ls_ack_delayed); + ospf_if_cleanup_ack_list(&oi->ls_ack_direct); if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: ospf interface %s vrf %s id %u deleted", @@ -542,6 +558,7 @@ static struct ospf_if_params *ospf_new_if_params(void) UNSET_IF_PARAM(oip, output_cost_cmd); UNSET_IF_PARAM(oip, transmit_delay); UNSET_IF_PARAM(oip, retransmit_interval); + UNSET_IF_PARAM(oip, retransmit_window); UNSET_IF_PARAM(oip, passive_interface); UNSET_IF_PARAM(oip, v_hello); UNSET_IF_PARAM(oip, fast_hello); @@ -599,6 +616,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr) if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd) && !OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay) && !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval) && + !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_window) && !OSPF_IF_PARAM_CONFIGURED(oip, passive_interface) && !OSPF_IF_PARAM_CONFIGURED(oip, v_hello) && !OSPF_IF_PARAM_CONFIGURED(oip, fast_hello) && @@ -695,6 +713,9 @@ int ospf_if_new_hook(struct interface *ifp) IF_DEF_PARAMS(ifp)->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window); + IF_DEF_PARAMS(ifp)->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), priority); IF_DEF_PARAMS(ifp)->priority = OSPF_ROUTER_PRIORITY_DEFAULT; diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 45d0b7943a..78a4fb9e59 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -13,6 +13,7 @@ #include "keychain.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" +#include <ospfd/ospf_flood.h> #define IF_OSPF_IF_INFO(I) ((struct ospf_if_info *)((I)->info)) #define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params) @@ -47,6 +48,8 @@ struct ospf_if_params { output_cost_cmd); /* Command Interface Output Cost */ DECLARE_IF_PARAM(uint32_t, retransmit_interval); /* Retransmission Interval */ + DECLARE_IF_PARAM(uint32_t, + retransmit_window); /* Retransmission Window */ DECLARE_IF_PARAM(uint8_t, passive_interface); /* OSPF Interface is passive: no sending or receiving (no need to @@ -263,20 +266,20 @@ struct ospf_interface { struct route_table *ls_upd_queue; - struct list *ls_ack; /* Link State Acknowledgment list. */ - - struct { - struct list *ls_ack; - struct in_addr dst; - } ls_ack_direct; + /* + * List of LSAs for delayed and direct link + * state acknowledgment transmission. + */ + struct ospf_lsa_list_head ls_ack_delayed; + struct ospf_lsa_list_head ls_ack_direct; /* Timer values. */ - uint32_t v_ls_ack; /* Delayed Link State Acknowledgment */ + uint32_t v_ls_ack_delayed; /* Delayed Link State Acknowledgment */ /* Threads. */ struct event *t_hello; /* timer */ struct event *t_wait; /* timer */ - struct event *t_ls_ack; /* timer */ + struct event *t_ls_ack_delayed; /* timer */ struct event *t_ls_ack_direct; /* event */ struct event *t_ls_upd_event; /* event */ struct event *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */ @@ -296,6 +299,7 @@ struct ospf_interface { uint32_t ls_ack_out; /* LS Ack message output count. */ uint32_t discarded; /* discarded input count by error. */ uint32_t state_change; /* Number of status change. */ + uint32_t ls_rxmt_lsa; /* Number of LSAs retransmitted. */ uint32_t full_nbrs; diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 878ab725bd..377e7a6bcc 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -285,7 +285,7 @@ static void ism_timer_set(struct ospf_interface *oi) reset also. */ EVENT_OFF(oi->t_hello); EVENT_OFF(oi->t_wait); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); EVENT_OFF(oi->gr.hello_delay.t_grace_send); break; case ISM_Loopback: @@ -293,7 +293,7 @@ static void ism_timer_set(struct ospf_interface *oi) unavailable for regular data traffic. */ EVENT_OFF(oi->t_hello); EVENT_OFF(oi->t_wait); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); EVENT_OFF(oi->gr.hello_delay.t_grace_send); break; case ISM_Waiting: @@ -304,7 +304,7 @@ static void ism_timer_set(struct ospf_interface *oi) OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); OSPF_ISM_TIMER_ON(oi->t_wait, ospf_wait_timer, OSPF_IF_PARAM(oi, v_wait)); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); break; case ISM_PointToPoint: /* The interface connects to a physical Point-to-point network @@ -314,8 +314,6 @@ static void ism_timer_set(struct ospf_interface *oi) /* send first hello immediately */ OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_DROther: /* The network type of the interface is broadcast or NBMA @@ -324,8 +322,6 @@ static void ism_timer_set(struct ospf_interface *oi) Backup Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_Backup: /* The network type of the interface is broadcast os NBMA @@ -333,8 +329,6 @@ static void ism_timer_set(struct ospf_interface *oi) and the router is Backup Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_DR: /* The network type of the interface is broadcast or NBMA @@ -342,8 +336,6 @@ static void ism_timer_set(struct ospf_interface *oi) and the router is Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; } } diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c index 0111c4924e..d1b3eb0d35 100644 --- a/ospfd/ospf_lsdb.c +++ b/ospfd/ospf_lsdb.c @@ -34,6 +34,59 @@ void ospf_lsdb_init(struct ospf_lsdb *lsdb) lsdb->type[i].db = route_table_init(); } +static struct route_node * +ospf_lsdb_linked_node_create(route_table_delegate_t *delegate, + struct route_table *table) +{ + struct ospf_lsdb_linked_node *node; + + node = XCALLOC(MTYPE_OSPF_LSDB_NODE, + sizeof(struct ospf_lsdb_linked_node)); + + return (struct route_node *)node; +} + +static void ospf_lsdb_linked_node_destroy(route_table_delegate_t *delegate, + struct route_table *table, + struct route_node *node) +{ + struct ospf_lsdb_linked_node *lsdb_linked_node = + (struct ospf_lsdb_linked_node *)node; + + XFREE(MTYPE_OSPF_LSDB_NODE, lsdb_linked_node); +} + +static route_table_delegate_t ospf_lsdb_linked_table_delegate = { + .create_node = ospf_lsdb_linked_node_create, + .destroy_node = ospf_lsdb_linked_node_destroy, +}; + +void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb) +{ + int i; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + lsdb->type[i].db = route_table_init_with_delegate( + &ospf_lsdb_linked_table_delegate); +} + +struct ospf_lsdb_linked_node *ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb, + struct ospf_lsa *lsa) +{ + struct ospf_lsdb_linked_node *lsdb_linked_node; + struct route_table *table; + struct prefix_ls lp; + + table = lsdb->type[lsa->data->type].db; + ls_prefix_set(&lp, lsa); + lsdb_linked_node = (struct ospf_lsdb_linked_node *) + route_node_lookup(table, (struct prefix *)&lp); + if (lsdb_linked_node) + route_unlock_node((struct route_node *)lsdb_linked_node); + + return lsdb_linked_node; +} + void ospf_lsdb_free(struct ospf_lsdb *lsdb) { ospf_lsdb_cleanup(lsdb); diff --git a/ospfd/ospf_lsdb.h b/ospfd/ospf_lsdb.h index bf295ca830..e5e3be8baa 100644 --- a/ospfd/ospf_lsdb.h +++ b/ospfd/ospf_lsdb.h @@ -7,6 +7,9 @@ #ifndef _ZEBRA_OSPF_LSDB_H #define _ZEBRA_OSPF_LSDB_H +#include "prefix.h" +#include "table.h" + /* OSPF LSDB structure. */ struct ospf_lsdb { struct { @@ -43,9 +46,29 @@ struct ospf_lsdb { #define AREA_LSDB(A,T) ((A)->lsdb->type[(T)].db) #define AS_LSDB(O,T) ((O)->lsdb->type[(T)].db) +/* + * Alternate route node structure for LSDB nodes linked to + * list elements. + */ +struct ospf_lsdb_linked_node { + /* + * Caution these must be the very first fields + */ + ROUTE_NODE_FIELDS + + /* + * List entry on an LSA list, e.g., a neighbor + * retransmission list. + */ + struct ospf_lsa_list_entry *lsa_list_entry; +}; + /* OSPF LSDB related functions. */ extern struct ospf_lsdb *ospf_lsdb_new(void); extern void ospf_lsdb_init(struct ospf_lsdb *); +extern void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb); +extern struct ospf_lsdb_linked_node * +ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa); extern void ospf_lsdb_free(struct ospf_lsdb *); extern void ospf_lsdb_cleanup(struct ospf_lsdb *); extern void ls_prefix_set(struct prefix_ls *lp, struct ospf_lsa *lsa); diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c index 9854c8cae8..478af323d3 100644 --- a/ospfd/ospf_memory.c +++ b/ospfd/ospf_memory.c @@ -45,3 +45,5 @@ DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper"); DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation"); DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space"); DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space"); +DEFINE_MTYPE(OSPFD, OSPF_LSA_LIST, "OSPF LSA List"); +DEFINE_MTYPE(OSPFD, OSPF_LSDB_NODE, "OSPF LSDB Linked Node"); diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h index d11b69abb0..e2139b517b 100644 --- a/ospfd/ospf_memory.h +++ b/ospfd/ospf_memory.h @@ -44,5 +44,7 @@ DECLARE_MTYPE(OSPF_GR_HELPER); DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR); DECLARE_MTYPE(OSPF_P_SPACE); DECLARE_MTYPE(OSPF_Q_SPACE); +DECLARE_MTYPE(OSPF_LSA_LIST); +DECLARE_MTYPE(OSPF_LSDB_NODE); #endif /* _QUAGGA_OSPF_MEMORY_H */ diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index d47d581605..2514fc0ab3 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -68,7 +68,7 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval); nbr->priority = -1; /* DD flags. */ @@ -80,8 +80,10 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->nbr_nbma = NULL; ospf_lsdb_init(&nbr->db_sum); - ospf_lsdb_init(&nbr->ls_rxmt); + + ospf_lsdb_linked_init(&nbr->ls_rxmt); ospf_lsdb_init(&nbr->ls_req); + ospf_lsa_list_init(&nbr->ls_rxmt_list); nbr->crypt_seqnum = 0; @@ -128,7 +130,7 @@ void ospf_nbr_free(struct ospf_neighbor *nbr) EVENT_OFF(nbr->t_inactivity); EVENT_OFF(nbr->t_db_desc); EVENT_OFF(nbr->t_ls_req); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); /* Cancel all events. */ /* Thread lookup cost would be negligible. */ event_cancel_event(master, nbr); diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h index 07d095f03d..0e041f9e6d 100644 --- a/ospfd/ospf_neighbor.h +++ b/ospfd/ospf_neighbor.h @@ -9,6 +9,7 @@ #include <ospfd/ospf_gr.h> #include <ospfd/ospf_packet.h> +#include <ospfd/ospf_flood.h> /* Neighbor Data Structure */ struct ospf_neighbor { @@ -44,6 +45,7 @@ struct ospf_neighbor { /* LSA data. */ struct ospf_lsdb ls_rxmt; + struct ospf_lsa_list_head ls_rxmt_list; struct ospf_lsdb db_sum; struct ospf_lsdb ls_req; struct ospf_lsa *ls_req_last; @@ -54,13 +56,13 @@ struct ospf_neighbor { uint32_t v_inactivity; uint32_t v_db_desc; uint32_t v_ls_req; - uint32_t v_ls_upd; + uint32_t v_ls_rxmt; /* Threads. */ struct event *t_inactivity; struct event *t_db_desc; struct event *t_ls_req; - struct event *t_ls_upd; + struct event *t_ls_rxmt; struct event *t_hello_reply; /* NBMA configured neighbour */ @@ -71,6 +73,7 @@ struct ospf_neighbor { struct timeval ts_last_regress; /* last regressive NSM change */ const char *last_regress_str; /* Event which last regressed NSM */ uint32_t state_change; /* NSM state change counter */ + uint32_t ls_rxmt_lsa; /* Number of LSAs retransmited. */ /* BFD information */ struct bfd_session_params *bfd_session; diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index c466ddcc6f..079a1fa55e 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -112,18 +112,16 @@ static void nsm_timer_set(struct ospf_neighbor *nbr) case NSM_Init: case NSM_TwoWay: EVENT_OFF(nbr->t_db_desc); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); EVENT_OFF(nbr->t_ls_req); break; case NSM_ExStart: OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); EVENT_OFF(nbr->t_ls_req); break; case NSM_Exchange: - OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, - nbr->v_ls_upd); if (!IS_SET_DD_MS(nbr->dd_flags)) EVENT_OFF(nbr->t_db_desc); break; diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 87aaccad92..2d15a7ecca 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -292,54 +292,66 @@ void ospf_ls_req_event(struct ospf_neighbor *nbr) event_add_event(master, ospf_ls_req_timer, nbr, 0, &nbr->t_ls_req); } -/* Cyclic timer function. Fist registered in ospf_nbr_new () in - ospf_neighbor.c */ -void ospf_ls_upd_timer(struct event *thread) +/* + * OSPF neighbor link state retransmission timer handler. Unicast + * unacknowledged LSAs to the neigbhors. + */ +void ospf_ls_rxmt_timer(struct event *thread) { struct ospf_neighbor *nbr; + int retransmit_interval, retransmit_window, rxmt_lsa_count = 0; nbr = EVENT_ARG(thread); - nbr->t_ls_upd = NULL; + nbr->t_ls_rxmt = NULL; + retransmit_interval = nbr->v_ls_rxmt; + retransmit_window = OSPF_IF_PARAM(nbr->oi, retransmit_window); /* Send Link State Update. */ if (ospf_ls_retransmit_count(nbr) > 0) { + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + struct timeval current_time, latest_rxmt_time, next_rxmt_time; + struct timeval rxmt_interval = { retransmit_interval, 0 }; + struct timeval rxmt_window; struct list *update; - struct ospf_lsdb *lsdb; - int i; - int retransmit_interval; - retransmit_interval = - OSPF_IF_PARAM(nbr->oi, retransmit_interval); + /* + * Set the retransmission window based on the configured value + * in milliseconds. + */ + rxmt_window.tv_sec = retransmit_window / 1000; + rxmt_window.tv_usec = (retransmit_window % 1000) * 1000; + + /* + * Calculate the latest retransmit time for LSAs transmited in + * this timer pass by adding the retransmission window to the + * current time. Calculate the next retransmission time by adding + * the retransmit interval to the current time. + */ + monotime(¤t_time); + timeradd(¤t_time, &rxmt_window, &latest_rxmt_time); + timeradd(¤t_time, &rxmt_interval, &next_rxmt_time); - lsdb = &nbr->ls_rxmt; update = list_new(); + while ((ls_rxmt_list_entry = + ospf_lsa_list_first(&nbr->ls_rxmt_list))) { + if (timercmp(&ls_rxmt_list_entry->list_entry_time, + &latest_rxmt_time, >)) + break; - for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { - struct route_table *table = lsdb->type[i].db; - struct route_node *rn; - - for (rn = route_top(table); rn; rn = route_next(rn)) { - struct ospf_lsa *lsa; - - if ((lsa = rn->info) != NULL) { - /* Don't retransmit an LSA if we - received it within - the last RxmtInterval seconds - this - is to allow the - neighbour a chance to acknowledge the - LSA as it may - have ben just received before the - retransmit timer - fired. This is a small tweak to what - is in the RFC, - but it will cut out out a lot of - retransmit traffic - - MAG */ - if (monotime_since(&lsa->tv_recv, NULL) - >= retransmit_interval * 1000000LL) - listnode_add(update, rn->info); - } - } + listnode_add(update, ls_rxmt_list_entry->lsa); + rxmt_lsa_count++; + + /* + * Set the next retransmit time for the LSA and move it + * to the end of the neighbor's retransmission list. + */ + ls_rxmt_list_entry->list_entry_time = next_rxmt_time; + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_list_entry); + ospf_lsa_list_add_tail(&nbr->ls_rxmt_list, + ls_rxmt_list_entry); + nbr->ls_rxmt_lsa++; + nbr->oi->ls_rxmt_lsa++; } if (listcount(update) > 0) @@ -348,23 +360,25 @@ void ospf_ls_upd_timer(struct event *thread) list_delete(&update); } + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) timer event - sent %u LSAs", + ospf_ls_retransmit_count(nbr), &nbr->router_id, + ospf_get_name(nbr->oi->ospf), rxmt_lsa_count); + /* Set LS Update retransmission timer. */ - OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd); + ospf_ls_retransmit_set_timer(nbr); } -void ospf_ls_ack_timer(struct event *thread) +void ospf_ls_ack_delayed_timer(struct event *thread) { struct ospf_interface *oi; oi = EVENT_ARG(thread); - oi->t_ls_ack = NULL; + oi->t_ls_ack_delayed = NULL; /* Send Link State Acknowledgment. */ - if (listcount(oi->ls_ack) > 0) + if (ospf_lsa_list_count(&oi->ls_ack_delayed)) ospf_ls_ack_send_delayed(oi); - - /* Set LS Ack timer. */ - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); } #ifdef WANT_OSPF_WRITE_FRAGMENT @@ -1803,7 +1817,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(lsa) && !current && ospf_check_nbr_status(oi->ospf)) { /* (4a) Response Link State Acknowledgment. */ - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); /* (4b) Discard LSA. */ if (IS_DEBUG_OSPF(lsa, LSA)) { @@ -1828,7 +1842,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(lsa)) { zlog_info("LSA[%s]: Boomerang effect?", dump_lsa_key(lsa)); - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); ospf_lsa_discard(lsa); if (current != NULL && !IS_LSA_MAXAGE(current)) @@ -1862,7 +1876,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, SET_FLAG(lsa->flags, OSPF_LSA_SELF); - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); if (!ospf->gr_info.restart_in_progress) { ospf_opaque_self_originated_lsa_received( @@ -2001,9 +2015,8 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, */ if (oi->state == ISM_Backup) if (NBR_IS_DR(nbr)) - listnode_add( - oi->ls_ack, - ospf_lsa_lock(lsa)); + ospf_ls_ack_send_direct(nbr, + lsa); DISCARD_LSA(lsa, 6); } else @@ -2012,7 +2025,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, receiving interface. */ { - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); DISCARD_LSA(lsa, 7); } } @@ -3314,17 +3327,36 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update, return length; } -static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, - struct stream *s) +static int ospf_make_ls_ack(struct ospf_interface *oi, + struct ospf_lsa_list_head *ls_ack_list, + bool direct_ack, bool delete_ack, struct stream *s) { - struct listnode *node, *nnode; + struct ospf_lsa_list_entry *ls_ack_list_first; + struct ospf_lsa_list_entry *ls_ack_list_entry; uint16_t length = OSPF_LS_ACK_MIN_SIZE; - unsigned long delta = OSPF_LSA_HEADER_SIZE; struct ospf_lsa *lsa; + struct in_addr first_dst_addr; - for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) { + /* + * For direct LS Acks, assure the destination address doesn't + * change between queued acknowledgments. + */ + if (direct_ack) { + ls_ack_list_first = ospf_lsa_list_first(ls_ack_list); + if (ls_ack_list_first) + first_dst_addr.s_addr = + ls_ack_list_first->list_entry_dst.s_addr; + } else + first_dst_addr.s_addr = INADDR_ANY; + + frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; assert(lsa); + if (direct_ack && (ls_ack_list_entry->list_entry_dst.s_addr != + first_dst_addr.s_addr)) + break; + /* LS Ack packet overflows interface MTU * delta is just number of bytes required for * 1 LS Ack(1 LS Hdr) ospf_packet_max will return @@ -3333,19 +3365,46 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, * against ospf_packet_max to check if it can fit * another ls header in the same packet. */ - if ((length + delta) > ospf_packet_max(oi)) + if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi)) break; stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE); length += OSPF_LSA_HEADER_SIZE; - listnode_delete(ack, lsa); - ospf_lsa_unlock(&lsa); /* oi->ls_ack_direct.ls_ack */ + if (delete_ack) { + ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } } return length; } +/* + * On non-braodcast networks, the same LS acks must be sent to multiple + * neighbors and deletion must be deferred until after the LS Ack packet + * is sent to all neighbors. + */ +static void ospf_delete_ls_ack_delayed(struct ospf_interface *oi) +{ + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *lsa; + uint16_t length = OSPF_LS_ACK_MIN_SIZE; + + frr_each_safe (ospf_lsa_list, &oi->ls_ack_delayed, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; + assert(lsa); + if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi)) + break; + + length += OSPF_LSA_HEADER_SIZE; + ospf_lsa_list_del(&oi->ls_ack_delayed, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } +} + static void ospf_hello_send_sub(struct ospf_interface *oi, in_addr_t addr) { struct ospf_packet *op; @@ -3917,10 +3976,13 @@ void ospf_ls_upd_send(struct ospf_neighbor *nbr, struct list *update, int flag, &oi->t_ls_upd_event); } -static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, +static void ospf_ls_ack_send_list(struct ospf_interface *oi, + struct ospf_lsa_list_head *ls_ack_list, + bool direct_ack, bool delete_ack, struct in_addr dst) { struct ospf_packet *op; + struct ospf_lsa_list_entry *ls_ack_list_first; uint16_t length = OSPF_HEADER_SIZE; op = ospf_packet_new(oi->ifp->mtu); @@ -3928,8 +3990,18 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, /* Prepare OSPF common header. */ ospf_make_header(OSPF_MSG_LS_ACK, oi, op->s); + /* Determine the destination address - for direct acks, + * the list entries always include the distination address. + */ + if (direct_ack) { + ls_ack_list_first = ospf_lsa_list_first(ls_ack_list); + op->dst.s_addr = ls_ack_list_first->list_entry_dst.s_addr; + } else + op->dst.s_addr = dst.s_addr; + /* Prepare OSPF Link State Acknowledgment body. */ - length += ospf_make_ls_ack(oi, ack, op->s); + length += ospf_make_ls_ack(oi, ls_ack_list, direct_ack, delete_ack, + op->s); /* Fill OSPF header. */ ospf_fill_header(oi, op->s, length); @@ -3937,14 +4009,6 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, /* Set packet length. */ op->length = length; - /* Decide destination address. */ - if (oi->type == OSPF_IFTYPE_POINTOPOINT || - (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && - !oi->p2mp_non_broadcast)) - op->dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else - op->dst.s_addr = dst.s_addr; - /* Add packet to the interface output queue. */ ospf_packet_add(oi, op); @@ -3952,34 +4016,96 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, OSPF_ISM_WRITE_ON(oi->ospf); } -static void ospf_ls_ack_send_event(struct event *thread) +static void ospf_ls_ack_send_direct_event(struct event *thread) { struct ospf_interface *oi = EVENT_ARG(thread); + struct in_addr dst = { INADDR_ANY }; oi->t_ls_ack_direct = NULL; - while (listcount(oi->ls_ack_direct.ls_ack)) - ospf_ls_ack_send_list(oi, oi->ls_ack_direct.ls_ack, - oi->ls_ack_direct.dst); + while (ospf_lsa_list_count(&oi->ls_ack_direct)) + ospf_ls_ack_send_list(oi, &(oi->ls_ack_direct), true, true, dst); } -void ospf_ls_ack_send(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { + struct ospf_lsa_list_entry *ls_ack_list_entry; struct ospf_interface *oi = nbr->oi; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue", + __func__, lsa->data->type, &lsa->data->id, + &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), &nbr->router_id, + IF_NAME(nbr->oi)); + + /* + * On Point-to-Multipoint broadcast-capabile interfaces, + * where direct acks from are sent to the ALLSPFRouters + * address and one direct ack send event, may include LSAs + * from multiple neighbors, there is a possibility of the same + * LSA being processed more than once in the same send event. + * In this case, the instances subsequent to the first can be + * ignored. + */ + if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && !oi->p2mp_non_broadcast) { + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *ack_queue_lsa; + + frr_each (ospf_lsa_list, &oi->ls_ack_direct, ls_ack_list_entry) { + ack_queue_lsa = ls_ack_list_entry->lsa; + if ((lsa == ack_queue_lsa) || + ((lsa->data->type == ack_queue_lsa->data->type) && + (lsa->data->id.s_addr == + ack_queue_lsa->data->id.s_addr) && + (lsa->data->adv_router.s_addr == + ack_queue_lsa->data->adv_router.s_addr) && + (lsa->data->ls_seqnum == + ack_queue_lsa->data->ls_seqnum))) { + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue duplicate", + __func__, lsa->data->type, + &lsa->data->id, + &lsa->data->adv_router, + ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), + &nbr->router_id, + IF_NAME(nbr->oi)); + return; + } + } + } + if (IS_GRACE_LSA(lsa)) { if (IS_DEBUG_OSPF_GR) zlog_debug("%s, Sending GRACE ACK to Restarter.", __func__); } - if (listcount(oi->ls_ack_direct.ls_ack) == 0) - oi->ls_ack_direct.dst = nbr->address.u.prefix4; + ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); - listnode_add(oi->ls_ack_direct.ls_ack, ospf_lsa_lock(lsa)); + /* + * Determine the destination address - Direct LS acknowledgments + * are sent the AllSPFRouters multicast address on Point-to-Point + * and Point-to-Multipoint broadcast-capable interfaces. For all other + * interface types, they are unicast directly to the neighbor. + */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT || + (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && + !oi->p2mp_non_broadcast)) + ls_ack_list_entry->list_entry_dst.s_addr = + htonl(OSPF_ALLSPFROUTERS); + else + ls_ack_list_entry->list_entry_dst.s_addr = + nbr->address.u.prefix4.s_addr; + + ls_ack_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&nbr->oi->ls_ack_direct, ls_ack_list_entry); - event_add_event(master, ospf_ls_ack_send_event, oi, 0, - &oi->t_ls_ack_direct); + if (oi->t_ls_ack_direct == NULL) + event_add_event(master, ospf_ls_ack_send_direct_event, oi, 0, + &oi->t_ls_ack_direct); } /* Send Link State Acknowledgment delayed. */ @@ -3996,33 +4122,39 @@ void ospf_ls_ack_send_delayed(struct ospf_interface *oi) struct ospf_neighbor *nbr; struct route_node *rn; - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { - nbr = rn->info; + while (ospf_lsa_list_count(&oi->ls_ack_delayed)) { + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; - if (!nbr) - continue; + if (!nbr) + continue; - if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) - while (listcount(oi->ls_ack)) - ospf_ls_ack_send_list( - oi, oi->ls_ack, - nbr->address.u.prefix4); + if (nbr != oi->nbr_self && + nbr->state >= NSM_Exchange) + ospf_ls_ack_send_list(oi, + &oi->ls_ack_delayed, + false, false, + nbr->address.u + .prefix4); + } + ospf_delete_ls_ack_delayed(oi); } - return; - } - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - dst.s_addr = oi->vl_data->peer_addr.s_addr; - else if (oi->state == ISM_DR || oi->state == ISM_Backup) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else if (oi->type == OSPF_IFTYPE_POINTOPOINT) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else - dst.s_addr = htonl(OSPF_ALLDROUTERS); + } else { + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + dst.s_addr = oi->vl_data->peer_addr.s_addr; + else if (oi->state == ISM_DR || oi->state == ISM_Backup) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOPOINT) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else + dst.s_addr = htonl(OSPF_ALLDROUTERS); - while (listcount(oi->ls_ack)) - ospf_ls_ack_send_list(oi, oi->ls_ack, dst); + while (ospf_lsa_list_count(&oi->ls_ack_delayed)) + ospf_ls_ack_send_list(oi, &oi->ls_ack_delayed, false, + true, dst); + } } /* diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h index 234738979e..84e4b027e6 100644 --- a/ospfd/ospf_packet.h +++ b/ospfd/ospf_packet.h @@ -135,13 +135,14 @@ extern void ospf_ls_upd_send(struct ospf_neighbor *, struct list *, int, int); extern void ospf_ls_upd_queue_send(struct ospf_interface *oi, struct list *update, struct in_addr addr, int send_lsupd_now); -extern void ospf_ls_ack_send(struct ospf_neighbor *, struct ospf_lsa *); +extern void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr, + struct ospf_lsa *lsa); extern void ospf_ls_ack_send_delayed(struct ospf_interface *); extern void ospf_ls_retransmit(struct ospf_interface *, struct ospf_lsa *); extern void ospf_ls_req_event(struct ospf_neighbor *); -extern void ospf_ls_upd_timer(struct event *thread); -extern void ospf_ls_ack_timer(struct event *thread); +extern void ospf_ls_rxmt_timer(struct event *thread); +extern void ospf_ls_ack_delayed_timer(struct event *thread); extern void ospf_poll_timer(struct event *thread); extern void ospf_hello_reply_timer(struct event *thread); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 3a11b21232..7a7a684dd6 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -815,6 +815,7 @@ struct ospf_vl_config_data { int del_keychain; int hello_interval; /* Obvious what these are... */ int retransmit_interval; + int retransmit_window; int transmit_delay; int dead_interval; }; @@ -957,6 +958,12 @@ static int ospf_vl_set_timers(struct ospf_vl_data *vl_data, vl_config->retransmit_interval; } + if (vl_config->retransmit_window) { + SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window); + IF_DEF_PARAMS(ifp)->retransmit_window = + vl_config->retransmit_window; + } + if (vl_config->transmit_delay) { SET_IF_PARAM(IF_DEF_PARAMS(ifp), transmit_delay); IF_DEF_PARAMS(ifp)->transmit_delay = vl_config->transmit_delay; @@ -1012,14 +1019,16 @@ static int ospf_vl_set(struct ospf *ospf, struct ospf_vl_config_data *vl_config) "Use null authentication\n" \ "Use message-digest authentication\n" -#define VLINK_HELPSTR_TIME_PARAM \ - "Time between HELLO packets\n" \ - "Seconds\n" \ - "Time between retransmitting lost link state advertisements\n" \ - "Seconds\n" \ - "Link state transmit delay\n" \ - "Seconds\n" \ - "Interval time after which a neighbor is declared down\n" \ +#define VLINK_HELPSTR_TIME_PARAM \ + "Time between HELLO packets\n" \ + "Seconds\n" \ + "Time between retransmitting lost link state advertisements\n" \ + "Seconds\n" \ + "Window for LSA retransmit - Retransmit LSAs expiring in this window\n" \ + "Milliseconds\n" \ + "Link state transmit delay\n" \ + "Seconds\n" \ + "Interval time after which a neighbor is declared down\n" \ "Seconds\n" #define VLINK_HELPSTR_AUTH_SIMPLE \ @@ -1204,7 +1213,7 @@ DEFUN (no_ospf_area_vlink, DEFUN (ospf_area_vlink_intervals, ospf_area_vlink_intervals_cmd, - "area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}", + "area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-10000)|transmit-delay (1-65535)|dead-interval (1-65535)}", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) { @@ -1236,6 +1245,9 @@ DEFUN (ospf_area_vlink_intervals, else if (strmatch(argv[idx]->text, "retransmit-interval")) vl_config.retransmit_interval = strtol(argv[++idx]->arg, NULL, 10); + else if (strmatch(argv[idx]->text, "retransmit-window")) + vl_config.retransmit_window = strtol(argv[++idx]->arg, + NULL, 10); else if (strmatch(argv[idx]->text, "transmit-delay")) vl_config.transmit_delay = strtol(argv[++idx]->arg, NULL, 10); @@ -1250,7 +1262,7 @@ DEFUN (ospf_area_vlink_intervals, DEFUN (no_ospf_area_vlink_intervals, no_ospf_area_vlink_intervals_cmd, - "no area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}", + "no area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-1000)|transmit-delay (1-65535)|dead-interval (1-65535)}", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) @@ -1282,6 +1294,9 @@ DEFUN (no_ospf_area_vlink_intervals, else if (strmatch(argv[idx]->text, "retransmit-interval")) vl_config.retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + else if (strmatch(argv[idx]->text, "retransmit-window")) + vl_config.retransmit_window = + OSPF_RETRANSMIT_WINDOW_DEFAULT; else if (strmatch(argv[idx]->text, "transmit-delay")) vl_config.transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; else if (strmatch(argv[idx]->text, "dead-interval")) @@ -3846,6 +3861,10 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add( json_interface_sub, "timerRetransmitSecs", OSPF_IF_PARAM(oi, retransmit_interval)); + json_object_int_add(json_interface_sub, + "timerRetransmitWindowMsecs", + OSPF_IF_PARAM(oi, + retransmit_window)); } else { vty_out(vty, " Timer intervals configured,"); vty_out(vty, " Hello "); @@ -3964,6 +3983,16 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, "nbrFilterPrefixList", "N/A"); } + + /* Non-Traffic interface counters + */ + if (use_json) + json_object_int_add(json_interface_sub, + "lsaRetransmissions", + oi->ls_rxmt_lsa); + else + vty_out(vty, " LSA retransmissions: %u\n", + oi->ls_rxmt_lsa); } } @@ -5177,12 +5206,20 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, lookup_msg(ospf_ism_state_msg, ospf_nbr_ism_state(nbr), NULL)); } + /* Show state changes. */ if (use_json) json_object_int_add(json_neigh, "stateChangeCounter", nbr->state_change); else - vty_out(vty, " %d state changes\n", nbr->state_change); + vty_out(vty, " %d state changes\n", nbr->state_change); + + /* Show LSA retransmissions. */ + if (use_json) + json_object_int_add(json_neigh, "lsaRetransmissions", + nbr->ls_rxmt_lsa); + else + vty_out(vty, " %u LSA retransmissions\n", nbr->ls_rxmt_lsa); if (nbr->ts_last_progress.tv_sec || nbr->ts_last_progress.tv_usec) { struct timeval res; @@ -5231,7 +5268,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, if (DR(oi).s_addr == INADDR_ANY) { if (!use_json) vty_out(vty, - " No designated router on this network\n"); + " No designated router on this network\n"); } else { nbr_dr = ospf_nbr_lookup_by_addr(oi->nbrs, &DR(oi)); if (nbr_dr) { @@ -5250,14 +5287,14 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, if (nbr_bdr == NULL) { if (!use_json) vty_out(vty, - " No backup designated router on this network\n"); + " No backup designated router on this network\n"); } else { if (use_json) json_object_string_addf(json_neigh, "routerDesignatedBackupId", "%pI4", &nbr_bdr->router_id); else - vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id); + vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id); } /* Show options. */ @@ -5347,7 +5384,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, /* Show Link State Update Retransmission thread. */ if (use_json) { - if (nbr->t_ls_upd != NULL) + if (nbr->t_ls_rxmt != NULL) json_object_string_add( json_neigh, "threadLinkStateUpdateRetransmission", @@ -5355,7 +5392,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, } else vty_out(vty, " Thread Link State Update Retransmission %s\n\n", - nbr->t_ls_upd != NULL ? "on" : "off"); + nbr->t_ls_rxmt != NULL ? "on" : "off"); if (!use_json) { vty_out(vty, " Graceful restart Helper info:\n"); @@ -7993,7 +8030,7 @@ static void ospf_nbr_timer_update(struct ospf_interface *oi) nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval); } } @@ -8728,6 +8765,40 @@ DEFUN_HIDDEN (no_ospf_retransmit_interval, return no_ip_ospf_retransmit_interval(self, vty, argc, argv); } +DEFPY(ip_ospf_retransmit_window, ip_ospf_retransmit_window_addr_cmd, + "[no] ip ospf retransmit-window ![(20-1000)]$retransmit-window [A.B.C.D]$ip_addr", NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Window for LSA retransmit - Retransmit LSAs expiring in this window\n" + "Milliseconds\n" + "Address of interface\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + + params = IF_DEF_PARAMS(ifp); + + if (ip_addr.s_addr != INADDR_ANY) { + params = ospf_get_if_params(ifp, ip_addr); + ospf_if_update_params(ifp, ip_addr); + } + + if (no) { + UNSET_IF_PARAM(params, retransmit_window); + params->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT; + } else { + SET_IF_PARAM(params, retransmit_window); + params->retransmit_window = retransmit_window; + } + + /* + * There is nothing to do when the retransmit-window changes, any + * change will take effect the next time the interface LSA retransmision + * timer expires. + */ + return CMD_SUCCESS; +} + DEFPY (ip_ospf_gr_hdelay, ip_ospf_gr_hdelay_cmd, "ip ospf graceful-restart hello-delay (1-1800)", @@ -12210,6 +12281,17 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) vty_out(vty, "\n"); } + /* Retransmit Window print. */ + if (OSPF_IF_PARAM_CONFIGURED(params, retransmit_window) && + params->retransmit_window != + OSPF_RETRANSMIT_WINDOW_DEFAULT) { + vty_out(vty, " ip ospf retransmit-window %u", + params->retransmit_window); + if (params != IF_DEF_PARAMS(ifp) && rn) + vty_out(vty, " %pI4", &rn->p.u.prefix4); + vty_out(vty, "\n"); + } + /* Transmit Delay print. */ if (OSPF_IF_PARAM_CONFIGURED(params, transmit_delay) && params->transmit_delay @@ -12567,19 +12649,22 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf) oi = vl_data->vl_oi; /* timers */ - if (OSPF_IF_PARAM(oi, v_hello) - != OSPF_HELLO_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, v_wait) - != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, retransmit_interval) - != OSPF_RETRANSMIT_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, transmit_delay) - != OSPF_TRANSMIT_DELAY_DEFAULT) + if (OSPF_IF_PARAM(oi, v_hello) != + OSPF_HELLO_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, v_wait) != + OSPF_ROUTER_DEAD_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, retransmit_interval) != + OSPF_RETRANSMIT_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, retransmit_window) != + OSPF_RETRANSMIT_WINDOW_DEFAULT || + OSPF_IF_PARAM(oi, transmit_delay) != + OSPF_TRANSMIT_DELAY_DEFAULT) vty_out(vty, - " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d transmit-delay %d dead-interval %d\n", + " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d retransmit-window %d transmit-delay %d dead-interval %d\n", buf, &vl_data->vl_peer, OSPF_IF_PARAM(oi, v_hello), OSPF_IF_PARAM(oi, retransmit_interval), + OSPF_IF_PARAM(oi, retransmit_window), OSPF_IF_PARAM(oi, transmit_delay), OSPF_IF_PARAM(oi, v_wait)); else @@ -13112,6 +13197,9 @@ static void ospf_vty_if_init(void) install_element(INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd); + /* "ip ospf retransmit-window" commands. */ + install_element(INTERFACE_NODE, &ip_ospf_retransmit_window_addr_cmd); + /* "ip ospf transmit-delay" commands. */ install_element(INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd); install_element(INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd); diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c index 5ce6985c45..24443404eb 100644 --- a/pimd/pim6_main.c +++ b/pimd/pim6_main.c @@ -94,6 +94,7 @@ struct frr_signal_t pim6d_signals[] = { }, }; +/* clang-format off */ static const struct frr_yang_module_info *const pim6d_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -105,7 +106,6 @@ static const struct frr_yang_module_info *const pim6d_yang_modules[] = { &frr_gmp_info, }; -/* clang-format off */ FRR_DAEMON_INFO(pim6d, PIM6, .vty_port = PIM6D_VTY_PORT, .proghelp = "Protocol Independent Multicast (RFC7761) for IPv6", diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h index ecba739a5a..7b0c3f0350 100644 --- a/pimd/pim_addr.h +++ b/pimd/pim_addr.h @@ -14,11 +14,13 @@ #if PIM_IPV == 4 typedef struct in_addr pim_addr; +typedef struct prefix_ipv4 prefix_pim; #define PIM_ADDRSTRLEN INET_ADDRSTRLEN #define PIM_AF AF_INET #define PIM_AFI AFI_IP #define PIM_PROTO_REG IPPROTO_RAW +#define PIM_IANA_AFI IANA_AFI_IPV4 #define PIM_IPADDR IPADDR_V4 #define ipaddr_pim ipaddr_v4 #define PIM_MAX_BITLEN IPV4_MAX_BITLEN @@ -44,11 +46,13 @@ union pimprefixconstptr { #else typedef struct in6_addr pim_addr; +typedef struct prefix_ipv6 prefix_pim; #define PIM_ADDRSTRLEN INET6_ADDRSTRLEN #define PIM_AF AF_INET6 #define PIM_AFI AFI_IP6 #define PIM_PROTO_REG IPPROTO_PIM +#define PIM_IANA_AFI IANA_AFI_IPV6 #define PIM_IPADDR IPADDR_V6 #define ipaddr_pim ipaddr_v6 #define PIM_MAX_BITLEN IPV6_MAX_BITLEN diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index df9161943d..2d451718a9 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -1451,3 +1451,8 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf, return 0; } + +void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc) +{ + /* stub for Candidate-RP */ +} diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 400db396c2..8f2ce0bed3 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -59,6 +59,7 @@ struct zebra_privs_t pimd_privs = { .cap_num_p = array_size(_caps_p), .cap_num_i = 0}; +/* clang-format off */ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -70,7 +71,6 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_gmp_info, }; -/* clang-format off */ FRR_DAEMON_INFO(pimd, PIM, .vty_port = PIMD_VTY_PORT, .proghelp = "Implementation of the PIM routing protocol.", diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 32cdf4bf82..57dcff3b47 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -161,18 +161,27 @@ void pim_nht_bsr_add(struct pim_instance *pim, pim_addr addr) pnc->bsr_count++; } +bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr) +{ + struct pim_nexthop_cache *pnc; + + pnc = pim_nht_get(pim, addr); + + pnc->candrp_count++; + return CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID); +} + static void pim_nht_drop_maybe(struct pim_instance *pim, struct pim_nexthop_cache *pnc) { if (PIM_DEBUG_PIM_NHT) - zlog_debug( - "%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u", - __func__, &pnc->rpf.rpf_addr, pim->vrf->name, - pnc->rp_list->count, pnc->upstream_hash->count, - pnc->bsr_count); + zlog_debug("%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u Cand-RP count:%u", + __func__, &pnc->rpf.rpf_addr, pim->vrf->name, + pnc->rp_list->count, pnc->upstream_hash->count, + pnc->bsr_count, pnc->candrp_count); - if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 - && pnc->bsr_count == 0) { + if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 && + pnc->bsr_count == 0 && pnc->candrp_count == 0) { struct zclient *zclient = pim_zebra_zclient_get(); pim_sendmsg_zebra_rnh(pim, zclient, pnc, @@ -258,6 +267,27 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr addr) pim_nht_drop_maybe(pim, pnc); } +void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr) +{ + struct pim_nexthop_cache *pnc = NULL; + struct pim_nexthop_cache lookup; + + lookup.rpf.rpf_addr = addr; + + pnc = hash_lookup(pim->rpf_hash, &lookup); + + if (!pnc) { + zlog_warn("attempting to delete nonexistent NHT C-RP entry %pPA", + &addr); + return; + } + + assertf(pnc->candrp_count > 0, "addr=%pPA", &addr); + pnc->candrp_count--; + + pim_nht_drop_maybe(pim, pnc); +} + bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, struct interface *src_ifp, pim_addr src_ip) { @@ -900,6 +930,9 @@ void pim_nexthop_update(struct vrf *vrf, struct prefix *match, pim_update_rp_nh(pim, pnc); if (pnc->upstream_hash->count) pim_update_upstream_nh(pim, pnc); + + if (pnc->candrp_count) + pim_crp_nht_update(pim, pnc); } int pim_ecmp_nexthop_lookup(struct pim_instance *pim, diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index a1feb76e3b..e74b375dc6 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -38,6 +38,7 @@ struct pim_nexthop_cache { * same BSR */ uint32_t bsr_count; + uint32_t candrp_count; }; struct pnc_hash_walk_data { @@ -71,4 +72,10 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr bsr_addr); bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, struct interface *src_ifp, pim_addr src_ip); void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp); + +/* wrappers for usage with Candidate RPs in BSMs */ +bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr); +void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr); +void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc); + #endif diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 1bc265b138..6a7e8924f2 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -636,17 +636,15 @@ static int pim_msg_send_frame(pim_addr src, pim_addr dst, ifindex_t ifindex, int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, int pim_msg_size, struct interface *ifp) { - struct pim_interface *pim_ifp; - + if (ifp) { + struct pim_interface *pim_ifp = ifp->info; - pim_ifp = ifp->info; - - if (pim_ifp->pim_passive_enable) { - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug( - "skip sending PIM message on passive interface %s", - ifp->name); - return 0; + if (pim_ifp->pim_passive_enable) { + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("skip sending PIM message on passive interface %s", + ifp->name); + return 0; + } } #if PIM_IPV == 4 @@ -710,7 +708,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, if (PIM_DEBUG_PIM_PACKETS) zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x", - __func__, &dst, ifp->name, pim_msg_size, + __func__, &dst, ifp ? ifp->name : "*", pim_msg_size, header->checksum); if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { @@ -718,7 +716,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, } pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to, - tolen, ifp->name); + tolen, ifp ? ifp->name : "*"); return 0; #else @@ -727,7 +725,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, iovector[0].iov_base = pim_msg; iovector[0].iov_len = pim_msg_size; - pim_msg_send_frame(src, dst, ifp->ifindex, &iovector[0], fd); + pim_msg_send_frame(src, dst, ifp ? ifp->ifindex : 0, &iovector[0], fd); return 0; #endif diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index d8d25712a3..49be9c0a73 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -543,6 +543,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, pim_zebra_update_all_interfaces(pim); pim_rp_check_interfaces(pim, rp_all); + if (rp_all->i_am_rp && PIM_DEBUG_PIM_NHT_RP) + zlog_debug("new RP %pPA for %pFX is ourselves", + &rp_all->rp.rpf_addr, &rp_all->group); pim_rp_refresh_group_to_rp_mapping(pim); pim_find_or_track_nexthop(pim, nht_p, NULL, rp_all, NULL); @@ -634,6 +637,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, pim_zebra_update_all_interfaces(pim); pim_rp_check_interfaces(pim, rp_info); + if (rp_info->i_am_rp && PIM_DEBUG_PIM_NHT_RP) + zlog_debug("new RP %pPA for %pFX is ourselves", + &rp_info->rp.rpf_addr, &rp_info->group); pim_rp_refresh_group_to_rp_mapping(pim); /* Register addr with Zebra NHT */ @@ -1101,16 +1107,17 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, pim_addr source, pim_addr group) { struct rp_info *rp_info; - struct prefix g; + struct prefix g = {}; - memset(&g, 0, sizeof(g)); + if (!pim_addr_is_any(source)) { + *up = source; + return 1; + } pim_addr_to_prefix(&g, group); - rp_info = pim_rp_find_match_group(pim, &g); - if (!rp_info || ((pim_rpf_addr_is_inaddr_any(&rp_info->rp)) && - (pim_addr_is_any(source)))) { + if (!rp_info || pim_rpf_addr_is_inaddr_any(&rp_info->rp)) { if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __func__); @@ -1118,11 +1125,7 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, return 0; } - if (pim_addr_is_any(source)) - *up = rp_info->rp.rpf_addr; - else - *up = source; - + *up = rp_info->rp.rpf_addr; return 1; } diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index f42079cd50..d6775e6e9c 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -30,6 +30,7 @@ %{!?with_rtadv: %global with_rtadv 1 } %{!?with_watchfrr: %global with_watchfrr 1 } %{!?with_pathd: %global with_pathd 1 } +%{!?with_grpc: %global with_grpc 0 } # user and group %{!?frr_user: %global frr_user frr } @@ -201,6 +202,12 @@ BuildRequires: python3-devel BuildRequires: python3-sphinx %endif %endif +%if %{with_grpc} +BuildRequires: grpc-devel >= 1.16.1 +BuildRequires: protobuf-devel >= 3.6.1 +BuildRequires: protobuf-compiler >= 3.6.1 +BuildRequires: protobuf-c-devel +%endif %if 0%{?rhel} > 7 #platform-python-devel is needed for /usr/bin/pathfix.py BuildRequires: platform-python-devel @@ -301,6 +308,17 @@ through the AgentX protocol. Provides read-only access to current routing state through standard SNMP MIBs. +%if %{with_grpc} +%package grpc +Summary: GRPC support for FRR daemons +Group: System Environment/Daemons +License: GPLv3+ +Requires: %{name} = %{version}-%{release} + +%description grpc +Adds GRPC support to the individual FRR daemons. +%endif + %prep %setup -q -n frr-%{frrversion} @@ -425,6 +443,11 @@ routing state through standard SNMP MIBs. %else --disable-pathd \ %endif +%if %{with_grpc} + --enable-grpc \ +%else + --disable-grpc \ +%endif --enable-snmp # end @@ -783,6 +806,12 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %{_libdir}/frr/modules/*snmp.so +%if %{with_grpc} +%files grpc +%{_libdir}/libfrrgrpc_pb.* +%{_libdir}/frr/modules/grpc.so +%endif + %files devel %{_libdir}/lib*.so %dir %{_includedir}/%{name} diff --git a/ripd/ripd.c b/ripd/ripd.c index b8a140c9ca..8768819fe2 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -1051,7 +1051,7 @@ static size_t rip_auth_md5_ah_write(struct stream *s, struct rip_interface *ri, /* RFC2080: The value used in the sequence number is arbitrary, but two suggestions are the time of the message's creation or a simple message counter. */ - stream_putl(s, ++seq); + stream_putl(s, seq++); /* Reserved field must be zero. */ stream_putl(s, 0); @@ -3054,7 +3054,10 @@ DEFUN (show_ip_rip, } vty_out(vty, - "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP\n" + "Codes: K - kernel route, C - connected, L - local, S - static,\n" + " R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,\n" + " T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,\n" + " f - OpenFabric, t - Table-Direct\n" "Sub-codes:\n" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n" " (i) - interface\n\n" diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index f4dadf377d..0aa2a9e486 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -2070,7 +2070,10 @@ DEFUN (show_ipv6_ripng, /* Header of display. */ vty_out(vty, - "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n" + "Codes: K - kernel route, C - connected, L - local, S - static,\n" + " R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,\n" + " T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,\n" + " f - OpenFabric, t - Table-Direct\n" "Sub-codes:\n" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n" " (i) - interface, (a/S) - aggregated/Suppressed\n\n" diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 133da918fa..1048436b43 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -247,12 +247,12 @@ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance, memcpy(&api.prefix, p, sizeof(*p)); api.flags = flags; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); /* Only send via ID if nhgroup has been successfully installed */ if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) { zapi_route_set_nhg_id(&api, &nhgid); } else { + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); for (ALL_NEXTHOPS_PTR(nhg, nh)) { /* Check if we set a VNI label */ if (nh->nh_label && diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index 4ea28cda2f..6fe6993fdf 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -55,7 +55,7 @@ static void test_run_spf(struct vty *vty, const struct isis_topology *topology, isis_run_spf(spftree); /* Print the SPT and the corresponding routing table. */ - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, NULL); isis_print_routes(vty, spftree, NULL, false, false); /* Cleanup SPF tree. */ @@ -85,7 +85,7 @@ static void test_run_lfa(struct vty *vty, const struct isis_topology *topology, isis_lfa_compute(area, NULL, spftree_self, protected_resource); /* Print the SPT and the corresponding main/backup routing tables. */ - isis_print_spftree(vty, spftree_self); + isis_print_spftree(vty, spftree_self, NULL); vty_out(vty, "Main:\n"); isis_print_routes(vty, spftree_self, NULL, false, false); vty_out(vty, "Backup:\n"); @@ -148,7 +148,7 @@ static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology, vty_out(vty, "\n"); /* Print the post-convergence SPT. */ - isis_print_spftree(vty, spftree_pc); + isis_print_spftree(vty, spftree_pc, NULL); /* * Activate the computed RLFAs (if any) using artificial LDP labels for @@ -164,7 +164,7 @@ static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology, } /* Print the SPT and the corresponding main/backup routing tables. */ - isis_print_spftree(vty, spftree_self); + isis_print_spftree(vty, spftree_self, NULL); vty_out(vty, "Main:\n"); isis_print_routes(vty, spftree_self, NULL, false, false); vty_out(vty, "Backup:\n"); @@ -228,7 +228,7 @@ static void test_run_ti_lfa(struct vty *vty, /* * Print the post-convergence SPT and the corresponding routing table. */ - isis_print_spftree(vty, spftree_pc); + isis_print_spftree(vty, spftree_pc, NULL); isis_print_routes(vty, spftree_self, NULL, false, true); /* Cleanup everything. */ diff --git a/tests/isisd/test_isis_spf.refout b/tests/isisd/test_isis_spf.refout index 23d41b9e5d..255d920c10 100644 --- a/tests/isisd/test_isis_spf.refout +++ b/tests/isisd/test_isis_spf.refout @@ -1,20 +1,22 @@ test# test isis topology 1 root rt1 spf
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
- rt3 - rt5(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ rt3 - rt6(4)
+
IS-IS L1 IPv4 routing table:
@@ -29,21 +31,23 @@ IS-IS L1 IPv4 routing table: - rt3 16060
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
-2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
- rt3 - rt5(4)
-2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
-2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
-2001:db8::6/128 IP6 internal 40 rt2 - rt6(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+ 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+ 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
+ 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
+ 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4)
+ rt3 - rt6(4)
+
IS-IS L1 IPv6 routing table:
@@ -59,22 +63,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt1 spf
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt4 TE-IS 10 rt4 - rt1(4)
-rt5 TE-IS 10 rt5 - rt1(4)
-rt2 TE-IS 15 rt2 - rt1(4)
-rt1
-rt6 TE-IS 20 rt4 - rt4(4)
- rt5 - rt5(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-10.0.255.5/32 IP TE 20 rt5 - rt5(4)
-10.0.255.2/32 IP TE 25 rt2 - rt2(4)
-rt3 TE-IS 30 rt3 - rt1(4)
-10.0.255.6/32 IP TE 30 rt4 - rt6(4)
- rt5 -
-10.0.255.3/32 IP TE 40 rt3 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt5 TE-IS 10 rt5 - rt1(4)
+ rt2 TE-IS 15 rt2 - rt1(4)
+ rt1
+ rt6 TE-IS 20 rt4 - rt4(4)
+ rt5 - rt5(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ 10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+ 10.0.255.2/32 IP TE 25 rt2 - rt2(4)
+ rt3 TE-IS 30 rt3 - rt1(4)
+ 10.0.255.6/32 IP TE 30 rt4 - rt6(4)
+ rt5 - rt6(4)
+ 10.0.255.3/32 IP TE 40 rt3 - rt3(4)
+
IS-IS L1 IPv4 routing table:
@@ -89,22 +95,24 @@ IS-IS L1 IPv4 routing table: - rt5 16060
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt4 TE-IS 10 rt4 - rt1(4)
-rt5 TE-IS 10 rt5 - rt1(4)
-rt2 TE-IS 15 rt2 - rt1(4)
-rt1
-rt6 TE-IS 20 rt4 - rt4(4)
- rt5 - rt5(4)
-2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
-2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
-2001:db8::2/128 IP6 internal 25 rt2 - rt2(4)
-rt3 TE-IS 30 rt3 - rt1(4)
-2001:db8::6/128 IP6 internal 30 rt4 - rt6(4)
- rt5 -
-2001:db8::3/128 IP6 internal 40 rt3 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt5 TE-IS 10 rt5 - rt1(4)
+ rt2 TE-IS 15 rt2 - rt1(4)
+ rt1
+ rt6 TE-IS 20 rt4 - rt4(4)
+ rt5 - rt5(4)
+ 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+ 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
+ 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4)
+ rt3 TE-IS 30 rt3 - rt1(4)
+ 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4)
+ rt5 - rt6(4)
+ 2001:db8::3/128 IP6 internal 40 rt3 - rt3(4)
+
IS-IS L1 IPv6 routing table:
@@ -120,19 +128,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 spf ipv4-only
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt5 TE-IS 30 rt2 - rt4(4)
-rt6 TE-IS 30 rt2 - rt4(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 40 rt2 - rt5(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt5 TE-IS 30 rt2 - rt4(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 40 rt2 - rt5(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+
IS-IS L1 IPv4 routing table:
@@ -147,23 +157,25 @@ IS-IS L1 IPv4 routing table: test# test isis topology 4 root rt1 spf ipv4-only
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
-rt7 TE-IS 30 rt3 - rt5(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-rt8 TE-IS 40 rt2 - rt6(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
-10.0.255.7/32 IP TE 40 rt3 - rt7(4)
-10.0.255.8/32 IP TE 50 rt2 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt7 TE-IS 30 rt3 - rt5(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ rt8 TE-IS 40 rt2 - rt6(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ 10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+ 10.0.255.8/32 IP TE 50 rt2 - rt8(4)
+
IS-IS L1 IPv4 routing table:
@@ -180,25 +192,27 @@ IS-IS L1 IPv4 routing table: test# test isis topology 5 root rt1 spf ipv4-only
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
-rt7 TE-IS 30 rt3 - rt5(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-rt8 TE-IS 40 rt2 - rt6(4)
- rt3 - rt7(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
-10.0.255.7/32 IP TE 40 rt3 - rt7(4)
-10.0.255.8/32 IP TE 50 rt2 - rt8(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt7 TE-IS 30 rt3 - rt5(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ rt8 TE-IS 40 rt2 - rt6(4)
+ rt3 - rt7(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ 10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+ 10.0.255.8/32 IP TE 50 rt2 - rt8(4)
+ rt3 - rt8(4)
+
IS-IS L1 IPv4 routing table:
@@ -216,33 +230,35 @@ IS-IS L1 IPv4 routing table: test# test isis topology 6 root rt1 spf ipv4-only
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
- rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
- rt3 -
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
- rt3 -
-rt5 TE-IS 40 rt2 - rt6(4)
- rt3 -
-rt8 TE-IS 40 rt2 - rt6(4)
- rt3 -
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
- rt3 -
-rt7 TE-IS 50 rt2 - rt5(4)
- rt3 - rt8(4)
-10.0.255.5/32 IP TE 50 rt2 - rt5(4)
- rt3 -
-10.0.255.8/32 IP TE 50 rt2 - rt8(4)
- rt3 -
-10.0.255.7/32 IP TE 60 rt2 - rt7(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ rt3 - rt4(4)
+ rt5 TE-IS 40 rt2 - rt6(4)
+ rt3 - rt6(4)
+ rt8 TE-IS 40 rt2 - rt6(4)
+ rt3 - rt6(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ rt3 - rt6(4)
+ rt7 TE-IS 50 rt2 - rt5(4)
+ rt3 - rt8(4)
+ 10.0.255.5/32 IP TE 50 rt2 - rt5(4)
+ rt3 - rt5(4)
+ 10.0.255.8/32 IP TE 50 rt2 - rt8(4)
+ rt3 - rt8(4)
+ 10.0.255.7/32 IP TE 60 rt2 - rt7(4)
+ rt3 - rt7(4)
+
IS-IS L1 IPv4 routing table:
@@ -264,34 +280,36 @@ IS-IS L1 IPv4 routing table: test# test isis topology 7 root rt1 spf ipv4-only
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt4 TE-IS 10 rt4 - rt1(4)
-rt5 TE-IS 20 rt4 - rt4(4)
-rt7 TE-IS 20 rt4 - rt4(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-rt2 TE-IS 30 rt4 - rt5(4)
-rt6 TE-IS 30 rt4 - rt5(4)
-rt8 TE-IS 30 rt4 - rt5(4)
- rt7(4)
-10.0.255.5/32 IP TE 30 rt4 - rt5(4)
-10.0.255.7/32 IP TE 30 rt4 - rt7(4)
-rt10 TE-IS 40 rt4 - rt7(4)
-rt3 TE-IS 40 rt4 - rt2(4)
- rt6(4)
-rt9 TE-IS 40 rt4 - rt8(4)
-rt11 TE-IS 40 rt4 - rt8(4)
-10.0.255.2/32 IP TE 40 rt4 - rt2(4)
-10.0.255.6/32 IP TE 40 rt4 - rt6(4)
-10.0.255.8/32 IP TE 40 rt4 - rt8(4)
-rt12 TE-IS 50 rt4 - rt9(4)
- rt11(4)
-10.0.255.10/32 IP TE 50 rt4 - rt10(4)
-10.0.255.3/32 IP TE 50 rt4 - rt3(4)
-10.0.255.9/32 IP TE 50 rt4 - rt9(4)
-10.0.255.11/32 IP TE 50 rt4 - rt11(4)
-10.0.255.12/32 IP TE 60 rt4 - rt12(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt5 TE-IS 20 rt4 - rt4(4)
+ rt7 TE-IS 20 rt4 - rt4(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ rt2 TE-IS 30 rt4 - rt5(4)
+ rt6 TE-IS 30 rt4 - rt5(4)
+ rt8 TE-IS 30 rt4 - rt5(4)
+ rt7(4)
+ 10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+ 10.0.255.7/32 IP TE 30 rt4 - rt7(4)
+ rt10 TE-IS 40 rt4 - rt7(4)
+ rt3 TE-IS 40 rt4 - rt2(4)
+ rt6(4)
+ rt9 TE-IS 40 rt4 - rt8(4)
+ rt11 TE-IS 40 rt4 - rt8(4)
+ 10.0.255.2/32 IP TE 40 rt4 - rt2(4)
+ 10.0.255.6/32 IP TE 40 rt4 - rt6(4)
+ 10.0.255.8/32 IP TE 40 rt4 - rt8(4)
+ rt12 TE-IS 50 rt4 - rt9(4)
+ rt11(4)
+ 10.0.255.10/32 IP TE 50 rt4 - rt10(4)
+ 10.0.255.3/32 IP TE 50 rt4 - rt3(4)
+ 10.0.255.9/32 IP TE 50 rt4 - rt9(4)
+ 10.0.255.11/32 IP TE 50 rt4 - rt11(4)
+ 10.0.255.12/32 IP TE 60 rt4 - rt12(4)
+
IS-IS L1 IPv4 routing table:
@@ -312,33 +330,35 @@ IS-IS L1 IPv4 routing table: test# test isis topology 8 root rt1 spf ipv4-only
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt4 TE-IS 10 rt4 - rt1(4)
-rt3 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt2 - rt2(4)
-rt7 TE-IS 20 rt4 - rt4(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-rt6 TE-IS 30 rt2 - rt3(4)
- rt5(4)
-rt8 TE-IS 30 rt2 - rt5(4)
-rt10 TE-IS 30 rt4 - rt7(4)
-10.0.255.3/32 IP TE 30 rt2 - rt3(4)
-10.0.255.5/32 IP TE 30 rt2 - rt5(4)
-10.0.255.7/32 IP TE 30 rt4 - rt7(4)
-rt9 TE-IS 40 rt2 - rt8(4)
-rt11 TE-IS 40 rt2 - rt8(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
-10.0.255.8/32 IP TE 40 rt2 - rt8(4)
-10.0.255.10/32 IP TE 40 rt4 - rt10(4)
-rt12 TE-IS 50 rt2 - rt9(4)
- rt11(4)
-10.0.255.9/32 IP TE 50 rt2 - rt9(4)
-10.0.255.11/32 IP TE 50 rt2 - rt11(4)
-10.0.255.12/32 IP TE 60 rt2 - rt12(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt3 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt2 - rt2(4)
+ rt7 TE-IS 20 rt4 - rt4(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ rt6 TE-IS 30 rt2 - rt3(4)
+ rt5(4)
+ rt8 TE-IS 30 rt2 - rt5(4)
+ rt10 TE-IS 30 rt4 - rt7(4)
+ 10.0.255.3/32 IP TE 30 rt2 - rt3(4)
+ 10.0.255.5/32 IP TE 30 rt2 - rt5(4)
+ 10.0.255.7/32 IP TE 30 rt4 - rt7(4)
+ rt9 TE-IS 40 rt2 - rt8(4)
+ rt11 TE-IS 40 rt2 - rt8(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ 10.0.255.8/32 IP TE 40 rt2 - rt8(4)
+ 10.0.255.10/32 IP TE 40 rt4 - rt10(4)
+ rt12 TE-IS 50 rt2 - rt9(4)
+ rt11(4)
+ 10.0.255.9/32 IP TE 50 rt2 - rt9(4)
+ 10.0.255.11/32 IP TE 50 rt2 - rt11(4)
+ 10.0.255.12/32 IP TE 60 rt2 - rt12(4)
+
IS-IS L1 IPv4 routing table:
@@ -359,28 +379,30 @@ IS-IS L1 IPv4 routing table: test# test isis topology 9 root rt1 spf
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt5 TE-IS 30 rt2 - rt4(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-rt9 TE-IS 40 rt2 - rt5(4)
-10.0.255.5/32 IP TE 40 rt2 - rt5(4)
-rt6 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-rt7 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-rt8 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-10.0.255.9/32 IP TE 50 rt2 - rt9(4)
-10.0.255.6/32 IP TE 60 rt2 - rt6(4)
-10.0.255.7/32 IP TE 60 rt2 - rt7(4)
-10.0.255.8/32 IP TE 60 rt2 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt5 TE-IS 30 rt2 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ rt9 TE-IS 40 rt2 - rt5(4)
+ 10.0.255.5/32 IP TE 40 rt2 - rt5(4)
+ rt6 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ rt7 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ rt8 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ 10.0.255.9/32 IP TE 50 rt2 - rt9(4)
+ 10.0.255.6/32 IP TE 60 rt2 - rt6(4)
+ 10.0.255.7/32 IP TE 60 rt2 - rt7(4)
+ 10.0.255.8/32 IP TE 60 rt2 - rt8(4)
+
IS-IS L1 IPv4 routing table:
@@ -397,28 +419,30 @@ IS-IS L1 IPv4 routing table: 10.0.255.9/32 50 - rt2 16090
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
-2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
-rt5 TE-IS 30 rt2 - rt4(4)
-2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
-rt9 TE-IS 40 rt2 - rt5(4)
-2001:db8::5/128 IP6 internal 40 rt2 - rt5(4)
-rt6 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-rt7 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-rt8 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-2001:db8::9/128 IP6 internal 50 rt2 - rt9(4)
-2001:db8::6/128 IP6 internal 60 rt2 - rt6(4)
-2001:db8::7/128 IP6 internal 60 rt2 - rt7(4)
-2001:db8::8/128 IP6 internal 60 rt2 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+ 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+ rt5 TE-IS 30 rt2 - rt4(4)
+ 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
+ rt9 TE-IS 40 rt2 - rt5(4)
+ 2001:db8::5/128 IP6 internal 40 rt2 - rt5(4)
+ rt6 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ rt7 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ rt8 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ 2001:db8::9/128 IP6 internal 50 rt2 - rt9(4)
+ 2001:db8::6/128 IP6 internal 60 rt2 - rt6(4)
+ 2001:db8::7/128 IP6 internal 60 rt2 - rt7(4)
+ 2001:db8::8/128 IP6 internal 60 rt2 - rt8(4)
+
IS-IS L1 IPv6 routing table:
@@ -436,23 +460,25 @@ IS-IS L1 IPv6 routing table: test# test isis topology 10 root rt1 spf
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 20 rt3 - rt1(4)
-rt4 TE-IS 20 rt4 - rt1(4)
-rt5 TE-IS 20 rt2 - rt2(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-rt6 TE-IS 30 rt3 - rt3(4)
-rt7 TE-IS 30 rt4 - rt4(4)
-rt8 TE-IS 30 rt2 - rt5(4)
-10.0.255.3/32 IP TE 30 rt3 - rt3(4)
-10.0.255.4/32 IP TE 30 rt4 - rt4(4)
-10.0.255.5/32 IP TE 30 rt2 - rt5(4)
-10.0.255.6/32 IP TE 40 rt3 - rt6(4)
-10.0.255.7/32 IP TE 40 rt4 - rt7(4)
-10.0.255.8/32 IP TE 40 rt2 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 20 rt3 - rt1(4)
+ rt4 TE-IS 20 rt4 - rt1(4)
+ rt5 TE-IS 20 rt2 - rt2(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ rt6 TE-IS 30 rt3 - rt3(4)
+ rt7 TE-IS 30 rt4 - rt4(4)
+ rt8 TE-IS 30 rt2 - rt5(4)
+ 10.0.255.3/32 IP TE 30 rt3 - rt3(4)
+ 10.0.255.4/32 IP TE 30 rt4 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt2 - rt5(4)
+ 10.0.255.6/32 IP TE 40 rt3 - rt6(4)
+ 10.0.255.7/32 IP TE 40 rt4 - rt7(4)
+ 10.0.255.8/32 IP TE 40 rt2 - rt8(4)
+
IS-IS L1 IPv4 routing table:
@@ -468,23 +494,25 @@ IS-IS L1 IPv4 routing table: 10.0.255.8/32 40 - rt2 16080
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 20 rt3 - rt1(4)
-rt4 TE-IS 20 rt4 - rt1(4)
-rt5 TE-IS 20 rt2 - rt2(4)
-2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
-rt6 TE-IS 30 rt3 - rt3(4)
-rt7 TE-IS 30 rt4 - rt4(4)
-rt8 TE-IS 30 rt2 - rt5(4)
-2001:db8::3/128 IP6 internal 30 rt3 - rt3(4)
-2001:db8::4/128 IP6 internal 30 rt4 - rt4(4)
-2001:db8::5/128 IP6 internal 30 rt2 - rt5(4)
-2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
-2001:db8::7/128 IP6 internal 40 rt4 - rt7(4)
-2001:db8::8/128 IP6 internal 40 rt2 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 20 rt3 - rt1(4)
+ rt4 TE-IS 20 rt4 - rt1(4)
+ rt5 TE-IS 20 rt2 - rt2(4)
+ 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+ rt6 TE-IS 30 rt3 - rt3(4)
+ rt7 TE-IS 30 rt4 - rt4(4)
+ rt8 TE-IS 30 rt2 - rt5(4)
+ 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4)
+ 2001:db8::4/128 IP6 internal 30 rt4 - rt4(4)
+ 2001:db8::5/128 IP6 internal 30 rt2 - rt5(4)
+ 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
+ 2001:db8::7/128 IP6 internal 40 rt4 - rt7(4)
+ 2001:db8::8/128 IP6 internal 40 rt2 - rt8(4)
+
IS-IS L1 IPv6 routing table:
@@ -501,22 +529,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 11 root rt1 spf
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt2 pseudo_TE-IS 20 rt3 - rt3(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
- rt3 - rt5(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ ------------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt2 pseudo_TE-IS 20 rt3 - rt3(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ rt3 - rt6(4)
+
IS-IS L1 IPv4 routing table:
@@ -531,22 +561,24 @@ IS-IS L1 IPv4 routing table: - rt3 16060
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt2 pseudo_TE-IS 20 rt3 - rt3(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
-2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
- rt3 - rt5(4)
-2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
-2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
-2001:db8::6/128 IP6 internal 40 rt2 - rt6(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt2 pseudo_TE-IS 20 rt3 - rt3(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+ 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+ 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
+ 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
+ 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4)
+ rt3 - rt6(4)
+
IS-IS L1 IPv6 routing table:
@@ -562,27 +594,29 @@ IS-IS L1 IPv6 routing table: test# test isis topology 12 root rt1 spf ipv4-only
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
-rt7 TE-IS 30 rt3 - rt5(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-rt8 TE-IS 40 rt2 - rt6(4)
-rt9 TE-IS 40 rt3 - rt7(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
-10.0.255.7/32 IP TE 40 rt3 - rt7(4)
-rt10 TE-IS 50 rt2 - rt8(4)
-10.0.255.8/32 IP TE 50 rt2 - rt8(4)
-10.0.255.9/32 IP TE 50 rt3 - rt9(4)
-10.0.255.10/32 IP TE 60 rt2 - rt10(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt7 TE-IS 30 rt3 - rt5(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ rt8 TE-IS 40 rt2 - rt6(4)
+ rt9 TE-IS 40 rt3 - rt7(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ 10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+ rt10 TE-IS 50 rt2 - rt8(4)
+ 10.0.255.8/32 IP TE 50 rt2 - rt8(4)
+ 10.0.255.9/32 IP TE 50 rt3 - rt9(4)
+ 10.0.255.10/32 IP TE 60 rt2 - rt10(4)
+
IS-IS L1 IPv4 routing table:
@@ -601,24 +635,26 @@ IS-IS L1 IPv4 routing table: test# test isis topology 13 root rt1 spf ipv4-only
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
- rt3 - rt3(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-rt6 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt7 TE-IS 30 rt3 - rt5(4)
- rt6(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
- rt3 -
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-10.0.255.6/32 IP TE 30 rt3 - rt6(4)
-10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt3 - rt3(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ rt6 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt7 TE-IS 30 rt3 - rt5(4)
+ rt6(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ rt3 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ 10.0.255.6/32 IP TE 30 rt3 - rt6(4)
+ 10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+
IS-IS L1 IPv4 routing table:
@@ -636,23 +672,25 @@ IS-IS L1 IPv4 routing table: test#
test# test isis topology 4 root rt1 reverse-spf ipv4-only
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
-rt7 TE-IS 30 rt3 - rt5(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-rt8 TE-IS 40 rt2 - rt6(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
-10.0.255.7/32 IP TE 40 rt3 - rt7(4)
-10.0.255.8/32 IP TE 50 rt2 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt7 TE-IS 30 rt3 - rt5(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ rt8 TE-IS 40 rt2 - rt6(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ 10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+ 10.0.255.8/32 IP TE 50 rt2 - rt8(4)
+
IS-IS L1 IPv4 routing table:
@@ -669,21 +707,23 @@ IS-IS L1 IPv4 routing table: test# test isis topology 11 root rt1 reverse-spf
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt2 pseudo_TE-IS 20 rt3 - rt3(4)
-rt4 TE-IS 20 rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt3 - rt4(4)
- rt5(4)
-10.0.255.4/32 IP TE 30 rt4(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-10.0.255.6/32 IP TE 40 rt3 - rt6(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ------------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt2 pseudo_TE-IS 20 rt3 - rt3(4)
+ rt4 TE-IS 20 rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt3 - rt4(4)
+ rt5(4)
+ 10.0.255.4/32 IP TE 30 rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ 10.0.255.6/32 IP TE 40 rt3 - rt6(4)
+
IS-IS L1 IPv4 routing table:
@@ -695,21 +735,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 40 - rt3 16060
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt2 TE-IS 10 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt2 pseudo_TE-IS 20 rt3 - rt3(4)
-rt4 TE-IS 20 rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-2001:db8::2/128 IP6 internal 20 rt2(4)
-2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt3 - rt4(4)
- rt5(4)
-2001:db8::4/128 IP6 internal 30 rt4(4)
-2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
-2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt2 TE-IS 10 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt2 pseudo_TE-IS 20 rt3 - rt3(4)
+ rt4 TE-IS 20 rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 2001:db8::2/128 IP6 internal 20 rt2(4)
+ 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt3 - rt4(4)
+ rt5(4)
+ 2001:db8::4/128 IP6 internal 30 rt4(4)
+ 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
+ 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
+
IS-IS L1 IPv6 routing table:
@@ -723,21 +765,23 @@ IS-IS L1 IPv6 routing table: test#
test# test isis topology 1 root rt1 lfa system-id rt2
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
- rt3 - rt5(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ rt3 - rt6(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -756,21 +800,23 @@ Backup: IS-IS L1 IPv4 routing table:
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
-2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
- rt3 - rt5(4)
-2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
-2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
-2001:db8::6/128 IP6 internal 40 rt2 - rt6(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+ 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+ 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
+ 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
+ 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4)
+ rt3 - rt6(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -790,21 +836,23 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt4 lfa system-id rt1 pseudonode-id 1
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt4
-10.0.255.4/32 IP internal 0 rt4(4)
-rt1 TE-IS 10 rt1 - rt4(4)
-rt5 TE-IS 10 rt5 - rt4(4)
-rt6 TE-IS 10 rt6 - rt4(4)
-rt1 pseudo_TE-IS 20 rt1 - rt1(4)
- rt5 - rt5(4)
-10.0.255.1/32 IP TE 20 rt1 - rt1(4)
-10.0.255.5/32 IP TE 20 rt5 - rt5(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt2 TE-IS 25 rt1 - rt1(4)
-10.0.255.2/32 IP TE 35 rt1 - rt2(4)
-rt3 TE-IS 40 rt1 - rt1(4)
-10.0.255.3/32 IP TE 50 rt1 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ------------------------------------------------------------------
+ rt4
+ 10.0.255.4/32 IP internal 0 rt4(4)
+ rt1 TE-IS 10 rt1 - rt4(4)
+ rt5 TE-IS 10 rt5 - rt4(4)
+ rt6 TE-IS 10 rt6 - rt4(4)
+ rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt5 - rt5(4)
+ 10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+ 10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt2 TE-IS 25 rt1 - rt1(4)
+ 10.0.255.2/32 IP TE 35 rt1 - rt2(4)
+ rt3 TE-IS 40 rt1 - rt1(4)
+ 10.0.255.3/32 IP TE 50 rt1 - rt3(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -826,21 +874,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.2/32 50 - rt2 implicit-null
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt4
-2001:db8::4/128 IP6 internal 0 rt4(4)
-rt1 TE-IS 10 rt1 - rt4(4)
-rt5 TE-IS 10 rt5 - rt4(4)
-rt6 TE-IS 10 rt6 - rt4(4)
-rt1 pseudo_TE-IS 20 rt1 - rt1(4)
- rt5 - rt5(4)
-2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
-2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
-2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
-rt2 TE-IS 25 rt1 - rt1(4)
-2001:db8::2/128 IP6 internal 35 rt1 - rt2(4)
-rt3 TE-IS 40 rt1 - rt1(4)
-2001:db8::3/128 IP6 internal 50 rt1 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt4
+ 2001:db8::4/128 IP6 internal 0 rt4(4)
+ rt1 TE-IS 10 rt1 - rt4(4)
+ rt5 TE-IS 10 rt5 - rt4(4)
+ rt6 TE-IS 10 rt6 - rt4(4)
+ rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt5 - rt5(4)
+ 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
+ 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
+ 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
+ rt2 TE-IS 25 rt1 - rt1(4)
+ 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4)
+ rt3 TE-IS 40 rt1 - rt1(4)
+ 2001:db8::3/128 IP6 internal 50 rt1 - rt3(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -863,21 +913,23 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt4 lfa system-id rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt4
-10.0.255.4/32 IP internal 0 rt4(4)
-rt1 TE-IS 10 rt1 - rt4(4)
-rt5 TE-IS 10 rt5 - rt4(4)
-rt6 TE-IS 10 rt6 - rt4(4)
-rt1 pseudo_TE-IS 20 rt1 - rt1(4)
- rt5 - rt5(4)
-10.0.255.1/32 IP TE 20 rt1 - rt1(4)
-10.0.255.5/32 IP TE 20 rt5 - rt5(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt2 TE-IS 25 rt1 - rt1(4)
-10.0.255.2/32 IP TE 35 rt1 - rt2(4)
-rt3 TE-IS 40 rt1 - rt1(4)
-10.0.255.3/32 IP TE 50 rt1 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ------------------------------------------------------------------
+ rt4
+ 10.0.255.4/32 IP internal 0 rt4(4)
+ rt1 TE-IS 10 rt1 - rt4(4)
+ rt5 TE-IS 10 rt5 - rt4(4)
+ rt6 TE-IS 10 rt6 - rt4(4)
+ rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt5 - rt5(4)
+ 10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+ 10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt2 TE-IS 25 rt1 - rt1(4)
+ 10.0.255.2/32 IP TE 35 rt1 - rt2(4)
+ rt3 TE-IS 40 rt1 - rt1(4)
+ 10.0.255.3/32 IP TE 50 rt1 - rt3(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -899,21 +951,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 30 - rt5 16060
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt4
-2001:db8::4/128 IP6 internal 0 rt4(4)
-rt1 TE-IS 10 rt1 - rt4(4)
-rt5 TE-IS 10 rt5 - rt4(4)
-rt6 TE-IS 10 rt6 - rt4(4)
-rt1 pseudo_TE-IS 20 rt1 - rt1(4)
- rt5 - rt5(4)
-2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
-2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
-2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
-rt2 TE-IS 25 rt1 - rt1(4)
-2001:db8::2/128 IP6 internal 35 rt1 - rt2(4)
-rt3 TE-IS 40 rt1 - rt1(4)
-2001:db8::3/128 IP6 internal 50 rt1 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt4
+ 2001:db8::4/128 IP6 internal 0 rt4(4)
+ rt1 TE-IS 10 rt1 - rt4(4)
+ rt5 TE-IS 10 rt5 - rt4(4)
+ rt6 TE-IS 10 rt6 - rt4(4)
+ rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt5 - rt5(4)
+ 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
+ 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
+ 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
+ rt2 TE-IS 25 rt1 - rt1(4)
+ 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4)
+ rt3 TE-IS 40 rt1 - rt1(4)
+ 2001:db8::3/128 IP6 internal 50 rt1 - rt3(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -936,19 +990,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 lfa system-id rt2
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt5 TE-IS 30 rt2 - rt4(4)
-rt6 TE-IS 30 rt2 - rt4(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 40 rt2 - rt5(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt5 TE-IS 30 rt2 - rt4(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 40 rt2 - rt5(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -973,10 +1029,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 50 - rt3 16060
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ----------------------------------------------------
+ rt1
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -986,19 +1044,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 lfa system-id rt3
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt5 TE-IS 30 rt2 - rt4(4)
-rt6 TE-IS 30 rt2 - rt4(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 40 rt2 - rt5(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt5 TE-IS 30 rt2 - rt4(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 40 rt2 - rt5(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1020,10 +1080,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.3/32 30 - rt2 16030
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ----------------------------------------------------
+ rt1
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1033,34 +1095,36 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt1 lfa system-id rt4
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt4 TE-IS 10 rt4 - rt1(4)
-rt5 TE-IS 20 rt4 - rt4(4)
-rt7 TE-IS 20 rt4 - rt4(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-rt2 TE-IS 30 rt4 - rt5(4)
-rt6 TE-IS 30 rt4 - rt5(4)
-rt8 TE-IS 30 rt4 - rt5(4)
- rt7(4)
-10.0.255.5/32 IP TE 30 rt4 - rt5(4)
-10.0.255.7/32 IP TE 30 rt4 - rt7(4)
-rt10 TE-IS 40 rt4 - rt7(4)
-rt3 TE-IS 40 rt4 - rt2(4)
- rt6(4)
-rt9 TE-IS 40 rt4 - rt8(4)
-rt11 TE-IS 40 rt4 - rt8(4)
-10.0.255.2/32 IP TE 40 rt4 - rt2(4)
-10.0.255.6/32 IP TE 40 rt4 - rt6(4)
-10.0.255.8/32 IP TE 40 rt4 - rt8(4)
-rt12 TE-IS 50 rt4 - rt9(4)
- rt11(4)
-10.0.255.10/32 IP TE 50 rt4 - rt10(4)
-10.0.255.3/32 IP TE 50 rt4 - rt3(4)
-10.0.255.9/32 IP TE 50 rt4 - rt9(4)
-10.0.255.11/32 IP TE 50 rt4 - rt11(4)
-10.0.255.12/32 IP TE 60 rt4 - rt12(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt5 TE-IS 20 rt4 - rt4(4)
+ rt7 TE-IS 20 rt4 - rt4(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ rt2 TE-IS 30 rt4 - rt5(4)
+ rt6 TE-IS 30 rt4 - rt5(4)
+ rt8 TE-IS 30 rt4 - rt5(4)
+ rt7(4)
+ 10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+ 10.0.255.7/32 IP TE 30 rt4 - rt7(4)
+ rt10 TE-IS 40 rt4 - rt7(4)
+ rt3 TE-IS 40 rt4 - rt2(4)
+ rt6(4)
+ rt9 TE-IS 40 rt4 - rt8(4)
+ rt11 TE-IS 40 rt4 - rt8(4)
+ 10.0.255.2/32 IP TE 40 rt4 - rt2(4)
+ 10.0.255.6/32 IP TE 40 rt4 - rt6(4)
+ 10.0.255.8/32 IP TE 40 rt4 - rt8(4)
+ rt12 TE-IS 50 rt4 - rt9(4)
+ rt11(4)
+ 10.0.255.10/32 IP TE 50 rt4 - rt10(4)
+ 10.0.255.3/32 IP TE 50 rt4 - rt3(4)
+ 10.0.255.9/32 IP TE 50 rt4 - rt9(4)
+ 10.0.255.11/32 IP TE 50 rt4 - rt11(4)
+ 10.0.255.12/32 IP TE 60 rt4 - rt12(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1098,10 +1162,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.12/32 90 - rt2 16120
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-rt4 TE-IS 10 rt4 - rt1(4)
-rt2 TE-IS 40 rt2 - rt1(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ----------------------------------------------------
+ rt1
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt2 TE-IS 40 rt2 - rt1(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1111,40 +1177,42 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt7 lfa system-id rt8
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt7
-10.0.255.7/32 IP internal 0 rt7(4)
-rt4 TE-IS 10 rt4 - rt7(4)
-rt8 TE-IS 10 rt8 - rt7(4)
-rt10 TE-IS 20 rt10 - rt7(4)
-rt1 TE-IS 20 rt4 - rt4(4)
-rt5 TE-IS 20 rt4 - rt4(4)
- rt8 - rt8(4)
-rt9 TE-IS 20 rt8 - rt8(4)
-rt11 TE-IS 20 rt8 - rt8(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-10.0.255.8/32 IP TE 20 rt8 - rt8(4)
-rt2 TE-IS 30 rt4 - rt5(4)
- rt8 -
-rt6 TE-IS 30 rt4 - rt5(4)
- rt8 -
-rt12 TE-IS 30 rt8 - rt9(4)
- rt11(4)
-10.0.255.10/32 IP TE 30 rt10 - rt10(4)
-10.0.255.1/32 IP TE 30 rt4 - rt1(4)
-10.0.255.5/32 IP TE 30 rt4 - rt5(4)
- rt8 -
-10.0.255.9/32 IP TE 30 rt8 - rt9(4)
-10.0.255.11/32 IP TE 30 rt8 - rt11(4)
-rt3 TE-IS 40 rt4 - rt2(4)
- rt8 - rt6(4)
-10.0.255.2/32 IP TE 40 rt4 - rt2(4)
- rt8 -
-10.0.255.6/32 IP TE 40 rt4 - rt6(4)
- rt8 -
-10.0.255.12/32 IP TE 40 rt8 - rt12(4)
-10.0.255.3/32 IP TE 50 rt4 - rt3(4)
- rt8 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt7
+ 10.0.255.7/32 IP internal 0 rt7(4)
+ rt4 TE-IS 10 rt4 - rt7(4)
+ rt8 TE-IS 10 rt8 - rt7(4)
+ rt10 TE-IS 20 rt10 - rt7(4)
+ rt1 TE-IS 20 rt4 - rt4(4)
+ rt5 TE-IS 20 rt4 - rt4(4)
+ rt8 - rt8(4)
+ rt9 TE-IS 20 rt8 - rt8(4)
+ rt11 TE-IS 20 rt8 - rt8(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ 10.0.255.8/32 IP TE 20 rt8 - rt8(4)
+ rt2 TE-IS 30 rt4 - rt5(4)
+ rt8 - rt5(4)
+ rt6 TE-IS 30 rt4 - rt5(4)
+ rt8 - rt5(4)
+ rt12 TE-IS 30 rt8 - rt9(4)
+ rt11(4)
+ 10.0.255.10/32 IP TE 30 rt10 - rt10(4)
+ 10.0.255.1/32 IP TE 30 rt4 - rt1(4)
+ 10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+ rt8 - rt5(4)
+ 10.0.255.9/32 IP TE 30 rt8 - rt9(4)
+ 10.0.255.11/32 IP TE 30 rt8 - rt11(4)
+ rt3 TE-IS 40 rt4 - rt2(4)
+ rt8 - rt6(4)
+ 10.0.255.2/32 IP TE 40 rt4 - rt2(4)
+ rt8 - rt2(4)
+ 10.0.255.6/32 IP TE 40 rt4 - rt6(4)
+ rt8 - rt6(4)
+ 10.0.255.12/32 IP TE 40 rt8 - rt12(4)
+ 10.0.255.3/32 IP TE 50 rt4 - rt3(4)
+ rt8 - rt3(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1179,11 +1247,13 @@ IS-IS L1 IPv4 routing table: 10.0.255.12/32 50 - rt10 16120
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt7
-rt4 TE-IS 10 rt4 - rt7(4)
-rt8 TE-IS 10 rt8 - rt7(4)
-rt10 TE-IS 20 rt10 - rt7(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ----------------------------------------------------
+ rt7
+ rt4 TE-IS 10 rt4 - rt7(4)
+ rt8 TE-IS 10 rt8 - rt7(4)
+ rt10 TE-IS 20 rt10 - rt7(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1193,38 +1263,40 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt8 lfa system-id rt11
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt8
-10.0.255.8/32 IP internal 0 rt8(4)
-rt5 TE-IS 10 rt5 - rt8(4)
-rt7 TE-IS 10 rt7 - rt8(4)
-rt9 TE-IS 10 rt9 - rt8(4)
-rt11 TE-IS 10 rt11 - rt8(4)
-rt2 TE-IS 20 rt5 - rt5(4)
-rt4 TE-IS 20 rt5 - rt5(4)
- rt7 - rt7(4)
-rt6 TE-IS 20 rt5 - rt5(4)
-rt12 TE-IS 20 rt9 - rt9(4)
- rt11 - rt11(4)
-rt10 TE-IS 20 rt11 - rt11(4)
-10.0.255.5/32 IP TE 20 rt5 - rt5(4)
-10.0.255.7/32 IP TE 20 rt7 - rt7(4)
-10.0.255.9/32 IP TE 20 rt9 - rt9(4)
-10.0.255.11/32 IP TE 20 rt11 - rt11(4)
-rt3 TE-IS 30 rt5 - rt2(4)
- rt6(4)
-rt1 TE-IS 30 rt5 - rt4(4)
- rt7 -
-10.0.255.2/32 IP TE 30 rt5 - rt2(4)
-10.0.255.4/32 IP TE 30 rt5 - rt4(4)
- rt7 -
-10.0.255.6/32 IP TE 30 rt5 - rt6(4)
-10.0.255.12/32 IP TE 30 rt9 - rt12(4)
- rt11 -
-10.0.255.10/32 IP TE 30 rt11 - rt10(4)
-10.0.255.3/32 IP TE 40 rt5 - rt3(4)
-10.0.255.1/32 IP TE 40 rt5 - rt1(4)
- rt7 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt8
+ 10.0.255.8/32 IP internal 0 rt8(4)
+ rt5 TE-IS 10 rt5 - rt8(4)
+ rt7 TE-IS 10 rt7 - rt8(4)
+ rt9 TE-IS 10 rt9 - rt8(4)
+ rt11 TE-IS 10 rt11 - rt8(4)
+ rt2 TE-IS 20 rt5 - rt5(4)
+ rt4 TE-IS 20 rt5 - rt5(4)
+ rt7 - rt7(4)
+ rt6 TE-IS 20 rt5 - rt5(4)
+ rt12 TE-IS 20 rt9 - rt9(4)
+ rt11 - rt11(4)
+ rt10 TE-IS 20 rt11 - rt11(4)
+ 10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+ 10.0.255.7/32 IP TE 20 rt7 - rt7(4)
+ 10.0.255.9/32 IP TE 20 rt9 - rt9(4)
+ 10.0.255.11/32 IP TE 20 rt11 - rt11(4)
+ rt3 TE-IS 30 rt5 - rt2(4)
+ rt6(4)
+ rt1 TE-IS 30 rt5 - rt4(4)
+ rt7 - rt4(4)
+ 10.0.255.2/32 IP TE 30 rt5 - rt2(4)
+ 10.0.255.4/32 IP TE 30 rt5 - rt4(4)
+ rt7 - rt4(4)
+ 10.0.255.6/32 IP TE 30 rt5 - rt6(4)
+ 10.0.255.12/32 IP TE 30 rt9 - rt12(4)
+ rt11 - rt12(4)
+ 10.0.255.10/32 IP TE 30 rt11 - rt10(4)
+ 10.0.255.3/32 IP TE 40 rt5 - rt3(4)
+ 10.0.255.1/32 IP TE 40 rt5 - rt1(4)
+ rt7 - rt1(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1255,12 +1327,14 @@ IS-IS L1 IPv4 routing table: 10.0.255.10/32 40 - rt7 16100
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt8
-rt5 TE-IS 10 rt5 - rt8(4)
-rt7 TE-IS 10 rt7 - rt8(4)
-rt9 TE-IS 10 rt9 - rt8(4)
-rt11 TE-IS 10 rt11 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ----------------------------------------------------
+ rt8
+ rt5 TE-IS 10 rt5 - rt8(4)
+ rt7 TE-IS 10 rt7 - rt8(4)
+ rt9 TE-IS 10 rt9 - rt8(4)
+ rt11 TE-IS 10 rt11 - rt8(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1270,28 +1344,30 @@ IS-IS L1 IPv6 routing table: test# test isis topology 9 root rt3 lfa system-id rt1
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt3
-10.0.255.3/32 IP internal 0 rt3(4)
-rt1 TE-IS 10 rt1 - rt3(4)
-rt2 TE-IS 20 rt1 - rt1(4)
-10.0.255.1/32 IP TE 20 rt1 - rt1(4)
-rt4 TE-IS 30 rt1 - rt2(4)
-10.0.255.2/32 IP TE 30 rt1 - rt2(4)
-rt5 TE-IS 40 rt1 - rt4(4)
-10.0.255.4/32 IP TE 40 rt1 - rt4(4)
-rt9 TE-IS 50 rt1 - rt5(4)
-10.0.255.5/32 IP TE 50 rt1 - rt5(4)
-rt6 TE-IS 60 rt1 - rt4(4)
- rt9(4)
-rt7 TE-IS 60 rt1 - rt4(4)
- rt9(4)
-rt8 TE-IS 60 rt1 - rt4(4)
- rt9(4)
-10.0.255.9/32 IP TE 60 rt1 - rt9(4)
-10.0.255.6/32 IP TE 70 rt1 - rt6(4)
-10.0.255.7/32 IP TE 70 rt1 - rt7(4)
-10.0.255.8/32 IP TE 70 rt1 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt3
+ 10.0.255.3/32 IP internal 0 rt3(4)
+ rt1 TE-IS 10 rt1 - rt3(4)
+ rt2 TE-IS 20 rt1 - rt1(4)
+ 10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+ rt4 TE-IS 30 rt1 - rt2(4)
+ 10.0.255.2/32 IP TE 30 rt1 - rt2(4)
+ rt5 TE-IS 40 rt1 - rt4(4)
+ 10.0.255.4/32 IP TE 40 rt1 - rt4(4)
+ rt9 TE-IS 50 rt1 - rt5(4)
+ 10.0.255.5/32 IP TE 50 rt1 - rt5(4)
+ rt6 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+ rt7 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+ rt8 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+ 10.0.255.9/32 IP TE 60 rt1 - rt9(4)
+ 10.0.255.6/32 IP TE 70 rt1 - rt6(4)
+ 10.0.255.7/32 IP TE 70 rt1 - rt7(4)
+ 10.0.255.8/32 IP TE 70 rt1 - rt8(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1323,28 +1399,30 @@ IS-IS L1 IPv4 routing table: 10.0.255.9/32 130 - rt4 16090
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt3
-2001:db8::3/128 IP6 internal 0 rt3(4)
-rt1 TE-IS 10 rt1 - rt3(4)
-rt2 TE-IS 20 rt1 - rt1(4)
-2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
-rt4 TE-IS 30 rt1 - rt2(4)
-2001:db8::2/128 IP6 internal 30 rt1 - rt2(4)
-rt5 TE-IS 40 rt1 - rt4(4)
-2001:db8::4/128 IP6 internal 40 rt1 - rt4(4)
-rt9 TE-IS 50 rt1 - rt5(4)
-2001:db8::5/128 IP6 internal 50 rt1 - rt5(4)
-rt6 TE-IS 60 rt1 - rt4(4)
- rt9(4)
-rt7 TE-IS 60 rt1 - rt4(4)
- rt9(4)
-rt8 TE-IS 60 rt1 - rt4(4)
- rt9(4)
-2001:db8::9/128 IP6 internal 60 rt1 - rt9(4)
-2001:db8::6/128 IP6 internal 70 rt1 - rt6(4)
-2001:db8::7/128 IP6 internal 70 rt1 - rt7(4)
-2001:db8::8/128 IP6 internal 70 rt1 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt3
+ 2001:db8::3/128 IP6 internal 0 rt3(4)
+ rt1 TE-IS 10 rt1 - rt3(4)
+ rt2 TE-IS 20 rt1 - rt1(4)
+ 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
+ rt4 TE-IS 30 rt1 - rt2(4)
+ 2001:db8::2/128 IP6 internal 30 rt1 - rt2(4)
+ rt5 TE-IS 40 rt1 - rt4(4)
+ 2001:db8::4/128 IP6 internal 40 rt1 - rt4(4)
+ rt9 TE-IS 50 rt1 - rt5(4)
+ 2001:db8::5/128 IP6 internal 50 rt1 - rt5(4)
+ rt6 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+ rt7 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+ rt8 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+ 2001:db8::9/128 IP6 internal 60 rt1 - rt9(4)
+ 2001:db8::6/128 IP6 internal 70 rt1 - rt6(4)
+ 2001:db8::7/128 IP6 internal 70 rt1 - rt7(4)
+ 2001:db8::8/128 IP6 internal 70 rt1 - rt8(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1377,23 +1455,25 @@ IS-IS L1 IPv6 routing table: test# test isis topology 10 root rt8 lfa system-id rt5
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt8
-10.0.255.8/32 IP internal 0 rt8(4)
-rt5 TE-IS 10 rt5 - rt8(4)
-rt2 TE-IS 20 rt5 - rt5(4)
-10.0.255.5/32 IP TE 20 rt5 - rt5(4)
-rt1 TE-IS 30 rt5 - rt2(4)
-10.0.255.2/32 IP TE 30 rt5 - rt2(4)
-10.0.255.1/32 IP TE 40 rt5 - rt1(4)
-rt6 TE-IS 50 rt6 - rt8(4)
-rt7 TE-IS 50 rt7 - rt8(4)
-rt3 TE-IS 50 rt5 - rt1(4)
-rt4 TE-IS 50 rt5 - rt1(4)
-10.0.255.6/32 IP TE 60 rt6 - rt6(4)
-10.0.255.7/32 IP TE 60 rt7 - rt7(4)
-10.0.255.3/32 IP TE 60 rt5 - rt3(4)
-10.0.255.4/32 IP TE 60 rt5 - rt4(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt8
+ 10.0.255.8/32 IP internal 0 rt8(4)
+ rt5 TE-IS 10 rt5 - rt8(4)
+ rt2 TE-IS 20 rt5 - rt5(4)
+ 10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+ rt1 TE-IS 30 rt5 - rt2(4)
+ 10.0.255.2/32 IP TE 30 rt5 - rt2(4)
+ 10.0.255.1/32 IP TE 40 rt5 - rt1(4)
+ rt6 TE-IS 50 rt6 - rt8(4)
+ rt7 TE-IS 50 rt7 - rt8(4)
+ rt3 TE-IS 50 rt5 - rt1(4)
+ rt4 TE-IS 50 rt5 - rt1(4)
+ 10.0.255.6/32 IP TE 60 rt6 - rt6(4)
+ 10.0.255.7/32 IP TE 60 rt7 - rt7(4)
+ 10.0.255.3/32 IP TE 60 rt5 - rt3(4)
+ 10.0.255.4/32 IP TE 60 rt5 - rt4(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1426,23 +1506,25 @@ IS-IS L1 IPv4 routing table: - rt7 16050
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt8
-2001:db8::8/128 IP6 internal 0 rt8(4)
-rt5 TE-IS 10 rt5 - rt8(4)
-rt2 TE-IS 20 rt5 - rt5(4)
-2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
-rt1 TE-IS 30 rt5 - rt2(4)
-2001:db8::2/128 IP6 internal 30 rt5 - rt2(4)
-2001:db8::1/128 IP6 internal 40 rt5 - rt1(4)
-rt6 TE-IS 50 rt6 - rt8(4)
-rt7 TE-IS 50 rt7 - rt8(4)
-rt3 TE-IS 50 rt5 - rt1(4)
-rt4 TE-IS 50 rt5 - rt1(4)
-2001:db8::6/128 IP6 internal 60 rt6 - rt6(4)
-2001:db8::7/128 IP6 internal 60 rt7 - rt7(4)
-2001:db8::3/128 IP6 internal 60 rt5 - rt3(4)
-2001:db8::4/128 IP6 internal 60 rt5 - rt4(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt8
+ 2001:db8::8/128 IP6 internal 0 rt8(4)
+ rt5 TE-IS 10 rt5 - rt8(4)
+ rt2 TE-IS 20 rt5 - rt5(4)
+ 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
+ rt1 TE-IS 30 rt5 - rt2(4)
+ 2001:db8::2/128 IP6 internal 30 rt5 - rt2(4)
+ 2001:db8::1/128 IP6 internal 40 rt5 - rt1(4)
+ rt6 TE-IS 50 rt6 - rt8(4)
+ rt7 TE-IS 50 rt7 - rt8(4)
+ rt3 TE-IS 50 rt5 - rt1(4)
+ rt4 TE-IS 50 rt5 - rt1(4)
+ 2001:db8::6/128 IP6 internal 60 rt6 - rt6(4)
+ 2001:db8::7/128 IP6 internal 60 rt7 - rt7(4)
+ 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4)
+ 2001:db8::4/128 IP6 internal 60 rt5 - rt4(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1476,22 +1558,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 11 root rt3 lfa system-id rt5
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt3
-10.0.255.3/32 IP internal 0 rt3(4)
-rt1 TE-IS 10 rt1 - rt3(4)
-rt2 TE-IS 10 rt2 - rt3(4)
-rt5 TE-IS 10 rt5 - rt3(4)
-rt2 pseudo_TE-IS 20 rt1 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
- rt5 - rt5(4)
-rt6 TE-IS 20 rt5 - rt5(4)
-10.0.255.1/32 IP TE 20 rt1 - rt1(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.5/32 IP TE 20 rt5 - rt5(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
- rt5 -
-10.0.255.6/32 IP TE 30 rt5 - rt6(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ------------------------------------------------------------------
+ rt3
+ 10.0.255.3/32 IP internal 0 rt3(4)
+ rt1 TE-IS 10 rt1 - rt3(4)
+ rt2 TE-IS 10 rt2 - rt3(4)
+ rt5 TE-IS 10 rt5 - rt3(4)
+ rt2 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 - rt5(4)
+ rt6 TE-IS 20 rt5 - rt5(4)
+ 10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ rt5 - rt4(4)
+ 10.0.255.6/32 IP TE 30 rt5 - rt6(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1515,22 +1599,24 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 40 - rt2 16060
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt3
-2001:db8::3/128 IP6 internal 0 rt3(4)
-rt1 TE-IS 10 rt1 - rt3(4)
-rt2 TE-IS 10 rt2 - rt3(4)
-rt5 TE-IS 10 rt5 - rt3(4)
-rt2 pseudo_TE-IS 20 rt1 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
- rt5 - rt5(4)
-rt6 TE-IS 20 rt5 - rt5(4)
-2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
-2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
-2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
-2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
- rt5 -
-2001:db8::6/128 IP6 internal 30 rt5 - rt6(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt3
+ 2001:db8::3/128 IP6 internal 0 rt3(4)
+ rt1 TE-IS 10 rt1 - rt3(4)
+ rt2 TE-IS 10 rt2 - rt3(4)
+ rt5 TE-IS 10 rt5 - rt3(4)
+ rt2 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 - rt5(4)
+ rt6 TE-IS 20 rt5 - rt5(4)
+ 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
+ 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+ 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
+ 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
+ rt5 - rt4(4)
+ 2001:db8::6/128 IP6 internal 30 rt5 - rt6(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1555,24 +1641,26 @@ IS-IS L1 IPv6 routing table: test# test isis topology 13 root rt4 lfa system-id rt3
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt4
-10.0.255.4/32 IP internal 0 rt4(4)
-rt2 TE-IS 10 rt2 - rt4(4)
-rt3 TE-IS 10 rt3 - rt4(4)
-rt1 TE-IS 20 rt2 - rt2(4)
- rt3 - rt3(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-rt6 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt7 TE-IS 30 rt3 - rt5(4)
- rt6(4)
-10.0.255.1/32 IP TE 30 rt2 - rt1(4)
- rt3 -
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-10.0.255.6/32 IP TE 30 rt3 - rt6(4)
-10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt4
+ 10.0.255.4/32 IP internal 0 rt4(4)
+ rt2 TE-IS 10 rt2 - rt4(4)
+ rt3 TE-IS 10 rt3 - rt4(4)
+ rt1 TE-IS 20 rt2 - rt2(4)
+ rt3 - rt3(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ rt6 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt7 TE-IS 30 rt3 - rt5(4)
+ rt6(4)
+ 10.0.255.1/32 IP TE 30 rt2 - rt1(4)
+ rt3 - rt1(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ 10.0.255.6/32 IP TE 30 rt3 - rt6(4)
+ 10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1599,11 +1687,13 @@ IS-IS L1 IPv4 routing table: 10.0.255.7/32 120 - rt5 16070
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt4
-rt2 TE-IS 10 rt2 - rt4(4)
-rt3 TE-IS 10 rt3 - rt4(4)
-rt5 TE-IS 100 rt5 - rt4(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ----------------------------------------------------
+ rt4
+ rt2 TE-IS 10 rt2 - rt4(4)
+ rt3 TE-IS 10 rt3 - rt4(4)
+ rt5 TE-IS 100 rt5 - rt4(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1613,18 +1703,20 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt1 lfa system-id rt1 pseudonode-id 1
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 10 rt4 - rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt1
-rt5 TE-IS 20 rt4 - rt4(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt1
+ rt5 TE-IS 20 rt4 - rt4(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1641,18 +1733,20 @@ Backup: IS-IS L1 IPv4 routing table:
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 10 rt4 - rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt1
-rt5 TE-IS 20 rt4 - rt4(4)
-2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
-2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
-2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
-2001:db8::5/128 IP6 internal 30 rt4 - rt5(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt1
+ rt5 TE-IS 20 rt4 - rt4(4)
+ 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+ 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+ 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+ 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1670,18 +1764,20 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt1 lfa system-id rt2
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 10 rt4 - rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt1
-rt5 TE-IS 20 rt4 - rt4(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt1
+ rt5 TE-IS 20 rt4 - rt4(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1702,18 +1798,20 @@ IS-IS L1 IPv4 routing table: 10.0.255.2/32 30 - rt3 -
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 10 rt4 - rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt1
-rt5 TE-IS 20 rt4 - rt4(4)
-2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
-2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
-2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
-2001:db8::5/128 IP6 internal 30 rt4 - rt5(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt1
+ rt5 TE-IS 20 rt4 - rt4(4)
+ 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+ 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+ 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+ 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1735,19 +1833,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt5 lfa system-id rt4
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-10.0.255.5/32 IP internal 0 rt5(4)
-rt4 TE-IS 10 rt4 - rt5(4)
-rt1 pseudo_TE-IS 20 rt4 - rt4(4)
-rt1 TE-IS 20 rt4 - rt1(2)
-rt3 TE-IS 20 rt4 - rt1(2)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-rt2 TE-IS 30 rt4 - rt1(4)
- rt3(4)
-10.0.255.1/32 IP TE 30 rt4 - rt1(4)
-10.0.255.3/32 IP TE 30 rt4 - rt3(4)
-10.0.255.2/32 IP TE 40 rt4 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ------------------------------------------------------------------
+ rt5
+ 10.0.255.5/32 IP internal 0 rt5(4)
+ rt4 TE-IS 10 rt4 - rt5(4)
+ rt1 pseudo_TE-IS 20 rt4 - rt4(4)
+ rt1 TE-IS 20 rt4 - rt1(2)
+ rt3 TE-IS 20 rt4 - rt1(2)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ rt2 TE-IS 30 rt4 - rt1(4)
+ rt3(4)
+ 10.0.255.1/32 IP TE 30 rt4 - rt1(4)
+ 10.0.255.3/32 IP TE 30 rt4 - rt3(4)
+ 10.0.255.2/32 IP TE 40 rt4 - rt2(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1771,19 +1871,21 @@ IS-IS L1 IPv4 routing table: 10.0.255.4/32 70 - rt3 -
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-2001:db8::5/128 IP6 internal 0 rt5(4)
-rt4 TE-IS 10 rt4 - rt5(4)
-rt1 pseudo_TE-IS 20 rt4 - rt4(4)
-rt1 TE-IS 20 rt4 - rt1(2)
-rt3 TE-IS 20 rt4 - rt1(2)
-2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
-rt2 TE-IS 30 rt4 - rt1(4)
- rt3(4)
-2001:db8::1/128 IP6 internal 30 rt4 - rt1(4)
-2001:db8::3/128 IP6 internal 30 rt4 - rt3(4)
-2001:db8::2/128 IP6 internal 40 rt4 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt5
+ 2001:db8::5/128 IP6 internal 0 rt5(4)
+ rt4 TE-IS 10 rt4 - rt5(4)
+ rt1 pseudo_TE-IS 20 rt4 - rt4(4)
+ rt1 TE-IS 20 rt4 - rt1(2)
+ rt3 TE-IS 20 rt4 - rt1(2)
+ 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+ rt2 TE-IS 30 rt4 - rt1(4)
+ rt3(4)
+ 2001:db8::1/128 IP6 internal 30 rt4 - rt1(4)
+ 2001:db8::3/128 IP6 internal 30 rt4 - rt3(4)
+ 2001:db8::2/128 IP6 internal 40 rt4 - rt2(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1823,36 +1925,40 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt3 - rt5(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-rt4 TE-IS 40 rt3 - rt6(4)
-10.0.255.6/32 IP TE 40 rt3 - rt6(4)
-rt2 TE-IS 50 rt3 - rt4(4)
-10.0.255.4/32 IP TE 50 rt3 - rt4(4)
-10.0.255.2/32 IP TE 60 rt3 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt3 - rt5(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ rt4 TE-IS 40 rt3 - rt6(4)
+ 10.0.255.6/32 IP TE 40 rt3 - rt6(4)
+ rt2 TE-IS 50 rt3 - rt4(4)
+ 10.0.255.4/32 IP TE 50 rt3 - rt4(4)
+ 10.0.255.2/32 IP TE 60 rt3 - rt2(4)
+
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
- rt3 - rt5(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ rt3 - rt6(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -1890,36 +1996,40 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt3 - rt5(4)
-2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
-rt4 TE-IS 40 rt3 - rt6(4)
-2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
-rt2 TE-IS 50 rt3 - rt4(4)
-2001:db8::4/128 IP6 internal 50 rt3 - rt4(4)
-2001:db8::2/128 IP6 internal 60 rt3 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt3 - rt5(4)
+ 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
+ rt4 TE-IS 40 rt3 - rt6(4)
+ 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
+ rt2 TE-IS 50 rt3 - rt4(4)
+ 2001:db8::4/128 IP6 internal 50 rt3 - rt4(4)
+ 2001:db8::2/128 IP6 internal 60 rt3 - rt2(4)
+
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
-2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
- rt3 - rt5(4)
-2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
-2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
-2001:db8::6/128 IP6 internal 40 rt2 - rt6(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+ 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+ 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
+ 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
+ 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4)
+ rt3 - rt6(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -1964,39 +2074,43 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-10.0.255.5/32 IP internal 0 rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt4 TE-IS 20 rt6 - rt6(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt1 pseudo_TE-IS 30 rt6 - rt4(4)
-rt1 TE-IS 30 rt6 - rt1(2)
-10.0.255.4/32 IP TE 30 rt6 - rt4(4)
-rt3 TE-IS 40 rt3 - rt5(4)
-10.0.255.1/32 IP TE 40 rt6 - rt1(4)
-rt2 TE-IS 45 rt6 - rt1(4)
-10.0.255.3/32 IP TE 50 rt3 - rt3(4)
-10.0.255.2/32 IP TE 55 rt6 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ------------------------------------------------------------------
+ rt5
+ 10.0.255.5/32 IP internal 0 rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt4 TE-IS 20 rt6 - rt6(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt1 pseudo_TE-IS 30 rt6 - rt4(4)
+ rt1 TE-IS 30 rt6 - rt1(2)
+ 10.0.255.4/32 IP TE 30 rt6 - rt4(4)
+ rt3 TE-IS 40 rt3 - rt5(4)
+ 10.0.255.1/32 IP TE 40 rt6 - rt1(4)
+ rt2 TE-IS 45 rt6 - rt1(4)
+ 10.0.255.3/32 IP TE 50 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 55 rt6 - rt2(4)
+
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-10.0.255.5/32 IP internal 0 rt5(4)
-rt1 TE-IS 10 rt1 - rt5(4)
-rt4 TE-IS 10 rt4 - rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt1 pseudo_TE-IS 20 rt1 - rt1(4)
- rt4 - rt4(4)
-10.0.255.1/32 IP TE 20 rt1 - rt1(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt2 TE-IS 25 rt1 - rt1(4)
-10.0.255.2/32 IP TE 35 rt1 - rt2(4)
-rt3 TE-IS 40 rt3 - rt5(4)
- rt1 - rt1(4)
-10.0.255.3/32 IP TE 50 rt3 - rt3(4)
- rt1 -
+ Vertex Type Metric Next-Hop Interface Parent
+ ------------------------------------------------------------------
+ rt5
+ 10.0.255.5/32 IP internal 0 rt5(4)
+ rt1 TE-IS 10 rt1 - rt5(4)
+ rt4 TE-IS 10 rt4 - rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt4 - rt4(4)
+ 10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt2 TE-IS 25 rt1 - rt1(4)
+ 10.0.255.2/32 IP TE 35 rt1 - rt2(4)
+ rt3 TE-IS 40 rt3 - rt5(4)
+ rt1 - rt1(4)
+ 10.0.255.3/32 IP TE 50 rt3 - rt3(4)
+ rt1 - rt3(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -2041,39 +2155,43 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-2001:db8::5/128 IP6 internal 0 rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt4 TE-IS 20 rt6 - rt6(4)
-2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
-rt1 pseudo_TE-IS 30 rt6 - rt4(4)
-rt1 TE-IS 30 rt6 - rt1(2)
-2001:db8::4/128 IP6 internal 30 rt6 - rt4(4)
-rt3 TE-IS 40 rt3 - rt5(4)
-2001:db8::1/128 IP6 internal 40 rt6 - rt1(4)
-rt2 TE-IS 45 rt6 - rt1(4)
-2001:db8::3/128 IP6 internal 50 rt3 - rt3(4)
-2001:db8::2/128 IP6 internal 55 rt6 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt5
+ 2001:db8::5/128 IP6 internal 0 rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt4 TE-IS 20 rt6 - rt6(4)
+ 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
+ rt1 pseudo_TE-IS 30 rt6 - rt4(4)
+ rt1 TE-IS 30 rt6 - rt1(2)
+ 2001:db8::4/128 IP6 internal 30 rt6 - rt4(4)
+ rt3 TE-IS 40 rt3 - rt5(4)
+ 2001:db8::1/128 IP6 internal 40 rt6 - rt1(4)
+ rt2 TE-IS 45 rt6 - rt1(4)
+ 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4)
+ 2001:db8::2/128 IP6 internal 55 rt6 - rt2(4)
+
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-2001:db8::5/128 IP6 internal 0 rt5(4)
-rt1 TE-IS 10 rt1 - rt5(4)
-rt4 TE-IS 10 rt4 - rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt1 pseudo_TE-IS 20 rt1 - rt1(4)
- rt4 - rt4(4)
-2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
-2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
-2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
-rt2 TE-IS 25 rt1 - rt1(4)
-2001:db8::2/128 IP6 internal 35 rt1 - rt2(4)
-rt3 TE-IS 40 rt3 - rt5(4)
- rt1 - rt1(4)
-2001:db8::3/128 IP6 internal 50 rt3 - rt3(4)
- rt1 -
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt5
+ 2001:db8::5/128 IP6 internal 0 rt5(4)
+ rt1 TE-IS 10 rt1 - rt5(4)
+ rt4 TE-IS 10 rt4 - rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt4 - rt4(4)
+ 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
+ 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+ 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
+ rt2 TE-IS 25 rt1 - rt1(4)
+ 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4)
+ rt3 TE-IS 40 rt3 - rt5(4)
+ rt1 - rt1(4)
+ 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4)
+ rt1 - rt3(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -2123,38 +2241,42 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-10.0.255.5/32 IP internal 0 rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt4 TE-IS 20 rt6 - rt6(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt3 TE-IS 30 rt3 - rt5(4)
-rt2 TE-IS 30 rt6 - rt4(4)
-10.0.255.4/32 IP TE 30 rt6 - rt4(4)
-rt1 TE-IS 40 rt3 - rt3(4)
- rt6 - rt2(4)
-10.0.255.3/32 IP TE 40 rt3 - rt3(4)
-10.0.255.2/32 IP TE 40 rt6 - rt2(4)
-10.0.255.1/32 IP TE 50 rt3 - rt1(4)
- rt6 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt5
+ 10.0.255.5/32 IP internal 0 rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt4 TE-IS 20 rt6 - rt6(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt3 TE-IS 30 rt3 - rt5(4)
+ rt2 TE-IS 30 rt6 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt6 - rt4(4)
+ rt1 TE-IS 40 rt3 - rt3(4)
+ rt6 - rt2(4)
+ 10.0.255.3/32 IP TE 40 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 40 rt6 - rt2(4)
+ 10.0.255.1/32 IP TE 50 rt3 - rt1(4)
+ rt6 - rt1(4)
+
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-10.0.255.5/32 IP internal 0 rt5(4)
-rt4 TE-IS 10 rt4 - rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt2 TE-IS 20 rt4 - rt4(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt3 TE-IS 30 rt3 - rt5(4)
- rt4 - rt2(4)
-rt1 TE-IS 30 rt4 - rt2(4)
-10.0.255.2/32 IP TE 30 rt4 - rt2(4)
-10.0.255.3/32 IP TE 40 rt3 - rt3(4)
- rt4 -
-10.0.255.1/32 IP TE 40 rt4 - rt1(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt5
+ 10.0.255.5/32 IP internal 0 rt5(4)
+ rt4 TE-IS 10 rt4 - rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt2 TE-IS 20 rt4 - rt4(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt3 TE-IS 30 rt3 - rt5(4)
+ rt4 - rt2(4)
+ rt1 TE-IS 30 rt4 - rt2(4)
+ 10.0.255.2/32 IP TE 30 rt4 - rt2(4)
+ 10.0.255.3/32 IP TE 40 rt3 - rt3(4)
+ rt4 - rt3(4)
+ 10.0.255.1/32 IP TE 40 rt4 - rt1(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -2210,36 +2332,40 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-10.0.255.5/32 IP internal 0 rt5(4)
-rt4 TE-IS 10 rt4 - rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt2 TE-IS 20 rt4 - rt4(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt1 TE-IS 30 rt4 - rt2(4)
-rt3 TE-IS 30 rt4 - rt2(4)
-10.0.255.2/32 IP TE 30 rt4 - rt2(4)
-10.0.255.1/32 IP TE 40 rt4 - rt1(4)
-10.0.255.3/32 IP TE 40 rt4 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt5
+ 10.0.255.5/32 IP internal 0 rt5(4)
+ rt4 TE-IS 10 rt4 - rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt2 TE-IS 20 rt4 - rt4(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt1 TE-IS 30 rt4 - rt2(4)
+ rt3 TE-IS 30 rt4 - rt2(4)
+ 10.0.255.2/32 IP TE 30 rt4 - rt2(4)
+ 10.0.255.1/32 IP TE 40 rt4 - rt1(4)
+ 10.0.255.3/32 IP TE 40 rt4 - rt3(4)
+
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-10.0.255.5/32 IP internal 0 rt5(4)
-rt4 TE-IS 10 rt4 - rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt2 TE-IS 20 rt4 - rt4(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt3 TE-IS 30 rt3 - rt5(4)
- rt4 - rt2(4)
-rt1 TE-IS 30 rt4 - rt2(4)
-10.0.255.2/32 IP TE 30 rt4 - rt2(4)
-10.0.255.3/32 IP TE 40 rt3 - rt3(4)
- rt4 -
-10.0.255.1/32 IP TE 40 rt4 - rt1(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt5
+ 10.0.255.5/32 IP internal 0 rt5(4)
+ rt4 TE-IS 10 rt4 - rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt2 TE-IS 20 rt4 - rt4(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt3 TE-IS 30 rt3 - rt5(4)
+ rt4 - rt2(4)
+ rt1 TE-IS 30 rt4 - rt2(4)
+ 10.0.255.2/32 IP TE 30 rt4 - rt2(4)
+ 10.0.255.3/32 IP TE 40 rt3 - rt3(4)
+ rt4 - rt3(4)
+ 10.0.255.1/32 IP TE 40 rt4 - rt1(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -2276,44 +2402,48 @@ Q-space: rt8
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt7 TE-IS 30 rt3 - rt5(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-rt8 TE-IS 40 rt3 - rt7(4)
-10.0.255.7/32 IP TE 40 rt3 - rt7(4)
-rt6 TE-IS 50 rt3 - rt8(4)
-10.0.255.8/32 IP TE 50 rt3 - rt8(4)
-rt4 TE-IS 60 rt3 - rt6(4)
-10.0.255.6/32 IP TE 60 rt3 - rt6(4)
-rt2 TE-IS 70 rt3 - rt4(4)
-10.0.255.4/32 IP TE 70 rt3 - rt4(4)
-10.0.255.2/32 IP TE 80 rt3 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt7 TE-IS 30 rt3 - rt5(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ rt8 TE-IS 40 rt3 - rt7(4)
+ 10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+ rt6 TE-IS 50 rt3 - rt8(4)
+ 10.0.255.8/32 IP TE 50 rt3 - rt8(4)
+ rt4 TE-IS 60 rt3 - rt6(4)
+ 10.0.255.6/32 IP TE 60 rt3 - rt6(4)
+ rt2 TE-IS 70 rt3 - rt4(4)
+ 10.0.255.4/32 IP TE 70 rt3 - rt4(4)
+ 10.0.255.2/32 IP TE 80 rt3 - rt2(4)
+
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt2 - rt4(4)
-rt7 TE-IS 30 rt3 - rt5(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-rt8 TE-IS 40 rt2 - rt6(4)
- rt3 - rt7(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
-10.0.255.7/32 IP TE 40 rt3 - rt7(4)
-10.0.255.8/32 IP TE 50 rt2 - rt8(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ rt7 TE-IS 30 rt3 - rt5(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ rt8 TE-IS 40 rt2 - rt6(4)
+ rt3 - rt7(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ 10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+ 10.0.255.8/32 IP TE 50 rt2 - rt8(4)
+ rt3 - rt8(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -2362,46 +2492,50 @@ Q-space: rt3
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt4
-10.0.255.4/32 IP internal 0 rt4(4)
-rt2 TE-IS 10 rt2 - rt4(4)
-rt6 TE-IS 10 rt6 - rt4(4)
-rt1 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt6 - rt6(4)
-rt8 TE-IS 20 rt6 - rt6(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt3 TE-IS 30 rt2 - rt1(4)
-rt7 TE-IS 30 rt6 - rt5(4)
- rt8(4)
-10.0.255.1/32 IP TE 30 rt2 - rt1(4)
-10.0.255.5/32 IP TE 30 rt6 - rt5(4)
-10.0.255.8/32 IP TE 30 rt6 - rt8(4)
-10.0.255.3/32 IP TE 40 rt2 - rt3(4)
-10.0.255.7/32 IP TE 40 rt6 - rt7(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt4
+ 10.0.255.4/32 IP internal 0 rt4(4)
+ rt2 TE-IS 10 rt2 - rt4(4)
+ rt6 TE-IS 10 rt6 - rt4(4)
+ rt1 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt6 - rt6(4)
+ rt8 TE-IS 20 rt6 - rt6(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt3 TE-IS 30 rt2 - rt1(4)
+ rt7 TE-IS 30 rt6 - rt5(4)
+ rt8(4)
+ 10.0.255.1/32 IP TE 30 rt2 - rt1(4)
+ 10.0.255.5/32 IP TE 30 rt6 - rt5(4)
+ 10.0.255.8/32 IP TE 30 rt6 - rt8(4)
+ 10.0.255.3/32 IP TE 40 rt2 - rt3(4)
+ 10.0.255.7/32 IP TE 40 rt6 - rt7(4)
+
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt4
-10.0.255.4/32 IP internal 0 rt4(4)
-rt2 TE-IS 10 rt2 - rt4(4)
-rt3 TE-IS 10 rt3 - rt4(4)
-rt6 TE-IS 10 rt6 - rt4(4)
-rt1 TE-IS 20 rt2 - rt2(4)
- rt3 - rt3(4)
-rt5 TE-IS 20 rt6 - rt6(4)
-rt8 TE-IS 20 rt6 - rt6(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt7 TE-IS 30 rt6 - rt5(4)
- rt8(4)
-10.0.255.1/32 IP TE 30 rt2 - rt1(4)
- rt3 -
-10.0.255.5/32 IP TE 30 rt6 - rt5(4)
-10.0.255.8/32 IP TE 30 rt6 - rt8(4)
-10.0.255.7/32 IP TE 40 rt6 - rt7(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt4
+ 10.0.255.4/32 IP internal 0 rt4(4)
+ rt2 TE-IS 10 rt2 - rt4(4)
+ rt3 TE-IS 10 rt3 - rt4(4)
+ rt6 TE-IS 10 rt6 - rt4(4)
+ rt1 TE-IS 20 rt2 - rt2(4)
+ rt3 - rt3(4)
+ rt5 TE-IS 20 rt6 - rt6(4)
+ rt8 TE-IS 20 rt6 - rt6(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt7 TE-IS 30 rt6 - rt5(4)
+ rt8(4)
+ 10.0.255.1/32 IP TE 30 rt2 - rt1(4)
+ rt3 - rt1(4)
+ 10.0.255.5/32 IP TE 30 rt6 - rt5(4)
+ 10.0.255.8/32 IP TE 30 rt6 - rt8(4)
+ 10.0.255.7/32 IP TE 40 rt6 - rt7(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -2452,64 +2586,68 @@ Q-space: rt9
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt11
-10.0.255.11/32 IP internal 0 rt11(4)
-rt10 TE-IS 10 rt10 - rt11(4)
-rt12 TE-IS 10 rt12 - rt11(4)
-rt9 TE-IS 20 rt12 - rt12(4)
-10.0.255.10/32 IP TE 20 rt10 - rt10(4)
-10.0.255.12/32 IP TE 20 rt12 - rt12(4)
-rt7 TE-IS 30 rt10 - rt10(4)
-rt8 TE-IS 30 rt12 - rt9(4)
-10.0.255.9/32 IP TE 30 rt12 - rt9(4)
-rt4 TE-IS 40 rt10 - rt7(4)
-rt5 TE-IS 40 rt12 - rt8(4)
-10.0.255.7/32 IP TE 40 rt10 - rt7(4)
-10.0.255.8/32 IP TE 40 rt12 - rt8(4)
-rt6 TE-IS 50 rt12 - rt9(4)
- rt5(4)
-rt1 TE-IS 50 rt10 - rt4(4)
-rt2 TE-IS 50 rt12 - rt5(4)
-10.0.255.4/32 IP TE 50 rt10 - rt4(4)
-10.0.255.5/32 IP TE 50 rt12 - rt5(4)
-rt3 TE-IS 60 rt12 - rt6(4)
- rt2(4)
-10.0.255.6/32 IP TE 60 rt12 - rt6(4)
-10.0.255.1/32 IP TE 60 rt10 - rt1(4)
-10.0.255.2/32 IP TE 60 rt12 - rt2(4)
-10.0.255.3/32 IP TE 70 rt12 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt11
+ 10.0.255.11/32 IP internal 0 rt11(4)
+ rt10 TE-IS 10 rt10 - rt11(4)
+ rt12 TE-IS 10 rt12 - rt11(4)
+ rt9 TE-IS 20 rt12 - rt12(4)
+ 10.0.255.10/32 IP TE 20 rt10 - rt10(4)
+ 10.0.255.12/32 IP TE 20 rt12 - rt12(4)
+ rt7 TE-IS 30 rt10 - rt10(4)
+ rt8 TE-IS 30 rt12 - rt9(4)
+ 10.0.255.9/32 IP TE 30 rt12 - rt9(4)
+ rt4 TE-IS 40 rt10 - rt7(4)
+ rt5 TE-IS 40 rt12 - rt8(4)
+ 10.0.255.7/32 IP TE 40 rt10 - rt7(4)
+ 10.0.255.8/32 IP TE 40 rt12 - rt8(4)
+ rt6 TE-IS 50 rt12 - rt9(4)
+ rt5(4)
+ rt1 TE-IS 50 rt10 - rt4(4)
+ rt2 TE-IS 50 rt12 - rt5(4)
+ 10.0.255.4/32 IP TE 50 rt10 - rt4(4)
+ 10.0.255.5/32 IP TE 50 rt12 - rt5(4)
+ rt3 TE-IS 60 rt12 - rt6(4)
+ rt2(4)
+ 10.0.255.6/32 IP TE 60 rt12 - rt6(4)
+ 10.0.255.1/32 IP TE 60 rt10 - rt1(4)
+ 10.0.255.2/32 IP TE 60 rt12 - rt2(4)
+ 10.0.255.3/32 IP TE 70 rt12 - rt3(4)
+
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt11
-10.0.255.11/32 IP internal 0 rt11(4)
-rt8 TE-IS 10 rt8 - rt11(4)
-rt10 TE-IS 10 rt10 - rt11(4)
-rt12 TE-IS 10 rt12 - rt11(4)
-rt5 TE-IS 20 rt8 - rt8(4)
-rt7 TE-IS 20 rt8 - rt8(4)
-rt9 TE-IS 20 rt8 - rt8(4)
- rt12 - rt12(4)
-10.0.255.8/32 IP TE 20 rt8 - rt8(4)
-10.0.255.10/32 IP TE 20 rt10 - rt10(4)
-10.0.255.12/32 IP TE 20 rt12 - rt12(4)
-rt2 TE-IS 30 rt8 - rt5(4)
-rt4 TE-IS 30 rt8 - rt5(4)
- rt7(4)
-rt6 TE-IS 30 rt8 - rt5(4)
-10.0.255.5/32 IP TE 30 rt8 - rt5(4)
-10.0.255.7/32 IP TE 30 rt8 - rt7(4)
-10.0.255.9/32 IP TE 30 rt8 - rt9(4)
- rt12 -
-rt3 TE-IS 40 rt8 - rt2(4)
- rt6(4)
-rt1 TE-IS 40 rt8 - rt4(4)
-10.0.255.2/32 IP TE 40 rt8 - rt2(4)
-10.0.255.4/32 IP TE 40 rt8 - rt4(4)
-10.0.255.6/32 IP TE 40 rt8 - rt6(4)
-10.0.255.3/32 IP TE 50 rt8 - rt3(4)
-10.0.255.1/32 IP TE 50 rt8 - rt1(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt11
+ 10.0.255.11/32 IP internal 0 rt11(4)
+ rt8 TE-IS 10 rt8 - rt11(4)
+ rt10 TE-IS 10 rt10 - rt11(4)
+ rt12 TE-IS 10 rt12 - rt11(4)
+ rt5 TE-IS 20 rt8 - rt8(4)
+ rt7 TE-IS 20 rt8 - rt8(4)
+ rt9 TE-IS 20 rt8 - rt8(4)
+ rt12 - rt12(4)
+ 10.0.255.8/32 IP TE 20 rt8 - rt8(4)
+ 10.0.255.10/32 IP TE 20 rt10 - rt10(4)
+ 10.0.255.12/32 IP TE 20 rt12 - rt12(4)
+ rt2 TE-IS 30 rt8 - rt5(4)
+ rt4 TE-IS 30 rt8 - rt5(4)
+ rt7(4)
+ rt6 TE-IS 30 rt8 - rt5(4)
+ 10.0.255.5/32 IP TE 30 rt8 - rt5(4)
+ 10.0.255.7/32 IP TE 30 rt8 - rt7(4)
+ 10.0.255.9/32 IP TE 30 rt8 - rt9(4)
+ rt12 - rt9(4)
+ rt3 TE-IS 40 rt8 - rt2(4)
+ rt6(4)
+ rt1 TE-IS 40 rt8 - rt4(4)
+ 10.0.255.2/32 IP TE 40 rt8 - rt2(4)
+ 10.0.255.4/32 IP TE 40 rt8 - rt4(4)
+ 10.0.255.6/32 IP TE 40 rt8 - rt6(4)
+ 10.0.255.3/32 IP TE 50 rt8 - rt3(4)
+ 10.0.255.1/32 IP TE 50 rt8 - rt1(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -2577,73 +2715,77 @@ Q-space: rt12
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt6
-10.0.255.6/32 IP internal 0 rt6(4)
-rt3 TE-IS 10 rt3 - rt6(4)
-rt2 TE-IS 20 rt3 - rt3(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt9 TE-IS 30 rt9 - rt6(4)
-rt5 TE-IS 30 rt3 - rt2(4)
-10.0.255.2/32 IP TE 30 rt3 - rt2(4)
-rt8 TE-IS 40 rt9 - rt9(4)
- rt3 - rt5(4)
-rt12 TE-IS 40 rt9 - rt9(4)
-rt4 TE-IS 40 rt3 - rt5(4)
-10.0.255.9/32 IP TE 40 rt9 - rt9(4)
-10.0.255.5/32 IP TE 40 rt3 - rt5(4)
-rt7 TE-IS 50 rt9 - rt8(4)
- rt3 - rt4(4)
-rt11 TE-IS 50 rt9 - rt8(4)
- rt3 - rt12(4)
-rt1 TE-IS 50 rt3 - rt4(4)
-10.0.255.8/32 IP TE 50 rt9 - rt8(4)
- rt3 -
-10.0.255.12/32 IP TE 50 rt9 - rt12(4)
-10.0.255.4/32 IP TE 50 rt3 - rt4(4)
-rt10 TE-IS 60 rt9 - rt11(4)
- rt3 -
-10.0.255.7/32 IP TE 60 rt9 - rt7(4)
- rt3 -
-10.0.255.11/32 IP TE 60 rt9 - rt11(4)
- rt3 -
-10.0.255.1/32 IP TE 60 rt3 - rt1(4)
-10.0.255.10/32 IP TE 70 rt9 - rt10(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt6
+ 10.0.255.6/32 IP internal 0 rt6(4)
+ rt3 TE-IS 10 rt3 - rt6(4)
+ rt2 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt9 TE-IS 30 rt9 - rt6(4)
+ rt5 TE-IS 30 rt3 - rt2(4)
+ 10.0.255.2/32 IP TE 30 rt3 - rt2(4)
+ rt8 TE-IS 40 rt9 - rt9(4)
+ rt3 - rt5(4)
+ rt12 TE-IS 40 rt9 - rt9(4)
+ rt4 TE-IS 40 rt3 - rt5(4)
+ 10.0.255.9/32 IP TE 40 rt9 - rt9(4)
+ 10.0.255.5/32 IP TE 40 rt3 - rt5(4)
+ rt7 TE-IS 50 rt9 - rt8(4)
+ rt3 - rt4(4)
+ rt11 TE-IS 50 rt9 - rt8(4)
+ rt3 - rt12(4)
+ rt1 TE-IS 50 rt3 - rt4(4)
+ 10.0.255.8/32 IP TE 50 rt9 - rt8(4)
+ rt3 - rt8(4)
+ 10.0.255.12/32 IP TE 50 rt9 - rt12(4)
+ 10.0.255.4/32 IP TE 50 rt3 - rt4(4)
+ rt10 TE-IS 60 rt9 - rt11(4)
+ rt3 - rt11(4)
+ 10.0.255.7/32 IP TE 60 rt9 - rt7(4)
+ rt3 - rt7(4)
+ 10.0.255.11/32 IP TE 60 rt9 - rt11(4)
+ rt3 - rt11(4)
+ 10.0.255.1/32 IP TE 60 rt3 - rt1(4)
+ 10.0.255.10/32 IP TE 70 rt9 - rt10(4)
+ rt3 - rt10(4)
+
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt6
-10.0.255.6/32 IP internal 0 rt6(4)
-rt3 TE-IS 10 rt3 - rt6(4)
-rt5 TE-IS 10 rt5 - rt6(4)
-rt2 TE-IS 20 rt3 - rt3(4)
- rt5 - rt5(4)
-rt4 TE-IS 20 rt5 - rt5(4)
-rt8 TE-IS 20 rt5 - rt5(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-10.0.255.5/32 IP TE 20 rt5 - rt5(4)
-rt9 TE-IS 30 rt9 - rt6(4)
- rt5 - rt8(4)
-rt1 TE-IS 30 rt5 - rt4(4)
-rt7 TE-IS 30 rt5 - rt4(4)
- rt8(4)
-rt11 TE-IS 30 rt5 - rt8(4)
-10.0.255.2/32 IP TE 30 rt3 - rt2(4)
- rt5 -
-10.0.255.4/32 IP TE 30 rt5 - rt4(4)
-10.0.255.8/32 IP TE 30 rt5 - rt8(4)
-rt12 TE-IS 40 rt9 - rt9(4)
- rt5 - rt11(4)
-rt10 TE-IS 40 rt5 - rt11(4)
-10.0.255.9/32 IP TE 40 rt9 - rt9(4)
- rt5 -
-10.0.255.1/32 IP TE 40 rt5 - rt1(4)
-10.0.255.7/32 IP TE 40 rt5 - rt7(4)
-10.0.255.11/32 IP TE 40 rt5 - rt11(4)
-10.0.255.12/32 IP TE 50 rt9 - rt12(4)
- rt5 -
-10.0.255.10/32 IP TE 50 rt5 - rt10(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt6
+ 10.0.255.6/32 IP internal 0 rt6(4)
+ rt3 TE-IS 10 rt3 - rt6(4)
+ rt5 TE-IS 10 rt5 - rt6(4)
+ rt2 TE-IS 20 rt3 - rt3(4)
+ rt5 - rt5(4)
+ rt4 TE-IS 20 rt5 - rt5(4)
+ rt8 TE-IS 20 rt5 - rt5(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ 10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+ rt9 TE-IS 30 rt9 - rt6(4)
+ rt5 - rt8(4)
+ rt1 TE-IS 30 rt5 - rt4(4)
+ rt7 TE-IS 30 rt5 - rt4(4)
+ rt8(4)
+ rt11 TE-IS 30 rt5 - rt8(4)
+ 10.0.255.2/32 IP TE 30 rt3 - rt2(4)
+ rt5 - rt2(4)
+ 10.0.255.4/32 IP TE 30 rt5 - rt4(4)
+ 10.0.255.8/32 IP TE 30 rt5 - rt8(4)
+ rt12 TE-IS 40 rt9 - rt9(4)
+ rt5 - rt11(4)
+ rt10 TE-IS 40 rt5 - rt11(4)
+ 10.0.255.9/32 IP TE 40 rt9 - rt9(4)
+ rt5 - rt9(4)
+ 10.0.255.1/32 IP TE 40 rt5 - rt1(4)
+ 10.0.255.7/32 IP TE 40 rt5 - rt7(4)
+ 10.0.255.11/32 IP TE 40 rt5 - rt11(4)
+ 10.0.255.12/32 IP TE 50 rt9 - rt12(4)
+ rt5 - rt12(4)
+ 10.0.255.10/32 IP TE 50 rt5 - rt10(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -2706,62 +2848,66 @@ Q-space: rt12
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt2
-10.0.255.2/32 IP internal 0 rt2(4)
-rt1 TE-IS 10 rt1 - rt2(4)
-rt3 TE-IS 10 rt3 - rt2(4)
-rt4 TE-IS 20 rt1 - rt1(4)
-rt6 TE-IS 20 rt3 - rt3(4)
-10.0.255.1/32 IP TE 20 rt1 - rt1(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt7 TE-IS 30 rt1 - rt4(4)
-rt5 TE-IS 30 rt3 - rt6(4)
-10.0.255.4/32 IP TE 30 rt1 - rt4(4)
-10.0.255.6/32 IP TE 30 rt3 - rt6(4)
-rt10 TE-IS 40 rt1 - rt7(4)
-rt8 TE-IS 40 rt3 - rt5(4)
-10.0.255.7/32 IP TE 40 rt1 - rt7(4)
-10.0.255.5/32 IP TE 40 rt3 - rt5(4)
-rt9 TE-IS 50 rt3 - rt8(4)
-rt11 TE-IS 50 rt3 - rt8(4)
-10.0.255.10/32 IP TE 50 rt1 - rt10(4)
-10.0.255.8/32 IP TE 50 rt3 - rt8(4)
-rt12 TE-IS 60 rt3 - rt9(4)
- rt11(4)
-10.0.255.9/32 IP TE 60 rt3 - rt9(4)
-10.0.255.11/32 IP TE 60 rt3 - rt11(4)
-10.0.255.12/32 IP TE 70 rt3 - rt12(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt2
+ 10.0.255.2/32 IP internal 0 rt2(4)
+ rt1 TE-IS 10 rt1 - rt2(4)
+ rt3 TE-IS 10 rt3 - rt2(4)
+ rt4 TE-IS 20 rt1 - rt1(4)
+ rt6 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt7 TE-IS 30 rt1 - rt4(4)
+ rt5 TE-IS 30 rt3 - rt6(4)
+ 10.0.255.4/32 IP TE 30 rt1 - rt4(4)
+ 10.0.255.6/32 IP TE 30 rt3 - rt6(4)
+ rt10 TE-IS 40 rt1 - rt7(4)
+ rt8 TE-IS 40 rt3 - rt5(4)
+ 10.0.255.7/32 IP TE 40 rt1 - rt7(4)
+ 10.0.255.5/32 IP TE 40 rt3 - rt5(4)
+ rt9 TE-IS 50 rt3 - rt8(4)
+ rt11 TE-IS 50 rt3 - rt8(4)
+ 10.0.255.10/32 IP TE 50 rt1 - rt10(4)
+ 10.0.255.8/32 IP TE 50 rt3 - rt8(4)
+ rt12 TE-IS 60 rt3 - rt9(4)
+ rt11(4)
+ 10.0.255.9/32 IP TE 60 rt3 - rt9(4)
+ 10.0.255.11/32 IP TE 60 rt3 - rt11(4)
+ 10.0.255.12/32 IP TE 70 rt3 - rt12(4)
+
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt2
-10.0.255.2/32 IP internal 0 rt2(4)
-rt1 TE-IS 10 rt1 - rt2(4)
-rt3 TE-IS 10 rt3 - rt2(4)
-rt5 TE-IS 10 rt5 - rt2(4)
-rt4 TE-IS 20 rt1 - rt1(4)
-rt6 TE-IS 20 rt3 - rt3(4)
- rt5 - rt5(4)
-rt8 TE-IS 20 rt5 - rt5(4)
-10.0.255.1/32 IP TE 20 rt1 - rt1(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-10.0.255.5/32 IP TE 20 rt5 - rt5(4)
-rt7 TE-IS 30 rt1 - rt4(4)
-rt9 TE-IS 30 rt5 - rt8(4)
-rt11 TE-IS 30 rt5 - rt8(4)
-10.0.255.4/32 IP TE 30 rt1 - rt4(4)
-10.0.255.6/32 IP TE 30 rt3 - rt6(4)
- rt5 -
-10.0.255.8/32 IP TE 30 rt5 - rt8(4)
-rt10 TE-IS 40 rt1 - rt7(4)
-rt12 TE-IS 40 rt5 - rt9(4)
- rt11(4)
-10.0.255.7/32 IP TE 40 rt1 - rt7(4)
-10.0.255.9/32 IP TE 40 rt5 - rt9(4)
-10.0.255.11/32 IP TE 40 rt5 - rt11(4)
-10.0.255.10/32 IP TE 50 rt1 - rt10(4)
-10.0.255.12/32 IP TE 50 rt5 - rt12(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt2
+ 10.0.255.2/32 IP internal 0 rt2(4)
+ rt1 TE-IS 10 rt1 - rt2(4)
+ rt3 TE-IS 10 rt3 - rt2(4)
+ rt5 TE-IS 10 rt5 - rt2(4)
+ rt4 TE-IS 20 rt1 - rt1(4)
+ rt6 TE-IS 20 rt3 - rt3(4)
+ rt5 - rt5(4)
+ rt8 TE-IS 20 rt5 - rt5(4)
+ 10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ 10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+ rt7 TE-IS 30 rt1 - rt4(4)
+ rt9 TE-IS 30 rt5 - rt8(4)
+ rt11 TE-IS 30 rt5 - rt8(4)
+ 10.0.255.4/32 IP TE 30 rt1 - rt4(4)
+ 10.0.255.6/32 IP TE 30 rt3 - rt6(4)
+ rt5 - rt6(4)
+ 10.0.255.8/32 IP TE 30 rt5 - rt8(4)
+ rt10 TE-IS 40 rt1 - rt7(4)
+ rt12 TE-IS 40 rt5 - rt9(4)
+ rt11(4)
+ 10.0.255.7/32 IP TE 40 rt1 - rt7(4)
+ 10.0.255.9/32 IP TE 40 rt5 - rt9(4)
+ 10.0.255.11/32 IP TE 40 rt5 - rt11(4)
+ 10.0.255.10/32 IP TE 50 rt1 - rt10(4)
+ 10.0.255.12/32 IP TE 50 rt5 - rt12(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -2815,36 +2961,40 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt2
-10.0.255.2/32 IP internal 0 rt2(4)
-rt1 TE-IS 50 rt1 - rt2(4)
-rt3 TE-IS 50 rt3 - rt2(4)
-rt2
-rt5 TE-IS 60 rt3 - rt3(4)
-10.0.255.1/32 IP TE 60 rt1 - rt1(4)
-10.0.255.3/32 IP TE 60 rt3 - rt3(4)
-rt4 TE-IS 70 rt3 - rt5(4)
-rt6 TE-IS 70 rt3 - rt5(4)
-10.0.255.5/32 IP TE 70 rt3 - rt5(4)
-10.0.255.4/32 IP TE 80 rt3 - rt4(4)
-10.0.255.6/32 IP TE 80 rt3 - rt6(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt2
+ 10.0.255.2/32 IP internal 0 rt2(4)
+ rt1 TE-IS 50 rt1 - rt2(4)
+ rt3 TE-IS 50 rt3 - rt2(4)
+ rt2
+ rt5 TE-IS 60 rt3 - rt3(4)
+ 10.0.255.1/32 IP TE 60 rt1 - rt1(4)
+ 10.0.255.3/32 IP TE 60 rt3 - rt3(4)
+ rt4 TE-IS 70 rt3 - rt5(4)
+ rt6 TE-IS 70 rt3 - rt5(4)
+ 10.0.255.5/32 IP TE 70 rt3 - rt5(4)
+ 10.0.255.4/32 IP TE 80 rt3 - rt4(4)
+ 10.0.255.6/32 IP TE 80 rt3 - rt6(4)
+
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt2
-10.0.255.2/32 IP internal 0 rt2(4)
-rt4 TE-IS 10 rt4 - rt2(4)
-rt5 TE-IS 20 rt4 - rt4(4)
-rt6 TE-IS 20 rt4 - rt4(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-rt3 TE-IS 30 rt4 - rt5(4)
-10.0.255.5/32 IP TE 30 rt4 - rt5(4)
-10.0.255.6/32 IP TE 30 rt4 - rt6(4)
-rt2
-rt1 TE-IS 40 rt4 - rt2(2)
-10.0.255.3/32 IP TE 40 rt4 - rt3(4)
-10.0.255.1/32 IP TE 50 rt4 - rt1(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt2
+ 10.0.255.2/32 IP internal 0 rt2(4)
+ rt4 TE-IS 10 rt4 - rt2(4)
+ rt5 TE-IS 20 rt4 - rt4(4)
+ rt6 TE-IS 20 rt4 - rt4(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ rt3 TE-IS 30 rt4 - rt5(4)
+ 10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+ 10.0.255.6/32 IP TE 30 rt4 - rt6(4)
+ rt2
+ rt1 TE-IS 40 rt4 - rt2(2)
+ 10.0.255.3/32 IP TE 40 rt4 - rt3(4)
+ 10.0.255.1/32 IP TE 50 rt4 - rt1(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -2893,36 +3043,40 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt2
-2001:db8::2/128 IP6 internal 0 rt2(4)
-rt1 TE-IS 50 rt1 - rt2(4)
-rt3 TE-IS 50 rt3 - rt2(4)
-rt2
-rt5 TE-IS 60 rt3 - rt3(4)
-2001:db8::1/128 IP6 internal 60 rt1 - rt1(4)
-2001:db8::3/128 IP6 internal 60 rt3 - rt3(4)
-rt4 TE-IS 70 rt3 - rt5(4)
-rt6 TE-IS 70 rt3 - rt5(4)
-2001:db8::5/128 IP6 internal 70 rt3 - rt5(4)
-2001:db8::4/128 IP6 internal 80 rt3 - rt4(4)
-2001:db8::6/128 IP6 internal 80 rt3 - rt6(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt2
+ 2001:db8::2/128 IP6 internal 0 rt2(4)
+ rt1 TE-IS 50 rt1 - rt2(4)
+ rt3 TE-IS 50 rt3 - rt2(4)
+ rt2
+ rt5 TE-IS 60 rt3 - rt3(4)
+ 2001:db8::1/128 IP6 internal 60 rt1 - rt1(4)
+ 2001:db8::3/128 IP6 internal 60 rt3 - rt3(4)
+ rt4 TE-IS 70 rt3 - rt5(4)
+ rt6 TE-IS 70 rt3 - rt5(4)
+ 2001:db8::5/128 IP6 internal 70 rt3 - rt5(4)
+ 2001:db8::4/128 IP6 internal 80 rt3 - rt4(4)
+ 2001:db8::6/128 IP6 internal 80 rt3 - rt6(4)
+
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt2
-2001:db8::2/128 IP6 internal 0 rt2(4)
-rt4 TE-IS 10 rt4 - rt2(4)
-rt5 TE-IS 20 rt4 - rt4(4)
-rt6 TE-IS 20 rt4 - rt4(4)
-2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
-rt3 TE-IS 30 rt4 - rt5(4)
-2001:db8::5/128 IP6 internal 30 rt4 - rt5(4)
-2001:db8::6/128 IP6 internal 30 rt4 - rt6(4)
-rt2
-rt1 TE-IS 40 rt4 - rt2(2)
-2001:db8::3/128 IP6 internal 40 rt4 - rt3(4)
-2001:db8::1/128 IP6 internal 50 rt4 - rt1(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt2
+ 2001:db8::2/128 IP6 internal 0 rt2(4)
+ rt4 TE-IS 10 rt4 - rt2(4)
+ rt5 TE-IS 20 rt4 - rt4(4)
+ rt6 TE-IS 20 rt4 - rt4(4)
+ 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+ rt3 TE-IS 30 rt4 - rt5(4)
+ 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4)
+ 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4)
+ rt2
+ rt1 TE-IS 40 rt4 - rt2(2)
+ 2001:db8::3/128 IP6 internal 40 rt4 - rt3(4)
+ 2001:db8::1/128 IP6 internal 50 rt4 - rt1(4)
+
Main:
IS-IS L1 IPv6 routing table:
@@ -2966,42 +3120,46 @@ Q-space: rt7
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-rt3 TE-IS 30 rt2 - rt4(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-rt5 TE-IS 40 rt2 - rt3(4)
-rt6 TE-IS 40 rt2 - rt3(4)
-10.0.255.3/32 IP TE 40 rt2 - rt3(4)
-rt7 TE-IS 50 rt2 - rt5(4)
- rt6(4)
-10.0.255.5/32 IP TE 50 rt2 - rt5(4)
-10.0.255.6/32 IP TE 50 rt2 - rt6(4)
-10.0.255.7/32 IP TE 60 rt2 - rt7(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ rt3 TE-IS 30 rt2 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ rt5 TE-IS 40 rt2 - rt3(4)
+ rt6 TE-IS 40 rt2 - rt3(4)
+ 10.0.255.3/32 IP TE 40 rt2 - rt3(4)
+ rt7 TE-IS 50 rt2 - rt5(4)
+ rt6(4)
+ 10.0.255.5/32 IP TE 50 rt2 - rt5(4)
+ 10.0.255.6/32 IP TE 50 rt2 - rt6(4)
+ 10.0.255.7/32 IP TE 60 rt2 - rt7(4)
+
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
- rt3 - rt3(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-rt6 TE-IS 20 rt3 - rt3(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt7 TE-IS 30 rt3 - rt5(4)
- rt6(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
- rt3 -
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-10.0.255.6/32 IP TE 30 rt3 - rt6(4)
-10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ rt3 - rt3(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ rt6 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt7 TE-IS 30 rt3 - rt5(4)
+ rt6(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ rt3 - rt4(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ 10.0.255.6/32 IP TE 30 rt3 - rt6(4)
+ 10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+
Main:
IS-IS L1 IPv4 routing table:
@@ -3044,19 +3202,21 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt3 - rt5(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-rt4 TE-IS 40 rt3 - rt6(4)
-10.0.255.6/32 IP TE 40 rt3 - rt6(4)
-rt2 TE-IS 50 rt3 - rt4(4)
-10.0.255.4/32 IP TE 50 rt3 - rt4(4)
-10.0.255.2/32 IP TE 60 rt3 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt3 - rt5(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ rt4 TE-IS 40 rt3 - rt6(4)
+ 10.0.255.6/32 IP TE 40 rt3 - rt6(4)
+ rt2 TE-IS 50 rt3 - rt4(4)
+ 10.0.255.4/32 IP TE 50 rt3 - rt4(4)
+ 10.0.255.2/32 IP TE 60 rt3 - rt2(4)
+
IS-IS L1 IPv4 routing table:
@@ -3080,19 +3240,21 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
-rt6 TE-IS 30 rt3 - rt5(4)
-2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
-rt4 TE-IS 40 rt3 - rt6(4)
-2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
-rt2 TE-IS 50 rt3 - rt4(4)
-2001:db8::4/128 IP6 internal 50 rt3 - rt4(4)
-2001:db8::2/128 IP6 internal 60 rt3 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+ rt6 TE-IS 30 rt3 - rt5(4)
+ 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
+ rt4 TE-IS 40 rt3 - rt6(4)
+ 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
+ rt2 TE-IS 50 rt3 - rt4(4)
+ 2001:db8::4/128 IP6 internal 50 rt3 - rt4(4)
+ 2001:db8::2/128 IP6 internal 60 rt3 - rt2(4)
+
IS-IS L1 IPv6 routing table:
@@ -3127,22 +3289,24 @@ Q-space: rt3
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt4 TE-IS 10 rt4 - rt1(4)
-rt5 TE-IS 10 rt5 - rt1(4)
-rt2 TE-IS 15 rt2 - rt1(4)
-rt1
-rt6 TE-IS 20 rt4 - rt4(4)
- rt5 - rt5(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-10.0.255.5/32 IP TE 20 rt5 - rt5(4)
-10.0.255.2/32 IP TE 25 rt2 - rt2(4)
-10.0.255.6/32 IP TE 30 rt4 - rt6(4)
- rt5 -
-rt3 TE-IS 50 rt5 - rt5(4)
-10.0.255.3/32 IP TE 60 rt5 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt5 TE-IS 10 rt5 - rt1(4)
+ rt2 TE-IS 15 rt2 - rt1(4)
+ rt1
+ rt6 TE-IS 20 rt4 - rt4(4)
+ rt5 - rt5(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ 10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+ 10.0.255.2/32 IP TE 25 rt2 - rt2(4)
+ 10.0.255.6/32 IP TE 30 rt4 - rt6(4)
+ rt5 - rt6(4)
+ rt3 TE-IS 50 rt5 - rt5(4)
+ 10.0.255.3/32 IP TE 60 rt5 - rt3(4)
+
IS-IS L1 IPv4 routing table:
@@ -3175,22 +3339,24 @@ Q-space: rt3
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt4 TE-IS 10 rt4 - rt1(4)
-rt5 TE-IS 10 rt5 - rt1(4)
-rt2 TE-IS 15 rt2 - rt1(4)
-rt1
-rt6 TE-IS 20 rt4 - rt4(4)
- rt5 - rt5(4)
-2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
-2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
-2001:db8::2/128 IP6 internal 25 rt2 - rt2(4)
-2001:db8::6/128 IP6 internal 30 rt4 - rt6(4)
- rt5 -
-rt3 TE-IS 50 rt5 - rt5(4)
-2001:db8::3/128 IP6 internal 60 rt5 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt4 TE-IS 10 rt4 - rt1(4)
+ rt5 TE-IS 10 rt5 - rt1(4)
+ rt2 TE-IS 15 rt2 - rt1(4)
+ rt1
+ rt6 TE-IS 20 rt4 - rt4(4)
+ rt5 - rt5(4)
+ 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+ 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
+ 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4)
+ 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4)
+ rt5 - rt6(4)
+ rt3 TE-IS 50 rt5 - rt5(4)
+ 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4)
+
IS-IS L1 IPv6 routing table:
@@ -3217,20 +3383,22 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 15 rt2 - rt1(4)
-10.0.255.2/32 IP TE 25 rt2 - rt2(4)
-rt3 TE-IS 30 rt3 - rt1(4)
-10.0.255.3/32 IP TE 40 rt3 - rt3(4)
-rt4 TE-IS 55 rt2 - rt2(4)
-rt1
-rt6 TE-IS 65 rt2 - rt4(4)
-rt5 TE-IS 65 rt2 - rt1(2)
-10.0.255.4/32 IP TE 65 rt2 - rt4(4)
-10.0.255.6/32 IP TE 75 rt2 - rt6(4)
-10.0.255.5/32 IP TE 75 rt2 - rt5(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 15 rt2 - rt1(4)
+ 10.0.255.2/32 IP TE 25 rt2 - rt2(4)
+ rt3 TE-IS 30 rt3 - rt1(4)
+ 10.0.255.3/32 IP TE 40 rt3 - rt3(4)
+ rt4 TE-IS 55 rt2 - rt2(4)
+ rt1
+ rt6 TE-IS 65 rt2 - rt4(4)
+ rt5 TE-IS 65 rt2 - rt1(2)
+ 10.0.255.4/32 IP TE 65 rt2 - rt4(4)
+ 10.0.255.6/32 IP TE 75 rt2 - rt6(4)
+ 10.0.255.5/32 IP TE 75 rt2 - rt5(4)
+
IS-IS L1 IPv4 routing table:
@@ -3258,20 +3426,22 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt2 TE-IS 15 rt2 - rt1(4)
-2001:db8::2/128 IP6 internal 25 rt2 - rt2(4)
-rt3 TE-IS 30 rt3 - rt1(4)
-2001:db8::3/128 IP6 internal 40 rt3 - rt3(4)
-rt4 TE-IS 55 rt2 - rt2(4)
-rt1
-rt6 TE-IS 65 rt2 - rt4(4)
-rt5 TE-IS 65 rt2 - rt1(2)
-2001:db8::4/128 IP6 internal 65 rt2 - rt4(4)
-2001:db8::6/128 IP6 internal 75 rt2 - rt6(4)
-2001:db8::5/128 IP6 internal 75 rt2 - rt5(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt2 TE-IS 15 rt2 - rt1(4)
+ 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4)
+ rt3 TE-IS 30 rt3 - rt1(4)
+ 2001:db8::3/128 IP6 internal 40 rt3 - rt3(4)
+ rt4 TE-IS 55 rt2 - rt2(4)
+ rt1
+ rt6 TE-IS 65 rt2 - rt4(4)
+ rt5 TE-IS 65 rt2 - rt1(2)
+ 2001:db8::4/128 IP6 internal 65 rt2 - rt4(4)
+ 2001:db8::6/128 IP6 internal 75 rt2 - rt6(4)
+ 2001:db8::5/128 IP6 internal 75 rt2 - rt5(4)
+
IS-IS L1 IPv6 routing table:
@@ -3303,20 +3473,22 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-10.0.255.5/32 IP internal 0 rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt4 TE-IS 20 rt6 - rt6(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt1 pseudo_TE-IS 30 rt6 - rt4(4)
-rt1 TE-IS 30 rt6 - rt1(2)
-10.0.255.4/32 IP TE 30 rt6 - rt4(4)
-rt3 TE-IS 40 rt3 - rt5(4)
-10.0.255.1/32 IP TE 40 rt6 - rt1(4)
-rt2 TE-IS 45 rt6 - rt1(4)
-10.0.255.3/32 IP TE 50 rt3 - rt3(4)
-10.0.255.2/32 IP TE 55 rt6 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ ------------------------------------------------------------------
+ rt5
+ 10.0.255.5/32 IP internal 0 rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt4 TE-IS 20 rt6 - rt6(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt1 pseudo_TE-IS 30 rt6 - rt4(4)
+ rt1 TE-IS 30 rt6 - rt1(2)
+ 10.0.255.4/32 IP TE 30 rt6 - rt4(4)
+ rt3 TE-IS 40 rt3 - rt5(4)
+ 10.0.255.1/32 IP TE 40 rt6 - rt1(4)
+ rt2 TE-IS 45 rt6 - rt1(4)
+ 10.0.255.3/32 IP TE 50 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 55 rt6 - rt2(4)
+
IS-IS L1 IPv4 routing table:
@@ -3347,20 +3519,22 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-2001:db8::5/128 IP6 internal 0 rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt4 TE-IS 20 rt6 - rt6(4)
-2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
-rt1 pseudo_TE-IS 30 rt6 - rt4(4)
-rt1 TE-IS 30 rt6 - rt1(2)
-2001:db8::4/128 IP6 internal 30 rt6 - rt4(4)
-rt3 TE-IS 40 rt3 - rt5(4)
-2001:db8::1/128 IP6 internal 40 rt6 - rt1(4)
-rt2 TE-IS 45 rt6 - rt1(4)
-2001:db8::3/128 IP6 internal 50 rt3 - rt3(4)
-2001:db8::2/128 IP6 internal 55 rt6 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt5
+ 2001:db8::5/128 IP6 internal 0 rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt4 TE-IS 20 rt6 - rt6(4)
+ 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
+ rt1 pseudo_TE-IS 30 rt6 - rt4(4)
+ rt1 TE-IS 30 rt6 - rt1(2)
+ 2001:db8::4/128 IP6 internal 30 rt6 - rt4(4)
+ rt3 TE-IS 40 rt3 - rt5(4)
+ 2001:db8::1/128 IP6 internal 40 rt6 - rt1(4)
+ rt2 TE-IS 45 rt6 - rt1(4)
+ 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4)
+ 2001:db8::2/128 IP6 internal 55 rt6 - rt2(4)
+
IS-IS L1 IPv6 routing table:
@@ -3396,21 +3570,23 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-10.0.255.5/32 IP internal 0 rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt4 TE-IS 20 rt6 - rt6(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt3 TE-IS 30 rt3 - rt5(4)
-rt2 TE-IS 30 rt6 - rt4(4)
-10.0.255.4/32 IP TE 30 rt6 - rt4(4)
-rt1 TE-IS 40 rt3 - rt3(4)
- rt6 - rt2(4)
-10.0.255.3/32 IP TE 40 rt3 - rt3(4)
-10.0.255.2/32 IP TE 40 rt6 - rt2(4)
-10.0.255.1/32 IP TE 50 rt3 - rt1(4)
- rt6 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt5
+ 10.0.255.5/32 IP internal 0 rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt4 TE-IS 20 rt6 - rt6(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt3 TE-IS 30 rt3 - rt5(4)
+ rt2 TE-IS 30 rt6 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt6 - rt4(4)
+ rt1 TE-IS 40 rt3 - rt3(4)
+ rt6 - rt2(4)
+ 10.0.255.3/32 IP TE 40 rt3 - rt3(4)
+ 10.0.255.2/32 IP TE 40 rt6 - rt2(4)
+ 10.0.255.1/32 IP TE 50 rt3 - rt1(4)
+ rt6 - rt1(4)
+
IS-IS L1 IPv4 routing table:
@@ -3450,19 +3626,21 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt5
-10.0.255.5/32 IP internal 0 rt5(4)
-rt4 TE-IS 10 rt4 - rt5(4)
-rt6 TE-IS 10 rt6 - rt5(4)
-rt2 TE-IS 20 rt4 - rt4(4)
-10.0.255.4/32 IP TE 20 rt4 - rt4(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt1 TE-IS 30 rt4 - rt2(4)
-rt3 TE-IS 30 rt4 - rt2(4)
-10.0.255.2/32 IP TE 30 rt4 - rt2(4)
-10.0.255.1/32 IP TE 40 rt4 - rt1(4)
-10.0.255.3/32 IP TE 40 rt4 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt5
+ 10.0.255.5/32 IP internal 0 rt5(4)
+ rt4 TE-IS 10 rt4 - rt5(4)
+ rt6 TE-IS 10 rt6 - rt5(4)
+ rt2 TE-IS 20 rt4 - rt4(4)
+ 10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt1 TE-IS 30 rt4 - rt2(4)
+ rt3 TE-IS 30 rt4 - rt2(4)
+ 10.0.255.2/32 IP TE 30 rt4 - rt2(4)
+ 10.0.255.1/32 IP TE 40 rt4 - rt1(4)
+ 10.0.255.3/32 IP TE 40 rt4 - rt3(4)
+
IS-IS L1 IPv4 routing table:
@@ -3484,23 +3662,25 @@ Q-space: rt8
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt7 TE-IS 30 rt3 - rt5(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-10.0.255.7/32 IP TE 40 rt3 - rt7(4)
-rt6 TE-IS 70 rt3 - rt5(4)
-rt4 TE-IS 80 rt3 - rt6(4)
-rt8 TE-IS 80 rt3 - rt6(4)
-10.0.255.6/32 IP TE 80 rt3 - rt6(4)
-rt2 TE-IS 90 rt3 - rt4(4)
-10.0.255.4/32 IP TE 90 rt3 - rt4(4)
-10.0.255.8/32 IP TE 90 rt3 - rt8(4)
-10.0.255.2/32 IP TE 100 rt3 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt7 TE-IS 30 rt3 - rt5(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ 10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+ rt6 TE-IS 70 rt3 - rt5(4)
+ rt4 TE-IS 80 rt3 - rt6(4)
+ rt8 TE-IS 80 rt3 - rt6(4)
+ 10.0.255.6/32 IP TE 80 rt3 - rt6(4)
+ rt2 TE-IS 90 rt3 - rt4(4)
+ 10.0.255.4/32 IP TE 90 rt3 - rt4(4)
+ 10.0.255.8/32 IP TE 90 rt3 - rt8(4)
+ 10.0.255.2/32 IP TE 100 rt3 - rt2(4)
+
IS-IS L1 IPv4 routing table:
@@ -3531,23 +3711,25 @@ Q-space: rt8
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt4
-10.0.255.4/32 IP internal 0 rt4(4)
-rt2 TE-IS 10 rt2 - rt4(4)
-rt1 TE-IS 20 rt2 - rt2(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-rt3 TE-IS 30 rt2 - rt1(4)
-10.0.255.1/32 IP TE 30 rt2 - rt1(4)
-rt5 TE-IS 40 rt2 - rt3(4)
-10.0.255.3/32 IP TE 40 rt2 - rt3(4)
-rt7 TE-IS 50 rt2 - rt5(4)
-10.0.255.5/32 IP TE 50 rt2 - rt5(4)
-10.0.255.7/32 IP TE 60 rt2 - rt7(4)
-rt6 TE-IS 90 rt2 - rt5(4)
-rt8 TE-IS 100 rt2 - rt6(4)
-10.0.255.6/32 IP TE 100 rt2 - rt6(4)
-10.0.255.8/32 IP TE 110 rt2 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt4
+ 10.0.255.4/32 IP internal 0 rt4(4)
+ rt2 TE-IS 10 rt2 - rt4(4)
+ rt1 TE-IS 20 rt2 - rt2(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ rt3 TE-IS 30 rt2 - rt1(4)
+ 10.0.255.1/32 IP TE 30 rt2 - rt1(4)
+ rt5 TE-IS 40 rt2 - rt3(4)
+ 10.0.255.3/32 IP TE 40 rt2 - rt3(4)
+ rt7 TE-IS 50 rt2 - rt5(4)
+ 10.0.255.5/32 IP TE 50 rt2 - rt5(4)
+ 10.0.255.7/32 IP TE 60 rt2 - rt7(4)
+ rt6 TE-IS 90 rt2 - rt5(4)
+ rt8 TE-IS 100 rt2 - rt6(4)
+ 10.0.255.6/32 IP TE 100 rt2 - rt6(4)
+ 10.0.255.8/32 IP TE 110 rt2 - rt8(4)
+
IS-IS L1 IPv4 routing table:
@@ -3575,23 +3757,25 @@ Q-space: rt8
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-rt5 TE-IS 20 rt3 - rt3(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt7 TE-IS 30 rt3 - rt5(4)
-10.0.255.5/32 IP TE 30 rt3 - rt5(4)
-rt8 TE-IS 40 rt3 - rt7(4)
-10.0.255.7/32 IP TE 40 rt3 - rt7(4)
-rt6 TE-IS 50 rt3 - rt8(4)
-10.0.255.8/32 IP TE 50 rt3 - rt8(4)
-rt4 TE-IS 60 rt3 - rt6(4)
-10.0.255.6/32 IP TE 60 rt3 - rt6(4)
-rt2 TE-IS 70 rt3 - rt4(4)
-10.0.255.4/32 IP TE 70 rt3 - rt4(4)
-10.0.255.2/32 IP TE 80 rt3 - rt2(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ rt5 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt7 TE-IS 30 rt3 - rt5(4)
+ 10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+ rt8 TE-IS 40 rt3 - rt7(4)
+ 10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+ rt6 TE-IS 50 rt3 - rt8(4)
+ 10.0.255.8/32 IP TE 50 rt3 - rt8(4)
+ rt4 TE-IS 60 rt3 - rt6(4)
+ 10.0.255.6/32 IP TE 60 rt3 - rt6(4)
+ rt2 TE-IS 70 rt3 - rt4(4)
+ 10.0.255.4/32 IP TE 70 rt3 - rt4(4)
+ 10.0.255.2/32 IP TE 80 rt3 - rt2(4)
+
IS-IS L1 IPv4 routing table:
@@ -3624,24 +3808,26 @@ Q-space: rt3
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt4
-10.0.255.4/32 IP internal 0 rt4(4)
-rt2 TE-IS 10 rt2 - rt4(4)
-rt6 TE-IS 10 rt6 - rt4(4)
-rt1 TE-IS 20 rt2 - rt2(4)
-rt5 TE-IS 20 rt6 - rt6(4)
-rt8 TE-IS 20 rt6 - rt6(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-rt3 TE-IS 30 rt2 - rt1(4)
-rt7 TE-IS 30 rt6 - rt5(4)
- rt8(4)
-10.0.255.1/32 IP TE 30 rt2 - rt1(4)
-10.0.255.5/32 IP TE 30 rt6 - rt5(4)
-10.0.255.8/32 IP TE 30 rt6 - rt8(4)
-10.0.255.3/32 IP TE 40 rt2 - rt3(4)
-10.0.255.7/32 IP TE 40 rt6 - rt7(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt4
+ 10.0.255.4/32 IP internal 0 rt4(4)
+ rt2 TE-IS 10 rt2 - rt4(4)
+ rt6 TE-IS 10 rt6 - rt4(4)
+ rt1 TE-IS 20 rt2 - rt2(4)
+ rt5 TE-IS 20 rt6 - rt6(4)
+ rt8 TE-IS 20 rt6 - rt6(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ rt3 TE-IS 30 rt2 - rt1(4)
+ rt7 TE-IS 30 rt6 - rt5(4)
+ rt8(4)
+ 10.0.255.1/32 IP TE 30 rt2 - rt1(4)
+ 10.0.255.5/32 IP TE 30 rt6 - rt5(4)
+ 10.0.255.8/32 IP TE 30 rt6 - rt8(4)
+ 10.0.255.3/32 IP TE 40 rt2 - rt3(4)
+ 10.0.255.7/32 IP TE 40 rt6 - rt7(4)
+
IS-IS L1 IPv4 routing table:
@@ -3676,33 +3862,35 @@ Q-space: rt9
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt11
-10.0.255.11/32 IP internal 0 rt11(4)
-rt10 TE-IS 10 rt10 - rt11(4)
-rt12 TE-IS 10 rt12 - rt11(4)
-rt9 TE-IS 20 rt12 - rt12(4)
-10.0.255.10/32 IP TE 20 rt10 - rt10(4)
-10.0.255.12/32 IP TE 20 rt12 - rt12(4)
-rt7 TE-IS 30 rt10 - rt10(4)
-rt8 TE-IS 30 rt12 - rt9(4)
-10.0.255.9/32 IP TE 30 rt12 - rt9(4)
-rt4 TE-IS 40 rt10 - rt7(4)
-rt5 TE-IS 40 rt12 - rt8(4)
-10.0.255.7/32 IP TE 40 rt10 - rt7(4)
-10.0.255.8/32 IP TE 40 rt12 - rt8(4)
-rt6 TE-IS 50 rt12 - rt9(4)
- rt5(4)
-rt1 TE-IS 50 rt10 - rt4(4)
-rt2 TE-IS 50 rt12 - rt5(4)
-10.0.255.4/32 IP TE 50 rt10 - rt4(4)
-10.0.255.5/32 IP TE 50 rt12 - rt5(4)
-rt3 TE-IS 60 rt12 - rt6(4)
- rt2(4)
-10.0.255.6/32 IP TE 60 rt12 - rt6(4)
-10.0.255.1/32 IP TE 60 rt10 - rt1(4)
-10.0.255.2/32 IP TE 60 rt12 - rt2(4)
-10.0.255.3/32 IP TE 70 rt12 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt11
+ 10.0.255.11/32 IP internal 0 rt11(4)
+ rt10 TE-IS 10 rt10 - rt11(4)
+ rt12 TE-IS 10 rt12 - rt11(4)
+ rt9 TE-IS 20 rt12 - rt12(4)
+ 10.0.255.10/32 IP TE 20 rt10 - rt10(4)
+ 10.0.255.12/32 IP TE 20 rt12 - rt12(4)
+ rt7 TE-IS 30 rt10 - rt10(4)
+ rt8 TE-IS 30 rt12 - rt9(4)
+ 10.0.255.9/32 IP TE 30 rt12 - rt9(4)
+ rt4 TE-IS 40 rt10 - rt7(4)
+ rt5 TE-IS 40 rt12 - rt8(4)
+ 10.0.255.7/32 IP TE 40 rt10 - rt7(4)
+ 10.0.255.8/32 IP TE 40 rt12 - rt8(4)
+ rt6 TE-IS 50 rt12 - rt9(4)
+ rt5(4)
+ rt1 TE-IS 50 rt10 - rt4(4)
+ rt2 TE-IS 50 rt12 - rt5(4)
+ 10.0.255.4/32 IP TE 50 rt10 - rt4(4)
+ 10.0.255.5/32 IP TE 50 rt12 - rt5(4)
+ rt3 TE-IS 60 rt12 - rt6(4)
+ rt2(4)
+ 10.0.255.6/32 IP TE 60 rt12 - rt6(4)
+ 10.0.255.1/32 IP TE 60 rt10 - rt1(4)
+ 10.0.255.2/32 IP TE 60 rt12 - rt2(4)
+ 10.0.255.3/32 IP TE 70 rt12 - rt3(4)
+
IS-IS L1 IPv4 routing table:
@@ -3750,39 +3938,41 @@ Q-space: rt12
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt6
-10.0.255.6/32 IP internal 0 rt6(4)
-rt3 TE-IS 10 rt3 - rt6(4)
-rt2 TE-IS 20 rt3 - rt3(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt9 TE-IS 30 rt9 - rt6(4)
-rt5 TE-IS 30 rt3 - rt2(4)
-10.0.255.2/32 IP TE 30 rt3 - rt2(4)
-rt8 TE-IS 40 rt9 - rt9(4)
- rt3 - rt5(4)
-rt12 TE-IS 40 rt9 - rt9(4)
-rt4 TE-IS 40 rt3 - rt5(4)
-10.0.255.9/32 IP TE 40 rt9 - rt9(4)
-10.0.255.5/32 IP TE 40 rt3 - rt5(4)
-rt7 TE-IS 50 rt9 - rt8(4)
- rt3 - rt4(4)
-rt11 TE-IS 50 rt9 - rt8(4)
- rt3 - rt12(4)
-rt1 TE-IS 50 rt3 - rt4(4)
-10.0.255.8/32 IP TE 50 rt9 - rt8(4)
- rt3 -
-10.0.255.12/32 IP TE 50 rt9 - rt12(4)
-10.0.255.4/32 IP TE 50 rt3 - rt4(4)
-rt10 TE-IS 60 rt9 - rt11(4)
- rt3 -
-10.0.255.7/32 IP TE 60 rt9 - rt7(4)
- rt3 -
-10.0.255.11/32 IP TE 60 rt9 - rt11(4)
- rt3 -
-10.0.255.1/32 IP TE 60 rt3 - rt1(4)
-10.0.255.10/32 IP TE 70 rt9 - rt10(4)
- rt3 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt6
+ 10.0.255.6/32 IP internal 0 rt6(4)
+ rt3 TE-IS 10 rt3 - rt6(4)
+ rt2 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt9 TE-IS 30 rt9 - rt6(4)
+ rt5 TE-IS 30 rt3 - rt2(4)
+ 10.0.255.2/32 IP TE 30 rt3 - rt2(4)
+ rt8 TE-IS 40 rt9 - rt9(4)
+ rt3 - rt5(4)
+ rt12 TE-IS 40 rt9 - rt9(4)
+ rt4 TE-IS 40 rt3 - rt5(4)
+ 10.0.255.9/32 IP TE 40 rt9 - rt9(4)
+ 10.0.255.5/32 IP TE 40 rt3 - rt5(4)
+ rt7 TE-IS 50 rt9 - rt8(4)
+ rt3 - rt4(4)
+ rt11 TE-IS 50 rt9 - rt8(4)
+ rt3 - rt12(4)
+ rt1 TE-IS 50 rt3 - rt4(4)
+ 10.0.255.8/32 IP TE 50 rt9 - rt8(4)
+ rt3 - rt8(4)
+ 10.0.255.12/32 IP TE 50 rt9 - rt12(4)
+ 10.0.255.4/32 IP TE 50 rt3 - rt4(4)
+ rt10 TE-IS 60 rt9 - rt11(4)
+ rt3 - rt11(4)
+ 10.0.255.7/32 IP TE 60 rt9 - rt7(4)
+ rt3 - rt7(4)
+ 10.0.255.11/32 IP TE 60 rt9 - rt11(4)
+ rt3 - rt11(4)
+ 10.0.255.1/32 IP TE 60 rt3 - rt1(4)
+ 10.0.255.10/32 IP TE 70 rt9 - rt10(4)
+ rt3 - rt10(4)
+
IS-IS L1 IPv4 routing table:
@@ -3829,34 +4019,36 @@ Q-space: rt10
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt2
-10.0.255.2/32 IP internal 0 rt2(4)
-rt3 TE-IS 10 rt3 - rt2(4)
-rt5 TE-IS 10 rt5 - rt2(4)
-rt6 TE-IS 20 rt3 - rt3(4)
- rt5 - rt5(4)
-rt8 TE-IS 20 rt5 - rt5(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-10.0.255.5/32 IP TE 20 rt5 - rt5(4)
-rt9 TE-IS 30 rt5 - rt8(4)
-rt11 TE-IS 30 rt5 - rt8(4)
-10.0.255.6/32 IP TE 30 rt3 - rt6(4)
- rt5 -
-10.0.255.8/32 IP TE 30 rt5 - rt8(4)
-rt12 TE-IS 40 rt5 - rt9(4)
- rt11(4)
-10.0.255.9/32 IP TE 40 rt5 - rt9(4)
-10.0.255.11/32 IP TE 40 rt5 - rt11(4)
-10.0.255.12/32 IP TE 50 rt5 - rt12(4)
-rt10 TE-IS 60 rt5 - rt11(4)
-rt7 TE-IS 70 rt5 - rt10(4)
-10.0.255.10/32 IP TE 70 rt5 - rt10(4)
-rt4 TE-IS 80 rt5 - rt7(4)
-10.0.255.7/32 IP TE 80 rt5 - rt7(4)
-rt1 TE-IS 90 rt5 - rt4(4)
-10.0.255.4/32 IP TE 90 rt5 - rt4(4)
-10.0.255.1/32 IP TE 100 rt5 - rt1(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt2
+ 10.0.255.2/32 IP internal 0 rt2(4)
+ rt3 TE-IS 10 rt3 - rt2(4)
+ rt5 TE-IS 10 rt5 - rt2(4)
+ rt6 TE-IS 20 rt3 - rt3(4)
+ rt5 - rt5(4)
+ rt8 TE-IS 20 rt5 - rt5(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ 10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+ rt9 TE-IS 30 rt5 - rt8(4)
+ rt11 TE-IS 30 rt5 - rt8(4)
+ 10.0.255.6/32 IP TE 30 rt3 - rt6(4)
+ rt5 - rt6(4)
+ 10.0.255.8/32 IP TE 30 rt5 - rt8(4)
+ rt12 TE-IS 40 rt5 - rt9(4)
+ rt11(4)
+ 10.0.255.9/32 IP TE 40 rt5 - rt9(4)
+ 10.0.255.11/32 IP TE 40 rt5 - rt11(4)
+ 10.0.255.12/32 IP TE 50 rt5 - rt12(4)
+ rt10 TE-IS 60 rt5 - rt11(4)
+ rt7 TE-IS 70 rt5 - rt10(4)
+ 10.0.255.10/32 IP TE 70 rt5 - rt10(4)
+ rt4 TE-IS 80 rt5 - rt7(4)
+ 10.0.255.7/32 IP TE 80 rt5 - rt7(4)
+ rt1 TE-IS 90 rt5 - rt4(4)
+ 10.0.255.4/32 IP TE 90 rt5 - rt4(4)
+ 10.0.255.1/32 IP TE 100 rt5 - rt1(4)
+
IS-IS L1 IPv4 routing table:
@@ -3894,32 +4086,34 @@ Q-space: rt12
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt2
-10.0.255.2/32 IP internal 0 rt2(4)
-rt1 TE-IS 10 rt1 - rt2(4)
-rt3 TE-IS 10 rt3 - rt2(4)
-rt4 TE-IS 20 rt1 - rt1(4)
-rt6 TE-IS 20 rt3 - rt3(4)
-10.0.255.1/32 IP TE 20 rt1 - rt1(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt7 TE-IS 30 rt1 - rt4(4)
-rt5 TE-IS 30 rt3 - rt6(4)
-10.0.255.4/32 IP TE 30 rt1 - rt4(4)
-10.0.255.6/32 IP TE 30 rt3 - rt6(4)
-rt10 TE-IS 40 rt1 - rt7(4)
-rt8 TE-IS 40 rt3 - rt5(4)
-10.0.255.7/32 IP TE 40 rt1 - rt7(4)
-10.0.255.5/32 IP TE 40 rt3 - rt5(4)
-rt9 TE-IS 50 rt3 - rt8(4)
-rt11 TE-IS 50 rt3 - rt8(4)
-10.0.255.10/32 IP TE 50 rt1 - rt10(4)
-10.0.255.8/32 IP TE 50 rt3 - rt8(4)
-rt12 TE-IS 60 rt3 - rt9(4)
- rt11(4)
-10.0.255.9/32 IP TE 60 rt3 - rt9(4)
-10.0.255.11/32 IP TE 60 rt3 - rt11(4)
-10.0.255.12/32 IP TE 70 rt3 - rt12(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt2
+ 10.0.255.2/32 IP internal 0 rt2(4)
+ rt1 TE-IS 10 rt1 - rt2(4)
+ rt3 TE-IS 10 rt3 - rt2(4)
+ rt4 TE-IS 20 rt1 - rt1(4)
+ rt6 TE-IS 20 rt3 - rt3(4)
+ 10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt7 TE-IS 30 rt1 - rt4(4)
+ rt5 TE-IS 30 rt3 - rt6(4)
+ 10.0.255.4/32 IP TE 30 rt1 - rt4(4)
+ 10.0.255.6/32 IP TE 30 rt3 - rt6(4)
+ rt10 TE-IS 40 rt1 - rt7(4)
+ rt8 TE-IS 40 rt3 - rt5(4)
+ 10.0.255.7/32 IP TE 40 rt1 - rt7(4)
+ 10.0.255.5/32 IP TE 40 rt3 - rt5(4)
+ rt9 TE-IS 50 rt3 - rt8(4)
+ rt11 TE-IS 50 rt3 - rt8(4)
+ 10.0.255.10/32 IP TE 50 rt1 - rt10(4)
+ 10.0.255.8/32 IP TE 50 rt3 - rt8(4)
+ rt12 TE-IS 60 rt3 - rt9(4)
+ rt11(4)
+ 10.0.255.9/32 IP TE 60 rt3 - rt9(4)
+ 10.0.255.11/32 IP TE 60 rt3 - rt11(4)
+ 10.0.255.12/32 IP TE 70 rt3 - rt12(4)
+
IS-IS L1 IPv4 routing table:
@@ -3954,28 +4148,30 @@ Q-space: rt3
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-rt5 TE-IS 30 rt2 - rt4(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-rt9 TE-IS 40 rt2 - rt5(4)
-10.0.255.5/32 IP TE 40 rt2 - rt5(4)
-rt6 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-rt7 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-rt8 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-10.0.255.9/32 IP TE 50 rt2 - rt9(4)
-10.0.255.6/32 IP TE 60 rt2 - rt6(4)
-10.0.255.7/32 IP TE 60 rt2 - rt7(4)
-10.0.255.8/32 IP TE 60 rt2 - rt8(4)
-rt3 TE-IS 120 rt2 - rt4(4)
-10.0.255.3/32 IP TE 130 rt2 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ rt5 TE-IS 30 rt2 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ rt9 TE-IS 40 rt2 - rt5(4)
+ 10.0.255.5/32 IP TE 40 rt2 - rt5(4)
+ rt6 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ rt7 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ rt8 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ 10.0.255.9/32 IP TE 50 rt2 - rt9(4)
+ 10.0.255.6/32 IP TE 60 rt2 - rt6(4)
+ 10.0.255.7/32 IP TE 60 rt2 - rt7(4)
+ 10.0.255.8/32 IP TE 60 rt2 - rt8(4)
+ rt3 TE-IS 120 rt2 - rt4(4)
+ 10.0.255.3/32 IP TE 130 rt2 - rt3(4)
+
IS-IS L1 IPv4 routing table:
@@ -4005,28 +4201,30 @@ Q-space: rt3
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
-rt5 TE-IS 30 rt2 - rt4(4)
-2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
-rt9 TE-IS 40 rt2 - rt5(4)
-2001:db8::5/128 IP6 internal 40 rt2 - rt5(4)
-rt6 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-rt7 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-rt8 TE-IS 50 rt2 - rt4(4)
- rt9(4)
-2001:db8::9/128 IP6 internal 50 rt2 - rt9(4)
-2001:db8::6/128 IP6 internal 60 rt2 - rt6(4)
-2001:db8::7/128 IP6 internal 60 rt2 - rt7(4)
-2001:db8::8/128 IP6 internal 60 rt2 - rt8(4)
-rt3 TE-IS 120 rt2 - rt4(4)
-2001:db8::3/128 IP6 internal 130 rt2 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+ rt5 TE-IS 30 rt2 - rt4(4)
+ 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
+ rt9 TE-IS 40 rt2 - rt5(4)
+ 2001:db8::5/128 IP6 internal 40 rt2 - rt5(4)
+ rt6 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ rt7 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ rt8 TE-IS 50 rt2 - rt4(4)
+ rt9(4)
+ 2001:db8::9/128 IP6 internal 50 rt2 - rt9(4)
+ 2001:db8::6/128 IP6 internal 60 rt2 - rt6(4)
+ 2001:db8::7/128 IP6 internal 60 rt2 - rt7(4)
+ 2001:db8::8/128 IP6 internal 60 rt2 - rt8(4)
+ rt3 TE-IS 120 rt2 - rt4(4)
+ 2001:db8::3/128 IP6 internal 130 rt2 - rt3(4)
+
IS-IS L1 IPv6 routing table:
@@ -4051,28 +4249,30 @@ Q-space: rt9
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-10.0.255.3/32 IP TE 20 rt3 - rt3(4)
-rt4 TE-IS 110 rt3 - rt3(4)
-rt2 TE-IS 120 rt3 - rt4(4)
-rt5 TE-IS 120 rt3 - rt4(4)
-10.0.255.4/32 IP TE 120 rt3 - rt4(4)
-rt9 TE-IS 130 rt3 - rt5(4)
-10.0.255.2/32 IP TE 130 rt3 - rt2(4)
-10.0.255.5/32 IP TE 130 rt3 - rt5(4)
-rt6 TE-IS 140 rt3 - rt4(4)
- rt9(4)
-rt7 TE-IS 140 rt3 - rt4(4)
- rt9(4)
-rt8 TE-IS 140 rt3 - rt4(4)
- rt9(4)
-10.0.255.9/32 IP TE 140 rt3 - rt9(4)
-10.0.255.6/32 IP TE 150 rt3 - rt6(4)
-10.0.255.7/32 IP TE 150 rt3 - rt7(4)
-10.0.255.8/32 IP TE 150 rt3 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ 10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+ rt4 TE-IS 110 rt3 - rt3(4)
+ rt2 TE-IS 120 rt3 - rt4(4)
+ rt5 TE-IS 120 rt3 - rt4(4)
+ 10.0.255.4/32 IP TE 120 rt3 - rt4(4)
+ rt9 TE-IS 130 rt3 - rt5(4)
+ 10.0.255.2/32 IP TE 130 rt3 - rt2(4)
+ 10.0.255.5/32 IP TE 130 rt3 - rt5(4)
+ rt6 TE-IS 140 rt3 - rt4(4)
+ rt9(4)
+ rt7 TE-IS 140 rt3 - rt4(4)
+ rt9(4)
+ rt8 TE-IS 140 rt3 - rt4(4)
+ rt9(4)
+ 10.0.255.9/32 IP TE 140 rt3 - rt9(4)
+ 10.0.255.6/32 IP TE 150 rt3 - rt6(4)
+ 10.0.255.7/32 IP TE 150 rt3 - rt7(4)
+ 10.0.255.8/32 IP TE 150 rt3 - rt8(4)
+
IS-IS L1 IPv4 routing table:
@@ -4102,28 +4302,30 @@ Q-space: rt9
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt3 TE-IS 10 rt3 - rt1(4)
-2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
-rt4 TE-IS 110 rt3 - rt3(4)
-rt2 TE-IS 120 rt3 - rt4(4)
-rt5 TE-IS 120 rt3 - rt4(4)
-2001:db8::4/128 IP6 internal 120 rt3 - rt4(4)
-rt9 TE-IS 130 rt3 - rt5(4)
-2001:db8::2/128 IP6 internal 130 rt3 - rt2(4)
-2001:db8::5/128 IP6 internal 130 rt3 - rt5(4)
-rt6 TE-IS 140 rt3 - rt4(4)
- rt9(4)
-rt7 TE-IS 140 rt3 - rt4(4)
- rt9(4)
-rt8 TE-IS 140 rt3 - rt4(4)
- rt9(4)
-2001:db8::9/128 IP6 internal 140 rt3 - rt9(4)
-2001:db8::6/128 IP6 internal 150 rt3 - rt6(4)
-2001:db8::7/128 IP6 internal 150 rt3 - rt7(4)
-2001:db8::8/128 IP6 internal 150 rt3 - rt8(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt3 TE-IS 10 rt3 - rt1(4)
+ 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+ rt4 TE-IS 110 rt3 - rt3(4)
+ rt2 TE-IS 120 rt3 - rt4(4)
+ rt5 TE-IS 120 rt3 - rt4(4)
+ 2001:db8::4/128 IP6 internal 120 rt3 - rt4(4)
+ rt9 TE-IS 130 rt3 - rt5(4)
+ 2001:db8::2/128 IP6 internal 130 rt3 - rt2(4)
+ 2001:db8::5/128 IP6 internal 130 rt3 - rt5(4)
+ rt6 TE-IS 140 rt3 - rt4(4)
+ rt9(4)
+ rt7 TE-IS 140 rt3 - rt4(4)
+ rt9(4)
+ rt8 TE-IS 140 rt3 - rt4(4)
+ rt9(4)
+ 2001:db8::9/128 IP6 internal 140 rt3 - rt9(4)
+ 2001:db8::6/128 IP6 internal 150 rt3 - rt6(4)
+ 2001:db8::7/128 IP6 internal 150 rt3 - rt7(4)
+ 2001:db8::8/128 IP6 internal 150 rt3 - rt8(4)
+
IS-IS L1 IPv6 routing table:
@@ -4160,45 +4362,47 @@ Q-space: rt5
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt9
-10.0.255.9/32 IP internal 0 rt9(4)
-rt6 TE-IS 10 rt6 - rt9(4)
-rt7 TE-IS 10 rt7 - rt9(4)
-rt8 TE-IS 10 rt8 - rt9(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-10.0.255.7/32 IP TE 20 rt7 - rt7(4)
-10.0.255.8/32 IP TE 20 rt8 - rt8(4)
-rt4 TE-IS 40 rt6 - rt6(4)
- rt7 - rt7(4)
- rt8 - rt8(4)
-rt2 TE-IS 50 rt6 - rt4(4)
- rt7 -
- rt8 -
-rt5 TE-IS 50 rt6 - rt4(4)
- rt7 -
- rt8 -
-10.0.255.4/32 IP TE 50 rt6 - rt4(4)
- rt7 -
- rt8 -
-rt1 TE-IS 60 rt6 - rt2(4)
- rt7 -
- rt8 -
-10.0.255.2/32 IP TE 60 rt6 - rt2(4)
- rt7 -
- rt8 -
-10.0.255.5/32 IP TE 60 rt6 - rt5(4)
- rt7 -
- rt8 -
-rt3 TE-IS 70 rt6 - rt1(4)
- rt7 -
- rt8 -
-10.0.255.1/32 IP TE 70 rt6 - rt1(4)
- rt7 -
- rt8 -
-10.0.255.3/32 IP TE 80 rt6 - rt3(4)
- rt7 -
- rt8 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt9
+ 10.0.255.9/32 IP internal 0 rt9(4)
+ rt6 TE-IS 10 rt6 - rt9(4)
+ rt7 TE-IS 10 rt7 - rt9(4)
+ rt8 TE-IS 10 rt8 - rt9(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ 10.0.255.7/32 IP TE 20 rt7 - rt7(4)
+ 10.0.255.8/32 IP TE 20 rt8 - rt8(4)
+ rt4 TE-IS 40 rt6 - rt6(4)
+ rt7 - rt7(4)
+ rt8 - rt8(4)
+ rt2 TE-IS 50 rt6 - rt4(4)
+ rt7 - rt4(4)
+ rt8 - rt4(4)
+ rt5 TE-IS 50 rt6 - rt4(4)
+ rt7 - rt4(4)
+ rt8 - rt4(4)
+ 10.0.255.4/32 IP TE 50 rt6 - rt4(4)
+ rt7 - rt4(4)
+ rt8 - rt4(4)
+ rt1 TE-IS 60 rt6 - rt2(4)
+ rt7 - rt2(4)
+ rt8 - rt2(4)
+ 10.0.255.2/32 IP TE 60 rt6 - rt2(4)
+ rt7 - rt2(4)
+ rt8 - rt2(4)
+ 10.0.255.5/32 IP TE 60 rt6 - rt5(4)
+ rt7 - rt5(4)
+ rt8 - rt5(4)
+ rt3 TE-IS 70 rt6 - rt1(4)
+ rt7 - rt1(4)
+ rt8 - rt1(4)
+ 10.0.255.1/32 IP TE 70 rt6 - rt1(4)
+ rt7 - rt1(4)
+ rt8 - rt1(4)
+ 10.0.255.3/32 IP TE 80 rt6 - rt3(4)
+ rt7 - rt3(4)
+ rt8 - rt3(4)
+
IS-IS L1 IPv4 routing table:
@@ -4242,45 +4446,47 @@ Q-space: rt5
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt9
-2001:db8::9/128 IP6 internal 0 rt9(4)
-rt6 TE-IS 10 rt6 - rt9(4)
-rt7 TE-IS 10 rt7 - rt9(4)
-rt8 TE-IS 10 rt8 - rt9(4)
-2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
-2001:db8::7/128 IP6 internal 20 rt7 - rt7(4)
-2001:db8::8/128 IP6 internal 20 rt8 - rt8(4)
-rt4 TE-IS 40 rt6 - rt6(4)
- rt7 - rt7(4)
- rt8 - rt8(4)
-rt2 TE-IS 50 rt6 - rt4(4)
- rt7 -
- rt8 -
-rt5 TE-IS 50 rt6 - rt4(4)
- rt7 -
- rt8 -
-2001:db8::4/128 IP6 internal 50 rt6 - rt4(4)
- rt7 -
- rt8 -
-rt1 TE-IS 60 rt6 - rt2(4)
- rt7 -
- rt8 -
-2001:db8::2/128 IP6 internal 60 rt6 - rt2(4)
- rt7 -
- rt8 -
-2001:db8::5/128 IP6 internal 60 rt6 - rt5(4)
- rt7 -
- rt8 -
-rt3 TE-IS 70 rt6 - rt1(4)
- rt7 -
- rt8 -
-2001:db8::1/128 IP6 internal 70 rt6 - rt1(4)
- rt7 -
- rt8 -
-2001:db8::3/128 IP6 internal 80 rt6 - rt3(4)
- rt7 -
- rt8 -
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt9
+ 2001:db8::9/128 IP6 internal 0 rt9(4)
+ rt6 TE-IS 10 rt6 - rt9(4)
+ rt7 TE-IS 10 rt7 - rt9(4)
+ rt8 TE-IS 10 rt8 - rt9(4)
+ 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
+ 2001:db8::7/128 IP6 internal 20 rt7 - rt7(4)
+ 2001:db8::8/128 IP6 internal 20 rt8 - rt8(4)
+ rt4 TE-IS 40 rt6 - rt6(4)
+ rt7 - rt7(4)
+ rt8 - rt8(4)
+ rt2 TE-IS 50 rt6 - rt4(4)
+ rt7 - rt4(4)
+ rt8 - rt4(4)
+ rt5 TE-IS 50 rt6 - rt4(4)
+ rt7 - rt4(4)
+ rt8 - rt4(4)
+ 2001:db8::4/128 IP6 internal 50 rt6 - rt4(4)
+ rt7 - rt4(4)
+ rt8 - rt4(4)
+ rt1 TE-IS 60 rt6 - rt2(4)
+ rt7 - rt2(4)
+ rt8 - rt2(4)
+ 2001:db8::2/128 IP6 internal 60 rt6 - rt2(4)
+ rt7 - rt2(4)
+ rt8 - rt2(4)
+ 2001:db8::5/128 IP6 internal 60 rt6 - rt5(4)
+ rt7 - rt5(4)
+ rt8 - rt5(4)
+ rt3 TE-IS 70 rt6 - rt1(4)
+ rt7 - rt1(4)
+ rt8 - rt1(4)
+ 2001:db8::1/128 IP6 internal 70 rt6 - rt1(4)
+ rt7 - rt1(4)
+ rt8 - rt1(4)
+ 2001:db8::3/128 IP6 internal 80 rt6 - rt3(4)
+ rt7 - rt3(4)
+ rt8 - rt3(4)
+
IS-IS L1 IPv6 routing table:
@@ -4329,25 +4535,27 @@ Q-space: rt8
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt9
-10.0.255.9/32 IP internal 0 rt9(4)
-rt5 TE-IS 10 rt5 - rt9(4)
-rt6 TE-IS 10 rt6 - rt9(4)
-rt7 TE-IS 10 rt7 - rt9(4)
-rt4 TE-IS 20 rt5 - rt5(4)
-10.0.255.5/32 IP TE 20 rt5 - rt5(4)
-10.0.255.6/32 IP TE 20 rt6 - rt6(4)
-10.0.255.7/32 IP TE 20 rt7 - rt7(4)
-rt2 TE-IS 30 rt5 - rt4(4)
-10.0.255.4/32 IP TE 30 rt5 - rt4(4)
-rt1 TE-IS 40 rt5 - rt2(4)
-10.0.255.2/32 IP TE 40 rt5 - rt2(4)
-rt8 TE-IS 50 rt5 - rt4(4)
-rt3 TE-IS 50 rt5 - rt1(4)
-10.0.255.1/32 IP TE 50 rt5 - rt1(4)
-10.0.255.8/32 IP TE 60 rt5 - rt8(4)
-10.0.255.3/32 IP TE 60 rt5 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt9
+ 10.0.255.9/32 IP internal 0 rt9(4)
+ rt5 TE-IS 10 rt5 - rt9(4)
+ rt6 TE-IS 10 rt6 - rt9(4)
+ rt7 TE-IS 10 rt7 - rt9(4)
+ rt4 TE-IS 20 rt5 - rt5(4)
+ 10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+ 10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+ 10.0.255.7/32 IP TE 20 rt7 - rt7(4)
+ rt2 TE-IS 30 rt5 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt5 - rt4(4)
+ rt1 TE-IS 40 rt5 - rt2(4)
+ 10.0.255.2/32 IP TE 40 rt5 - rt2(4)
+ rt8 TE-IS 50 rt5 - rt4(4)
+ rt3 TE-IS 50 rt5 - rt1(4)
+ 10.0.255.1/32 IP TE 50 rt5 - rt1(4)
+ 10.0.255.8/32 IP TE 60 rt5 - rt8(4)
+ 10.0.255.3/32 IP TE 60 rt5 - rt3(4)
+
IS-IS L1 IPv4 routing table:
@@ -4381,25 +4589,27 @@ Q-space: rt8
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt9
-2001:db8::9/128 IP6 internal 0 rt9(4)
-rt5 TE-IS 10 rt5 - rt9(4)
-rt6 TE-IS 10 rt6 - rt9(4)
-rt7 TE-IS 10 rt7 - rt9(4)
-rt4 TE-IS 20 rt5 - rt5(4)
-2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
-2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
-2001:db8::7/128 IP6 internal 20 rt7 - rt7(4)
-rt2 TE-IS 30 rt5 - rt4(4)
-2001:db8::4/128 IP6 internal 30 rt5 - rt4(4)
-rt1 TE-IS 40 rt5 - rt2(4)
-2001:db8::2/128 IP6 internal 40 rt5 - rt2(4)
-rt8 TE-IS 50 rt5 - rt4(4)
-rt3 TE-IS 50 rt5 - rt1(4)
-2001:db8::1/128 IP6 internal 50 rt5 - rt1(4)
-2001:db8::8/128 IP6 internal 60 rt5 - rt8(4)
-2001:db8::3/128 IP6 internal 60 rt5 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt9
+ 2001:db8::9/128 IP6 internal 0 rt9(4)
+ rt5 TE-IS 10 rt5 - rt9(4)
+ rt6 TE-IS 10 rt6 - rt9(4)
+ rt7 TE-IS 10 rt7 - rt9(4)
+ rt4 TE-IS 20 rt5 - rt5(4)
+ 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
+ 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
+ 2001:db8::7/128 IP6 internal 20 rt7 - rt7(4)
+ rt2 TE-IS 30 rt5 - rt4(4)
+ 2001:db8::4/128 IP6 internal 30 rt5 - rt4(4)
+ rt1 TE-IS 40 rt5 - rt2(4)
+ 2001:db8::2/128 IP6 internal 40 rt5 - rt2(4)
+ rt8 TE-IS 50 rt5 - rt4(4)
+ rt3 TE-IS 50 rt5 - rt1(4)
+ 2001:db8::1/128 IP6 internal 50 rt5 - rt1(4)
+ 2001:db8::8/128 IP6 internal 60 rt5 - rt8(4)
+ 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4)
+
IS-IS L1 IPv6 routing table:
@@ -4428,29 +4638,31 @@ Q-space: rt8
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt3 TE-IS 20 rt3 - rt1(4)
-rt4 TE-IS 20 rt4 - rt1(4)
-rt6 TE-IS 30 rt3 - rt3(4)
-rt7 TE-IS 30 rt4 - rt4(4)
-10.0.255.3/32 IP TE 30 rt3 - rt3(4)
-10.0.255.4/32 IP TE 30 rt4 - rt4(4)
-10.0.255.6/32 IP TE 40 rt3 - rt6(4)
-10.0.255.7/32 IP TE 40 rt4 - rt7(4)
-rt8 TE-IS 80 rt3 - rt6(4)
- rt4 - rt7(4)
-rt5 TE-IS 90 rt3 - rt8(4)
- rt4 -
-10.0.255.8/32 IP TE 90 rt3 - rt8(4)
- rt4 -
-rt2 TE-IS 100 rt3 - rt5(4)
- rt4 -
-10.0.255.5/32 IP TE 100 rt3 - rt5(4)
- rt4 -
-10.0.255.2/32 IP TE 110 rt3 - rt2(4)
- rt4 -
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt3 TE-IS 20 rt3 - rt1(4)
+ rt4 TE-IS 20 rt4 - rt1(4)
+ rt6 TE-IS 30 rt3 - rt3(4)
+ rt7 TE-IS 30 rt4 - rt4(4)
+ 10.0.255.3/32 IP TE 30 rt3 - rt3(4)
+ 10.0.255.4/32 IP TE 30 rt4 - rt4(4)
+ 10.0.255.6/32 IP TE 40 rt3 - rt6(4)
+ 10.0.255.7/32 IP TE 40 rt4 - rt7(4)
+ rt8 TE-IS 80 rt3 - rt6(4)
+ rt4 - rt7(4)
+ rt5 TE-IS 90 rt3 - rt8(4)
+ rt4 - rt8(4)
+ 10.0.255.8/32 IP TE 90 rt3 - rt8(4)
+ rt4 - rt8(4)
+ rt2 TE-IS 100 rt3 - rt5(4)
+ rt4 - rt5(4)
+ 10.0.255.5/32 IP TE 100 rt3 - rt5(4)
+ rt4 - rt5(4)
+ 10.0.255.2/32 IP TE 110 rt3 - rt2(4)
+ rt4 - rt2(4)
+
IS-IS L1 IPv4 routing table:
@@ -4483,29 +4695,31 @@ Q-space: rt8
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt3 TE-IS 20 rt3 - rt1(4)
-rt4 TE-IS 20 rt4 - rt1(4)
-rt6 TE-IS 30 rt3 - rt3(4)
-rt7 TE-IS 30 rt4 - rt4(4)
-2001:db8::3/128 IP6 internal 30 rt3 - rt3(4)
-2001:db8::4/128 IP6 internal 30 rt4 - rt4(4)
-2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
-2001:db8::7/128 IP6 internal 40 rt4 - rt7(4)
-rt8 TE-IS 80 rt3 - rt6(4)
- rt4 - rt7(4)
-rt5 TE-IS 90 rt3 - rt8(4)
- rt4 -
-2001:db8::8/128 IP6 internal 90 rt3 - rt8(4)
- rt4 -
-rt2 TE-IS 100 rt3 - rt5(4)
- rt4 -
-2001:db8::5/128 IP6 internal 100 rt3 - rt5(4)
- rt4 -
-2001:db8::2/128 IP6 internal 110 rt3 - rt2(4)
- rt4 -
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt3 TE-IS 20 rt3 - rt1(4)
+ rt4 TE-IS 20 rt4 - rt1(4)
+ rt6 TE-IS 30 rt3 - rt3(4)
+ rt7 TE-IS 30 rt4 - rt4(4)
+ 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4)
+ 2001:db8::4/128 IP6 internal 30 rt4 - rt4(4)
+ 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
+ 2001:db8::7/128 IP6 internal 40 rt4 - rt7(4)
+ rt8 TE-IS 80 rt3 - rt6(4)
+ rt4 - rt7(4)
+ rt5 TE-IS 90 rt3 - rt8(4)
+ rt4 - rt8(4)
+ 2001:db8::8/128 IP6 internal 90 rt3 - rt8(4)
+ rt4 - rt8(4)
+ rt2 TE-IS 100 rt3 - rt5(4)
+ rt4 - rt5(4)
+ 2001:db8::5/128 IP6 internal 100 rt3 - rt5(4)
+ rt4 - rt5(4)
+ 2001:db8::2/128 IP6 internal 110 rt3 - rt2(4)
+ rt4 - rt2(4)
+
IS-IS L1 IPv6 routing table:
@@ -4540,23 +4754,25 @@ Q-space: rt7
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 20 rt3 - rt1(4)
-rt5 TE-IS 20 rt2 - rt2(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-rt6 TE-IS 30 rt3 - rt3(4)
-rt8 TE-IS 30 rt2 - rt5(4)
-10.0.255.3/32 IP TE 30 rt3 - rt3(4)
-10.0.255.5/32 IP TE 30 rt2 - rt5(4)
-10.0.255.6/32 IP TE 40 rt3 - rt6(4)
-10.0.255.8/32 IP TE 40 rt2 - rt8(4)
-rt7 TE-IS 80 rt2 - rt8(4)
-rt4 TE-IS 90 rt2 - rt7(4)
-10.0.255.7/32 IP TE 90 rt2 - rt7(4)
-10.0.255.4/32 IP TE 100 rt2 - rt4(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 20 rt3 - rt1(4)
+ rt5 TE-IS 20 rt2 - rt2(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ rt6 TE-IS 30 rt3 - rt3(4)
+ rt8 TE-IS 30 rt2 - rt5(4)
+ 10.0.255.3/32 IP TE 30 rt3 - rt3(4)
+ 10.0.255.5/32 IP TE 30 rt2 - rt5(4)
+ 10.0.255.6/32 IP TE 40 rt3 - rt6(4)
+ 10.0.255.8/32 IP TE 40 rt2 - rt8(4)
+ rt7 TE-IS 80 rt2 - rt8(4)
+ rt4 TE-IS 90 rt2 - rt7(4)
+ 10.0.255.7/32 IP TE 90 rt2 - rt7(4)
+ 10.0.255.4/32 IP TE 100 rt2 - rt4(4)
+
IS-IS L1 IPv4 routing table:
@@ -4586,23 +4802,25 @@ Q-space: rt7
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-2001:db8::1/128 IP6 internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt3 TE-IS 20 rt3 - rt1(4)
-rt5 TE-IS 20 rt2 - rt2(4)
-2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
-rt6 TE-IS 30 rt3 - rt3(4)
-rt8 TE-IS 30 rt2 - rt5(4)
-2001:db8::3/128 IP6 internal 30 rt3 - rt3(4)
-2001:db8::5/128 IP6 internal 30 rt2 - rt5(4)
-2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
-2001:db8::8/128 IP6 internal 40 rt2 - rt8(4)
-rt7 TE-IS 80 rt2 - rt8(4)
-rt4 TE-IS 90 rt2 - rt7(4)
-2001:db8::7/128 IP6 internal 90 rt2 - rt7(4)
-2001:db8::4/128 IP6 internal 100 rt2 - rt4(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt1
+ 2001:db8::1/128 IP6 internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt3 TE-IS 20 rt3 - rt1(4)
+ rt5 TE-IS 20 rt2 - rt2(4)
+ 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+ rt6 TE-IS 30 rt3 - rt3(4)
+ rt8 TE-IS 30 rt2 - rt5(4)
+ 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4)
+ 2001:db8::5/128 IP6 internal 30 rt2 - rt5(4)
+ 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
+ 2001:db8::8/128 IP6 internal 40 rt2 - rt8(4)
+ rt7 TE-IS 80 rt2 - rt8(4)
+ rt4 TE-IS 90 rt2 - rt7(4)
+ 2001:db8::7/128 IP6 internal 90 rt2 - rt7(4)
+ 2001:db8::4/128 IP6 internal 100 rt2 - rt4(4)
+
IS-IS L1 IPv6 routing table:
@@ -4633,20 +4851,22 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt2
-10.0.255.2/32 IP internal 0 rt2(4)
-rt1 TE-IS 50 rt1 - rt2(4)
-rt3 TE-IS 50 rt3 - rt2(4)
-rt2
-rt5 TE-IS 60 rt3 - rt3(4)
-10.0.255.1/32 IP TE 60 rt1 - rt1(4)
-10.0.255.3/32 IP TE 60 rt3 - rt3(4)
-rt4 TE-IS 70 rt3 - rt5(4)
-rt6 TE-IS 70 rt3 - rt5(4)
-10.0.255.5/32 IP TE 70 rt3 - rt5(4)
-10.0.255.4/32 IP TE 80 rt3 - rt4(4)
-10.0.255.6/32 IP TE 80 rt3 - rt6(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt2
+ 10.0.255.2/32 IP internal 0 rt2(4)
+ rt1 TE-IS 50 rt1 - rt2(4)
+ rt3 TE-IS 50 rt3 - rt2(4)
+ rt2
+ rt5 TE-IS 60 rt3 - rt3(4)
+ 10.0.255.1/32 IP TE 60 rt1 - rt1(4)
+ 10.0.255.3/32 IP TE 60 rt3 - rt3(4)
+ rt4 TE-IS 70 rt3 - rt5(4)
+ rt6 TE-IS 70 rt3 - rt5(4)
+ 10.0.255.5/32 IP TE 70 rt3 - rt5(4)
+ 10.0.255.4/32 IP TE 80 rt3 - rt4(4)
+ 10.0.255.6/32 IP TE 80 rt3 - rt6(4)
+
IS-IS L1 IPv4 routing table:
@@ -4679,20 +4899,22 @@ Q-space: rt6
IS-IS paths to level-1 routers that speak IPv6
-Vertex Type Metric Next-Hop Interface Parent
-rt2
-2001:db8::2/128 IP6 internal 0 rt2(4)
-rt1 TE-IS 50 rt1 - rt2(4)
-rt3 TE-IS 50 rt3 - rt2(4)
-rt2
-rt5 TE-IS 60 rt3 - rt3(4)
-2001:db8::1/128 IP6 internal 60 rt1 - rt1(4)
-2001:db8::3/128 IP6 internal 60 rt3 - rt3(4)
-rt4 TE-IS 70 rt3 - rt5(4)
-rt6 TE-IS 70 rt3 - rt5(4)
-2001:db8::5/128 IP6 internal 70 rt3 - rt5(4)
-2001:db8::4/128 IP6 internal 80 rt3 - rt4(4)
-2001:db8::6/128 IP6 internal 80 rt3 - rt6(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ --------------------------------------------------------------------
+ rt2
+ 2001:db8::2/128 IP6 internal 0 rt2(4)
+ rt1 TE-IS 50 rt1 - rt2(4)
+ rt3 TE-IS 50 rt3 - rt2(4)
+ rt2
+ rt5 TE-IS 60 rt3 - rt3(4)
+ 2001:db8::1/128 IP6 internal 60 rt1 - rt1(4)
+ 2001:db8::3/128 IP6 internal 60 rt3 - rt3(4)
+ rt4 TE-IS 70 rt3 - rt5(4)
+ rt6 TE-IS 70 rt3 - rt5(4)
+ 2001:db8::5/128 IP6 internal 70 rt3 - rt5(4)
+ 2001:db8::4/128 IP6 internal 80 rt3 - rt4(4)
+ 2001:db8::6/128 IP6 internal 80 rt3 - rt6(4)
+
IS-IS L1 IPv6 routing table:
@@ -4723,27 +4945,29 @@ Q-space: rt3
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-rt6 TE-IS 30 rt2 - rt4(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-rt8 TE-IS 40 rt2 - rt6(4)
-10.0.255.6/32 IP TE 40 rt2 - rt6(4)
-rt10 TE-IS 50 rt2 - rt8(4)
-10.0.255.8/32 IP TE 50 rt2 - rt8(4)
-10.0.255.10/32 IP TE 60 rt2 - rt10(4)
-rt7 TE-IS 140 rt2 - rt8(4)
-rt9 TE-IS 150 rt2 - rt7(4)
-10.0.255.7/32 IP TE 150 rt2 - rt7(4)
-10.0.255.9/32 IP TE 160 rt2 - rt9(4)
-rt5 TE-IS 340 rt2 - rt7(4)
-10.0.255.5/32 IP TE 350 rt2 - rt5(4)
-rt3 TE-IS 740 rt2 - rt5(4)
-10.0.255.3/32 IP TE 750 rt2 - rt3(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -------------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ rt6 TE-IS 30 rt2 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ rt8 TE-IS 40 rt2 - rt6(4)
+ 10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ rt10 TE-IS 50 rt2 - rt8(4)
+ 10.0.255.8/32 IP TE 50 rt2 - rt8(4)
+ 10.0.255.10/32 IP TE 60 rt2 - rt10(4)
+ rt7 TE-IS 140 rt2 - rt8(4)
+ rt9 TE-IS 150 rt2 - rt7(4)
+ 10.0.255.7/32 IP TE 150 rt2 - rt7(4)
+ 10.0.255.9/32 IP TE 160 rt2 - rt9(4)
+ rt5 TE-IS 340 rt2 - rt7(4)
+ 10.0.255.5/32 IP TE 350 rt2 - rt5(4)
+ rt3 TE-IS 740 rt2 - rt5(4)
+ 10.0.255.3/32 IP TE 750 rt2 - rt3(4)
+
IS-IS L1 IPv4 routing table:
@@ -4770,22 +4994,24 @@ Q-space: rt7
IS-IS paths to level-1 routers that speak IP
-Vertex Type Metric Next-Hop Interface Parent
-rt1
-10.0.255.1/32 IP internal 0 rt1(4)
-rt2 TE-IS 10 rt2 - rt1(4)
-rt4 TE-IS 20 rt2 - rt2(4)
-10.0.255.2/32 IP TE 20 rt2 - rt2(4)
-rt3 TE-IS 30 rt2 - rt4(4)
-10.0.255.4/32 IP TE 30 rt2 - rt4(4)
-rt5 TE-IS 40 rt2 - rt3(4)
-rt6 TE-IS 40 rt2 - rt3(4)
-10.0.255.3/32 IP TE 40 rt2 - rt3(4)
-rt7 TE-IS 50 rt2 - rt5(4)
- rt6(4)
-10.0.255.5/32 IP TE 50 rt2 - rt5(4)
-10.0.255.6/32 IP TE 50 rt2 - rt6(4)
-10.0.255.7/32 IP TE 60 rt2 - rt7(4)
+ Vertex Type Metric Next-Hop Interface Parent
+ -----------------------------------------------------------------
+ rt1
+ 10.0.255.1/32 IP internal 0 rt1(4)
+ rt2 TE-IS 10 rt2 - rt1(4)
+ rt4 TE-IS 20 rt2 - rt2(4)
+ 10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+ rt3 TE-IS 30 rt2 - rt4(4)
+ 10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ rt5 TE-IS 40 rt2 - rt3(4)
+ rt6 TE-IS 40 rt2 - rt3(4)
+ 10.0.255.3/32 IP TE 40 rt2 - rt3(4)
+ rt7 TE-IS 50 rt2 - rt5(4)
+ rt6(4)
+ 10.0.255.5/32 IP TE 50 rt2 - rt5(4)
+ 10.0.255.6/32 IP TE 50 rt2 - rt6(4)
+ 10.0.255.7/32 IP TE 60 rt2 - rt7(4)
+
IS-IS L1 IPv4 routing table:
@@ -4796,5 +5022,5 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 50 - rt2 16040/16060
10.0.255.7/32 60 - rt2 16040/16070
-test# -end. +test#
+end.
diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c index b50216cf92..afcfa98791 100644 --- a/tests/lib/test_atomlist.c +++ b/tests/lib/test_atomlist.c @@ -62,7 +62,7 @@ static struct asort_head shead; static struct testthread { pthread_t pt; struct seqlock sqlo; - size_t counter, nullops; + _Atomic size_t counter, nullops; } thr[NTHREADS]; struct testrun { @@ -97,10 +97,10 @@ static void trfunc_##name(unsigned int offset) \ { \ size_t i = 0, n = 0; -#define endtestrun \ - thr[offset].counter = i; \ - thr[offset].nullops = n; \ -} +#define endtestrun \ + atomic_store_explicit(&thr[offset].counter, i, memory_order_seq_cst); \ + atomic_store_explicit(&thr[offset].nullops, n, memory_order_seq_cst); \ + } deftestrun(add, "add vs. add", 0, false) for (; i < NITEM / NTHREADS; i++) @@ -288,10 +288,10 @@ static void run_tr(struct testrun *tr) sv = seqlock_bump(&sqlo) - SEQLOCK_INCR; for (size_t i = 0; i < NTHREADS; i++) { seqlock_wait(&thr[i].sqlo, seqlock_cur(&sqlo)); - s += thr[i].counter; - n += thr[i].nullops; - thr[i].counter = 0; - thr[i].nullops = 0; + s += atomic_load_explicit(&thr[i].counter, memory_order_seq_cst); + n += atomic_load_explicit(&thr[i].nullops, memory_order_seq_cst); + atomic_store_explicit(&thr[i].counter, 0, memory_order_seq_cst); + atomic_store_explicit(&thr[i].nullops, 0, memory_order_seq_cst); } delta = monotime_since(&tv, NULL); diff --git a/tests/lib/test_seqlock.c b/tests/lib/test_seqlock.c index 288d4a8c25..937b3f34f5 100644 --- a/tests/lib/test_seqlock.c +++ b/tests/lib/test_seqlock.c @@ -82,11 +82,11 @@ int main(int argc, char **argv) assert(seqlock_held(&sqlo)); assert(seqlock_cur(&sqlo) == 1); - assert(seqlock_bump(&sqlo) == 1); - assert(seqlock_cur(&sqlo) == 5); assert(seqlock_bump(&sqlo) == 5); + assert(seqlock_cur(&sqlo) == 5); assert(seqlock_bump(&sqlo) == 9); assert(seqlock_bump(&sqlo) == 13); + assert(seqlock_bump(&sqlo) == 17); assert(seqlock_cur(&sqlo) == 17); assert(seqlock_held(&sqlo)); @@ -111,4 +111,5 @@ int main(int argc, char **argv) writestr("main @release\n"); seqlock_release(&sqlo); sleep(1); + pthread_join(thr1, NULL); } diff --git a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref index f52b51d9d8..e4e3290111 100644 --- a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref +++ b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref @@ -11,6 +11,7 @@ r1-eth0 is up Hello due in XX.XXXs Neighbor Count is 0, Adjacent neighbor count is 0 Graceful Restart hello delay: 10s + LSA retransmissions: 0 r1-eth3 is up ifindex X, MTU 1500 bytes, BW XX Mbit <UP,LOWER_UP,BROADCAST,RUNNING,MULTICAST> Internet Address 192.168.3.1/26, Broadcast 192.168.3.63, Area 0.0.0.0 @@ -24,3 +25,4 @@ r1-eth3 is up Hello due in XX.XXXs Neighbor Count is 0, Adjacent neighbor count is 0 Graceful Restart hello delay: 10s + LSA retransmissions: 0 diff --git a/tests/topotests/bgp_confed1/r2/bgpd.conf b/tests/topotests/bgp_confed1/r2/bgpd.conf index fe13dfe729..ba2da4160e 100644 --- a/tests/topotests/bgp_confed1/r2/bgpd.conf +++ b/tests/topotests/bgp_confed1/r2/bgpd.conf @@ -4,7 +4,6 @@ !debug bgp updates out ! router bgp 200 - no bgp ebgp-requires-policy bgp confederation identifier 300 bgp confederation peers 300 neighbor 192.0.2.1 remote-as 100 @@ -12,7 +11,9 @@ router bgp 200 ! address-family ipv4 unicast network 203.0.113.16/28 + neighbor 192.0.2.1 route-map any in + neighbor 192.0.2.1 route-map any out neighbor 192.0.2.18 default-originate exit-address-family ! - +route-map any permit 10 diff --git a/tests/topotests/bgp_dampening_per_safi/__init__.py b/tests/topotests/bgp_dampening_per_safi/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/__init__.py diff --git a/tests/topotests/bgp_dampening_per_safi/r1/frr.conf b/tests/topotests/bgp_dampening_per_safi/r1/frr.conf new file mode 100644 index 0000000000..b4e82f581d --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/r1/frr.conf @@ -0,0 +1,13 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + 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 unicast + bgp dampening 1 1 1 1 + exit-address-family +! diff --git a/tests/topotests/bgp_dampening_per_safi/r2/frr.conf b/tests/topotests/bgp_dampening_per_safi/r2/frr.conf new file mode 100644 index 0000000000..d68d13d075 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/r2/frr.conf @@ -0,0 +1,17 @@ +! +int lo + ip address 10.10.10.10/32 +! +int 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 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py b/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py new file mode 100644 index 0000000000..c8d7e675d1 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +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, get_topogen + + +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_dampening_per_peer(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _show_dampening_parameters(): + output = json.loads(r1.vtysh_cmd("show ip bgp dampening parameters json")) + expected = { + "halfLifeSecs": 60, + "reusePenalty": 1, + "suppressPenalty": 1, + "maxSuppressTimeSecs": 60, + "maxSuppressPenalty": 2, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _show_dampening_parameters, + ) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=1) + assert result is None, "Can't show BGP per-safi dampening parameters" + + def _converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + #### + # Withdraw 10.10.10.10/32, and check if it's flagged as history. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + no redistribute connected + """ + ) + + def _check_bgp_dampening_history(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "dampeningHistoryEntry": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_history, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as history entry" + + #### + # Reannounce 10.10.10.10/32, and check if it's flagged as dampened. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + redistribute connected + """ + ) + + def _check_bgp_dampening_dampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningSuppressed": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_dampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as dampened entry" + + #### + # Check if the route becomes non-dampened again after some time. + #### + def _check_bgp_dampening_undampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningHistoryEntry": None, + "dampeningSuppressed": None, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_undampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=10) + assert result is None, "10.10.10.10/32 is flagged as history/dampened" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py index 955881e6f9..83fae71bf5 100644 --- a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py +++ b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py @@ -320,7 +320,7 @@ def check_ipv4_prefix_recursive_with_multiple_nexthops( ) test_func = functools.partial( - ip_check_path_selection, tgen.gears["r1"], prefix, expected + ip_check_path_selection, tgen.gears["r1"], prefix, expected, check_fib=True ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py index 31aaa0b8a6..de4b94032c 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py @@ -81,6 +81,8 @@ import os import sys import time import pytest +import functools +import json # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -91,6 +93,7 @@ sys.path.append(os.path.join("../lib/")) # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen from lib.topolog import logger +from lib import topotest # Required to instantiate the topology builder class. @@ -1680,6 +1683,304 @@ def BGP_GR_TC_52_p1(request): write_test_footer(tc_name) +def test_BGP_GR_TC_53_p1(request): + """ + Test Objective : Peer-level inherit from BGP wide Restarting + Global Mode : GR Restart + PerPeer Mode : None + GR Mode effective : GR Restart + + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Check router status + check_router_status(tgen) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Configure R1 as GR restarting node in global level") + + input_dict = { + "r1": {"graceful-restart": {"graceful-restart": True}}, + "r2": {"graceful-restart": {"graceful-restart-helper": True}}, + } + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + bgp graceful-restart + ! + """ + ) + + step("Verify that R2 receives GR restarting capabilities" " from R1") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r2" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Kill BGPd on router R1") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + step( + "Verify that R1 keeps the stale entries in FIB and R2 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Configure graceful-restart-disable at config global level verify that the functionality works + step("Bring up BGP on R1 and configure graceful-restart-disable") + + start_router_daemons(tgen, "r1", ["bgpd"]) + + input_dict = { + "r1": {"graceful-restart": {"graceful-restart-disable": True}}, + "r2": {"graceful-restart": {"graceful-restart-helper": True}}, + } + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + bgp graceful-restart-disable + ! + """ + ) + + step("Verify on R2 that R1 does't advertise any GR capabilities") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r2" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Kill BGP on R1") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + step("Verify on R2 and R1 that none of the routers keep stale entries") + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} FIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib( + tgen, addr_type, dut, input_topo, next_hop, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} BGP RIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} FIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + step( + "Bring up BGP on R1, enable GR and configure bgp graceful-restart restart-time at global level" + ) + + start_router_daemons(tgen, "r1", ["bgpd"]) + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + no bgp graceful-restart-disable + bgp graceful-restart + bgp graceful-restart stalepath-time 420 + bgp graceful-restart restart-time 240 + bgp graceful-restart select-defer-time 420 + ! + """ + ) + + step("Verify on R2 that R1 sent the updated GR restart-time") + + def _bgp_check_if_gr_restart_time_was_updated(): + output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp neighbor json")) + + expected = { + "192.168.0.1": { + "gracefulRestartInfo": { + "localGrMode": "Helper*", + "remoteGrMode": "Restart", + "timers": { + "configuredRestartTimer": 120, + "receivedRestartTimer": 240, + }, + }, + }, + "fd00::1": { + "gracefulRestartInfo": { + "localGrMode": "Helper*", + "remoteGrMode": "Restart", + "timers": { + "configuredRestartTimer": 120, + "receivedRestartTimer": 240, + }, + }, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_gr_restart_time_was_updated, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "R2 did not receive the updated GR restart-time of 240s" + + def _bgp_check_if_gr_timer_on_restarting_node_was_updated(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp neighbor json")) + + expected = { + "192.168.0.2": { + "gracefulRestartInfo": { + "localGrMode": "Restart*", + "remoteGrMode": "Helper", + "timers": { + "configuredRestartTimer": 240, + "receivedRestartTimer": 120, + }, + "ipv4Unicast": { + "timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420} + }, + }, + }, + "fd00::2": { + "gracefulRestartInfo": { + "localGrMode": "Restart*", + "remoteGrMode": "Helper", + "timers": { + "configuredRestartTimer": 240, + "receivedRestartTimer": 120, + }, + "ipv6Unicast": { + "timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420} + }, + }, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_gr_timer_on_restarting_node_was_updated, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "R1 did not update the GR select-deferral and stale-path timer to 420s" + + write_test_footer(tc_name) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py index 16459a25a3..5d8338d6eb 100644 --- a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py +++ b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py @@ -195,16 +195,16 @@ def test_bgp_administrative_reset_gr(): step("Reset and shutdown R1") _bgp_clear_r1_and_shutdown() - step("Check if Hard Reset notification wasn't sent from R2") - test_func = functools.partial(_bgp_check_hard_reset) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) - assert result is None, "Failed to send Administrative Reset notification from R2" - step("Check if stale routes are retained on R1") test_func = functools.partial(_bgp_check_gr_notification_stale) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see retained stale routes on R1" + step("Check if Hard Reset notification wasn't sent from R2") + test_func = functools.partial(_bgp_check_hard_reset) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to send Administrative Reset notification from R2" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_oad/test_bgp_oad.py b/tests/topotests/bgp_oad/test_bgp_oad.py index a2ca37a2b7..bb779462db 100644 --- a/tests/topotests/bgp_oad/test_bgp_oad.py +++ b/tests/topotests/bgp_oad/test_bgp_oad.py @@ -46,7 +46,7 @@ def teardown_module(mod): tgen.stop_topology() -def test_bgp_dynamic_capability_role(): +def test_bgp_oad(): tgen = get_topogen() if tgen.routers_have_failure(): diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json index 22ec2c298b..483165c0f3 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json @@ -23,7 +23,7 @@ "recursive":true }, { - "fib":true, + "duplicate":true, "ip":"10.0.3.2", "active":true } diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json index facddcda46..638a825395 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json @@ -23,7 +23,7 @@ "recursive":true }, { - "fib":true, + "duplicate":true, "ip":"10.0.3.2", "active":true } diff --git a/tests/topotests/bgp_remote_as_auto/__init__.py b/tests/topotests/bgp_remote_as_auto/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/__init__.py diff --git a/tests/topotests/bgp_remote_as_auto/r1/frr.conf b/tests/topotests/bgp_remote_as_auto/r1/frr.conf new file mode 100644 index 0000000000..2f1bcd275f --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r1/frr.conf @@ -0,0 +1,23 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +int r1-eth1 + ip address 192.168.14.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as auto + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.3 remote-as auto + neighbor 192.168.1.3 timers 1 3 + neighbor 192.168.1.3 timers connect 1 + neighbor r1-eth1 interface remote-as auto + neighbor r1-eth1 timers 1 3 + neighbor r1-eth1 timers connect 1 + address-family ipv4 unicast + network 10.0.0.1/32 + exit-address-family +! diff --git a/tests/topotests/bgp_remote_as_auto/r2/frr.conf b/tests/topotests/bgp_remote_as_auto/r2/frr.conf new file mode 100644 index 0000000000..f8d19a0bfd --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r2/frr.conf @@ -0,0 +1,10 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/r3/frr.conf b/tests/topotests/bgp_remote_as_auto/r3/frr.conf new file mode 100644 index 0000000000..fc6862764f --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r3/frr.conf @@ -0,0 +1,10 @@ +! +int r3-eth0 + ip address 192.168.1.3/24 +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/r4/frr.conf b/tests/topotests/bgp_remote_as_auto/r4/frr.conf new file mode 100644 index 0000000000..e280a6c6e8 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r4/frr.conf @@ -0,0 +1,10 @@ +! +int r4-eth0 + ip address 192.168.14.4/24 +! +router bgp 65004 + no bgp ebgp-requires-policy + neighbor r4-eth0 interface remote-as auto + neighbor r4-eth0 timers 1 3 + neighbor r4-eth0 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py new file mode 100644 index 0000000000..1db6d98a42 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +import os +import re +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, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2", "r3"), "s2": ("r1", "r4")} + 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_remote_as_auto(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + r4 = tgen.gears["r4"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast summary json")) + expected = { + "peers": { + "r1-eth1": { + "hostname": "r4", + "remoteAs": 65004, + "localAs": 65001, + "state": "Established", + }, + "192.168.1.2": { + "hostname": "r2", + "remoteAs": 65001, + "localAs": 65001, + "state": "Established", + }, + "192.168.1.3": { + "hostname": "r3", + "remoteAs": 65003, + "localAs": 65001, + "state": "Established", + }, + } + } + 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 see automatic iBGP/eBGP peerings" + + def _bgp_converge_internal(): + output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "Local", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "internal", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_internal, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic iBGP peering" + + def _bgp_converge_external(): + output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "65001", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "external", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_external, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic eBGP peering" + + def _bgp_converge_external_unnumbered(): + output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "65001", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "external", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_external_unnumbered, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic unnumbered eBGP peering" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf b/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf index 9bef24f931..c70b4934a0 100644 --- a/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf +++ b/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf @@ -8,10 +8,19 @@ router bgp 65001 exit-address-family ! ip prefix-list p1 seq 5 permit 172.16.255.31/32 +ip prefix-list p2 seq 5 permit 172.16.255.32/32 +ip prefix-list p3 seq 5 permit 172.16.255.30/32 ! +bgp as-path access-list FIRST permit ^65 +bgp as-path access-list SECOND permit 2$ + +route-map r2 permit 6 + match ip address prefix-list p2 + set as-path exclude as-path-access-list SECOND route-map r2 permit 10 match ip address prefix-list p1 set as-path exclude 65003 route-map r2 permit 20 + match ip address prefix-list p3 set as-path exclude all ! diff --git a/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf b/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf index 3fa6c64484..56893158a4 100644 --- a/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf +++ b/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf @@ -1,5 +1,6 @@ ! int lo + ip address 172.16.255.30/32 ip address 172.16.255.31/32 ip address 172.16.255.32/32 ! diff --git a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py index 64cc48e54f..63f1719e1d 100644 --- a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py +++ b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py @@ -64,29 +64,33 @@ def teardown_module(mod): expected_1 = { "routes": { + "172.16.255.30/32": [{"path": ""}], "172.16.255.31/32": [{"path": "65002"}], - "172.16.255.32/32": [{"path": ""}], + "172.16.255.32/32": [{"path": "65003"}], } } expected_2 = { "routes": { - "172.16.255.31/32": [{"path": ""}], + "172.16.255.30/32": [{"path": ""}], + "172.16.255.31/32": [{"path": "65002"}], "172.16.255.32/32": [{"path": ""}], } } expected_3 = { "routes": { - "172.16.255.31/32": [{"path": "65003"}], - "172.16.255.32/32": [{"path": "65003"}], + "172.16.255.30/32": [{"path": ""}], + "172.16.255.31/32": [{"path": "65002"}], + "172.16.255.32/32": [{"path": "65002 65003"}], } } expected_4 = { "routes": { - "172.16.255.31/32": [{"path": "65002 65003"}], - "172.16.255.32/32": [{"path": "65002 65003"}], + "172.16.255.30/32": [{"path": ""}], + "172.16.255.31/32": [{"path": "65002"}], + "172.16.255.32/32": [{"path": "65002"}], } } @@ -117,34 +121,42 @@ def test_bgp_set_aspath_exclude_access_list(): rname = "r1" r1 = tgen.gears[rname] + # tgen.mininet_cli() r1.vtysh_cmd( """ conf bgp as-path access-list FIRST permit ^65 route-map r2 permit 6 + no set as-path exclude as-path-access-list SECOND set as-path exclude as-path-access-list FIRST """ ) + # tgen.mininet_cli() + r1.vtysh_cmd( + """ +clear bgp * + """ + ) test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_2) _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) - assert result is None, "Failed overriding incoming AS-PATH with regex 1 route-map" + assert result is None, "Failed change of exclude rule in route map" r1.vtysh_cmd( """ conf - bgp as-path access-list SECOND permit 2 route-map r2 permit 6 + no set as-path exclude as-path-access-list FIRST set as-path exclude as-path-access-list SECOND """ ) # tgen.mininet_cli() - test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3) + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_1) _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) - assert result is None, "Failed overriding incoming AS-PATH with regex 2 route-map" + assert result is None, "Failed reverting exclude rule in route map" def test_no_bgp_set_aspath_exclude_access_list(): @@ -159,15 +171,28 @@ def test_no_bgp_set_aspath_exclude_access_list(): r1.vtysh_cmd( """ conf - no bgp as-path access-list SECOND permit 2 + no bgp as-path access-list SECOND permit 2$ + """ + ) + + r1.vtysh_cmd( + """ +clear bgp * """ ) test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3) _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) - assert result is None, "Failed removing bgp as-path access-list" + assert result is None, "Failed to removing current accesslist" + # tgen.mininet_cli() + r1.vtysh_cmd( + """ +conf + bgp as-path access-list SECOND permit 3$ + """ + ) r1.vtysh_cmd( """ clear bgp * @@ -177,7 +202,26 @@ clear bgp * test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_4) _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) - assert result is None, "Failed to renegotiate with peers" + assert result is None, "Failed to renegotiate with peers 2" + + r1.vtysh_cmd( + """ +conf + route-map r2 permit 6 + no set as-path exclude as-path-access-list SECOND + """ + ) + + r1.vtysh_cmd( + """ +clear bgp * + """ + ) + + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, "Failed to renegotiate with peers 2" if __name__ == "__main__": 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 index bb10aba942..c4a5d7507b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] 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 index bb10aba942..c4a5d7507b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] 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 index bb10aba942..c4a5d7507b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] 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 index bb10aba942..c4a5d7507b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] 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 index bb10aba942..c4a5d7507b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] 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 index f3399319f3..f8a5d93f3c 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] 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 index f3399319f3..f8a5d93f3c 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] 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 index f3399319f3..f8a5d93f3c 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] 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 index f3399319f3..f8a5d93f3c 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] 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 index f3399319f3..f8a5d93f3c 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] 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 index f3399319f3..f8a5d93f3c 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] 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 index f3399319f3..f8a5d93f3c 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] 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 index f3399319f3..f8a5d93f3c 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] 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 index f3399319f3..f8a5d93f3c 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] 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 index ffa626123d..c62870587b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] 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 index ffa626123d..c62870587b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] 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 index ffa626123d..c62870587b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] 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 index ffa626123d..c62870587b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] 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 index ffa626123d..c62870587b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] 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 index ffa626123d..c62870587b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] 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 index ffa626123d..c62870587b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] 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 index ffa626123d..c62870587b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] 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 index ffa626123d..c62870587b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] 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 index 189943f737..cb052dbbb5 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] 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 index 189943f737..cb052dbbb5 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] 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 index 189943f737..cb052dbbb5 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] 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 index 189943f737..cb052dbbb5 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] 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 index 189943f737..cb052dbbb5 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] 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 index 189943f737..cb052dbbb5 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] 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 index 189943f737..cb052dbbb5 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] 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 index 189943f737..cb052dbbb5 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] 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 index 189943f737..cb052dbbb5 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] 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 index 54780fce8a..ec55f24d7b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] 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 index 54780fce8a..ec55f24d7b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] 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 index 54780fce8a..ec55f24d7b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] 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 index 54780fce8a..ec55f24d7b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] 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 index 54780fce8a..ec55f24d7b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] 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 index 54780fce8a..ec55f24d7b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] 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 index 54780fce8a..ec55f24d7b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] 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 index 54780fce8a..ec55f24d7b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] 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 index 54780fce8a..ec55f24d7b 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] 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 index 35aa61d8e6..abcdeddea4 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] 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 index 35aa61d8e6..abcdeddea4 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] 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 index 35aa61d8e6..abcdeddea4 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] 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 index 35aa61d8e6..abcdeddea4 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] 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 index 35aa61d8e6..abcdeddea4 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] 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 index 35aa61d8e6..abcdeddea4 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] 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 index 35aa61d8e6..abcdeddea4 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] 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 index 35aa61d8e6..abcdeddea4 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] 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 index 35aa61d8e6..abcdeddea4 100644 --- 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 @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_topo1/r1/r1_topology.json b/tests/topotests/isis_topo1/r1/r1_topology.json index 337d6bf5ef..6b3374cc4d 100644 --- a/tests/topotests/isis_topo1/r1/r1_topology.json +++ b/tests/topotests/isis_topo1/r1/r1_topology.json @@ -1,96 +1,98 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r1" - } - ], - "ipv6": [ - { - "vertex": "r1" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - } - ], - "ipv6": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r1" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + } + ] }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r2/r2_topology.json b/tests/topotests/isis_topo1/r2/r2_topology.json index de90fb5a32..8720bc1cac 100644 --- a/tests/topotests/isis_topo1/r2/r2_topology.json +++ b/tests/topotests/isis_topo1/r2/r2_topology.json @@ -1,96 +1,98 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r2" - } - ], - "ipv6": [ - { - "vertex": "r2" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" - } - ], - "ipv6": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r2" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + } + ] }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r3/r3_topology.json b/tests/topotests/isis_topo1/r3/r3_topology.json index 2d36f9b427..568b6dfeed 100644 --- a/tests/topotests/isis_topo1/r3/r3_topology.json +++ b/tests/topotests/isis_topo1/r3/r3_topology.json @@ -1,194 +1,196 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.254.0.5/32" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::5/128" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.254.0.1/32" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "metric": "10", - "interface": "r3-eth0", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::1/128" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.254.0.5/32" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::5/128" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] + }, + "level-2": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.254.0.1/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "metric": 10, + "interface": "r3-eth0", + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::1/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r4/r4_topology.json b/tests/topotests/isis_topo1/r4/r4_topology.json index e7d7841912..9a53955cc9 100644 --- a/tests/topotests/isis_topo1/r4/r4_topology.json +++ b/tests/topotests/isis_topo1/r4/r4_topology.json @@ -1,194 +1,196 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.254.0.5/32" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::5/128" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r3" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.254.0.2/32" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "metric": "10", - "interface": "r4-eth0", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::2/128" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.254.0.5/32" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::5/128" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + } + ] + }, + "level-2": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.254.0.2/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "metric": 10, + "interface": "r4-eth0", + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::2/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r5/r5_topology.json b/tests/topotests/isis_topo1/r5/r5_topology.json index 3d887b7cea..64590d8eb2 100644 --- a/tests/topotests/isis_topo1/r5/r5_topology.json +++ b/tests/topotests/isis_topo1/r5/r5_topology.json @@ -1,156 +1,154 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] } - ], - "ipv6": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" - } - ] - }, - "level-2": { - "ipv4": [], - "ipv6": [] } - } -} +] diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index cea284963d..a574f43d89 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -120,19 +120,13 @@ def test_isis_convergence(): pytest.skip(tgen.errors) logger.info("waiting for ISIS protocol to converge") - # Code to generate the json files. - # for rname, router in tgen.routers().items(): - # open('/tmp/{}_topology.json'.format(rname), 'w').write( - # json.dumps(show_isis_topology(router), indent=2, sort_keys=True) - # ) - for rname, router in tgen.routers().items(): filename = "{0}/{1}/{1}_topology.json".format(CWD, rname) expected = json.loads(open(filename).read()) def compare_isis_topology(router, expected): "Helper function to test ISIS topology convergence." - actual = show_isis_topology(router) + actual = json.loads(router.vtysh_cmd("show isis topology json")) return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_topology, router, expected) @@ -685,6 +679,9 @@ def _check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected): ) database_json = json.loads(isis_database_output) + if "lsps" not in database_json["areas"][0]["levels"][1]: + return "The LSP of {} has not been synchronized yet ".format(router.name) + att_p_ol = database_json["areas"][0]["levels"][1]["lsps"][0]["attPOl"] if att_p_ol == att_p_ol_expected: return True @@ -845,52 +842,3 @@ def parse_topology(lines, level): continue return areas - - -def show_isis_topology(router): - """ - Get the ISIS topology in a dictionary format. - - Sample: - { - 'area-name': { - 'level-1': [ - { - 'vertex': 'r1' - } - ], - 'level-2': [ - { - 'vertex': '10.0.0.1/24', - 'type': 'IP', - 'parent': '0', - 'metric': 'internal' - } - ] - }, - 'area-name-2': { - 'level-2': [ - { - "interface": "rX-ethY", - "metric": "Z", - "next-hop": "rA", - "parent": "rC(B)", - "type": "TE-IS", - "vertex": "rD" - } - ] - } - } - """ - l1out = topotest.normalize_text( - router.vtysh_cmd("show isis topology level-1") - ).splitlines() - l2out = topotest.normalize_text( - router.vtysh_cmd("show isis topology level-2") - ).splitlines() - - l1 = parse_topology(l1out, "level-1") - l2 = parse_topology(l2out, "level-2") - - dict_merge(l1, l2) - return l1 diff --git a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json index 666fa52b19..da537c552b 100644 --- a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json +++ b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json @@ -1,80 +1,82 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r1" - } - ], - "ipv6": [ - { - "vertex": "r1" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - } - ], - "ipv6": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r1" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + } + ] }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json index c26ad1ee37..bf965659be 100644 --- a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json +++ b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json @@ -1,80 +1,82 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r2" - } - ], - "ipv6": [ - { - "vertex": "r2" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - } - ], - "ipv6": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r2" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + } + ] }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json index 044a6c0438..94592b50a7 100644 --- a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json +++ b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json @@ -1,132 +1,148 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r3" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + } + ] }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json index d40008aa30..b8295e87b9 100644 --- a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json +++ b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json @@ -1,132 +1,148 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r4" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + } + ] }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json index 2a088cae30..8b5159cbfb 100644 --- a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json +++ b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json @@ -1,124 +1,122 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + } + ] } - ], - "ipv6": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - } - ] - }, - "level-2": { - "ipv4": [], - "ipv6": [] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py index 7aac7c704d..afc6864b98 100644 --- a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py @@ -141,8 +141,9 @@ def test_isis_convergence(): def compare_isis_topology(router, expected): "Helper function to test ISIS vrf topology convergence." - actual = show_isis_topology(router) - + actual = json.loads( + router.vtysh_cmd(f"show isis vrf {router.name}-cust1 topology json") + ) return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_topology, router, expected) @@ -377,52 +378,3 @@ def parse_topology(lines, level): continue return areas - - -def show_isis_topology(router): - """ - Get the ISIS vrf topology in a dictionary format. - - Sample: - { - 'area-name': { - 'level-1': [ - { - 'vertex': 'r1' - } - ], - 'level-2': [ - { - 'vertex': '10.0.0.1/24', - 'type': 'IP', - 'parent': '0', - 'metric': 'internal' - } - ] - }, - 'area-name-2': { - 'level-2': [ - { - "interface": "rX-ethY", - "metric": "Z", - "next-hop": "rA", - "parent": "rC(B)", - "type": "TE-IS", - "vertex": "rD" - } - ] - } - } - """ - l1out = topotest.normalize_text( - router.vtysh_cmd("show isis vrf {}-cust1 topology level-1".format(router.name)) - ).splitlines() - l2out = topotest.normalize_text( - router.vtysh_cmd("show isis vrf {}-cust1 topology level-2".format(router.name)) - ).splitlines() - - l1 = parse_topology(l1out, "level-1") - l2 = parse_topology(l2out, "level-2") - - dict_merge(l1, l2) - return l1 diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 4250c405f3..bcd1c74812 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -3266,27 +3266,43 @@ def verify_graceful_restart( lmode = None rmode = None + # Local GR mode - if "address_family" in input_dict[dut]["bgp"]: - bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][ - "unicast" - ]["neighbor"][peer]["dest_link"] + if "bgp" not in input_dict[dut] and "graceful-restart" in input_dict[dut]: + if ( + "graceful-restart" in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"]["graceful-restart"] + ): + lmode = "Restart*" + elif ( + "graceful-restart-disable" in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"]["graceful-restart-disable"] + ): + lmode = "Disable*" + else: + lmode = "Helper*" - for dest_link, data in bgp_neighbors.items(): - if ( - "graceful-restart-helper" in data - and data["graceful-restart-helper"] - ): - lmode = "Helper" - elif "graceful-restart" in data and data["graceful-restart"]: - lmode = "Restart" - elif ( - "graceful-restart-disable" in data - and data["graceful-restart-disable"] - ): - lmode = "Disable" - else: - lmode = None + if lmode is None: + if "address_family" in input_dict[dut]["bgp"]: + bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][ + "unicast" + ]["neighbor"][peer]["dest_link"] + + for dest_link, data in bgp_neighbors.items(): + if ( + "graceful-restart-helper" in data + and data["graceful-restart-helper"] + ): + lmode = "Helper" + elif "graceful-restart" in data and data["graceful-restart"]: + lmode = "Restart" + elif ( + "graceful-restart-disable" in data + and data["graceful-restart-disable"] + ): + lmode = "Disable" + else: + lmode = None if lmode is None: if "graceful-restart" in input_dict[dut]["bgp"]: @@ -3314,7 +3330,11 @@ def verify_graceful_restart( return True # Remote GR mode - if "address_family" in input_dict[peer]["bgp"]: + + if ( + "bgp" in input_dict[peer] + and "address_family" in input_dict[peer]["bgp"] + ): bgp_neighbors = input_dict[peer]["bgp"]["address_family"][addr_type][ "unicast" ]["neighbor"][dut]["dest_link"] @@ -3336,7 +3356,10 @@ def verify_graceful_restart( rmode = None if rmode is None: - if "graceful-restart" in input_dict[peer]["bgp"]: + if ( + "bgp" in input_dict[peer] + and "graceful-restart" in input_dict[peer]["bgp"] + ): if ( "graceful-restart" in input_dict[peer]["bgp"]["graceful-restart"] @@ -3355,6 +3378,27 @@ def verify_graceful_restart( rmode = "Disable" else: rmode = "Helper" + + if rmode is None: + if ( + "bgp" not in input_dict[peer] + and "graceful-restart" in input_dict[peer] + ): + if ( + "graceful-restart" in input_dict[peer]["graceful-restart"] + and input_dict[peer]["graceful-restart"]["graceful-restart"] + ): + rmode = "Restart" + elif ( + "graceful-restart-disable" + in input_dict[peer]["graceful-restart"] + and input_dict[peer]["graceful-restart"][ + "graceful-restart-disable" + ] + ): + rmode = "Disable" + else: + rmode = "Helper" else: rmode = "Helper" diff --git a/tests/topotests/lib/common_check.py b/tests/topotests/lib/common_check.py index be3241fd20..19f02dbadc 100644 --- a/tests/topotests/lib/common_check.py +++ b/tests/topotests/lib/common_check.py @@ -10,11 +10,13 @@ import json from lib import topotest -def ip_check_path_selection(router, ipaddr_str, expected, vrf_name=None): +def ip_check_path_selection( + router, ipaddr_str, expected, vrf_name=None, check_fib=False +): if vrf_name: - cmdstr = f'show ip route vrf {vrf_name} {ipaddr_str} json' + cmdstr = f"show ip route vrf {vrf_name} {ipaddr_str} json" else: - cmdstr = f'show ip route {ipaddr_str} json' + cmdstr = f"show ip route {ipaddr_str} json" try: output = json.loads(router.vtysh_cmd(cmdstr)) except: @@ -25,6 +27,21 @@ def ip_check_path_selection(router, ipaddr_str, expected, vrf_name=None): num_nh_expected = len(expected[ipaddr_str][0]["nexthops"]) num_nh_observed = len(output[ipaddr_str][0]["nexthops"]) if num_nh_expected == num_nh_observed: + if check_fib: + # special case: when fib flag is unset, + # an extra test should be done to check that the flag is really unset + for nh_output, nh_expected in zip( + output[ipaddr_str][0]["nexthops"], + expected[ipaddr_str][0]["nexthops"], + ): + if ( + "fib" in nh_output.keys() + and nh_output["fib"] + and ("fib" not in nh_expected.keys() or not nh_expected["fib"]) + ): + return "{}, prefix {} nexthop {} has the fib flag set, whereas it is not expected".format( + router.name, ipaddr_str, nh_output["ip"] + ) return ret return "{}, prefix {} does not have the correct number of nexthops : observed {}, expected {}".format( router.name, ipaddr_str, num_nh_observed, num_nh_expected @@ -37,9 +54,9 @@ def iproute2_check_path_selection(router, ipaddr_str, expected, vrf_name=None): return None if vrf_name: - cmdstr = f'ip -json route show vrf {vrf_name} {ipaddr_str}' + cmdstr = f"ip -json route show vrf {vrf_name} {ipaddr_str}" else: - cmdstr = f'ip -json route show {ipaddr_str}' + cmdstr = f"ip -json route show {ipaddr_str}" try: output = json.loads(cmdstr) except: diff --git a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf index cb4538c0e3..89f255bb44 100644 --- a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all + hostname r1 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf index 0ca8aec3bf..429330987e 100644 --- a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r2 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf index 41ea70d443..eada78450e 100644 --- a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r3 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf index 21fa9c72f9..3146ea0957 100644 --- a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r4 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py index d52c8147fe..455c737f0d 100644 --- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py @@ -9,6 +9,7 @@ import os import sys +from time import sleep from functools import partial import pytest @@ -113,7 +114,9 @@ def teardown_module(): tgen.stop_topology() -def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter): +def verify_p2mp_interface( + tgen, router, nbr_cnt, nbr_adj_cnt, delay_reflood, nbr_filter +): "Verify the P2MP Configuration and interface settings" topo_router = tgen.gears[router] @@ -147,7 +150,7 @@ def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter): "nbrCount": nbr_cnt, "nbrAdjacentCount": nbr_adj_cnt, "prefixSuppression": False, - "p2mpDelayReflood": False, + "p2mpDelayReflood": delay_reflood, "nbrFilterPrefixList": nbr_filter, } } @@ -280,7 +283,7 @@ def test_p2mp_broadcast_interface(): pytest.skip("Skipped because of router(s) failure") step("Verify router r1 interface r1-eth0 p2mp configuration") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A") step("Verify router r1 p2mp interface r1-eth0 neighbors") verify_p2mp_neighbor( @@ -305,7 +308,7 @@ def test_p2mp_broadcast_interface(): step("Verify router r1 interface r1-eth0 p2mp configuration application") r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf network point-to-multipoint") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A") step("Verify restablishment of r1-eth0 p2mp neighbors") verify_p2mp_neighbor( @@ -324,14 +327,14 @@ def test_p2mp_broadcast_interface(): verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.4", "r1-eth0") -def test_p2mp_broadcast_neighbor_filter(): +def p2mp_broadcast_neighbor_filter_common(delay_reflood): tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip("Skipped because of router(s) failure") step("Verify router r1 interface r1-eth0 p2mp configuration") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Verify router r1 p2mp interface r1-eth0 neighbors") verify_p2mp_neighbor( @@ -362,7 +365,7 @@ def test_p2mp_broadcast_neighbor_filter(): assert neighbor_filter_cfg == " ip ospf neighbor-filter nbr-filter", assertmsg step("Verify non-existent neighbor-filter is not applied to r1 interfaces") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Add nbr-filter prefix-list configuration to r1") r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 200 permit any") @@ -370,7 +373,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and neighbors still adjacent" ) - verify_p2mp_interface(tgen, "r1", 3, 3, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "nbr-filter") step("Add nbr-filter prefix-list configuration to block r4") r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32") @@ -378,7 +381,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and r4 is no longer adjacent" ) - verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4") step("Verify route to r4 subnet is now through r2") @@ -390,7 +393,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and r2 is no longer adjacent" ) - verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2") step("Verify route to r4 and r2 subnet are now through r3") @@ -406,24 +409,105 @@ def test_p2mp_broadcast_neighbor_filter(): assert rc, assertmsg step("Verify interface neighbor-filter is removed and neighbors present") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Add neighbor filter configuration and verify neighbors are filtered") r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter") - verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2") verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4") step("Remove nbr-filter prefix-list configuration to block r2 and verify neighbor") r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter seq 20") - verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter") verify_p2mp_neighbor( tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1" ) step("Delete nbr-filter prefix-list and verify neighbors are present") r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") + + +def test_p2mp_broadcast_neighbor_filter(): + p2mp_broadcast_neighbor_filter_common(False) + + +def test_p2mp_broadcast_neighbor_filter_delay_reflood(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("Skipped because of router(s) failure") + + step("Modify router r1 interface r1-eth0 p2mp delay-reflood configuration") + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + "conf t\ninterface r1-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + verify_p2mp_interface(tgen, "r1", 3, 3, True, "N/A") + + step("Modify router r2 interface r2-eth0 p2mp delay-reflood configuration") + r2 = tgen.gears["r2"] + r2.vtysh_cmd( + "conf t\ninterface r2-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + step("Modify router r3 interface r3-eth0 p2mp delay-reflood configuration") + r3 = tgen.gears["r3"] + r3.vtysh_cmd( + "conf t\ninterface r3-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + step("Modify router r4 interface r4-eth0 p2mp delay-reflood configuration") + r4 = tgen.gears["r4"] + r4.vtysh_cmd( + "conf t\ninterface r4-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + p2mp_broadcast_neighbor_filter_common(True) + + step("Recreate a partial P2MP mesh with neighbor filters") + step("Add nbr-filter prefix-list configuration to block r4") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.3/32") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.4/32") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter") + + r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32") + r2.vtysh_cmd("conf t\ninterface r2-eth0\nip ospf neighbor-filter nbr-filter") + + r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32") + r3.vtysh_cmd("conf t\ninterface r3-eth0\nip ospf neighbor-filter nbr-filter") + + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32") + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.2/32") + r4.vtysh_cmd("conf t\ninterface r4-eth0\nip ospf neighbor-filter nbr-filter") + + step( + "Add redistribution and spaced static routes to r1 to test delay flood retransmission" + ) + r1.vtysh_cmd("conf t\nrouter ospf\nredistribute static") + r1.vtysh_cmd("conf t\nip route 20.1.1.1/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.2/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.3/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.4/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.5/32 null0") + sleep(1) + + step( + "Verify the routes are installed on r1 with delay-reflood in P2MP partial mesh" + ) + verify_p2mp_route(tgen, "r4", "20.1.1.1/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.2/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.3/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.4/32", 32, "10.1.0.3", "r4-eth0") def test_memory_leak(): diff --git a/tests/topotests/rip_topo1/r1/show_ip_rip.ref b/tests/topotests/rip_topo1/r1/show_ip_rip.ref index a0b77c886e..b49a042dac 100644 --- a/tests/topotests/rip_topo1/r1/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r1/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/rip_topo1/r2/show_ip_rip.ref b/tests/topotests/rip_topo1/r2/show_ip_rip.ref index b61fb45eac..d0e7e81bc5 100644 --- a/tests/topotests/rip_topo1/r2/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r2/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/rip_topo1/r3/show_ip_rip.ref b/tests/topotests/rip_topo1/r3/show_ip_rip.ref index 1df299b5e6..bb4afc76b7 100644 --- a/tests/topotests/rip_topo1/r3/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r3/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref index 30d0f31e18..8645979cc0 100644 --- a/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref index fe5bcc8b31..2c4db1ab54 100644 --- a/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref index 909ad663ba..2ba0aa6d8f 100644 --- a/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl index f52f1a1616..3e7abeda39 100755 --- a/tools/checkpatch.pl +++ b/tools/checkpatch.pl @@ -4668,6 +4668,7 @@ sub process { # check for new typedefs, only function parameters and sparse annotations # make sense. if ($line =~ /\btypedef\s/ && + $line !~ /\btypedef.*\s(pim_[^\s]+|[^\s]+_pim)\s*;/ && $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && $line !~ /\b$typeTypedefs\b/ && diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index 26d56acc03..c875a6ec7f 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -360,16 +360,16 @@ module frr-route-map { case set-min-metric { when "derived-from-or-self(../action, 'set-min-metric')"; - choice minimun-metric-value { + choice minimum-metric-value { description - "Mimimum metric to set or use"; + "Minimum metric to set or use"; case min-metric { leaf min-metric { type uint32 { range "0..4294967295"; } description - "Use the following mimumn metric value"; + "Use the following minimum metric value"; } } } diff --git a/zebra/interface.c b/zebra/interface.c index b824977f9e..f1f24cc29f 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1656,8 +1656,10 @@ static void interface_if_protodown(struct interface *ifp, bool protodown, uint32_t rc_bitfield) { struct zebra_if *zif = ifp->info; - bool old_protodown; + bool old_protodown, reason_extern; + reason_extern = !!CHECK_FLAG(zif->protodown_rc, + ZEBRA_PROTODOWN_EXTERNAL); /* * Set our reason code to note it wasn't us. * If the reason we got from the kernel is ONLY frr though, don't @@ -1673,8 +1675,8 @@ static void interface_if_protodown(struct interface *ifp, bool protodown, return; if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_DPLANE) - zlog_debug("interface %s dplane change, protodown %s", - ifp->name, protodown ? "on" : "off"); + zlog_debug("interface %s dplane change, protodown %s curr reason_extern %u", + ifp->name, protodown ? "on" : "off", reason_extern); /* Set protodown, respectively */ COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, protodown); @@ -1699,6 +1701,13 @@ static void interface_if_protodown(struct interface *ifp, bool protodown, return; } + if (!protodown && reason_extern) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("bond member %s has protodown reason external and clear the reason, skip reinstall.", + ifp->name); + return; + } + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "bond mbr %s reinstate protodown %s in the dplane", diff --git a/zebra/main.c b/zebra/main.c index ea1e1cbdbb..687da70cab 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -65,8 +65,6 @@ struct mgmt_be_client *mgmt_be_client; /* Route retain mode flag. */ int retain_mode = 0; -int graceful_restart; - /* Receive buffer size for kernel control sockets */ #define RCVBUFSIZE_MIN 4194304 #ifdef HAVE_NETLINK @@ -88,7 +86,6 @@ const struct option longopts[] = { { "socket", required_argument, NULL, 'z' }, { "ecmp", required_argument, NULL, 'e' }, { "retain", no_argument, NULL, 'r' }, - { "graceful_restart", required_argument, NULL, 'K' }, { "asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD }, { "v6-with-v4-nexthops", no_argument, NULL, OPTION_V6_WITH_V4_NEXTHOP }, #ifdef HAVE_NETLINK @@ -96,7 +93,7 @@ const struct option longopts[] = { { "nl-bufsize", required_argument, NULL, 's' }, { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, #endif /* HAVE_NETLINK */ - {"routing-table", optional_argument, NULL, 'R'}, + { "routing-table", optional_argument, NULL, 'R' }, { 0 } }; @@ -326,7 +323,6 @@ int main(int argc, char **argv) bool v6_with_v4_nexthop = false; bool notify_on_ack = true; - graceful_restart = 0; vrf_configure_backend(VRF_BACKEND_VRF_LITE); frr_preinit(&zebra_di, argc, argv); @@ -342,7 +338,6 @@ int main(int argc, char **argv) " -z, --socket Set path of zebra socket\n" " -e, --ecmp Specify ECMP to use.\n" " -r, --retain When program terminates, retain added route by zebra.\n" - " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops" #ifdef HAVE_NETLINK @@ -352,8 +347,7 @@ int main(int argc, char **argv) #else " -s, Set kernel socket receive buffer size\n" #endif /* HAVE_NETLINK */ - " -R, --routing-table Set kernel routing table\n" - ); + " -R, --routing-table Set kernel routing table\n"); while (1) { int opt = frr_getopt(argc, argv, NULL); @@ -397,9 +391,6 @@ int main(int argc, char **argv) case 'r': retain_mode = 1; break; - case 'K': - graceful_restart = atoi(optarg); - break; case 's': rcvbufsize = atoi(optarg); if (rcvbufsize < RCVBUFSIZE_MIN) @@ -488,11 +479,25 @@ int main(int argc, char **argv) * Clean up zebra-originated routes. The requests will be sent to OS * immediately, so originating PID in notifications from kernel * will be equal to the current getpid(). To know about such routes, - * we have to have route_read() called before. + * we have to have route_read() called before. + * If FRR is gracefully restarting, we either wait for clients + * (e.g., BGP) to signal GR is complete else we wait for specified + * duration. */ zrouter.startup_time = monotime(NULL); - event_add_timer(zrouter.master, rib_sweep_route, NULL, graceful_restart, - &zrouter.sweeper); + zrouter.rib_sweep_time = 0; + zrouter.graceful_restart = zebra_di.graceful_restart; + if (!zrouter.graceful_restart) + event_add_timer(zrouter.master, rib_sweep_route, NULL, 0, NULL); + else { + int gr_cleanup_time; + + gr_cleanup_time = zebra_di.gr_cleanup_time + ? zebra_di.gr_cleanup_time + : ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME; + event_add_timer(zrouter.master, rib_sweep_route, NULL, + gr_cleanup_time, &zrouter.t_rib_sweep); + } /* Needed for BSD routing socket. */ pid = getpid(); diff --git a/zebra/rib.h b/zebra/rib.h index a721f4bac4..84ea766c47 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -622,10 +622,10 @@ static inline struct nexthop_group *rib_get_fib_backup_nhg( } extern void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + uint8_t instance, time_t restart_time); extern int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + uint8_t instance, time_t restart_time); extern void zebra_vty_init(void); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 2a1eea9594..654ade8063 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2414,6 +2414,7 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) stream_putl(s, zrouter.multipath_num); stream_putc(s, zebra_mlag_get_role()); stream_putc(s, zrouter.v6_with_v4_nexthop); + stream_putc(s, zrouter.graceful_restart); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 7910559c4b..0844b34672 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -4315,6 +4315,10 @@ dplane_route_update_internal(struct route_node *rn, continue; if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_DUPLICATE)) + continue; + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c index cee66cc055..d84f680e22 100644 --- a/zebra/zebra_gr.c +++ b/zebra/zebra_gr.c @@ -103,6 +103,7 @@ static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client) info->stale_client_ptr = client; TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info); + info->client_ptr = client; return info; } @@ -290,6 +291,7 @@ struct zebra_gr_afi_clean { afi_t afi; uint8_t proto; uint8_t instance; + time_t restart_time; struct event *t_gac; }; @@ -420,7 +422,7 @@ void zread_client_capabilities(ZAPI_HANDLER_ARGS) * Schedule for after anything already in the meta Q */ rib_add_gr_run(api.afi, api.vrf_id, client->proto, - client->instance); + client->instance, client->restart_time); zebra_gr_process_client_stale_routes(client, info); break; case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: @@ -455,7 +457,11 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) struct zserv *client; struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - client = (struct zserv *)info->stale_client_ptr; + info->t_stale_removal = NULL; + if (zrouter.graceful_restart) + client = (struct zserv *)info->client_ptr; + else + client = (struct zserv *)info->stale_client_ptr; cnt = zebra_gr_delete_stale_routes(info); @@ -486,16 +492,24 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) * * Returns true when a node is deleted else false */ -static bool zebra_gr_process_route_entry(struct zserv *client, - struct route_node *rn, - struct route_entry *re) +static bool zebra_gr_process_route_entry(struct route_node *rn, + struct route_entry *re, + time_t compare_time, uint8_t proto) { + struct nexthop *nexthop; + char buf[PREFIX2STR_BUFFER]; + /* If the route is not refreshed after restart, delete the entry */ - if (re->uptime < client->restart_time) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("%s: Client %s stale route %pFX is deleted", - __func__, zebra_route_string(client->proto), - &rn->p); + if (re->uptime < compare_time) { + if (IS_ZEBRA_DEBUG_RIB) { + prefix2str(&rn->p, buf, sizeof(buf)); + zlog_debug("%s: Client %s stale route %s is deleted", + __func__, zebra_route_string(proto), buf); + } + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + rib_delnode(rn, re); return true; @@ -532,8 +546,9 @@ static void zebra_gr_delete_stale_route_table_afi(struct event *event) if (re->type == gac->proto && re->instance == gac->instance && - zebra_gr_process_route_entry( - gac->info->stale_client_ptr, rn, re)) + zebra_gr_process_route_entry(rn, re, + gac->restart_time, + gac->proto)) n++; /* If the max route count is reached @@ -567,28 +582,42 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, uint8_t proto; uint16_t instance; struct zserv *s_client; + struct zserv *client; + time_t restart_time = time(NULL); - s_client = info->stale_client_ptr; - if (s_client == NULL) { - LOG_GR("%s: Stale client %s(%u) not present", __func__, - zvrf->vrf->name, zvrf->vrf->vrf_id); + if ((info == NULL) || (zvrf == NULL)) return -1; - } - proto = s_client->proto; - instance = s_client->instance; + if (zrouter.graceful_restart) { + client = info->client_ptr; + if (client == NULL) { + LOG_GR("%s: client not present", __func__); + return -1; + } + proto = client->proto; + instance = client->instance; + restart_time = zrouter.startup_time; + } else { + s_client = info->stale_client_ptr; + if (s_client == NULL) { + LOG_GR("%s: Stale client not present", __func__); + return -1; + } + proto = s_client->proto; + instance = s_client->instance; + restart_time = s_client->restart_time; + } LOG_GR("%s: Client %s %s(%u) stale routes are being deleted", __func__, zebra_route_string(proto), zvrf->vrf->name, zvrf->vrf->vrf_id); /* Process routes for all AFI */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { - /* * Schedule for immediately after anything in the * meta-Q */ - rib_add_gr_run(afi, info->vrf_id, proto, instance); + rib_add_gr_run(afi, info->vrf_id, proto, instance, restart_time); } return 0; } @@ -641,12 +670,13 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, /* * Route update completed for all AFI, SAFI - * Cancel the stale timer, routes are already being processed + * Also perform the cleanup if FRR itself is gracefully restarting. */ - if (info->t_stale_removal) { + info->route_sync_done_time = monotime(NULL); + if (info->t_stale_removal || zrouter.graceful_restart) { struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - LOG_GR("%s: Client %s canceled stale delete timer vrf %s(%d)", + LOG_GR("%s: Client %s route update complete for all AFI/SAFI in vrf %s(%d)", __func__, zebra_route_string(client->proto), VRF_LOGNAME(vrf), info->vrf_id); EVENT_OFF(info->t_stale_removal); @@ -654,7 +684,7 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, } void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance) + uint8_t instance, time_t restart_time) { struct zserv *client = zserv_find_client(proto, instance); struct client_gr_info *info = NULL; @@ -676,6 +706,7 @@ void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, gac->afi = afi; gac->proto = proto; gac->instance = instance; + gac->restart_time = restart_time; event_add_event(zrouter.master, zebra_gr_delete_stale_route_table_afi, gac, 0, &gac->t_gac); diff --git a/zebra/zebra_nb_rpcs.c b/zebra/zebra_nb_rpcs.c index 938193df2f..744ba620f2 100644 --- a/zebra/zebra_nb_rpcs.c +++ b/zebra/zebra_nb_rpcs.c @@ -12,6 +12,8 @@ #include "zebra/zebra_router.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_vxlan_if.h" +#include "zebra/zebra_evpn.h" /* * XPath: /frr-zebra:clear-evpn-dup-addr @@ -21,6 +23,11 @@ int clear_evpn_dup_addr_rpc(struct nb_cb_rpc_args *args) struct zebra_vrf *zvrf; int ret = NB_OK; + if (!is_evpn_enabled()) { + snprintf(args->errmsg, args->errmsg_len, + "%% EVPN not enabled\n"); + return NB_ERR_VALIDATION; + } zvrf = zebra_vrf_get_evpn(); if (yang_dnode_exists(args->input, "all-vnis")) { @@ -30,6 +37,12 @@ int clear_evpn_dup_addr_rpc(struct nb_cb_rpc_args *args) struct ipaddr host_ip = {.ipa_type = IPADDR_NONE}; struct ethaddr mac; + if (!zebra_evpn_lookup(vni)) { + snprintf(args->errmsg, args->errmsg_len, + "%% VNI %u does not exist\n", vni); + return NB_ERR_VALIDATION; + } + if (yang_dnode_exists(args->input, "mac-addr")) { yang_dnode_get_mac(&mac, args->input, "mac-addr"); ret = zebra_vxlan_clear_dup_detect_vni_mac(zvrf, vni, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5b95d8668a..142f83fb36 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1659,6 +1659,9 @@ static bool rib_update_nhg_from_ctx(struct nexthop_group *re_nhg, if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + continue; + /* Check for a FIB nexthop corresponding to the RIB nexthop */ if (!nexthop_same(ctx_nexthop, nexthop)) { /* If the FIB doesn't know about the nexthop, @@ -3159,6 +3162,7 @@ struct meta_q_gr_run { vrf_id_t vrf_id; uint8_t proto; uint8_t instance; + time_t restart_time; }; static void process_subq_gr_run(struct listnode *lnode) @@ -3166,7 +3170,7 @@ static void process_subq_gr_run(struct listnode *lnode) struct meta_q_gr_run *gr_run = listgetdata(lnode); zebra_gr_process_client(gr_run->afi, gr_run->vrf_id, gr_run->proto, - gr_run->instance); + gr_run->instance, gr_run->restart_time); XFREE(MTYPE_WQ_WRAPPER, gr_run); } @@ -4266,7 +4270,8 @@ static int rib_meta_queue_early_route_add(struct meta_queue *mq, void *data) return 0; } -int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) +int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance, + time_t restart_time) { struct meta_q_gr_run *gr_run; @@ -4276,6 +4281,7 @@ int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) gr_run->proto = proto; gr_run->vrf_id = vrf_id; gr_run->instance = instance; + gr_run->restart_time = restart_time; return mq_add_handler(gr_run, rib_meta_queue_gr_run_add); } @@ -4694,6 +4700,10 @@ void rib_sweep_route(struct event *t) struct vrf *vrf; struct zebra_vrf *zvrf; + zrouter.rib_sweep_time = monotime(NULL); + /* TODO: Change to debug */ + zlog_info("Sweeping the RIB for stale routes..."); + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { if ((zvrf = vrf->info) == NULL) continue; diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 3fd4e6eb1f..8d6b2f3476 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -238,7 +238,7 @@ void zebra_router_terminate(void) { struct zebra_router_table *zrt, *tmp; - EVENT_OFF(zrouter.sweeper); + EVENT_OFF(zrouter.t_rib_sweep); RB_FOREACH_SAFE (zrt, zebra_router_table_head, &zrouter.tables, tmp) zebra_router_free_table(zrt); diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 3041707439..c86c6be1ef 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -191,10 +191,16 @@ struct zebra_router { enum multicast_mode ipv4_multicast_mode; /* - * Time for when we sweep the rib from old routes + * zebra start time and time of sweeping RIB of old routes */ time_t startup_time; - struct event *sweeper; + time_t rib_sweep_time; + + /* FRR fast/graceful restart info */ + bool graceful_restart; + int gr_cleanup_time; +#define ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME 500 + struct event *t_rib_sweep; /* * The hash of nexthop groups associated with this router diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 0ca77a4974..e82b781c6f 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -956,11 +956,12 @@ static bool zebra_srv6_sid_compose(struct in6_addr *sid_value, uint32_t sid_func) { uint8_t offset, func_len; - struct srv6_sid_format *format = locator->sid_format; + struct srv6_sid_format *format; if (!sid_value || !locator) return false; + format = locator->sid_format; if (format) { offset = format->block_len + format->node_len; func_len = format->function_len; @@ -1742,8 +1743,7 @@ int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value, srv6_sid_alloc_mode2str(alloc_mode)); - switch (alloc_mode) { - case SRV6_SID_ALLOC_MODE_EXPLICIT: + if (alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) { /* * Explicit SID allocation: allocate a specific SID value */ @@ -1755,9 +1755,7 @@ int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, } ret = get_srv6_sid_explicit(sid, ctx, sid_value); - - break; - case SRV6_SID_ALLOC_MODE_DYNAMIC: + } else { /* * Dynamic SID allocation: allocate any available SID value */ @@ -1776,16 +1774,6 @@ int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, } ret = get_srv6_sid_dynamic(sid, ctx, locator); - - break; - case SRV6_SID_ALLOC_MODE_MAX: - case SRV6_SID_ALLOC_MODE_UNSPEC: - default: - flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, - "%s: SRv6 Manager: Unrecognized alloc mode %u", - __func__, alloc_mode); - /* We should never arrive here */ - assert(0); } return ret; @@ -1856,7 +1844,7 @@ static bool release_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, for (ALL_LIST_ELEMENTS_RO(block->u.usid .wide_lib[sid_func] .func_allocated, - node, sid_func_ptr)) + node, sid_wide_func_ptr)) if (*sid_wide_func_ptr == sid_wide_func) break; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index c31218a7c3..858e503031 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -3825,6 +3825,20 @@ DEFUN (show_zebra, struct vrf *vrf; struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]); char *out; + char timebuf[MONOTIME_STRLEN]; + + time_to_string(zrouter.startup_time, timebuf); + vty_out(vty, "Zebra started%s at time %s", + zrouter.graceful_restart ? " gracefully" : "", timebuf); + + if (zrouter.t_rib_sweep) + vty_out(vty, + "Zebra RIB sweep timer running, remaining time %lds\n", + event_timer_remain_second(zrouter.t_rib_sweep)); + else { + time_to_string(zrouter.rib_sweep_time, timebuf); + vty_out(vty, "Zebra RIB sweep happened at %s", timebuf); + } ttable_rowseps(table, 0, BOTTOM, true, '-'); ttable_add_row(table, "OS|%s(%s)", cmd_system_get(), cmd_release_get()); diff --git a/zebra/zserv.c b/zebra/zserv.c index 27668534ee..a731f7f278 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1031,6 +1031,7 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen) /* Display client info details */ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) { + struct client_gr_info *info; char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF]; char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF]; time_t connect_time, last_read_time, last_write_time; @@ -1125,6 +1126,45 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) vty_out(vty, "ES-EVI %-12u%-12u%-12u\n", client->local_es_evi_add_cnt, 0, client->local_es_evi_del_cnt); vty_out(vty, "Errors: %u\n", client->error_cnt); + + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + afi_t afi; + bool route_sync_done = true; + char timebuf[MONOTIME_STRLEN]; + + vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id)); + vty_out(vty, "Capabilities : "); + switch (info->capabilities) { + case ZEBRA_CLIENT_GR_CAPABILITIES: + vty_out(vty, "Graceful Restart\n"); + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: + case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: + case ZEBRA_CLIENT_GR_DISABLE: + case ZEBRA_CLIENT_RIB_STALE_TIME: + vty_out(vty, "None\n"); + break; + } + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + if (info->af_enabled[afi]) { + if (info->route_sync[afi]) + vty_out(vty, + "AFI %d enabled, route sync DONE\n", + afi); + else { + vty_out(vty, + "AFI %d enabled, route sync NOT DONE\n", + afi); + route_sync_done = false; + } + } + } + if (route_sync_done) { + time_to_string(info->route_sync_done_time, timebuf); + vty_out(vty, "Route sync finished at %s", timebuf); + } + } + vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n", client->ibuf_fifo->count, client->ibuf_fifo->max_count, client->obuf_fifo->count, client->obuf_fifo->max_count); diff --git a/zebra/zserv.h b/zebra/zserv.h index 57d673060f..87d2b4adbf 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -64,6 +64,8 @@ struct client_gr_info { /* Book keeping */ void *stale_client_ptr; struct event *t_stale_removal; + void *client_ptr; + time_t route_sync_done_time; TAILQ_ENTRY(client_gr_info) gr_info; }; |
