From 69052f3d3363646484816ebe4e2d549aab8c2b53 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 20 Aug 2020 21:24:07 -0300 Subject: [PATCH 1/9] isisd: make vid2string() fully reentrant Always fill the buffer provided by the user to prevent unexpected results and make the function fully reentrant. Signed-off-by: Renato Westphal --- isisd/isis_spf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index ebce86bed9..6f3c125e95 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -155,7 +155,9 @@ static const char *vtype2string(enum vertextype vtype) const char *vid2string(struct isis_vertex *vertex, char *buff, int size) { if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) { - return print_sys_hostname(vertex->N.id); + const char *hostname = print_sys_hostname(vertex->N.id); + strlcpy(buff, hostname, size); + return buff; } if (VTYPE_IP(vertex->type)) { From 0af5e414d1b1a6a89aee261f3fea9e32310714ea Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 20 Aug 2020 21:25:24 -0300 Subject: [PATCH 2/9] isisd: don't add Adj-SIDs when an IP address is missing Signed-off-by: Renato Westphal --- isisd/isis_sr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index bdbdc30b4a..5f6335c7d0 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -1521,13 +1521,13 @@ static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, /* Determine nexthop IP address */ switch (family) { case AF_INET: - if (!circuit->ip_router) + if (!circuit->ip_router || !adj->ipv4_address_count) return; nexthop.ipv4 = adj->ipv4_addresses[0]; break; case AF_INET6: - if (!circuit->ipv6_router) + if (!circuit->ipv6_router || !adj->ipv6_address_count) return; nexthop.ipv6 = adj->ipv6_addresses[0]; From 98a496368a8d1c5c2d1caf35142ecfae55cae615 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 20 Aug 2020 21:27:56 -0300 Subject: [PATCH 3/9] isisd: introduce two LSP iteration functions Iterating over all IP or IS reachability information from a given LSP isn't a trivial task. That information is scattered throughout different TLV types, and which ones need to be used depend on multiple variables (e.g. the SPF tree address family, MT-ID, etc). This not to mention that an LSP might consist of multiple fragments. Introduce the following two LSP iteration function to facilitate obtaining IP/IS reachability information from a given LSP: * isis_lsp_iterate_ip_reach() * isis_lsp_iterate_is_reach() These functions will be used extensively by the upcoming TI-LFA code. Signed-off-by: Renato Westphal --- isisd/isis_lsp.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++ isisd/isis_lsp.h | 20 ++++++ 2 files changed, 174 insertions(+) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 90c7c0efb5..1af6f417dc 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -2046,6 +2046,160 @@ static int lsp_handle_adj_state_change(struct isis_adjacency *adj) return 0; } +/* + * Iterate over all IP reachability TLVs in a LSP (all fragments) of the given + * address-family and MT-ID. + */ +int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid, + lsp_ip_reach_iter_cb cb, void *arg) +{ + bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id); + struct isis_lsp *frag; + struct listnode *node; + + if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0) + return LSP_ITER_CONTINUE; + + /* Parse main LSP. */ + if (lsp->tlvs) { + if (!fabricd && !pseudo_lsp && family == AF_INET + && mtid == ISIS_MT_IPV4_UNICAST) { + struct isis_item_list *reachs[] = { + &lsp->tlvs->oldstyle_ip_reach, + &lsp->tlvs->oldstyle_ip_reach_ext}; + + for (unsigned int i = 0; i < array_size(reachs); i++) { + struct isis_oldstyle_ip_reach *r; + + for (r = (struct isis_oldstyle_ip_reach *) + reachs[i] + ->head; + r; r = r->next) { + bool external = i ? true : false; + + if ((*cb)((struct prefix *)&r->prefix, + r->metric, external, NULL, + arg) + == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + } + } + + if (!pseudo_lsp && family == AF_INET) { + struct isis_item_list *ipv4_reachs; + + if (mtid == ISIS_MT_IPV4_UNICAST) + ipv4_reachs = &lsp->tlvs->extended_ip_reach; + else + ipv4_reachs = isis_lookup_mt_items( + &lsp->tlvs->mt_ip_reach, mtid); + + struct isis_extended_ip_reach *r; + for (r = ipv4_reachs ? (struct isis_extended_ip_reach *) + ipv4_reachs->head + : NULL; + r; r = r->next) { + if ((*cb)((struct prefix *)&r->prefix, + r->metric, false, r->subtlvs, arg) + == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + } + + if (!pseudo_lsp && family == AF_INET6) { + struct isis_item_list *ipv6_reachs; + struct isis_ipv6_reach *r; + + if (mtid == ISIS_MT_IPV4_UNICAST) + ipv6_reachs = &lsp->tlvs->ipv6_reach; + else + ipv6_reachs = isis_lookup_mt_items( + &lsp->tlvs->mt_ipv6_reach, mtid); + + for (r = ipv6_reachs ? (struct isis_ipv6_reach *) + ipv6_reachs->head + : NULL; + r; r = r->next) { + if ((*cb)((struct prefix *)&r->prefix, + r->metric, r->external, r->subtlvs, + arg) + == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + } + } + + /* Parse LSP fragments. */ + for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) { + if (!frag->tlvs) + continue; + + isis_lsp_iterate_ip_reach(frag, family, mtid, cb, arg); + } + + return LSP_ITER_CONTINUE; +} + +/* + * Iterate over all IS reachability TLVs in a LSP (all fragments) of the given + * MT-ID. + */ +int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid, + lsp_is_reach_iter_cb cb, void *arg) +{ + bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id); + struct isis_lsp *frag; + struct listnode *node; + struct isis_item *head; + struct isis_item_list *te_neighs; + + if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0) + return LSP_ITER_CONTINUE; + + /* Parse main LSP. */ + if (lsp->tlvs) { + if (pseudo_lsp || mtid == ISIS_MT_IPV4_UNICAST) { + head = lsp->tlvs->oldstyle_reach.head; + for (struct isis_oldstyle_reach *reach = + (struct isis_oldstyle_reach *)head; + reach; reach = reach->next) { + if ((*cb)(reach->id, reach->metric, true, NULL, + arg) + == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + } + + if (pseudo_lsp || mtid == ISIS_MT_IPV4_UNICAST) + te_neighs = &lsp->tlvs->extended_reach; + else + te_neighs = + isis_get_mt_items(&lsp->tlvs->mt_reach, mtid); + if (te_neighs) { + head = te_neighs->head; + for (struct isis_extended_reach *reach = + (struct isis_extended_reach *)head; + reach; reach = reach->next) { + if ((*cb)(reach->id, reach->metric, false, + reach->subtlvs, arg) + == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + } + } + + /* Parse LSP fragments. */ + for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) { + if (!frag->tlvs) + continue; + + isis_lsp_iterate_is_reach(frag, mtid, cb, arg); + } + + return LSP_ITER_CONTINUE; +} + void lsp_init(void) { hook_register(isis_adj_state_change_hook, diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 6cbea47496..0783036e49 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -127,6 +127,26 @@ int lsp_print_all(struct vty *vty, struct lspdb_head *head, char detail, /* sets SRMflags for all active circuits of an lsp */ void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set); +#define LSP_ITER_CONTINUE 0 +#define LSP_ITER_STOP -1 + +/* Callback used by isis_lsp_iterate_ip_reach() function. */ +struct isis_subtlvs; +typedef int (*lsp_ip_reach_iter_cb)(const struct prefix *prefix, + uint32_t metric, bool external, + struct isis_subtlvs *subtlvs, void *arg); + +/* Callback used by isis_lsp_iterate_is_reach() function. */ +typedef int (*lsp_is_reach_iter_cb)(const uint8_t *id, uint32_t metric, + bool oldmetric, + struct isis_ext_subtlvs *subtlvs, + void *arg); + +int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid, + lsp_ip_reach_iter_cb cb, void *arg); +int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid, + lsp_is_reach_iter_cb cb, void *arg); + #define lsp_flood(lsp, circuit) \ _lsp_flood((lsp), (circuit), __func__, __FILE__, __LINE__) void _lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit, From 56ea2b212f94b19486fd2f6e006acae1ef0d8552 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 20 Aug 2020 21:36:59 -0300 Subject: [PATCH 4/9] isisd: reuse adjacency state change hook in the SPF code This is mostly a cosmetic change to make the code more modular, more elegant and easier to understand. Signed-off-by: Renato Westphal --- isisd/isis_adjacency.c | 4 ---- isisd/isis_main.c | 2 +- isisd/isis_spf.c | 15 +++++++++++++-- isisd/isis_spf.h | 3 +-- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index af5258846a..f7cdd58f72 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -43,7 +43,6 @@ #include "isisd/isis_dynhn.h" #include "isisd/isis_pdu.h" #include "isisd/isis_lsp.h" -#include "isisd/isis_spf.h" #include "isisd/isis_events.h" #include "isisd/isis_mt.h" #include "isisd/isis_tlvs.h" @@ -152,9 +151,6 @@ void isis_delete_adj(void *arg) if (adj->adj_state != ISIS_ADJ_DOWN) adj->adj_state = ISIS_ADJ_DOWN; - /* remove from SPF trees */ - spftree_area_adj_del(adj->circuit->area, adj); - hook_call(isis_adj_state_change_hook, adj); XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index ed4b206851..6352303c23 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -252,7 +252,7 @@ int main(int argc, char **argv, char **envp) #ifndef FABRICD isis_cli_init(); #endif /* ifdef FABRICD */ - isis_spf_cmds_init(); + isis_spf_init(); isis_redist_init(); isis_route_map_init(); isis_mpls_te_init(); diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 6f3c125e95..174f4dfe85 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -275,8 +275,14 @@ void spftree_area_del(struct isis_area *area) } } -void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj) +static int spf_adj_state_change(struct isis_adjacency *adj) { + struct isis_area *area = adj->circuit->area; + + if (adj->adj_state == ISIS_ADJ_UP) + return 0; + + /* Remove adjacency from all SPF trees. */ for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) { for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { if (!(area->is_type & level)) @@ -290,6 +296,8 @@ void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj) if (fabricd_spftree(area) != NULL) isis_spftree_adj_del(fabricd_spftree(area), adj); + + return 0; } /* @@ -1513,9 +1521,12 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, return CMD_SUCCESS; } -void isis_spf_cmds_init(void) +void isis_spf_init(void) { install_element(VIEW_NODE, &show_isis_topology_cmd); + + /* Register hook(s). */ + hook_register(isis_adj_state_change_hook, spf_adj_state_change); } void isis_spf_print(struct isis_spftree *spftree, struct vty *vty) diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 8bf9c9978a..a85e596bb0 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -33,13 +33,12 @@ void isis_spf_verify_routes(struct isis_area *area, void isis_spftree_del(struct isis_spftree *spftree); void spftree_area_init(struct isis_area *area); void spftree_area_del(struct isis_area *area); -void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj); #define isis_spf_schedule(area, level) \ _isis_spf_schedule((area), (level), __func__, \ __FILE__, __LINE__) int _isis_spf_schedule(struct isis_area *area, int level, const char *func, const char *file, int line); -void isis_spf_cmds_init(void); +void isis_spf_init(void); void isis_spf_print(struct isis_spftree *spftree, struct vty *vty); struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area, uint8_t *sysid, From 36944791620d1b223dede262948a0afe3dadca1f Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 20 Aug 2020 21:44:27 -0300 Subject: [PATCH 5/9] isisd: minor cleanup * Bring back some consts that were removed; * Replace ALL_LIST_ELEMENTS by ALL_LIST_ELEMENTS_RO whenever possible; * Fix some CLI return values; * Remove some unnecessary initializations. Signed-off-by: Renato Westphal --- isisd/isis_misc.c | 5 +- isisd/isis_misc.h | 2 +- isisd/isis_spf.c | 7 ++- isisd/isis_sr.c | 14 +++--- isisd/isis_te.c | 8 ++-- isisd/isisd.c | 113 +++++++++++++++++++++++----------------------- isisd/isisd.h | 2 +- 7 files changed, 75 insertions(+), 76 deletions(-) diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index 3aedd8ba1f..27425f24a4 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -437,7 +437,7 @@ struct in_addr newprefix2inaddr(uint8_t *prefix_start, uint8_t prefix_masklen) * Returns the dynamic hostname associated with the passed system ID. * If no dynamic hostname found then returns formatted system ID. */ -const char *print_sys_hostname(uint8_t *sysid) +const char *print_sys_hostname(const uint8_t *sysid) { struct isis_dynhn *dyn; struct isis *isis = NULL; @@ -447,8 +447,7 @@ const char *print_sys_hostname(uint8_t *sysid) /* For our system ID return our host name */ isis = isis_lookup_by_sysid(sysid); - - if (isis != NULL) + if (isis) return cmd_hostname_get(); dyn = dynhn_find_by_id(sysid); diff --git a/isisd/isis_misc.h b/isisd/isis_misc.h index c6a5832f33..5cdbbfb058 100644 --- a/isisd/isis_misc.h +++ b/isisd/isis_misc.h @@ -49,7 +49,7 @@ const char *time2string(uint32_t); const char *nlpid2str(uint8_t nlpid); /* typedef struct nlpids nlpids; */ char *nlpid2string(struct nlpids *); -const char *print_sys_hostname(uint8_t *sysid); +const char *print_sys_hostname(const uint8_t *sysid); void zlog_dump_data(void *data, int len); /* diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 174f4dfe85..ec10bb77e6 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1484,7 +1484,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, ) { int levels = ISIS_LEVELS; - struct listnode *inode, *nnode; + struct listnode *node; struct isis *isis = NULL; int idx = 0; const char *vrf_name = VRF_DEFAULT_NAME; @@ -1508,10 +1508,9 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, if (vrf_name) { if (all_vrf) { - for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) show_isis_topology_common(vty, levels, isis); - } - return 0; + return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); if (isis != NULL) diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index 5f6335c7d0..d05afaa630 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -210,7 +210,7 @@ int isis_sr_cfg_srlb_update(struct isis_area *area, uint32_t lower_bound, uint32_t upper_bound) { struct isis_sr_db *srdb = &area->srdb; - struct listnode *node, *nnode; + struct listnode *node; struct sr_adjacency *sra; sr_debug("ISIS-Sr (%s): Update SRLB with new range [%u/%u]", @@ -236,7 +236,7 @@ int isis_sr_cfg_srlb_update(struct isis_area *area, uint32_t lower_bound, return -1; /* Reinstall local Adjacency-SIDs with new labels. */ - for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra)) + for (ALL_LIST_ELEMENTS_RO(area->srdb.adj_sids, node, sra)) sr_adj_sid_update(sra, &srdb->srlb); /* Update and Flood LSP */ @@ -1986,7 +1986,7 @@ DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd, "Segment-Routing\n" "Segment-Routing Prefix-SIDs\n") { - struct listnode *node, *inode, *nnode; + struct listnode *node, *inode; struct isis_area *area; struct isis *isis = NULL; const char *vrf_name = VRF_DEFAULT_NAME; @@ -1996,7 +1996,7 @@ DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd, ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); if (vrf_name) { if (all_vrf) { - for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { vty_out(vty, "Area %s:\n", @@ -2084,11 +2084,11 @@ DEFUN(show_sr_node, show_sr_node_cmd, "Segment-Routing\n" "Segment-Routing node\n") { - struct listnode *node, *inode, *nnode; + struct listnode *node, *inode; struct isis_area *area; - struct isis *isis = NULL; + struct isis *isis; - for (ALL_LIST_ELEMENTS(im->isis, inode, nnode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { vty_out(vty, "Area %s:\n", area->area_tag ? area->area_tag : "null"); diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 016f811a72..87c4428155 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -311,7 +311,7 @@ DEFUN(show_isis_mpls_te_router, MPLS_TE_STR "Router information\n") { - struct listnode *anode, *nnode, *inode; + struct listnode *anode, *inode; struct isis_area *area; struct isis *isis = NULL; const char *vrf_name = VRF_DEFAULT_NAME; @@ -325,7 +325,7 @@ DEFUN(show_isis_mpls_te_router, ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); if (vrf_name) { if (all_vrf) { - for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { if (!IS_MPLS_TE(area->mta)) @@ -483,7 +483,7 @@ DEFUN (show_isis_mpls_te_interface, "Interface information\n" "Interface name\n") { - struct listnode *anode, *cnode, *nnode, *inode; + struct listnode *anode, *cnode, *inode; struct isis_area *area; struct isis_circuit *circuit; struct interface *ifp; @@ -497,7 +497,7 @@ DEFUN (show_isis_mpls_te_interface, if (argc == idx_interface) { /* Show All Interfaces. */ - for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { diff --git a/isisd/isisd.c b/isisd/isisd.c index 0d39aba20b..453b440e23 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -125,33 +125,37 @@ void isis_vrf_unlink(struct isis *isis, struct vrf *vrf) struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id) { - struct isis *isis = NULL; - struct listnode *node, *nnode; + struct isis *isis; + struct listnode *node; - for (ALL_LIST_ELEMENTS(im->isis, node, nnode, isis)) + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) if (isis->vrf_id == vrf_id) return isis; + return NULL; } struct isis *isis_lookup_by_vrfname(const char *vrfname) { - struct isis *isis = NULL; - struct listnode *node, *nnode; + struct isis *isis; + struct listnode *node; - for (ALL_LIST_ELEMENTS(im->isis, node, nnode, isis)) + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) if (isis->name && vrfname && strcmp(isis->name, vrfname) == 0) return isis; + return NULL; } -struct isis *isis_lookup_by_sysid(uint8_t *sysid) +struct isis *isis_lookup_by_sysid(const uint8_t *sysid) { - struct isis *isis = NULL; - struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS(im->isis, node, nnode, isis)) + struct isis *isis; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) if (!memcmp(isis->sysid, sysid, ISIS_SYS_ID_LEN)) return isis; + return NULL; } @@ -165,7 +169,7 @@ void isis_master_init(struct thread_master *master) void isis_global_instance_create() { - struct isis *isis = NULL; + struct isis *isis; isis = isis_lookup_by_vrfid(VRF_DEFAULT); if (isis == NULL) { @@ -176,8 +180,8 @@ void isis_global_instance_create() struct isis *isis_new(vrf_id_t vrf_id) { - struct vrf *vrf = NULL; - struct isis *isis = NULL; + struct vrf *vrf; + struct isis *isis; isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis)); isis->vrf_id = vrf_id; @@ -335,7 +339,7 @@ struct isis_area *isis_area_lookup(const char *area_tag, vrf_id_t vrf_id) { struct isis_area *area; struct listnode *node; - struct isis *isis = NULL; + struct isis *isis; isis = isis_lookup_by_vrfid(vrf_id); if (isis == NULL) @@ -464,7 +468,7 @@ void isis_finish(struct isis *isis) void isis_terminate() { - struct isis *isis = NULL; + struct isis *isis; struct listnode *node, *nnode; if (listcount(im->isis) == 0) @@ -643,10 +647,10 @@ int area_clear_net_title(struct vty *vty, const char *net_title) int show_isis_interface_common(struct vty *vty, const char *ifname, char detail, const char *vrf_name, bool all_vrf) { - struct listnode *anode, *cnode, *mnode, *inode; + struct listnode *anode, *cnode, *inode; struct isis_area *area; struct isis_circuit *circuit; - struct isis *isis = NULL; + struct isis *isis; if (!im) { vty_out(vty, "IS-IS Routing Process not enabled\n"); @@ -654,7 +658,7 @@ int show_isis_interface_common(struct vty *vty, const char *ifname, char detail, } if (vrf_name) { if (all_vrf) { - for (ALL_LIST_ELEMENTS(im->isis, mnode, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { vty_out(vty, "Area %s:\n", @@ -677,7 +681,7 @@ int show_isis_interface_common(struct vty *vty, const char *ifname, char detail, detail); } } - return 0; + return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); if (isis != NULL) { @@ -822,10 +826,10 @@ static void isis_neighbor_common(struct vty *vty, const char *id, char detail, int show_isis_neighbor_common(struct vty *vty, const char *id, char detail, const char *vrf_name, bool all_vrf) { - struct listnode *nnode, *inode; + struct listnode *node; struct isis_dynhn *dynhn; uint8_t sysid[ISIS_SYS_ID_LEN]; - struct isis *isis = NULL; + struct isis *isis; if (!im) { vty_out(vty, "IS-IS Routing Process not enabled\n"); @@ -846,11 +850,11 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail, if (vrf_name) { if (all_vrf) { - for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { isis_neighbor_common(vty, id, detail, isis, sysid); } - return 0; + return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); if (isis != NULL) @@ -863,7 +867,7 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail, static void isis_neighbor_common_clear(struct vty *vty, const char *id, uint8_t *sysid, struct isis *isis) { - struct listnode *anode, *cnode, *cnextnode, *node, *nnode; + struct listnode *anode, *cnode, *node, *nnode; struct isis_area *area; struct isis_circuit *circuit; struct list *adjdb; @@ -871,8 +875,7 @@ static void isis_neighbor_common_clear(struct vty *vty, const char *id, int i; for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { - for (ALL_LIST_ELEMENTS(area->circuit_list, cnode, cnextnode, - circuit)) { + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) { for (i = 0; i < 2; i++) { adjdb = circuit->u.bc.adjdb[i]; @@ -910,10 +913,10 @@ static void isis_neighbor_common_clear(struct vty *vty, const char *id, int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_name, bool all_vrf) { - struct listnode *nnode, *inode; + struct listnode *node; struct isis_dynhn *dynhn; uint8_t sysid[ISIS_SYS_ID_LEN]; - struct isis *isis = NULL; + struct isis *isis; if (!im) { vty_out(vty, "IS-IS Routing Process not enabled\n"); @@ -933,11 +936,10 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_ } if (vrf_name) { if (all_vrf) { - for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) isis_neighbor_common_clear(vty, id, sysid, isis); - } - return 0; + return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); if (isis != NULL) @@ -1554,19 +1556,19 @@ DEFUN(show_hostname, show_hostname_cmd, "All VRFs\n" "IS-IS Dynamic hostname mapping\n") { - struct listnode *nnode, *inode; + struct listnode *node; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; - struct isis *isis = NULL; + struct isis *isis; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); if (vrf_name) { if (all_vrf) { - for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) dynhn_print_all(vty, isis); - } - return 0; + + return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); if (isis != NULL) @@ -1621,8 +1623,8 @@ DEFUN(show_isis_spf_ietf, show_isis_spf_ietf_cmd, "All VRFs\n" "SPF delay IETF information\n") { - struct listnode *nnode, *inode; - struct isis *isis = NULL; + struct listnode *node; + struct isis *isis; int idx_vrf = 0; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; @@ -1636,10 +1638,10 @@ DEFUN(show_isis_spf_ietf, show_isis_spf_ietf_cmd, if (vrf_name) { if (all_vrf) { - for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) isis_spf_ietf_common(vty, isis); - } - return 0; + + return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); if (isis != NULL) @@ -1755,9 +1757,9 @@ DEFUN(show_isis_summary, show_isis_summary_cmd, "All VRFs\n" "summary\n") { - struct listnode *inode, *nnode; + struct listnode *node; int idx_vrf = 0; - struct isis *isis = NULL; + struct isis *isis; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; @@ -1768,10 +1770,10 @@ DEFUN(show_isis_summary, show_isis_summary_cmd, } if (vrf_name) { if (all_vrf) { - for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) common_isis_summary(vty, isis); - } - return 0; + + return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); if (isis != NULL) @@ -1918,19 +1920,19 @@ static int show_isis_database_common(struct vty *vty, const char *argv, static int show_isis_database(struct vty *vty, const char *argv, int ui_level, const char *vrf_name, bool all_vrf) { - struct listnode *inode, *nnode; - struct isis *isis = NULL; + struct listnode *node; + struct isis *isis; if (vrf_name) { if (all_vrf) { - for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) show_isis_database_common(vty, argv, ui_level, isis); - } - return 0; + + return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) + if (isis) show_isis_database_common(vty, argv, ui_level, isis); } @@ -2352,16 +2354,15 @@ static int isis_config_write(struct vty *vty) { int write = 0; struct isis_area *area; - struct listnode *node, *node2, *inode, *nnode; - struct isis *isis = NULL; + struct listnode *node, *node2, *inode; + struct isis *isis; if (!im) { vty_out(vty, "IS-IS Routing Process not enabled\n"); return CMD_SUCCESS; } - for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) { - + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { /* ISIS - Area name */ vty_out(vty, "router " PROTO_NAME " %s\n", area->area_tag); diff --git a/isisd/isisd.h b/isisd/isisd.h index 41b69df2bf..2314cc262c 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -215,7 +215,7 @@ void isis_vrf_unlink(struct isis *isis, struct vrf *vrf); void isis_global_instance_create(void); struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id); struct isis *isis_lookup_by_vrfname(const char *vrfname); -struct isis *isis_lookup_by_sysid(uint8_t *sysid); +struct isis *isis_lookup_by_sysid(const uint8_t *sysid); void isis_init(void); struct isis *isis_new(vrf_id_t vrf_id); From 675269d48324ab42c63fc0ed79da0bbad06ecdb1 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Sat, 22 Aug 2020 23:24:06 -0300 Subject: [PATCH 6/9] isisd: introduce command to display IS-IS routes Introduce the "show isis route" command to display the routes associated to an SPF tree. Different from the "show ip route" command, "show isis route" displays the L1 and L2 routes separately (and not the best routes only). Signed-off-by: Renato Westphal --- doc/user/isisd.rst | 4 +- isisd/isis_spf.c | 178 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+), 2 deletions(-) diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 200d00821f..1155b49eb1 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -418,8 +418,8 @@ Showing ISIS information Show topology IS-IS paths to Intermediate Systems, globally, in area (level-1) or domain (level-2). -.. index:: show ip route isis -.. clicmd:: show ip route isis +.. index:: show isis route [level-1|level-2] +.. clicmd:: show isis route [level-1|level-2] Show the ISIS routing table, as determined by the most recent SPF calculation. diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index ec10bb77e6..01affb1597 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -29,6 +29,7 @@ #include "vty.h" #include "log.h" #include "command.h" +#include "termtable.h" #include "memory.h" #include "prefix.h" #include "if.h" @@ -1520,9 +1521,186 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, return CMD_SUCCESS; } +static void isis_print_routes(struct vty *vty, struct isis_spftree *spftree) +{ + struct ttable *tt; + struct route_node *rn; + const char *tree_id_text = NULL; + + if (!spftree) + return; + + switch (spftree->tree_id) { + case SPFTREE_IPV4: + tree_id_text = "IPv4"; + break; + case SPFTREE_IPV6: + tree_id_text = "IPv6"; + break; + case SPFTREE_DSTSRC: + tree_id_text = "IPv6 (dst-src routing)"; + break; + case SPFTREE_COUNT: + assert(!"isis_print_routes shouldn't be called with SPFTREE_COUNT as type"); + return; + } + + vty_out(vty, "IS-IS %s %s routing table:\n\n", + circuit_t2string(spftree->level), tree_id_text); + + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Prefix|Metric|Interface|Nexthop|Label(s)"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); + + for (rn = route_top(spftree->route_table); rn; rn = route_next(rn)) { + struct isis_route_info *rinfo; + struct isis_nexthop *nexthop; + struct listnode *node; + bool first = true; + char buf_prefix[BUFSIZ]; + + rinfo = rn->info; + if (!rinfo) + continue; + + (void)prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix)); + for (ALL_LIST_ELEMENTS_RO(rinfo->nexthops, node, nexthop)) { + struct interface *ifp; + char buf_iface[BUFSIZ]; + char buf_nhop[BUFSIZ]; + char buf_labels[BUFSIZ] = {}; + + inet_ntop(nexthop->family, &nexthop->ip, buf_nhop, + sizeof(buf_nhop)); + ifp = if_lookup_by_index(nexthop->ifindex, VRF_DEFAULT); + if (ifp) + strlcpy(buf_iface, ifp->name, + sizeof(buf_iface)); + else + snprintf(buf_iface, sizeof(buf_iface), + "ifindex %u", nexthop->ifindex); + + if (nexthop->sr.label != MPLS_INVALID_LABEL) + label2str(nexthop->sr.label, buf_labels, + sizeof(buf_labels)); + else + strlcpy(buf_labels, "-", sizeof(buf_labels)); + + if (first) { + ttable_add_row(tt, "%s|%u|%s|%s|%s", buf_prefix, + rinfo->cost, buf_iface, buf_nhop, + buf_labels); + first = false; + } else + ttable_add_row(tt, "||%s|%s|%s", buf_iface, + buf_nhop, buf_labels); + } + } + + /* Dump the generated table. */ + if (tt->nrows > 1) { + char *table; + + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + } + ttable_del(tt); +} + +static void show_isis_route_common(struct vty *vty, int levels, + struct isis *isis) +{ + struct listnode *node; + struct isis_area *area; + + if (!isis->area_list || isis->area_list->count == 0) + return; + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + vty_out(vty, "Area %s:\n", + area->area_tag ? area->area_tag : "null"); + + for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { + if ((level & levels) == 0) + continue; + + if (area->ip_circuits > 0) { + isis_print_routes( + vty, + area->spftree[SPFTREE_IPV4][level - 1]); + } + if (area->ipv6_circuits > 0) { + isis_print_routes( + vty, + area->spftree[SPFTREE_IPV6][level - 1]); + } + if (isis_area_ipv6_dstsrc_enabled(area)) { + isis_print_routes(vty, + area->spftree[SPFTREE_DSTSRC] + [level - 1]); + } + } + } +} + +DEFUN(show_isis_route, show_isis_route_cmd, + "show " PROTO_NAME + " [vrf ] route" +#ifndef FABRICD + " []" +#endif + , + SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR + "IS-IS routing table\n" +#ifndef FABRICD + "level-1 routes\n" + "level-2 routes\n" +#endif +) +{ + int levels; + struct isis *isis; + struct listnode *node; + const char *vrf_name = VRF_DEFAULT_NAME; + bool all_vrf = false; + int idx = 0; + + if (argv_find(argv, argc, "level-1", &idx)) + levels = ISIS_LEVEL1; + else if (argv_find(argv, argc, "level-2", &idx)) + levels = ISIS_LEVEL2; + else + levels = ISIS_LEVEL1 | ISIS_LEVEL2; + + if (!im) { + vty_out(vty, "IS-IS Routing Process not enabled\n"); + return CMD_SUCCESS; + } + ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf); + + if (vrf_name) { + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) + show_isis_route_common(vty, levels, isis); + return CMD_SUCCESS; + } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) + show_isis_route_common(vty, levels, isis); + } + + return CMD_SUCCESS; +} + void isis_spf_init(void) { install_element(VIEW_NODE, &show_isis_topology_cmd); + install_element(VIEW_NODE, &show_isis_route_cmd); /* Register hook(s). */ hook_register(isis_adj_state_change_hook, spf_adj_state_change); From 7b36d36e0ed2a233c3a908c9e821e3f45c68d4e8 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Sun, 23 Aug 2020 00:22:32 -0300 Subject: [PATCH 7/9] isisd: make the SPF code more modular The goal of modularizing the SPF code is to make it possible for isisd to run SPF in the behalf of other nodes in the network, which is going to be necessary later when implementing the R-LFA/TI-LFA solutions. On top of that, a modularized SPF opens the door for much needed unit testing. Summary of the changes: * Change the isis_spf_preload_tent() function to use the local LSP as an input (as per the ISO specification) instead of populating the TENT based on the list of local interfaces; * Introduce the "isis_spf_adj" structure to represent an SPF adjacency. SPF adjacencies are inferred from the LSPDB, different from normal adjacencies formed using IIH messages; * Introduce the F_SPFTREE_NO_ROUTES flag to control whether the SPT should create routes or not; * Introduce the F_SPFTREE_NO_ADJACENCIES flag to specify whether IS-IS adjacency information is available or not. When running SPF in the behalf of other nodes, or under the context of an unit test, no adjacency information will be present. * On isis_area_create(), move some code around so that the area's isis backpointer is set as early as possible. Signed-off-by: Renato Westphal --- isisd/fabricd.c | 4 +- isisd/isis_route.c | 8 +- isisd/isis_spf.c | 837 ++++++++++++++++++++++----------------- isisd/isis_spf.h | 20 +- isisd/isis_spf_private.h | 19 +- isisd/isisd.c | 42 +- 6 files changed, 542 insertions(+), 388 deletions(-) diff --git a/isisd/fabricd.c b/isisd/fabricd.c index ebaf14461e..2953ee681c 100644 --- a/isisd/fabricd.c +++ b/isisd/fabricd.c @@ -221,7 +221,9 @@ struct fabricd *fabricd_new(struct isis_area *area) rv->area = area; rv->initial_sync_state = FABRICD_SYNC_PENDING; - rv->spftree = isis_spftree_new(area); + rv->spftree = isis_spftree_new(area, &area->lspdb[IS_LEVEL_2 - 1], + area->isis->sysid, ISIS_LEVEL2, + SPFTREE_IPV4, F_SPFTREE_HOPCOUNT_METRIC); rv->neighbors = skiplist_new(0, neighbor_entry_list_cmp, neighbor_entry_del_void); rv->neighbors_neighbors = hash_create(neighbor_entry_hash_key, diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 7b761f5cda..c12f9fd339 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -46,6 +46,7 @@ #include "isis_pdu.h" #include "isis_lsp.h" #include "isis_spf.h" +#include "isis_spf_private.h" #include "isis_route.h" #include "isis_zebra.h" @@ -165,13 +166,16 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix, struct list *adjacencies) { struct isis_route_info *rinfo; - struct isis_adjacency *adj; + struct isis_vertex_adj *vadj; struct listnode *node; rinfo = XCALLOC(MTYPE_ISIS_ROUTE_INFO, sizeof(struct isis_route_info)); rinfo->nexthops = list_new(); - for (ALL_LIST_ELEMENTS_RO(adjacencies, node, adj)) { + for (ALL_LIST_ELEMENTS_RO(adjacencies, node, vadj)) { + struct isis_spf_adj *sadj = vadj->sadj; + struct isis_adjacency *adj = sadj->adj; + /* check for force resync this route */ if (CHECK_FLAG(adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 01affb1597..72f2beaafe 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -57,6 +57,13 @@ #include "isis_spf_private.h" DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_ADJ, "ISIS SPF Adjacency"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_VERTEX_ADJ, "ISIS SPF Vertex Adjacency"); + +static void spf_adj_list_parse_lsp(struct isis_spftree *spftree, + struct list *adj_list, struct isis_lsp *lsp, + const uint8_t *pseudo_nodeid, + uint32_t pseudo_metric); /* * supports the given af ? @@ -81,22 +88,29 @@ struct isis_spf_run { static void remove_excess_adjs(struct list *adjs) { struct listnode *node, *excess = NULL; - struct isis_adjacency *adj, *candidate = NULL; + struct isis_vertex_adj *vadj, *candidate = NULL; int comp; - for (ALL_LIST_ELEMENTS_RO(adjs, node, adj)) { + for (ALL_LIST_ELEMENTS_RO(adjs, node, vadj)) { + struct isis_adjacency *adj, *candidate_adj; + + adj = vadj->sadj->adj; + assert(adj); + if (excess == NULL) excess = node; candidate = listgetdata(excess); + candidate_adj = candidate->sadj->adj; - if (candidate->sys_type < adj->sys_type) { + if (candidate_adj->sys_type < adj->sys_type) { excess = node; continue; } - if (candidate->sys_type > adj->sys_type) + if (candidate_adj->sys_type > adj->sys_type) continue; - comp = memcmp(candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN); + comp = memcmp(candidate_adj->sysid, adj->sysid, + ISIS_SYS_ID_LEN); if (comp > 0) { excess = node; continue; @@ -104,15 +118,15 @@ static void remove_excess_adjs(struct list *adjs) if (comp < 0) continue; - if (candidate->circuit->idx > adj->circuit->idx) { + if (candidate_adj->circuit->idx > adj->circuit->idx) { excess = node; continue; } - if (candidate->circuit->idx < adj->circuit->idx) + if (candidate_adj->circuit->idx < adj->circuit->idx) continue; - comp = memcmp(candidate->snpa, adj->snpa, ETH_ALEN); + comp = memcmp(candidate_adj->snpa, adj->snpa, ETH_ALEN); if (comp > 0) { excess = node; continue; @@ -171,6 +185,13 @@ const char *vid2string(struct isis_vertex *vertex, char *buff, int size) return "UNKNOWN"; } +static void isis_vertex_adj_free(void *arg) +{ + struct isis_vertex_adj *vadj = arg; + + XFREE(MTYPE_ISIS_VERTEX_ADJ, vadj); +} + static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree, void *id, enum vertextype vtype) @@ -182,9 +203,10 @@ static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree, isis_vertex_id_init(vertex, id, vtype); vertex->Adj_N = list_new(); + vertex->Adj_N->del = isis_vertex_adj_free; vertex->parents = list_new(); - if (spftree->hopcount_metric) { + if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)) { vertex->firsthops = hash_create(isis_vertex_queue_hash_key, isis_vertex_queue_hash_cmp, NULL); @@ -193,21 +215,68 @@ static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree, return vertex; } +static struct isis_vertex_adj *isis_vertex_adj_add(struct isis_vertex *vertex, + struct isis_spf_adj *sadj) +{ + struct isis_vertex_adj *vadj; + + vadj = XCALLOC(MTYPE_ISIS_VERTEX_ADJ, sizeof(*vadj)); + vadj->sadj = sadj; + listnode_add(vertex->Adj_N, vadj); + + return vadj; +} + static void isis_vertex_adj_del(struct isis_vertex *vertex, struct isis_adjacency *adj) { + struct isis_vertex_adj *vadj; struct listnode *node, *nextnode; + if (!vertex) return; - for (node = listhead(vertex->Adj_N); node; node = nextnode) { - nextnode = listnextnode(node); - if (listgetdata(node) == adj) - list_delete_node(vertex->Adj_N, node); + + for (ALL_LIST_ELEMENTS(vertex->Adj_N, node, nextnode, vadj)) { + if (vadj->sadj->adj == adj) { + listnode_delete(vertex->Adj_N, vadj); + isis_vertex_adj_free(vadj); + } } return; } -struct isis_spftree *isis_spftree_new(struct isis_area *area) +bool isis_vertex_adj_exists(const struct isis_spftree *spftree, + const struct isis_vertex *vertex, + const struct isis_spf_adj *sadj) +{ + struct isis_vertex_adj *tmp; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(vertex->Adj_N, node, tmp)) { + if (CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)) { + if (memcmp(sadj->id, tmp->sadj->id, sizeof(sadj->id)) + == 0) + return true; + } else { + if (sadj->adj == tmp->sadj->adj) + return true; + } + } + + return false; +} + +static void isis_spf_adj_free(void *arg) +{ + struct isis_spf_adj *sadj = arg; + + XFREE(MTYPE_ISIS_SPF_ADJ, sadj); +} + +struct isis_spftree *isis_spftree_new(struct isis_area *area, + struct lspdb_head *lspdb, + const uint8_t *sysid, int level, + enum spf_tree_id tree_id, uint8_t flags) { struct isis_spftree *tree; @@ -217,15 +286,25 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area) isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false); tree->route_table = srcdest_table_init(); tree->area = area; + tree->lspdb = lspdb; + tree->sadj_list = list_new(); + tree->sadj_list->del = isis_spf_adj_free; tree->last_run_timestamp = 0; tree->last_run_monotime = 0; tree->last_run_duration = 0; tree->runcount = 0; + memcpy(tree->sysid, sysid, ISIS_SYS_ID_LEN); + tree->level = level; + tree->tree_id = tree_id; + tree->family = (tree->tree_id == SPFTREE_IPV4) ? AF_INET : AF_INET6; + tree->flags = flags; + return tree; } void isis_spftree_del(struct isis_spftree *spftree) { + list_delete(&spftree->sadj_list); isis_vertex_queue_free(&spftree->tents); isis_vertex_queue_free(&spftree->paths); route_table_finish(spftree->route_table); @@ -257,7 +336,9 @@ void spftree_area_init(struct isis_area *area) if (area->spftree[tree][level - 1]) continue; - area->spftree[tree][level - 1] = isis_spftree_new(area); + area->spftree[tree][level - 1] = isis_spftree_new( + area, &area->lspdb[level - 1], + area->isis->sysid, level, tree, 0); } } } @@ -305,7 +386,7 @@ static int spf_adj_state_change(struct isis_adjacency *adj) * Find the system LSP: returns the LSP in our LSP database * associated with the given system ID. */ -static struct isis_lsp *isis_root_system_lsp(struct isis_area *area, int level, +static struct isis_lsp *isis_root_system_lsp(struct lspdb_head *lspdb, uint8_t *sysid) { struct isis_lsp *lsp; @@ -314,7 +395,7 @@ static struct isis_lsp *isis_root_system_lsp(struct isis_area *area, int level, memcpy(lspid, sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID(lspid) = 0; LSP_FRAGMENT(lspid) = 0; - lsp = lsp_search(&area->lspdb[level - 1], lspid); + lsp = lsp_search(lspdb, lspid); if (lsp && lsp->hdr.rem_lifetime != 0) return lsp; return NULL; @@ -323,28 +404,21 @@ static struct isis_lsp *isis_root_system_lsp(struct isis_area *area, int level, /* * Add this IS to the root of SPT */ -static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree, - uint8_t *sysid) +static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree) { struct isis_vertex *vertex; - struct isis_lsp *lsp; #ifdef EXTREME_DEBUG char buff[VID2STR_BUFFER]; #endif /* EXTREME_DEBUG */ - lsp = isis_root_system_lsp(spftree->area, spftree->level, sysid); - if (lsp == NULL) - zlog_warn("ISIS-Spf: could not find own l%d LSP!", - spftree->level); - - vertex = isis_vertex_new(spftree, sysid, + vertex = isis_vertex_new(spftree, spftree->sysid, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS : VTYPE_NONPSEUDO_TE_IS); isis_vertex_queue_append(&spftree->paths, vertex); #ifdef EXTREME_DEBUG - zlog_debug("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS", + zlog_debug("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS", vtype2string(vertex->type), vid2string(vertex, buff, sizeof(buff)), vertex->depth, vertex->d_N); @@ -379,12 +453,11 @@ static void vertex_update_firsthops(struct isis_vertex *vertex, static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree, enum vertextype vtype, void *id, uint32_t cost, int depth, - struct isis_adjacency *adj, + struct isis_spf_adj *sadj, struct isis_vertex *parent) { struct isis_vertex *vertex; struct listnode *node; - struct isis_adjacency *parent_adj; char buff[VID2STR_BUFFER]; vertex = isis_find_vertex(&spftree->paths, id, vtype); @@ -412,14 +485,16 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree, listnode_add(vertex->parents, parent); } - if (spftree->hopcount_metric) + if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)) vertex_update_firsthops(vertex, parent); if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) { - for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, parent_adj)) - listnode_add(vertex->Adj_N, parent_adj); - } else if (adj) { - listnode_add(vertex->Adj_N, adj); + struct isis_vertex_adj *parent_vadj; + + for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, parent_vadj)) + isis_vertex_adj_add(vertex, parent_vadj->sadj); + } else if (sadj) { + isis_vertex_adj_add(vertex, sadj); } #ifdef EXTREME_DEBUG @@ -436,7 +511,7 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree, static void isis_spf_add_local(struct isis_spftree *spftree, enum vertextype vtype, void *id, - struct isis_adjacency *adj, uint32_t cost, + struct isis_spf_adj *sadj, uint32_t cost, struct isis_vertex *parent) { struct isis_vertex *vertex; @@ -446,10 +521,12 @@ static void isis_spf_add_local(struct isis_spftree *spftree, if (vertex) { /* C.2.5 c) */ if (vertex->d_N == cost) { - if (adj) - listnode_add(vertex->Adj_N, adj); + if (sadj) + isis_vertex_adj_add(vertex, sadj); /* d) */ - if (listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS) + if (!CHECK_FLAG(spftree->flags, + F_SPFTREE_NO_ADJACENCIES) + && listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS) remove_excess_adjs(vertex->Adj_N); if (parent && (listnode_lookup(vertex->parents, parent) == NULL)) @@ -465,7 +542,7 @@ static void isis_spf_add_local(struct isis_spftree *spftree, } } - isis_spf_add2tent(spftree, vtype, id, cost, 1, adj, parent); + isis_spf_add2tent(spftree, vtype, id, cost, 1, sadj, parent); return; } @@ -480,7 +557,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype, assert(spftree && parent); - if (spftree->hopcount_metric + if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC) && !VTYPE_IS(vtype)) return; @@ -530,16 +607,20 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype, #endif /* EXTREME_DEBUG */ if (vertex->d_N == dist) { struct listnode *node; - struct isis_adjacency *parent_adj; + struct isis_vertex_adj *parent_vadj; for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, - parent_adj)) - if (listnode_lookup(vertex->Adj_N, parent_adj) - == NULL) - listnode_add(vertex->Adj_N, parent_adj); - if (spftree->hopcount_metric) + parent_vadj)) + if (!isis_vertex_adj_exists(spftree, vertex, + parent_vadj->sadj)) + isis_vertex_adj_add(vertex, + parent_vadj->sadj); + if (CHECK_FLAG(spftree->flags, + F_SPFTREE_HOPCOUNT_METRIC)) vertex_update_firsthops(vertex, parent); /* 2) */ - if (listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS) + if (!CHECK_FLAG(spftree->flags, + F_SPFTREE_NO_ADJACENCIES) + && listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS) remove_excess_adjs(vertex->Adj_N); if (listnode_lookup(vertex->parents, parent) == NULL) listnode_add(vertex->parents, parent); @@ -622,7 +703,9 @@ lspfragloop: /* C.2.6 a) */ /* Two way connectivity */ - if (!memcmp(r->id, root_sysid, ISIS_SYS_ID_LEN)) + if (!LSP_PSEUDO_ID(r->id) + && !memcmp(r->id, root_sysid, + ISIS_SYS_ID_LEN)) continue; if (!pseudo_lsp && !memcmp(r->id, null_sysid, @@ -651,12 +734,19 @@ lspfragloop: te_neighs->head : NULL; er; er = er->next) { - if (!memcmp(er->id, root_sysid, ISIS_SYS_ID_LEN)) + /* C.2.6 a) */ + /* Two way connectivity */ + if (!LSP_PSEUDO_ID(er->id) + && !memcmp(er->id, root_sysid, ISIS_SYS_ID_LEN)) continue; if (!pseudo_lsp && !memcmp(er->id, null_sysid, ISIS_SYS_ID_LEN)) continue; - dist = cost + (spftree->hopcount_metric ? 1 : er->metric); + dist = cost + + (CHECK_FLAG(spftree->flags, + F_SPFTREE_HOPCOUNT_METRIC) + ? 1 + : er->metric); process_N(spftree, LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS : VTYPE_NONPSEUDO_TE_IS, @@ -770,236 +860,238 @@ lspfragloop: return ISIS_OK; } -static int isis_spf_preload_tent(struct isis_spftree *spftree, - uint8_t *root_sysid, - struct isis_vertex *parent) +static struct isis_adjacency *adj_find(struct list *adj_list, const uint8_t *id, + int level, uint16_t mtid, int family) { - struct isis_circuit *circuit; - struct listnode *cnode, *anode, *ipnode; struct isis_adjacency *adj; - struct isis_lsp *lsp; - struct list *adj_list; - struct list *adjdb; - struct prefix_ipv4 *ipv4; - struct prefix_pair ip_info; - int retval = ISIS_OK; - uint8_t lsp_id[ISIS_SYS_ID_LEN + 2]; - static uint8_t null_lsp_id[ISIS_SYS_ID_LEN + 2]; - struct prefix_ipv6 *ipv6; - struct isis_circuit_mt_setting *circuit_mt; + struct listnode *node; - for (ALL_LIST_ELEMENTS_RO(spftree->area->circuit_list, cnode, - circuit)) { - circuit_mt = circuit_lookup_mt_setting(circuit, spftree->mtid); - if (circuit_mt && !circuit_mt->enabled) + for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) { + if (!(adj->level & level)) continue; - if (circuit->state != C_STATE_UP) + if (memcmp(adj->sysid, id, ISIS_SYS_ID_LEN) != 0) continue; - if (!(circuit->is_type & spftree->level)) + if (adj->adj_state != ISIS_ADJ_UP) continue; - if (spftree->family == AF_INET && !circuit->ip_router) + if (!adj_has_mt(adj, mtid)) continue; - if (spftree->family == AF_INET6 && !circuit->ipv6_router) + if (mtid == ISIS_MT_IPV4_UNICAST + && !speaks(adj->nlpids.nlpids, adj->nlpids.count, family)) continue; - /* - * Add IP(v6) addresses of this circuit - */ - if (spftree->family == AF_INET && !spftree->hopcount_metric) { - memset(&ip_info, 0, sizeof(ip_info)); - ip_info.dest.family = AF_INET; - for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode, - ipv4)) { - ip_info.dest.u.prefix4 = ipv4->prefix; - ip_info.dest.prefixlen = ipv4->prefixlen; - apply_mask(&ip_info.dest); - isis_spf_add_local(spftree, - VTYPE_IPREACH_INTERNAL, - &ip_info, NULL, 0, parent); + return adj; + } + + return NULL; +} + +struct spf_preload_tent_ip_reach_args { + struct isis_spftree *spftree; + struct isis_vertex *parent; +}; + +static int isis_spf_preload_tent_ip_reach_cb(const struct prefix *prefix, + uint32_t metric, bool external, + struct isis_subtlvs *subtlvs, + void *arg) +{ + struct spf_preload_tent_ip_reach_args *args = arg; + struct isis_spftree *spftree = args->spftree; + struct isis_vertex *parent = args->parent; + struct prefix_pair ip_info; + enum vertextype vtype; + + if (external) + return LSP_ITER_CONTINUE; + + assert(spftree->family == prefix->family); + memset(&ip_info, 0, sizeof(ip_info)); + prefix_copy(&ip_info.dest, prefix); + apply_mask(&ip_info.dest); + + if (prefix->family == AF_INET) + vtype = VTYPE_IPREACH_INTERNAL; + else + vtype = VTYPE_IP6REACH_INTERNAL; + + isis_spf_add_local(spftree, vtype, &ip_info, NULL, 0, parent); + + return LSP_ITER_CONTINUE; +} + +static void isis_spf_preload_tent(struct isis_spftree *spftree, + uint8_t *root_sysid, + struct isis_lsp *root_lsp, + struct isis_vertex *parent) +{ + struct spf_preload_tent_ip_reach_args ip_reach_args; + struct isis_spf_adj *sadj; + struct listnode *node; + + if (!CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)) { + ip_reach_args.spftree = spftree; + ip_reach_args.parent = parent; + isis_lsp_iterate_ip_reach( + root_lsp, spftree->family, spftree->mtid, + isis_spf_preload_tent_ip_reach_cb, &ip_reach_args); + } + + /* Iterate over adjacencies. */ + for (ALL_LIST_ELEMENTS_RO(spftree->sadj_list, node, sadj)) { + uint32_t metric; + + metric = CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC) + ? 1 + : sadj->metric; + if (!LSP_PSEUDO_ID(sadj->id)) { + isis_spf_add_local(spftree, + CHECK_FLAG(sadj->flags, + F_ISIS_SPF_ADJ_OLDMETRIC) + ? VTYPE_NONPSEUDO_IS + : VTYPE_NONPSEUDO_TE_IS, + sadj->id, sadj, metric, parent); + } else if (sadj->lan.lsp_pseudo) { + isis_spf_process_lsp(spftree, sadj->lan.lsp_pseudo, + metric, 0, spftree->sysid, parent); + } + } +} + +static void spf_adj_list_parse_tlv(struct isis_spftree *spftree, + struct list *adj_list, const uint8_t *id, + const uint8_t *desig_is_id, + uint32_t pseudo_metric, uint32_t metric, + bool oldmetric, + struct isis_ext_subtlvs *subtlvs) +{ + struct isis_spf_adj *sadj; + uint8_t flags = 0; + + /* Skip self in the pseudonode. */ + if (desig_is_id && !memcmp(id, spftree->sysid, ISIS_SYS_ID_LEN)) + return; + + sadj = XCALLOC(MTYPE_ISIS_SPF_ADJ, sizeof(*sadj)); + memcpy(sadj->id, id, sizeof(sadj->id)); + if (desig_is_id) { + memcpy(sadj->lan.desig_is_id, desig_is_id, + sizeof(sadj->lan.desig_is_id)); + SET_FLAG(flags, F_ISIS_SPF_ADJ_BROADCAST); + sadj->metric = pseudo_metric; + } else + sadj->metric = metric; + if (oldmetric) + SET_FLAG(flags, F_ISIS_SPF_ADJ_OLDMETRIC); + sadj->subtlvs = subtlvs; + sadj->flags = flags; + + /* Set real adjacency. */ + if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES) + && !LSP_PSEUDO_ID(id)) { + struct isis_adjacency *adj; + + adj = adj_find(adj_list, id, spftree->level, spftree->mtid, + spftree->family); + if (!adj) { + XFREE(MTYPE_ISIS_SPF_ADJ, sadj); + return; + } + + listnode_delete(adj_list, adj); + sadj->adj = adj; + } + + /* Add adjacency to the list. */ + listnode_add(spftree->sadj_list, sadj); + + /* Parse pseudonode LSP too. */ + if (LSP_PSEUDO_ID(id)) { + uint8_t lspid[ISIS_SYS_ID_LEN + 2]; + struct isis_lsp *lsp_pseudo; + + memcpy(lspid, id, ISIS_SYS_ID_LEN + 1); + LSP_FRAGMENT(lspid) = 0; + lsp_pseudo = lsp_search(spftree->lspdb, lspid); + if (lsp_pseudo == NULL || lsp_pseudo->hdr.rem_lifetime == 0) { + zlog_warn( + "ISIS-Spf: No LSP found from root to L%d DR %s", + spftree->level, rawlspid_print(id)); + return; + } + + sadj->lan.lsp_pseudo = lsp_pseudo; + spf_adj_list_parse_lsp(spftree, adj_list, lsp_pseudo, id, + metric); + } +} + +static void spf_adj_list_parse_lsp(struct isis_spftree *spftree, + struct list *adj_list, struct isis_lsp *lsp, + const uint8_t *pseudo_nodeid, + uint32_t pseudo_metric) +{ + bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id); + struct isis_lsp *frag; + struct listnode *node; + struct isis_item *head; + struct isis_item_list *te_neighs; + + if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0) + return; + + /* Parse main LSP. */ + if (lsp->tlvs) { + if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) { + head = lsp->tlvs->oldstyle_reach.head; + for (struct isis_oldstyle_reach *reach = + (struct isis_oldstyle_reach *)head; + reach; reach = reach->next) { + spf_adj_list_parse_tlv( + spftree, adj_list, reach->id, + pseudo_nodeid, pseudo_metric, + reach->metric, true, NULL); } } - if (spftree->family == AF_INET6 && !spftree->hopcount_metric) { - memset(&ip_info, 0, sizeof(ip_info)); - ip_info.dest.family = AF_INET6; - for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, - ipnode, ipv6)) { - ip_info.dest.u.prefix6 = ipv6->prefix; - ip_info.dest.prefixlen = ipv6->prefixlen; - apply_mask(&ip_info.dest); - isis_spf_add_local(spftree, - VTYPE_IP6REACH_INTERNAL, - &ip_info, NULL, 0, parent); + + if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) + te_neighs = &lsp->tlvs->extended_reach; + else + te_neighs = isis_get_mt_items(&lsp->tlvs->mt_reach, + spftree->mtid); + if (te_neighs) { + head = te_neighs->head; + for (struct isis_extended_reach *reach = + (struct isis_extended_reach *)head; + reach; reach = reach->next) { + spf_adj_list_parse_tlv( + spftree, adj_list, reach->id, + pseudo_nodeid, pseudo_metric, + reach->metric, false, reach->subtlvs); } } - if (circuit->circ_type == CIRCUIT_T_BROADCAST) { - /* - * Add the adjacencies - */ - adj_list = list_new(); - adjdb = circuit->u.bc.adjdb[spftree->level - 1]; - isis_adj_build_up_list(adjdb, adj_list); - if (listcount(adj_list) == 0) { - list_delete(&adj_list); - if (IS_DEBUG_SPF_EVENTS) - zlog_debug( - "ISIS-Spf: no L%d adjacencies on circuit %s", - spftree->level, - circuit->interface->name); - continue; - } - for (ALL_LIST_ELEMENTS_RO(adj_list, anode, adj)) { - if (!adj_has_mt(adj, spftree->mtid)) - continue; - if (spftree->mtid == ISIS_MT_IPV4_UNICAST - && !speaks(adj->nlpids.nlpids, - adj->nlpids.count, - spftree->family)) - continue; - switch (adj->sys_type) { - case ISIS_SYSTYPE_ES: - memcpy(lsp_id, adj->sysid, - ISIS_SYS_ID_LEN); - LSP_PSEUDO_ID(lsp_id) = 0; - isis_spf_add_local( - spftree, VTYPE_ES, lsp_id, adj, - spftree->hopcount_metric ? 1 : - circuit->te_metric - [spftree->level - 1], - parent); - break; - case ISIS_SYSTYPE_IS: - case ISIS_SYSTYPE_L1_IS: - case ISIS_SYSTYPE_L2_IS: - memcpy(lsp_id, adj->sysid, - ISIS_SYS_ID_LEN); - LSP_PSEUDO_ID(lsp_id) = 0; - LSP_FRAGMENT(lsp_id) = 0; - isis_spf_add_local( - spftree, - spftree->area->oldmetric - ? VTYPE_NONPSEUDO_IS - : VTYPE_NONPSEUDO_TE_IS, - lsp_id, adj, - spftree->hopcount_metric ? 1 : - circuit->te_metric - [spftree->level - 1], - parent); - lsp = lsp_search( - &spftree->area->lspdb[spftree->level- 1], - lsp_id); - if (lsp == NULL - || lsp->hdr.rem_lifetime == 0) - zlog_warn( - "ISIS-Spf: No LSP %s found for IS adjacency L%d on %s (ID %u)", - rawlspid_print(lsp_id), - spftree->level, - circuit->interface->name, - circuit->circuit_id); - break; - case ISIS_SYSTYPE_UNKNOWN: - default: - zlog_warn( - "isis_spf_preload_tent unknown adj type"); - } - } - list_delete(&adj_list); - /* - * Add the pseudonode - */ - if (spftree->level == 1) - memcpy(lsp_id, circuit->u.bc.l1_desig_is, - ISIS_SYS_ID_LEN + 1); - else - memcpy(lsp_id, circuit->u.bc.l2_desig_is, - ISIS_SYS_ID_LEN + 1); - /* can happen during DR reboot */ - if (memcmp(lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1) - == 0) { - if (IS_DEBUG_SPF_EVENTS) - zlog_debug( - "ISIS-Spf: No L%d DR on %s (ID %d)", - spftree->level, - circuit->interface->name, - circuit->circuit_id); - continue; - } - adj = isis_adj_lookup(lsp_id, adjdb); - /* if no adj, we are the dis or error */ - if (!adj && !circuit->u.bc.is_dr[spftree->level - 1]) { - zlog_warn( - "ISIS-Spf: No adjacency found from root to L%d DR %s on %s (ID %d)", - spftree->level, rawlspid_print(lsp_id), - circuit->interface->name, - circuit->circuit_id); - continue; - } - lsp = lsp_search( - &spftree->area->lspdb[spftree->level - 1], - lsp_id); - if (lsp == NULL || lsp->hdr.rem_lifetime == 0) { - zlog_warn( - "ISIS-Spf: No lsp (%p) found from root to L%d DR %s on %s (ID %d)", - (void *)lsp, spftree->level, - rawlspid_print(lsp_id), - circuit->interface->name, - circuit->circuit_id); - continue; - } - isis_spf_process_lsp(spftree, lsp, - spftree->hopcount_metric ? - 1 : circuit->te_metric[spftree->level - 1], - 0, root_sysid, parent); - } else if (circuit->circ_type == CIRCUIT_T_P2P) { - adj = circuit->u.p2p.neighbor; - if (!adj || adj->adj_state != ISIS_ADJ_UP) - continue; - if (!adj_has_mt(adj, spftree->mtid)) - continue; - switch (adj->sys_type) { - case ISIS_SYSTYPE_ES: - memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN); - LSP_PSEUDO_ID(lsp_id) = 0; - isis_spf_add_local( - spftree, VTYPE_ES, lsp_id, adj, - spftree->hopcount_metric ? 1 : - circuit->te_metric[spftree->level - 1], - parent); - break; - case ISIS_SYSTYPE_IS: - case ISIS_SYSTYPE_L1_IS: - case ISIS_SYSTYPE_L2_IS: - memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN); - LSP_PSEUDO_ID(lsp_id) = 0; - LSP_FRAGMENT(lsp_id) = 0; - if (spftree->mtid != ISIS_MT_IPV4_UNICAST - || speaks(adj->nlpids.nlpids, - adj->nlpids.count, - spftree->family)) - isis_spf_add_local( - spftree, - spftree->area->oldmetric - ? VTYPE_NONPSEUDO_IS - : VTYPE_NONPSEUDO_TE_IS, - lsp_id, adj, - spftree->hopcount_metric ? 1 : - circuit->te_metric - [spftree->level - 1], - parent); - break; - case ISIS_SYSTYPE_UNKNOWN: - default: - zlog_warn( - "isis_spf_preload_tent unknown adj type"); - break; - } - } else if (circuit->circ_type == CIRCUIT_T_LOOPBACK) { - continue; - } else { - zlog_warn("isis_spf_preload_tent unsupported media"); - retval = ISIS_WARNING; - } } - return retval; + /* Parse LSP fragments. */ + for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) { + if (!frag->tlvs) + continue; + + spf_adj_list_parse_lsp(spftree, adj_list, frag, pseudo_nodeid, + pseudo_metric); + } +} + +static void isis_spf_build_adj_list(struct isis_spftree *spftree, + struct isis_lsp *lsp) +{ + struct list *adj_list = NULL; + + if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)) + adj_list = list_dup(spftree->area->adjacency_list); + + spf_adj_list_parse_lsp(spftree, adj_list, lsp, NULL, 0); + + if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)) + list_delete(&adj_list); } /* @@ -1022,10 +1114,10 @@ static void add_to_paths(struct isis_spftree *spftree, vertex->d_N); #endif /* EXTREME_DEBUG */ - if (VTYPE_IP(vertex->type)) { + if (VTYPE_IP(vertex->type) + && !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ROUTES)) { if (listcount(vertex->Adj_N) > 0) - isis_route_create(&vertex->N.ip.dest, - &vertex->N.ip.src, + isis_route_create(&vertex->N.ip.dest, &vertex->N.ip.src, vertex->d_N, vertex->depth, vertex->Adj_N, spftree->area, spftree->route_table); @@ -1039,18 +1131,14 @@ static void add_to_paths(struct isis_spftree *spftree, return; } -static void init_spt(struct isis_spftree *spftree, int mtid, int level, - int family, enum spf_tree_id tree_id, - bool hopcount_metric) +static void init_spt(struct isis_spftree *spftree, int mtid) { + /* Clear data from previous run. */ + list_delete_all_node(spftree->sadj_list); isis_vertex_queue_clear(&spftree->tents); isis_vertex_queue_clear(&spftree->paths); spftree->mtid = mtid; - spftree->level = level; - spftree->family = family; - spftree->tree_id = tree_id; - spftree->hopcount_metric = hopcount_metric; } static void isis_spf_loop(struct isis_spftree *spftree, @@ -1091,19 +1179,30 @@ struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area, struct isis_spftree *spftree) { if (!spftree) - spftree = isis_spftree_new(area); - - init_spt(spftree, ISIS_MT_IPV4_UNICAST, ISIS_LEVEL2, - AF_INET, SPFTREE_IPV4, true); + spftree = isis_spftree_new(area, &area->lspdb[IS_LEVEL_2 - 1], + sysid, ISIS_LEVEL2, SPFTREE_IPV4, + F_SPFTREE_HOPCOUNT_METRIC); + init_spt(spftree, ISIS_MT_IPV4_UNICAST); if (!memcmp(sysid, area->isis->sysid, ISIS_SYS_ID_LEN)) { - /* If we are running locally, initialize with information from adjacencies */ - struct isis_vertex *root = isis_spf_add_root(spftree, sysid); - isis_spf_preload_tent(spftree, sysid, root); + struct isis_lsp *root_lsp; + struct isis_vertex *root_vertex; + + root_lsp = isis_root_system_lsp(spftree->lspdb, spftree->sysid); + if (root_lsp) { + /* + * If we are running locally, initialize with + * information from adjacencies + */ + root_vertex = isis_spf_add_root(spftree); + + isis_spf_preload_tent(spftree, sysid, root_lsp, + root_vertex); + } } else { - isis_vertex_queue_insert(&spftree->tents, isis_vertex_new( - spftree, sysid, - VTYPE_NONPSEUDO_TE_IS)); + isis_vertex_queue_insert( + &spftree->tents, + isis_vertex_new(spftree, sysid, VTYPE_NONPSEUDO_TE_IS)); } isis_spf_loop(spftree, sysid); @@ -1111,54 +1210,56 @@ struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area, return spftree; } -static int isis_run_spf(struct isis_area *area, int level, - enum spf_tree_id tree_id, uint8_t *sysid) +void isis_run_spf(struct isis_spftree *spftree) { - int retval = ISIS_OK; + struct isis_lsp *root_lsp; struct isis_vertex *root_vertex; - struct isis_spftree *spftree = area->spftree[tree_id][level - 1]; struct timeval time_start; struct timeval time_end; + struct isis_mt_router_info *mt_router_info; uint16_t mtid = 0; /* Get time that can't roll backwards. */ monotime(&time_start); - int family = -1; - switch (tree_id) { + root_lsp = isis_root_system_lsp(spftree->lspdb, spftree->sysid); + if (root_lsp == NULL) { + zlog_err("ISIS-Spf: could not find own l%d LSP!", + spftree->level); + return; + } + + /* Get Multi-Topology ID. */ + switch (spftree->tree_id) { case SPFTREE_IPV4: - family = AF_INET; mtid = ISIS_MT_IPV4_UNICAST; break; case SPFTREE_IPV6: - family = AF_INET6; - mtid = isis_area_ipv6_topology(area); + mt_router_info = isis_tlvs_lookup_mt_router_info( + root_lsp->tlvs, ISIS_MT_IPV6_UNICAST); + if (mt_router_info) + mtid = ISIS_MT_IPV6_UNICAST; + else + mtid = ISIS_MT_IPV4_UNICAST; break; case SPFTREE_DSTSRC: - family = AF_INET6; mtid = ISIS_MT_IPV6_DSTSRC; break; case SPFTREE_COUNT: - assert(!"isis_run_spf should never be called with SPFTREE_COUNT as argument!"); - return ISIS_WARNING; + zlog_err( + "isis_run_spf should never be called with SPFTREE_COUNT as argument!"); + exit(1); } - assert(spftree); - assert(sysid); - /* * C.2.5 Step 0 */ - init_spt(spftree, mtid, level, family, tree_id, false); + init_spt(spftree, mtid); /* a) */ - root_vertex = isis_spf_add_root(spftree, sysid); + root_vertex = isis_spf_add_root(spftree); /* b) */ - retval = isis_spf_preload_tent(spftree, sysid, root_vertex); - if (retval != ISIS_OK) { - zlog_warn("ISIS-Spf: failed to load TENT SPF-root:%s", - print_sys_hostname(sysid)); - goto out; - } + isis_spf_build_adj_list(spftree, root_lsp); + isis_spf_preload_tent(spftree, spftree->sysid, root_lsp, root_vertex); /* * C.2.7 Step 2 @@ -1166,19 +1267,16 @@ static int isis_run_spf(struct isis_area *area, int level, if (!isis_vertex_queue_count(&spftree->tents) && (IS_DEBUG_SPF_EVENTS)) { zlog_warn("ISIS-Spf: TENT is empty SPF-root:%s", - print_sys_hostname(sysid)); + print_sys_hostname(spftree->sysid)); } - isis_spf_loop(spftree, sysid); -out: + isis_spf_loop(spftree, spftree->sysid); spftree->runcount++; spftree->last_run_timestamp = time(NULL); spftree->last_run_monotime = monotime(&time_end); spftree->last_run_duration = ((time_end.tv_sec - time_start.tv_sec) * 1000000) + (time_end.tv_usec - time_start.tv_usec); - - return retval; } void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees) @@ -1202,8 +1300,8 @@ static int isis_run_spf_cb(struct thread *thread) { struct isis_spf_run *run = THREAD_ARG(thread); struct isis_area *area = run->area; + struct isis_spftree *spftree; int level = run->level; - int retval = ISIS_OK; XFREE(MTYPE_ISIS_SPF_RUN, run); area->spf_timer[level - 1] = NULL; @@ -1221,15 +1319,21 @@ static int isis_run_spf_cb(struct thread *thread) zlog_debug("ISIS-Spf (%s) L%d SPF needed, periodic SPF", area->area_tag, level); - if (area->ip_circuits) - retval = isis_run_spf(area, level, SPFTREE_IPV4, - area->isis->sysid); - if (area->ipv6_circuits) - retval = isis_run_spf(area, level, SPFTREE_IPV6, - area->isis->sysid); - if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area)) - retval = isis_run_spf(area, level, SPFTREE_DSTSRC, - area->isis->sysid); + if (area->ip_circuits) { + spftree = area->spftree[SPFTREE_IPV4][level - 1]; + memcpy(spftree->sysid, area->isis->sysid, ISIS_SYS_ID_LEN); + isis_run_spf(spftree); + } + if (area->ipv6_circuits) { + spftree = area->spftree[SPFTREE_IPV6][level - 1]; + memcpy(spftree->sysid, area->isis->sysid, ISIS_SYS_ID_LEN); + isis_run_spf(spftree); + } + if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area)) { + spftree = area->spftree[SPFTREE_DSTSRC][level - 1]; + memcpy(spftree->sysid, area->isis->sysid, ISIS_SYS_ID_LEN); + isis_run_spf(spftree); + } isis_area_verify_routes(area); @@ -1243,7 +1347,7 @@ static int isis_run_spf_cb(struct thread *thread) fabricd_run_spf(area); - return retval; + return 0; } static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level) @@ -1342,7 +1446,7 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, int rows = 0; struct listnode *anode = listhead(vertex->Adj_N); struct listnode *pnode = listhead(vertex->parents); - struct isis_adjacency *adj; + struct isis_vertex_adj *vadj; struct isis_vertex *pvertex; vty_out(vty, "%-20s %-12s %-6u ", @@ -1353,10 +1457,10 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, vertex->parents ? listcount(vertex->parents) : 0); i++) { if (anode) { - adj = listgetdata(anode); + vadj = listgetdata(anode); anode = anode->next; } else { - adj = NULL; + vadj = NULL; } if (pnode) { @@ -1371,14 +1475,18 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, vty_out(vty, "%-20s %-12s %-6s ", "", "", ""); } - if (adj) { + if (vadj) { + struct isis_spf_adj *sadj = vadj->sadj; + vty_out(vty, "%-20s %-9s ", - print_sys_hostname(adj->sysid), - adj->circuit->interface->name); + print_sys_hostname(sadj->id), + sadj->adj ? sadj->adj->circuit + ->interface->name + : "-"); } if (pvertex) { - if (!adj) + if (!vadj) vty_out(vty, "%-20s %-9s ", "", ""); vty_out(vty, "%s(%d)", @@ -1392,13 +1500,14 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, } } -static void isis_print_spftree(struct vty *vty, int level, - struct isis_area *area, - enum spf_tree_id tree_id) +static void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) { const char *tree_id_text = NULL; - switch (tree_id) { + if (!spftree || !isis_vertex_queue_count(&spftree->paths)) + return; + + switch (spftree->tree_id) { case SPFTREE_IPV4: tree_id_text = "that speak IP"; break; @@ -1413,16 +1522,9 @@ static void isis_print_spftree(struct vty *vty, int level, return; } - if (!area->spftree[tree_id][level - 1] - || !isis_vertex_queue_count( - &area->spftree[tree_id][level - 1]->paths)) - return; - - vty_out(vty, "IS-IS paths to level-%d routers %s\n", - level, tree_id_text); - isis_print_paths(vty, &area->spftree[tree_id][level - 1]->paths, - area->isis->sysid); - + 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"); } @@ -1444,16 +1546,19 @@ static void show_isis_topology_common(struct vty *vty, int levels, continue; if (area->ip_circuits > 0) { - isis_print_spftree(vty, level, area, - SPFTREE_IPV4); + isis_print_spftree( + vty, + area->spftree[SPFTREE_IPV4][level - 1]); } if (area->ipv6_circuits > 0) { - isis_print_spftree(vty, level, area, - SPFTREE_IPV6); + isis_print_spftree( + vty, + area->spftree[SPFTREE_IPV6][level - 1]); } if (isis_area_ipv6_dstsrc_enabled(area)) { - isis_print_spftree(vty, level, area, - SPFTREE_DSTSRC); + isis_print_spftree(vty, + area->spftree[SPFTREE_DSTSRC] + [level - 1]); } } @@ -1574,15 +1679,25 @@ static void isis_print_routes(struct vty *vty, struct isis_spftree *spftree) char buf_nhop[BUFSIZ]; char buf_labels[BUFSIZ] = {}; - inet_ntop(nexthop->family, &nexthop->ip, buf_nhop, - sizeof(buf_nhop)); - ifp = if_lookup_by_index(nexthop->ifindex, VRF_DEFAULT); - if (ifp) - strlcpy(buf_iface, ifp->name, - sizeof(buf_iface)); - else - snprintf(buf_iface, sizeof(buf_iface), - "ifindex %u", nexthop->ifindex); + if (!CHECK_FLAG(spftree->flags, + F_SPFTREE_NO_ADJACENCIES)) { + inet_ntop(nexthop->family, &nexthop->ip, + buf_nhop, sizeof(buf_nhop)); + ifp = if_lookup_by_index(nexthop->ifindex, + VRF_DEFAULT); + if (ifp) + strlcpy(buf_iface, ifp->name, + sizeof(buf_iface)); + else + snprintf(buf_iface, sizeof(buf_iface), + "ifindex %u", + nexthop->ifindex); + } else { + strlcpy(buf_nhop, + print_sys_hostname(nexthop->sysid), + sizeof(buf_nhop)); + strlcpy(buf_iface, "-", sizeof(buf_iface)); + } if (nexthop->sr.label != MPLS_INVALID_LABEL) label2str(nexthop->sr.label, buf_labels, diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index a85e596bb0..e3c0fbc8b8 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -26,7 +26,24 @@ struct isis_spftree; -struct isis_spftree *isis_spftree_new(struct isis_area *area); +struct isis_spf_adj { + uint8_t id[ISIS_SYS_ID_LEN + 1]; + struct isis_adjacency *adj; + uint32_t metric; + struct isis_ext_subtlvs *subtlvs; + struct { + uint8_t desig_is_id[ISIS_SYS_ID_LEN + 1]; + struct isis_lsp *lsp_pseudo; + } lan; + uint8_t flags; +#define F_ISIS_SPF_ADJ_BROADCAST 0x01 +#define F_ISIS_SPF_ADJ_OLDMETRIC 0x02 +}; + +struct isis_spftree *isis_spftree_new(struct isis_area *area, + struct lspdb_head *lspdb, + const uint8_t *sysid, int level, + enum spf_tree_id tree_id, uint8_t flags); void isis_spf_invalidate_routes(struct isis_spftree *tree); void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees); @@ -40,6 +57,7 @@ int _isis_spf_schedule(struct isis_area *area, int level, const char *func, const char *file, int line); void isis_spf_init(void); void isis_spf_print(struct isis_spftree *spftree, struct vty *vty); +void isis_run_spf(struct isis_spftree *spftree); struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area, uint8_t *sysid, struct isis_spftree *spftree); diff --git a/isisd/isis_spf_private.h b/isisd/isis_spf_private.h index 05aae14b94..6bdf900d1c 100644 --- a/isisd/isis_spf_private.h +++ b/isisd/isis_spf_private.h @@ -50,6 +50,11 @@ struct prefix_pair { struct prefix_ipv6 src; }; +struct isis_vertex_adj { + struct isis_spf_adj *sadj; + struct mpls_label_stack *label_stack; +}; + /* * Triple */ @@ -180,6 +185,10 @@ static void isis_vertex_del(struct isis_vertex *vertex) XFREE(MTYPE_ISIS_VERTEX, vertex); } +bool isis_vertex_adj_exists(const struct isis_spftree *spftree, + const struct isis_vertex *vertex, + const struct isis_spf_adj *sadj); + __attribute__((__unused__)) static void isis_vertex_queue_clear(struct isis_vertex_queue *queue) { @@ -297,18 +306,25 @@ struct isis_spftree { struct isis_vertex_queue paths; /* the SPT */ struct isis_vertex_queue tents; /* TENT */ struct route_table *route_table; + struct lspdb_head *lspdb; /* link-state db */ + struct list *sadj_list; struct isis_area *area; /* back pointer to area */ unsigned int runcount; /* number of runs since uptime */ time_t last_run_timestamp; /* last run timestamp as wall time for display */ time_t last_run_monotime; /* last run as monotime for scheduling */ time_t last_run_duration; /* last run duration in msec */ + uint8_t sysid[ISIS_SYS_ID_LEN]; uint16_t mtid; int family; int level; enum spf_tree_id tree_id; bool hopcount_metric; + uint8_t flags; }; +#define F_SPFTREE_HOPCOUNT_METRIC 0x01 +#define F_SPFTREE_NO_ROUTES 0x02 +#define F_SPFTREE_NO_ADJACENCIES 0x04 __attribute__((__unused__)) static void isis_vertex_id_init(struct isis_vertex *vertex, const void *id, @@ -347,8 +363,7 @@ static struct isis_lsp *lsp_for_vertex(struct isis_spftree *spftree, memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT(lsp_id) = 0; - struct lspdb_head *lspdb = &spftree->area->lspdb[spftree->level - 1]; - struct isis_lsp *lsp = lsp_search(lspdb, lsp_id); + struct isis_lsp *lsp = lsp_search(spftree->lspdb, lsp_id); if (lsp && lsp->hdr.rem_lifetime != 0) return lsp; diff --git a/isisd/isisd.c b/isisd/isisd.c index 453b440e23..1ce3829548 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -218,6 +218,27 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) struct vrf *vrf = NULL; area = XCALLOC(MTYPE_ISIS_AREA, sizeof(struct isis_area)); + if (vrf_name) { + vrf = vrf_lookup_by_name(vrf_name); + if (vrf) { + isis = isis_lookup_by_vrfid(vrf->vrf_id); + if (isis == NULL) { + isis = isis_new(vrf->vrf_id); + isis_add(isis); + } + } else + return NULL; + } else { + isis = isis_lookup_by_vrfid(VRF_DEFAULT); + if (isis == NULL) { + isis = isis_new(VRF_DEFAULT); + isis_add(isis); + } + } + + listnode_add(isis->area_list, area); + area->isis = isis; + /* * Fabricd runs only as level-2. * For IS-IS, the default is level-1-2 @@ -297,27 +318,6 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) area->area_tag = strdup(area_tag); - if (vrf_name) { - vrf = vrf_lookup_by_name(vrf_name); - if (vrf) { - isis = isis_lookup_by_vrfid(vrf->vrf_id); - if (isis == NULL) { - isis = isis_new(vrf->vrf_id); - isis_add(isis); - } - } else - return NULL; - } else { - isis = isis_lookup_by_vrfid(VRF_DEFAULT); - if (isis == NULL) { - isis = isis_new(VRF_DEFAULT); - isis_add(isis); - } - } - - listnode_add(isis->area_list, area); - area->isis = isis; - if (fabricd) area->fabricd = fabricd_new(area); From 52a7c25e63a3d62072aa4fb1ed415fe478ce2ef9 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Mon, 24 Aug 2020 14:46:36 -0300 Subject: [PATCH 8/9] tests, isisd: add IS-IS SPF unit tests Now that the IS-IS SPF code is more modular, write some unit tests for it. This commit includes a new test program called "test_isis_spf" which can load any test topology (there are 13 different ones available) and run SPF on any desired node. In the future this same test program and topologies will also be used to test reverse SPF and TI-LFA. The "test_common.c" file contains helper functions used to parse the topology descriptions from "test_topologies.c" into LSP databases that can be used as an input to the SPF code. This commit also introduces the F_ISIS_UNIT_TEST flag which is used to prevent the IS-IS code from scheduling any event when running under the context of an unit test. Signed-off-by: Renato Westphal --- isisd/isis_dynhn.c | 16 +- isisd/isis_dynhn.h | 1 + isisd/isis_misc.c | 2 +- isisd/isis_route.c | 20 + isisd/isis_spf.c | 7 +- isisd/isis_spf.h | 2 + isisd/isisd.c | 93 +- isisd/isisd.h | 4 + tests/.gitignore | 1 + tests/isisd/test_common.c | 331 +++ tests/isisd/test_common.h | 82 + tests/isisd/test_fuzz_isis_tlv.c | 11 +- tests/isisd/test_isis_lspdb.c | 10 +- tests/isisd/test_isis_spf.c | 291 +++ tests/isisd/test_isis_spf.in | 13 + tests/isisd/test_isis_spf.py | 4 + tests/isisd/test_isis_spf.refout | 619 +++++ tests/isisd/test_isis_vertex_queue.c | 9 +- tests/isisd/test_topologies.c | 3307 ++++++++++++++++++++++++++ tests/subdir.am | 16 +- 20 files changed, 4760 insertions(+), 79 deletions(-) create mode 100644 tests/isisd/test_common.c create mode 100644 tests/isisd/test_common.h create mode 100644 tests/isisd/test_isis_spf.c create mode 100644 tests/isisd/test_isis_spf.in create mode 100644 tests/isisd/test_isis_spf.py create mode 100644 tests/isisd/test_isis_spf.refout create mode 100644 tests/isisd/test_topologies.c diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c index e34c59be11..244f388c26 100644 --- a/isisd/isis_dynhn.c +++ b/isisd/isis_dynhn.c @@ -49,11 +49,23 @@ void dyn_cache_init(struct isis *isis) { if (dyn_cache == NULL) dyn_cache = list_new(); - thread_add_timer(master, dyn_cache_cleanup, isis, 120, - &isis->t_dync_clean); + if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) + thread_add_timer(master, dyn_cache_cleanup, isis, 120, + &isis->t_dync_clean); return; } +void dyn_cache_cleanup_all(void) +{ + struct listnode *node, *nnode; + struct isis_dynhn *dyn; + + for (ALL_LIST_ELEMENTS(dyn_cache, node, nnode, dyn)) { + list_delete_node(dyn_cache, node); + XFREE(MTYPE_ISIS_DYNHN, dyn); + } +} + static int dyn_cache_cleanup(struct thread *thread) { struct listnode *node, *nnode; diff --git a/isisd/isis_dynhn.h b/isisd/isis_dynhn.h index 2cfc43fc17..973fde8307 100644 --- a/isisd/isis_dynhn.h +++ b/isisd/isis_dynhn.h @@ -31,6 +31,7 @@ struct isis_dynhn { }; void dyn_cache_init(struct isis *isis); +void dyn_cache_cleanup_all(void); void isis_dynhn_insert(const uint8_t *id, const char *hostname, int level); void isis_dynhn_remove(const uint8_t *id); struct isis_dynhn *dynhn_find_by_id(const uint8_t *id); diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index 27425f24a4..6e9cbaf98e 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -447,7 +447,7 @@ const char *print_sys_hostname(const uint8_t *sysid) /* For our system ID return our host name */ isis = isis_lookup_by_sysid(sysid); - if (isis) + if (isis && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) return cmd_hostname_get(); dyn = dynhn_find_by_id(sysid); diff --git a/isisd/isis_route.c b/isisd/isis_route.c index c12f9fd339..c83a7c04bb 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -159,6 +159,17 @@ static void adjinfo2nexthop(int family, struct list *nexthops, } } +static void isis_route_add_dummy_nexthops(struct isis_route_info *rinfo, + const uint8_t *sysid) +{ + struct isis_nexthop *nh; + + nh = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop)); + memcpy(nh->sysid, sysid, sizeof(nh->sysid)); + isis_sr_nexthop_reset(&nh->sr); + listnode_add(rinfo->nexthops, nh); +} + static struct isis_route_info *isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p, uint32_t cost, @@ -176,6 +187,15 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix, struct isis_spf_adj *sadj = vadj->sadj; struct isis_adjacency *adj = sadj->adj; + /* + * Create dummy nexthops when running SPF on a testing + * environment. + */ + if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) { + isis_route_add_dummy_nexthops(rinfo, sadj->id); + continue; + } + /* check for force resync this route */ if (CHECK_FLAG(adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 72f2beaafe..19a373791e 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1367,6 +1367,9 @@ int _isis_spf_schedule(struct isis_area *area, int level, time_t now = monotime(NULL); int diff = now - spftree->last_run_monotime; + if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) + return 0; + assert(diff >= 0); assert(area->is_type & level); @@ -1500,7 +1503,7 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, } } -static void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) +void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) { const char *tree_id_text = NULL; @@ -1626,7 +1629,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, return CMD_SUCCESS; } -static void isis_print_routes(struct vty *vty, struct isis_spftree *spftree) +void isis_print_routes(struct vty *vty, struct isis_spftree *spftree) { struct ttable *tt; struct route_node *rn; diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index e3c0fbc8b8..61a107bea2 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -55,6 +55,8 @@ void spftree_area_del(struct isis_area *area); __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_routes(struct vty *vty, struct isis_spftree *spftree); void isis_spf_init(void); void isis_spf_print(struct isis_spftree *spftree, struct vty *vty); void isis_run_spf(struct isis_spftree *spftree); diff --git a/isisd/isisd.c b/isisd/isisd.c index 1ce3829548..aca98bf651 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -262,7 +262,8 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) area->circuit_list = list_new(); area->adjacency_list = list_new(); area->area_addrs = list_new(); - thread_add_timer(master, lsp_tick, area, 1, &area->t_tick); + if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) + thread_add_timer(master, lsp_tick, area, 1, &area->t_tick); flags_initialize(&area->flags); isis_sr_area_init(area); @@ -418,7 +419,8 @@ void isis_area_destroy(struct isis_area *area) spf_backoff_free(area->spf_delay_ietf[0]); spf_backoff_free(area->spf_delay_ietf[1]); - isis_redist_area_finish(area); + if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) + isis_redist_area_finish(area); for (ALL_LIST_ELEMENTS(area->area_addrs, node, nnode, addr)) { list_delete_node(area->area_addrs, node); @@ -1846,60 +1848,61 @@ struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv, return lsp; } -static int show_isis_database_common(struct vty *vty, const char *argv, - int ui_level, struct isis *isis) +void show_isis_database_lspdb(struct vty *vty, struct isis_area *area, + int level, struct lspdb_head *lspdb, + const char *argv, int ui_level) +{ + struct isis_lsp *lsp; + int lsp_count; + + if (lspdb_count(lspdb) > 0) { + lsp = lsp_for_arg(lspdb, argv, area->isis); + + if (lsp != NULL || argv == NULL) { + vty_out(vty, "IS-IS Level-%d link-state database:\n", + level + 1); + + /* print the title in all cases */ + vty_out(vty, + "LSP ID PduLen SeqNumber Chksum Holdtime ATT/P/OL\n"); + } + + if (lsp) { + if (ui_level == ISIS_UI_LEVEL_DETAIL) + lsp_print_detail(lsp, vty, area->dynhostname, + area->isis); + else + lsp_print(lsp, vty, area->dynhostname, + area->isis); + } else if (argv == NULL) { + lsp_count = + lsp_print_all(vty, lspdb, ui_level, + area->dynhostname, area->isis); + + vty_out(vty, " %u LSPs\n\n", lsp_count); + } + } +} + +static void show_isis_database_common(struct vty *vty, const char *argv, + int ui_level, struct isis *isis) { struct listnode *node; struct isis_area *area; - struct isis_lsp *lsp; - int level, lsp_count; + int level; if (isis->area_list->count == 0) - return CMD_SUCCESS; + return; for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { vty_out(vty, "Area %s:\n", area->area_tag ? area->area_tag : "null"); - for (level = 0; level < ISIS_LEVELS; level++) { - if (lspdb_count(&area->lspdb[level]) > 0) { - lsp = NULL; - lsp = lsp_for_arg(&area->lspdb[level], argv, - isis); - - if (lsp != NULL || argv == NULL) { - vty_out(vty, - "IS-IS Level-%d link-state database:\n", - level + 1); - - /* print the title in all cases */ - vty_out(vty, - "LSP ID PduLen SeqNumber Chksum Holdtime ATT/P/OL\n"); - } - - if (lsp) { - if (ui_level == ISIS_UI_LEVEL_DETAIL) - lsp_print_detail( - lsp, vty, - area->dynhostname, - isis); - else - lsp_print(lsp, vty, - area->dynhostname, - isis); - } else if (argv == NULL) { - lsp_count = lsp_print_all( - vty, &area->lspdb[level], - ui_level, area->dynhostname, - isis); - - vty_out(vty, " %u LSPs\n\n", - lsp_count); - } - } - } + for (level = 0; level < ISIS_LEVELS; level++) + show_isis_database_lspdb(vty, area, level, + &area->lspdb[level], argv, + ui_level); } - return CMD_SUCCESS; } /* * This function supports following display options: diff --git a/isisd/isisd.h b/isisd/isisd.h index 2314cc262c..0c0a1eed10 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -76,6 +76,7 @@ struct isis_master { /* Various OSPF global configuration. */ uint8_t options; }; +#define F_ISIS_UNIT_TEST 0x01 struct isis { vrf_id_t vrf_id; @@ -247,6 +248,9 @@ int isis_area_passwd_cleartext_set(struct isis_area *area, int level, const char *passwd, uint8_t snp_auth); int isis_area_passwd_hmac_md5_set(struct isis_area *area, int level, const char *passwd, uint8_t snp_auth); +void show_isis_database_lspdb(struct vty *vty, struct isis_area *area, + int level, struct lspdb_head *lspdb, + const char *argv, int ui_level); /* YANG paths */ #define ISIS_INSTANCE "/frr-isisd:isis/instance" diff --git a/tests/.gitignore b/tests/.gitignore index 5414cb8cc9..5e809a81e6 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -13,6 +13,7 @@ /isisd/test_fuzz_isis_tlv /isisd/test_fuzz_isis_tlv_tests.h /isisd/test_isis_lspdb +/isisd/test_isis_spf /isisd/test_isis_vertex_queue /lib/cli/test_cli /lib/cli/test_cli_clippy.c diff --git a/tests/isisd/test_common.c b/tests/isisd/test_common.c new file mode 100644 index 0000000000..536847a1da --- /dev/null +++ b/tests/isisd/test_common.c @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2020 NetDEF, Inc. + * Renato Westphal + * + * This program 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 2 of the License, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "isisd/isisd.h" +#include "isisd/isis_dynhn.h" +#include "isisd/isis_mt.h" + +#include "test_common.h" + +struct thread_master *master; +struct zebra_privs_t isisd_privs; + +int isis_sock_init(struct isis_circuit *circuit) +{ + return 0; +} + +const struct isis_test_node * +test_topology_find_node(const struct isis_topology *topology, + const char *hostname, uint8_t pseudonode_id) +{ + for (size_t i = 0; topology->nodes[i].hostname[0]; i++) + if (strmatch(hostname, topology->nodes[i].hostname) + && pseudonode_id == topology->nodes[i].pseudonode_id) + return &topology->nodes[i]; + + return NULL; +} + +const struct isis_topology * +test_topology_find(struct isis_topology *test_topologies, uint16_t number) +{ + for (size_t i = 0; test_topologies[i].number; i++) + if (test_topologies[i].number == number) + return &test_topologies[i]; + + return NULL; +} + +static const struct isis_test_node * +test_find_adjacency(const struct isis_test_node *tnode, const char *hostname) +{ + for (size_t i = 0; tnode->adjacencies[i].hostname[0]; i++) { + const struct isis_test_adj *tadj; + + tadj = &tnode->adjacencies[i]; + if (strmatch(hostname, tadj->hostname)) + return tnode; + } + + return NULL; +} + +static struct isis_lsp *lsp_add(struct lspdb_head *lspdb, + struct isis_area *area, int level, + const uint8_t *sysid, uint8_t pseudonode_id) +{ + struct isis_lsp *lsp; + uint8_t lspid[ISIS_SYS_ID_LEN + 2]; + + memcpy(lspid, sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID(lspid) = pseudonode_id; + LSP_FRAGMENT(lspid) = 0; + + lsp = lsp_new(area, lspid, 6000, 1, 0, 0, NULL, level); + lsp->tlvs = isis_alloc_tlvs(); + lspdb_add(lspdb, lsp); + + return lsp; +} + +static void lsp_add_ip_reach(struct isis_lsp *lsp, + const struct isis_test_node *tnode, + const char *prefix_str, uint32_t *next_sid_index) +{ + struct prefix prefix; + struct sr_prefix_cfg pcfg = {}; + struct sr_prefix_cfg *pcfg_p = NULL; + + if (str2prefix(prefix_str, &prefix) != 1) { + zlog_debug("%s: invalid network: %s", __func__, prefix_str); + return; + } + + if (CHECK_FLAG(tnode->flags, F_ISIS_TEST_NODE_SR)) { + pcfg_p = &pcfg; + + pcfg.sid = *next_sid_index; + *next_sid_index = *next_sid_index + 1; + pcfg.sid_type = SR_SID_VALUE_TYPE_INDEX; + pcfg.last_hop_behavior = SR_LAST_HOP_BEHAVIOR_PHP; + } + + if (prefix.family == AF_INET) + isis_tlvs_add_extended_ip_reach(lsp->tlvs, + (struct prefix_ipv4 *)&prefix, + 10, false, pcfg_p); + else + isis_tlvs_add_ipv6_reach(lsp->tlvs, ISIS_MT_IPV6_UNICAST, + (struct prefix_ipv6 *)&prefix, 10, + false, pcfg_p); +} + +static void lsp_add_reach(struct isis_lsp *lsp, + const struct isis_test_node *tnode, + const uint8_t *ne_id, uint8_t pseudonode_id, + uint32_t metric, int family, mpls_label_t *next_label) +{ + uint8_t nodeid[ISIS_SYS_ID_LEN + 1]; + uint16_t mtid; + struct isis_ext_subtlvs *ext = NULL; + + memcpy(nodeid, ne_id, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID(nodeid) = pseudonode_id; + + if (CHECK_FLAG(tnode->flags, F_ISIS_TEST_NODE_SR)) { + struct isis_adj_sid *adj_sid; + + adj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*adj_sid)); + adj_sid->family = family; + SET_FLAG(adj_sid->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG); + SET_FLAG(adj_sid->flags, EXT_SUBTLV_LINK_ADJ_SID_LFLG); + if (family == AF_INET6) + SET_FLAG(adj_sid->flags, EXT_SUBTLV_LINK_ADJ_SID_FFLG); + adj_sid->weight = 0; + adj_sid->sid = *next_label; + *next_label = *next_label + 1; + + ext = isis_alloc_ext_subtlvs(); + isis_tlvs_add_adj_sid(ext, adj_sid); + } + + mtid = (family == AF_INET) ? ISIS_MT_IPV4_UNICAST + : ISIS_MT_IPV6_UNICAST; + + isis_tlvs_add_extended_reach(lsp->tlvs, mtid, nodeid, metric, ext); +} + +static void lsp_add_router_capability(struct isis_lsp *lsp, + const struct isis_test_node *tnode) +{ + struct isis_router_cap cap = {}; + + if (!tnode->router_id) + return; + + if (inet_pton(AF_INET, tnode->router_id, &cap.router_id) != 1) { + zlog_debug("%s: invalid router-id: %s", __func__, + tnode->router_id); + return; + } + + if (CHECK_FLAG(tnode->flags, F_ISIS_TEST_NODE_SR)) { + cap.srgb.flags = + ISIS_SUBTLV_SRGB_FLAG_I | ISIS_SUBTLV_SRGB_FLAG_V; + cap.srgb.lower_bound = tnode->srgb.lower_bound + ? tnode->srgb.lower_bound + : SRGB_DFTL_LOWER_BOUND; + cap.srgb.range_size = tnode->srgb.range_size + ? tnode->srgb.range_size + : SRGB_DFTL_RANGE_SIZE; + cap.algo[0] = SR_ALGORITHM_SPF; + cap.algo[1] = SR_ALGORITHM_UNSET; + } + + isis_tlvs_set_router_capability(lsp->tlvs, &cap); +} + +static void lsp_add_mt_router_info(struct isis_lsp *lsp, + const struct isis_test_node *tnode) +{ + if (tnode->protocols.ipv4) + isis_tlvs_add_mt_router_info(lsp->tlvs, ISIS_MT_IPV4_UNICAST, 0, + false); + if (tnode->protocols.ipv6) + isis_tlvs_add_mt_router_info(lsp->tlvs, ISIS_MT_IPV6_UNICAST, 0, + false); +} + +static void lsp_add_protocols_supported(struct isis_lsp *lsp, + const struct isis_test_node *tnode) +{ + struct nlpids nlpids = {}; + + if (!tnode->protocols.ipv4 && !tnode->protocols.ipv6) + return; + + if (tnode->protocols.ipv4) { + nlpids.nlpids[nlpids.count] = NLPID_IP; + nlpids.count++; + } + if (tnode->protocols.ipv6) { + nlpids.nlpids[nlpids.count] = NLPID_IPV6; + nlpids.count++; + } + isis_tlvs_set_protocols_supported(lsp->tlvs, &nlpids); +} + +static int topology_load_node_level(const struct isis_topology *topology, + const struct isis_test_node *tnode, + size_t tnode_index, struct isis_area *area, + struct lspdb_head *lspdb, int level) +{ + struct isis_lsp *lsp; + uint32_t next_sid_index = (tnode_index + 1) * 10; + mpls_label_t next_label = 16; + + lsp = lsp_add(lspdb, area, level, tnode->sysid, tnode->pseudonode_id); + lsp_add_mt_router_info(lsp, tnode); + lsp_add_protocols_supported(lsp, tnode); + lsp_add_router_capability(lsp, tnode); + + /* Add IP Reachability Information. */ + for (size_t i = 0; tnode->networks[i]; i++) { + if (i > MAX_NETWORKS) { + zlog_debug( + "%s: node has too many networks (maximum is %u)", + __func__, MAX_NETWORKS); + return -1; + } + lsp_add_ip_reach(lsp, tnode, tnode->networks[i], + &next_sid_index); + } + + /* Add IS Reachability Information. */ + for (size_t i = 0; tnode->adjacencies[i].hostname[0]; i++) { + const struct isis_test_adj *tadj; + const struct isis_test_node *tadj_node; + + if (i > MAX_ADJACENCIES) { + zlog_debug( + "%s: node has too many adjacencies (maximum is %u)", + __func__, MAX_ADJACENCIES); + return -1; + } + + tadj = &tnode->adjacencies[i]; + tadj_node = test_topology_find_node(topology, tadj->hostname, + tadj->pseudonode_id); + if (!tadj_node) { + zlog_debug( + "%s: node \"%s\" has an adjacency with non-existing node \"%s\"", + __func__, tnode->hostname, tadj->hostname); + return -1; + } + if (!test_find_adjacency(tadj_node, tnode->hostname)) { + zlog_debug( + "%s: node \"%s\" has an one-way adjacency with node \"%s\"", + __func__, tnode->hostname, tadj->hostname); + return -1; + } + + if (tnode->pseudonode_id || tadj_node->pseudonode_id + || (tnode->protocols.ipv4 && tadj_node->protocols.ipv4)) + lsp_add_reach(lsp, tnode, tadj_node->sysid, + tadj_node->pseudonode_id, tadj->metric, + AF_INET, &next_label); + if (tadj_node->pseudonode_id + || (tnode->protocols.ipv6 && tadj_node->protocols.ipv6)) + lsp_add_reach(lsp, tnode, tadj_node->sysid, + tadj_node->pseudonode_id, tadj->metric, + AF_INET6, &next_label); + } + + return 0; +} + +static int topology_load_node(const struct isis_topology *topology, + const struct isis_test_node *tnode, + size_t tnode_index, struct isis_area *area, + struct lspdb_head lspdb[]) +{ + int ret; + + isis_dynhn_insert(tnode->sysid, tnode->hostname, tnode->level); + + for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) { + if ((tnode->level & level) == 0) + continue; + + ret = topology_load_node_level(topology, tnode, tnode_index, + area, &lspdb[level - 1], level); + if (ret != 0) + return ret; + } + + return 0; +} + +int test_topology_load(const struct isis_topology *topology, + struct isis_area *area, struct lspdb_head lspdb[]) +{ + for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) + lsp_db_init(&lspdb[level - 1]); + + for (size_t i = 0; topology->nodes[i].hostname[0]; i++) { + const struct isis_test_node *tnode = &topology->nodes[i]; + int ret; + + if (i > MAX_NODES) { + zlog_debug( + "%s: topology has too many nodes (maximum is %u)", + __func__, MAX_NODES); + return -1; + } + + ret = topology_load_node(topology, tnode, i, area, lspdb); + if (ret != 0) + return ret; + } + + return 0; +} diff --git a/tests/isisd/test_common.h b/tests/isisd/test_common.h new file mode 100644 index 0000000000..6fd0d3813e --- /dev/null +++ b/tests/isisd/test_common.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2020 NetDEF, Inc. + * Renato Westphal + * + * This program 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 2 of the License, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _COMMON_ISIS_H +#define _COMMON_ISIS_H + +#include "isisd/isisd.h" +#include "isisd/isis_spf.h" +#include "isisd/isis_spf_private.h" + +#define MAX_HOSTNAME 16 +#define MAX_NETWORKS 8 +#define MAX_ADJACENCIES 8 +#define MAX_NODES 12 + +#define SRGB_DFTL_LOWER_BOUND 16000 +#define SRGB_DFTL_RANGE_SIZE 8000 + +struct isis_test_adj { + char hostname[MAX_HOSTNAME]; + uint8_t pseudonode_id; + uint32_t metric; +}; + +struct isis_test_node { + char hostname[MAX_HOSTNAME]; + uint8_t sysid[ISIS_SYS_ID_LEN]; + uint8_t pseudonode_id; + int level; + struct { + bool ipv4; + bool ipv6; + } protocols; + const char *router_id; + struct { + uint32_t lower_bound; + uint32_t range_size; + } srgb; + const char *networks[MAX_NETWORKS + 1]; + struct isis_test_adj adjacencies[MAX_ADJACENCIES + 1]; + uint8_t flags; +}; +#define F_ISIS_TEST_NODE_SR 0x01 + +struct isis_topology { + uint16_t number; + struct isis_test_node nodes[MAX_NODES + 1]; +}; + +/* Prototypes. */ +extern int isis_sock_init(struct isis_circuit *circuit); +extern const struct isis_test_node * +test_topology_find_node(const struct isis_topology *topology, + const char *hostname, uint8_t pseudonode_id); +extern const struct isis_topology * +test_topology_find(struct isis_topology *test_topologies, uint16_t number); +extern int test_topology_load(const struct isis_topology *topology, + struct isis_area *area, + struct lspdb_head lspdb[]); + +/* Global variables. */ +extern struct thread_master *master; +extern struct zebra_privs_t isisd_privs; +extern struct isis_topology test_topologies[]; + +#endif /* _COMMON_ISIS_H */ diff --git a/tests/isisd/test_fuzz_isis_tlv.c b/tests/isisd/test_fuzz_isis_tlv.c index 917ea66f13..97aade6578 100644 --- a/tests/isisd/test_fuzz_isis_tlv.c +++ b/tests/isisd/test_fuzz_isis_tlv.c @@ -14,17 +14,10 @@ #include "isisd/isis_circuit.h" #include "isisd/isis_tlvs.h" +#include "test_common.h" + #define TEST_STREAM_SIZE 1500 -struct thread_master *master; -int isis_sock_init(struct isis_circuit *circuit); -int isis_sock_init(struct isis_circuit *circuit) -{ - return 0; -} - -struct zebra_privs_t isisd_privs; - static bool atexit_registered; static void show_meminfo_at_exit(void) diff --git a/tests/isisd/test_isis_lspdb.c b/tests/isisd/test_isis_lspdb.c index 6a571eaa84..244922ea4e 100644 --- a/tests/isisd/test_isis_lspdb.c +++ b/tests/isisd/test_isis_lspdb.c @@ -2,15 +2,7 @@ #include "isisd/isis_lsp.c" -struct thread_master *master; - -int isis_sock_init(struct isis_circuit *circuit); -int isis_sock_init(struct isis_circuit *circuit) -{ - return 0; -} - -struct zebra_privs_t isisd_privs; +#include "test_common.h" static void test_lsp_build_list_nonzero_ht(void) { diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c new file mode 100644 index 0000000000..4e1d7b050f --- /dev/null +++ b/tests/isisd/test_isis_spf.c @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2020 NetDEF, Inc. + * Renato Westphal + * + * This program 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 2 of the License, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include "getopt.h" +#include "thread.h" +#include "vty.h" +#include "command.h" +#include "log.h" +#include "vrf.h" +#include "yang.h" + +#include "isisd/isisd.h" +#include "isisd/isis_dynhn.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_spf.h" +#include "isisd/isis_spf_private.h" + +#include "test_common.h" + +enum test_type { + TEST_SPF = 1, +}; + +#define F_DISPLAY_LSPDB 0x01 +#define F_IPV4_ONLY 0x02 +#define F_IPV6_ONLY 0x04 +#define F_LEVEL1_ONLY 0x08 +#define F_LEVEL2_ONLY 0x10 + +static struct isis *isis; + +static void test_run_spf(struct vty *vty, const struct isis_topology *topology, + const struct isis_test_node *root, + struct isis_area *area, struct lspdb_head *lspdb, + int level, int tree) +{ + struct isis_spftree *spftree; + + /* Run SPF. */ + spftree = isis_spftree_new(area, lspdb, root->sysid, level, tree, + F_SPFTREE_NO_ADJACENCIES); + isis_run_spf(spftree); + + /* Print the SPT and the corresponding routing table. */ + isis_print_spftree(vty, spftree); + isis_print_routes(vty, spftree); + + /* Cleanup SPF tree. */ + isis_spftree_del(spftree); +} + +static int test_run(struct vty *vty, const struct isis_topology *topology, + const struct isis_test_node *root, enum test_type test_type, + uint8_t flags) +{ + struct isis_area *area; + + /* Init topology. */ + memcpy(isis->sysid, root->sysid, sizeof(isis->sysid)); + area = isis_area_create("1", NULL); + area->is_type = IS_LEVEL_1_AND_2; + area->srdb.enabled = true; + if (test_topology_load(topology, area, area->lspdb) != 0) { + vty_out(vty, "%% Failed to load topology\n"); + return CMD_WARNING; + } + + for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) { + if (level == IS_LEVEL_1 && CHECK_FLAG(flags, F_LEVEL2_ONLY)) + continue; + if (level == IS_LEVEL_2 && CHECK_FLAG(flags, F_LEVEL1_ONLY)) + continue; + if ((root->level & level) == 0) + continue; + + /* Print the LDPDB. */ + if (CHECK_FLAG(flags, F_DISPLAY_LSPDB)) + show_isis_database_lspdb(vty, area, level - 1, + &area->lspdb[level - 1], NULL, + ISIS_UI_LEVEL_DETAIL); + + for (int tree = SPFTREE_IPV4; tree <= SPFTREE_IPV6; tree++) { + if (tree == SPFTREE_IPV4 + && CHECK_FLAG(flags, F_IPV6_ONLY)) + continue; + if (tree == SPFTREE_IPV6 + && CHECK_FLAG(flags, F_IPV4_ONLY)) + continue; + + switch (test_type) { + case TEST_SPF: + test_run_spf(vty, topology, root, area, + &area->lspdb[level - 1], level, + tree); + break; + } + } + } + + /* Cleanup IS-IS area. */ + isis_area_destroy(area); + + /* Cleanup hostnames. */ + dyn_cache_cleanup_all(); + + return CMD_SUCCESS; +} + +DEFUN(test_isis, test_isis_cmd, + "test isis topology (1-13) root HOSTNAME spf\ + [display-lspdb] [] []", + "Test command\n" + "IS-IS routing protocol\n" + "Test topology\n" + "Test topology number\n" + "SPF root\n" + "SPF root hostname\n" + "Normal Shortest Path First\n" + "Display the LSPDB\n" + "Do IPv4 processing only\n" + "Do IPv6 processing only\n" + "Skip L2 LSPs\n" + "Skip L1 LSPs\n") +{ + uint16_t topology_number; + const struct isis_topology *topology; + const struct isis_test_node *root; + uint8_t flags = 0; + int idx = 0; + + /* Load topology. */ + argv_find(argv, argc, "topology", &idx); + topology_number = atoi(argv[idx + 1]->arg); + topology = test_topology_find(test_topologies, topology_number); + if (!topology) { + vty_out(vty, "%% Topology \"%s\" not found\n", + argv[idx + 1]->arg); + return CMD_WARNING; + } + + /* Find root node. */ + argv_find(argv, argc, "root", &idx); + root = test_topology_find_node(topology, argv[idx + 1]->arg, 0); + if (!root) { + vty_out(vty, "%% Node \"%s\" not found\n", argv[idx + 1]->arg); + return CMD_WARNING; + } + + /* Parse control flags. */ + if (argv_find(argv, argc, "display-lspdb", &idx)) + SET_FLAG(flags, F_DISPLAY_LSPDB); + if (argv_find(argv, argc, "ipv4-only", &idx)) + SET_FLAG(flags, F_IPV4_ONLY); + else if (argv_find(argv, argc, "ipv6-only", &idx)) + SET_FLAG(flags, F_IPV6_ONLY); + if (argv_find(argv, argc, "level-1-only", &idx)) + SET_FLAG(flags, F_LEVEL1_ONLY); + else if (argv_find(argv, argc, "level-2-only", &idx)) + SET_FLAG(flags, F_LEVEL2_ONLY); + + return test_run(vty, topology, root, TEST_SPF, flags); +} + +static void vty_do_exit(int isexit) +{ + printf("\nend.\n"); + + isis_finish(isis); + cmd_terminate(); + vty_terminate(); + yang_terminate(); + thread_master_free(master); + + log_memstats(stderr, "test-isis-spf"); + if (!isexit) + exit(0); +} + +struct option longopts[] = {{"help", no_argument, NULL, 'h'}, + {"debug", no_argument, NULL, 'd'}, + {0}}; + +/* Help information display. */ +static void usage(char *progname, int status) +{ + if (status != 0) + fprintf(stderr, "Try `%s --help' for more information.\n", + progname); + else { + printf("Usage : %s [OPTION...]\n\ +isisd SPF test program.\n\n\ +-u, --debug Enable debugging\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", + progname, FRR_BUG_ADDRESS); + } + exit(status); +} + +int main(int argc, char **argv) +{ + char *p; + char *progname; + struct thread thread; + bool debug = false; + + /* Set umask before anything for security */ + umask(0027); + + /* get program name */ + progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]); + + while (1) { + int opt; + + opt = getopt_long(argc, argv, "hd", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) { + case 0: + break; + case 'd': + debug = true; + break; + case 'h': + usage(progname, 0); + break; + default: + usage(progname, 1); + break; + } + } + + /* master init. */ + master = thread_master_create(NULL); + isis_master_init(master); + + /* Library inits. */ + cmd_init(1); + cmd_hostname_set("test"); + vty_init(master, false); + yang_init(true); + if (debug) + zlog_aux_init("NONE: ", LOG_DEBUG); + else + zlog_aux_init("NONE: ", ZLOG_DISABLED); + + /* IS-IS inits. */ + yang_module_load("frr-isisd"); + isis = isis_new(VRF_DEFAULT); + listnode_add(im->isis, isis); + SET_FLAG(im->options, F_ISIS_UNIT_TEST); + debug_spf_events |= DEBUG_SPF_EVENTS; + debug_events |= DEBUG_EVENTS; + debug_rte_events |= DEBUG_RTE_EVENTS; + + /* Install test command. */ + install_element(VIEW_NODE, &test_isis_cmd); + + /* Read input from .in file. */ + vty_stdio(vty_do_exit); + + /* Fetch next active thread. */ + while (thread_fetch(master, &thread)) + thread_call(&thread); + + /* Not reached. */ + exit(0); +} diff --git a/tests/isisd/test_isis_spf.in b/tests/isisd/test_isis_spf.in new file mode 100644 index 0000000000..28d3c59e1e --- /dev/null +++ b/tests/isisd/test_isis_spf.in @@ -0,0 +1,13 @@ +test isis topology 1 root rt1 spf +test isis topology 2 root rt1 spf +test isis topology 3 root rt1 spf ipv4-only +test isis topology 4 root rt1 spf ipv4-only +test isis topology 5 root rt1 spf ipv4-only +test isis topology 6 root rt1 spf ipv4-only +test isis topology 7 root rt1 spf ipv4-only +test isis topology 8 root rt1 spf ipv4-only +test isis topology 9 root rt1 spf +test isis topology 10 root rt1 spf +test isis topology 11 root rt1 spf +test isis topology 12 root rt1 spf ipv4-only +test isis topology 13 root rt1 spf ipv4-only diff --git a/tests/isisd/test_isis_spf.py b/tests/isisd/test_isis_spf.py new file mode 100644 index 0000000000..21e7ef6269 --- /dev/null +++ b/tests/isisd/test_isis_spf.py @@ -0,0 +1,4 @@ +import frrtest + +class TestIsisSPF(frrtest.TestRefOut): + program = './test_isis_spf' diff --git a/tests/isisd/test_isis_spf.refout b/tests/isisd/test_isis_spf.refout new file mode 100644 index 0000000000..ee82926197 --- /dev/null +++ b/tests/isisd/test_isis_spf.refout @@ -0,0 +1,619 @@ +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 - + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 20 - rt3 - + 10.0.255.4/32 30 - rt2 - + 10.0.255.5/32 30 - rt3 - + 10.0.255.6/32 40 - rt2 - + - 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) +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 - + +IS-IS L1 IPv6 routing table: + + Prefix Metric Interface Nexthop Label(s) + ------------------------------------------------------- + 2001:db8::2/128 20 - rt2 - + 2001:db8::3/128 20 - rt3 - + 2001:db8::4/128 30 - rt2 - + 2001:db8::5/128 30 - rt3 - + 2001:db8::6/128 40 - rt2 - + - rt3 - + +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) + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.2/32 25 - rt2 - + 10.0.255.3/32 40 - rt3 - + 10.0.255.4/32 20 - rt4 - + 10.0.255.5/32 20 - rt5 - + 10.0.255.6/32 30 - rt4 - + - rt5 - + +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) + +IS-IS L1 IPv6 routing table: + + Prefix Metric Interface Nexthop Label(s) + ------------------------------------------------------- + 2001:db8::2/128 25 - rt2 - + 2001:db8::3/128 40 - rt3 - + 2001:db8::4/128 20 - rt4 - + 2001:db8::5/128 20 - rt5 - + 2001:db8::6/128 30 - rt4 - + - rt5 - + +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) + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 20 - rt3 - + 10.0.255.4/32 30 - rt2 - + 10.0.255.5/32 40 - rt2 - + 10.0.255.6/32 40 - rt2 - + +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) + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 20 - rt3 - + 10.0.255.4/32 30 - rt2 - + 10.0.255.5/32 30 - rt3 - + 10.0.255.6/32 40 - rt2 - + 10.0.255.7/32 40 - rt3 - + 10.0.255.8/32 50 - rt2 - + +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 - + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 20 - rt3 - + 10.0.255.4/32 30 - rt2 - + 10.0.255.5/32 30 - rt3 - + 10.0.255.6/32 40 - rt2 - + 10.0.255.7/32 40 - rt3 - + 10.0.255.8/32 50 - rt2 - + - rt3 - + +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 - + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 20 - rt3 - + 10.0.255.4/32 30 - rt2 - + - rt3 - + 10.0.255.5/32 50 - rt2 - + - rt3 - + 10.0.255.6/32 40 - rt2 - + - rt3 - + 10.0.255.7/32 60 - rt2 - + - rt3 - + 10.0.255.8/32 50 - rt2 - + - rt3 - + +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) + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ------------------------------------------------------ + 10.0.255.2/32 40 - rt4 - + 10.0.255.3/32 50 - rt4 - + 10.0.255.4/32 20 - rt4 - + 10.0.255.5/32 30 - rt4 - + 10.0.255.6/32 40 - rt4 - + 10.0.255.7/32 30 - rt4 - + 10.0.255.8/32 40 - rt4 - + 10.0.255.9/32 50 - rt4 - + 10.0.255.10/32 50 - rt4 - + 10.0.255.11/32 50 - rt4 - + 10.0.255.12/32 60 - rt4 - + +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) + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ------------------------------------------------------ + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 30 - rt2 - + 10.0.255.4/32 20 - rt4 - + 10.0.255.5/32 30 - rt2 - + 10.0.255.6/32 40 - rt2 - + 10.0.255.7/32 30 - rt4 - + 10.0.255.8/32 40 - rt2 - + 10.0.255.9/32 50 - rt2 - + 10.0.255.10/32 40 - rt4 - + 10.0.255.11/32 50 - rt2 - + 10.0.255.12/32 60 - rt2 - + +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) + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 20 - rt3 - + 10.0.255.4/32 30 - rt2 - + 10.0.255.5/32 40 - rt2 - + 10.0.255.6/32 60 - rt2 - + 10.0.255.7/32 60 - rt2 - + 10.0.255.8/32 60 - rt2 - + 10.0.255.9/32 50 - rt2 - + +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) + +IS-IS L1 IPv6 routing table: + + Prefix Metric Interface Nexthop Label(s) + ------------------------------------------------------- + 2001:db8::2/128 20 - rt2 - + 2001:db8::3/128 20 - rt3 - + 2001:db8::4/128 30 - rt2 - + 2001:db8::5/128 40 - rt2 - + 2001:db8::6/128 60 - rt2 - + 2001:db8::7/128 60 - rt2 - + 2001:db8::8/128 60 - rt2 - + 2001:db8::9/128 50 - rt2 - + +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) + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 30 - rt3 - + 10.0.255.4/32 30 - rt4 - + 10.0.255.5/32 30 - rt2 - + 10.0.255.6/32 40 - rt3 - + 10.0.255.7/32 40 - rt4 - + 10.0.255.8/32 40 - rt2 - + +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) + +IS-IS L1 IPv6 routing table: + + Prefix Metric Interface Nexthop Label(s) + ------------------------------------------------------- + 2001:db8::2/128 20 - rt2 - + 2001:db8::3/128 30 - rt3 - + 2001:db8::4/128 30 - rt4 - + 2001:db8::5/128 30 - rt2 - + 2001:db8::6/128 40 - rt3 - + 2001:db8::7/128 40 - rt4 - + 2001:db8::8/128 40 - rt2 - + +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 - + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 20 - rt3 - + 10.0.255.4/32 30 - rt2 - + 10.0.255.5/32 30 - rt3 - + 10.0.255.6/32 40 - rt2 - + - 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) +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 - + +IS-IS L1 IPv6 routing table: + + Prefix Metric Interface Nexthop Label(s) + ------------------------------------------------------- + 2001:db8::2/128 20 - rt2 - + 2001:db8::3/128 20 - rt3 - + 2001:db8::4/128 30 - rt2 - + 2001:db8::5/128 30 - rt3 - + 2001:db8::6/128 40 - rt2 - + - rt3 - + +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) + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ------------------------------------------------------ + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 20 - rt3 - + 10.0.255.4/32 30 - rt2 - + 10.0.255.5/32 30 - rt3 - + 10.0.255.6/32 40 - rt2 - + 10.0.255.7/32 40 - rt3 - + 10.0.255.8/32 50 - rt2 - + 10.0.255.9/32 50 - rt3 - + 10.0.255.10/32 60 - rt2 - + +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) + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 20 - rt3 - + 10.0.255.4/32 30 - rt2 - + - rt3 - + 10.0.255.5/32 30 - rt3 - + 10.0.255.6/32 30 - rt3 - + 10.0.255.7/32 40 - rt3 - + +test# +end. diff --git a/tests/isisd/test_isis_vertex_queue.c b/tests/isisd/test_isis_vertex_queue.c index 869dd732eb..d2d9f6293a 100644 --- a/tests/isisd/test_isis_vertex_queue.c +++ b/tests/isisd/test_isis_vertex_queue.c @@ -2,14 +2,7 @@ #include "isisd/isis_spf.c" -struct thread_master *master; -int isis_sock_init(struct isis_circuit *circuit); -int isis_sock_init(struct isis_circuit *circuit) -{ - return 0; -} - -struct zebra_privs_t isisd_privs; +#include "test_common.h" static struct isis_vertex **vertices; static size_t vertex_count; diff --git a/tests/isisd/test_topologies.c b/tests/isisd/test_topologies.c new file mode 100644 index 0000000000..ee89407a79 --- /dev/null +++ b/tests/isisd/test_topologies.c @@ -0,0 +1,3307 @@ +/* + * Copyright (C) 2020 NetDEF, Inc. + * Renato Westphal + * + * This program 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 2 of the License, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "isisd/isisd.h" + +#include "test_common.h" + +/* + * clang-format off + * + * All topologies have the following properties: + * - The System-ID is 0000.0000.000X, where X is the node number (in hex); + * - The Router-ID is 10.0.255.X, where X is the node number; + * - The default link metric is 10; + * - When SR is enabled, Adj-SIDs and Prefix-SIDs are generated automatically; + * - When SR is enabled, the default SRGB is [16000-23999] (can be overriden). + * + * Test topology 1: + * ================ + * + * +---------+ + * | | + * | RT1 | + * +----------+ +----------+ + * | | | | + * | +---------+ | + * | | + * | | + * | | + * +----+----+ +----+----+ + * | | | | + * | RT2 | | RT3 | + * | | | | + * | | | | + * +----+----+ +----+----+ + * | | + * | | + * | | + * +---+-+---+ +----+----+ + * | | | | + * | RT4 | | RT5 | + * | | | | + * | | | | + * +----+----+ +----+----+ + * | | + * | | + * | | + * | +---------+ | + * | | | | + * | | RT6 | | + * +----------+ +----------+ + * | | + * +---------+ + * + * Test topology 2: + * ================ + * + * +---------+ + * | | + * | RT1 | + * +----------+ +----------+ + * | | | | + * | +----+----+ | + * | | | + * 15 | | | 30 + * | | | + * +----+----+ | +----+----+ + * | | | | | + * | RT2 | | | RT3 | + * | | | | | + * | | | | | + * +----+----+ | +----+----+ + * | | | + * 40 | | | 40 + * | | | + * +----+----+ | +----+----+ + * | | | | | + * | RT4 | | | RT5 | + * | +----------+----------+ | + * | | | | + * +----+----+ +----+----+ + * | | + * | | + * | | + * | +---------+ | + * | | | | + * | | RT6 | | + * +----------+ +----------+ + * | | + * +---------+ + * + * Test topology 3: + * ================ + * + * +---------+ + * | | + * | RT1 | + * +----------+ +----------+ + * | | | | + * | +---------+ | + * | | + * | | + * | | + * +----+----+ +----+----+ + * | | | | + * | RT2 | | RT3 | + * | +---------------------+ | + * | | | | + * +----+----+ +----+----+ + * | | + * | | 30 + * | | + * +----+----+ +----+----+ + * | | | | + * | RT4 | | RT5 | + * | +---------------------+ | + * | | | | + * +----+----+ +----+----+ + * | | + * | | + * | | + * | +---------+ | + * | | | | + * | | RT6 | | + * +----------+ +----------+ + * | | + * +---------+ + * + * Test topology 4: + * ================ + * + * +---------+ +---------+ + * | | | | + * | RT1 | | RT2 | + * | +---------------------+ | + * | | | | + * +---+-----+ +------+--+ + * | | + * | | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT3 | | RT4 | + * | | | | + * | | | | + * +---+-----+ +------+--+ + * |^ | + * ||200 | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT5 | 50 | RT6 | + * | +---------------------+ | + * | | | | + * +---+-----+ +------+--+ + * | | + * | | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT7 | | RT8 | + * | | | | + * | | | | + * +---------+ +---------+ + * + * Test topology 5: + * ================ + * + * +---------+ +---------+ + * | | | | + * | RT1 | | RT2 | + * | +---------------------+ | + * | | | | + * +---+-----+ +------+--+ + * | | + * | | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT3 | | RT4 | + * | | | | + * | | | | + * +---+-----+ +------+--+ + * | | + * | | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT5 | | RT6 | + * | | | | + * | | | | + * +---+-----+ +------+--+ + * | | + * | | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT7 | | RT8 | + * | +---------------------+ | + * | | | | + * +---------+ +---------+ + * + * Test topology 6: + * ================ + * + * +---------+ +---------+ + * | | | | + * | RT1 | | RT2 | + * | +---------------------+ | + * | | | | + * +---+-----+ +------+--+ + * | | + * | | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT3 | | RT4 | + * | +---------------------+ | + * | | | | + * +---------+ +------+--+ + * | + * | + * | + * +---------+ +------+--+ + * | | | | + * | RT5 | | RT6 | + * | +---------------------+ | + * | | | | + * +---+-----+ +------+--+ + * | | + * | | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT7 | | RT8 | + * | +---------------------+ | + * | | | | + * +---------+ +---------+ + * + * Test topology 7: + * ================ + * + * +---------+ +---------+ +---------+ + * | | | | | | + * | RT1 | 40 | RT2 | | RT3 | + * | +---------------------+ +---------------------+ | + * | | | | | | + * +---+-----+ +----+----+ +------+--+ + * | | | + * | | | + * | | | + * +---+-----+ +----+----+ +------+--+ + * | | | | | | + * | RT4 | | RT5 | | RT6 | + * | +---------------------+ +---------------------+ | + * | | | | | | + * +---+-----+ +----+----+ +------+--+ + * | | | + * | | | 30 + * | | | + * +---+-----+ +----+----+ +------+--+ + * | | | | | | + * | RT7 | | RT8 | | RT9 | + * | +---------------------+ +---------------------+ | + * | | | | | | + * +---+-----+ +----+----+ +------+--+ + * | | | + * | 20 | | + * | | | + * +---+-----+ +----+----+ +------+--+ + * | | | | | | + * | RT10 | | RT11 | | RT12 | + * | +---------------------+ +---------------------+ | + * | | | | | | + * +---------+ +---------+ +---------+ + * + * Test topology 8: + * ================ + * + * +---------+ +---------+ +---------+ + * | | | | | | + * | RT1 | | RT2 | | RT3 | + * | +---------------------+ +---------------------+ | + * | | | | | | + * +---+-----+ +----+----+ +------+--+ + * | | | + * | | | + * | | | + * +---+-----+ +----+----+ +------+--+ + * | | | | | | + * | RT4 | | RT5 | | RT6 | + * | | | +---------------------+ | + * | | | | | | + * +---+-----+ +----+----+ +---------+ + * | | + * | | + * | | + * +---+-----+ +----+----+ +---------+ + * | | | | | | + * | RT7 | | RT8 | | RT9 | + * | | | +---------------------+ | + * | | | | | | + * +---+-----+ +----+----+ +------+--+ + * | | | + * | | | + * | | | + * +---+-----+ +----+----+ +------+--+ + * | | | | | | + * | RT10 | | RT11 | | RT12 | + * | +---------------------+ +---------------------+ | + * | | 30 | | | | + * +---------+ +---------+ +---------+ + * + * Test topology 9: + * ================ + * + * +---------+ + * | | + * | RT1 | + * +----------+ +----------+ + * | | | | + * | +---------+ | + * | | + * | | + * | | + * +----+----+ +----+----+ + * | | | | + * | RT2 | | RT3 | + * | | | | + * | | | | + * +----+----+ +------+--+ + * | | + * | | + * | |100 + * | +---------+ | + * | | | | + * +----------+ RT4 +------------+ + * +----------------| |----------------+ + * | +-+ +--+ | + * | | +---------+ | | + * | | | | + * | |30 |30 |30 + * | | | | + * +----+----+ +----+----+ +----+----+ +----+----+ + * | | | | | | | | + * | RT5 | | RT6 | | RT7 | | RT8 | + * | | | | | | | | + * | | | | | | | | + * +----+----+ +----+----+ +----+----+ +----+----+ + * | | | | + * | | | | + * | | | | + * | | +---------+ | | + * | +-+ +--+ | + * +----------------+ RT9 +----------------+ + * | | + * | | + * +---------+ + * + * Test topology 10: + * ================ + * + * +---------+ + * | | + * | RT1 | + * +----------+ +----------+ + * | | | | + * | +----+----+ | + * | | | + * | |20 |20 + * | | | + * +----+----+ +----+----+ +----+----+ + * | | | | | | + * | RT2 | | RT3 | | RT4 | + * | | | | | | + * | | | | | | + * +----+----+ +----+----+ +----+----+ + * | | | + * | | | + * | | | + * +----+----+ +----+----+ +----+----+ + * | | | | | | + * | RT5 | | RT6 | | RT7 | + * | | | | | | + * | | | | | | + * +----+----+ +----+----+ +----+----+ + * | | | + * | |50 |50 + * | | | + * | +----+----+ | + * | | | | + * +----------+ RT8 +----------+ + * | | + * | | + * +---------+ + * + * Test topology 11: + * ================ + * + * +---------+ + * | | + * | RT1 | + * | | + * | | + * +----+----+ + * | + * | + * | + * +---------+ | +---------+ + * | | | | | + * | RT2 |50 | | RT3 | + * | +----------+----------+ | + * | | | | + * +----+----+ +----+----+ + * | | + * | | + * | | + * +----+----+ +----+----+ + * | | | | + * | RT4 | | RT5 | + * | +---------------------+ | + * | | | | + * +----+----+ +----+----+ + * | | + * | | + * | | + * | +---------+ | + * | | | | + * | | RT6 | | + * +----------+ +----------+ + * | | + * +---------+ + * + * Test topology 12: + * ================ + * + * +---------+ +---------+ + * | | | | + * | RT1 | | RT2 | + * | +---------------------+ | + * | | | | + * +---+-----+ +------+--+ + * | | + * | | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT3 | | RT4 | + * | | | | + * | | | | + * +---+-----+ +------+--+ + * |^ | + * |400 | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT5 | | RT6 | + * | | | | + * | | | | + * +---+-----+ +------+--+ + * |^ | + * |200 | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT7 | | RT8 | + * | +---------------------+ | + * | | 100 | | + * +---+-----+ +------+--+ + * | | + * | | + * | | + * +---+-----+ +------+--+ + * | | | | + * | RT9 | | RT10 | + * | | | | + * | | | | + * +---------+ +---------+ + * + * Test topology 13: + * ================ + * + * +---------+ +---------+ + * | | | | + * | RT1 | | RT2 | + * | +---------------------+ | + * | | | | + * +---+-----+ +----+----+ + * | | + * | | + * | | + * | +----+----+ + * | | | + * | +----------+ RT4 | + * | | | | + * +---+-----+ | | | + * | | | +----+----+ + * | RT3 +----------+ | + * | +----------+ |100 + * | | | | + * +---+-----+ | +----+----+ + * | | | | + * | | | RT5 | + * | +----------+ | + * | | | + * | +----+----+ + * | | + * | | + * | | + * +---+-----+ +----+----+ + * | | | | + * | RT6 | | RT7 | + * | +---------------------+ | + * | | | | + * +---------+ +---------+ + */ + +struct isis_topology test_topologies[] = { + { + .number = 1, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.1/32", + "2001:db8::1/128", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.2/32", + "2001:db8::2/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.3/32", + "2001:db8::3/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.4/32", + "2001:db8::4/128", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.5/32", + "2001:db8::5/128", + }, + .adjacencies = { + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.6/32", + "2001:db8::6/128", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + }, + }, + { + .number = 2, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.1/32", + "2001:db8::1/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .pseudonode_id = 1, + .metric = 10, + }, + { + .hostname = "rt2", + .metric = 15, + }, + { + .hostname = "rt3", + .metric = 30, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.2/32", + "2001:db8::2/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 15, + }, + { + .hostname = "rt4", + .metric = 40, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.3/32", + "2001:db8::3/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 30, + }, + { + .hostname = "rt5", + .metric = 40, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.4/32", + "2001:db8::4/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .pseudonode_id = 1, + .metric = 10, + }, + { + .hostname = "rt2", + .metric = 40, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.5/32", + "2001:db8::5/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .pseudonode_id = 1, + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 40, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.6/32", + "2001:db8::6/128", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .pseudonode_id = 1, + .level = IS_LEVEL_1, + .adjacencies = { + { + .hostname = "rt1", + .metric = 0, + }, + { + .hostname = "rt4", + .metric = 0, + }, + { + .hostname = "rt5", + .metric = 0, + }, + }, + }, + }, + }, + { + .number = 3, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.1/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.2/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.3/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 30, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.4/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.5/32", + }, + .adjacencies = { + { + .hostname = "rt3", + .metric = 30, + }, + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.6/32", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + }, + }, + { + .number = 4, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.1/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.2/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.3/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.4/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.5/32", + }, + .adjacencies = { + { + .hostname = "rt3", + .metric = 200, + }, + { + .hostname = "rt6", + .metric = 50, + }, + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.6/32", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 50, + }, + { + .hostname = "rt8", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt7", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x07}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.7", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.7/32", + }, + .adjacencies = { + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt8", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x08}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.8", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.8/32", + }, + .adjacencies = { + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + }, + }, + { + .number = 5, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.1/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.2/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.3/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.4/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.5/32", + }, + .adjacencies = { + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.6/32", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt7", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x07}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.7", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.7/32", + }, + .adjacencies = { + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt8", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x08}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.8", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.8/32", + }, + .adjacencies = { + { + .hostname = "rt6", + .metric = 10, + }, + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + }, + }, + { + .number = 6, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.1/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.2/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.3/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.4/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.5/32", + }, + .adjacencies = { + { + .hostname = "rt6", + .metric = 10, + }, + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.6/32", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt7", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x07}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.7", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.7/32", + }, + .adjacencies = { + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt8", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x08}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.8", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.8/32", + }, + .adjacencies = { + { + .hostname = "rt6", + .metric = 10, + }, + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + }, + }, + { + .number = 7, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.1/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 40, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.2/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 40, + }, + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.3/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.4/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.5/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.6/32", + }, + .adjacencies = { + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt9", + .metric = 30, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt7", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x07}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.7", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.7/32", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 10, + }, + { + .hostname = "rt10", + .metric = 20, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt8", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x08}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.8", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.8/32", + }, + .adjacencies = { + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt7", + .metric = 10, + }, + { + .hostname = "rt9", + .metric = 10, + }, + { + .hostname = "rt11", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt9", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x09}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.9", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.9/32", + }, + .adjacencies = { + { + .hostname = "rt6", + .metric = 30, + }, + { + .hostname = "rt8", + .metric = 10, + }, + { + .hostname = "rt12", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt10", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0a}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.10", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.10/32", + }, + .adjacencies = { + { + .hostname = "rt7", + .metric = 20, + }, + { + .hostname = "rt11", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt11", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0b}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.11", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.11/32", + }, + .adjacencies = { + { + .hostname = "rt8", + .metric = 10, + }, + { + .hostname = "rt10", + .metric = 10, + }, + { + .hostname = "rt12", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt12", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0c}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.12", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.12/32", + }, + .adjacencies = { + { + .hostname = "rt9", + .metric = 10, + }, + { + .hostname = "rt11", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + }, + }, + { + .number = 8, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.1/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.2/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.3/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.4/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.5/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.6/32", + }, + .adjacencies = { + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt7", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x07}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.7", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.7/32", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt10", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt8", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x08}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.8", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.8/32", + }, + .adjacencies = { + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt9", + .metric = 10, + }, + { + .hostname = "rt11", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt9", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x09}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.9", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.9/32", + }, + .adjacencies = { + { + .hostname = "rt8", + .metric = 10, + }, + { + .hostname = "rt12", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt10", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0a}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.10", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.10/32", + }, + .adjacencies = { + { + .hostname = "rt7", + .metric = 10, + }, + { + .hostname = "rt11", + .metric = 30, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt11", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0b}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.11", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.11/32", + }, + .adjacencies = { + { + .hostname = "rt8", + .metric = 10, + }, + { + .hostname = "rt10", + .metric = 30, + }, + { + .hostname = "rt12", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt12", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0c}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.12", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.12/32", + }, + .adjacencies = { + { + .hostname = "rt9", + .metric = 10, + }, + { + .hostname = "rt11", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + }, + }, + { + .number = 9, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.1/32", + "2001:db8::1/128", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.2/32", + "2001:db8::2/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.3/32", + "2001:db8::3/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 100, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.4/32", + "2001:db8::4/128", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 100, + }, + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 30, + }, + { + .hostname = "rt7", + .metric = 30, + }, + { + .hostname = "rt8", + .metric = 30, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.5/32", + "2001:db8::5/128", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt9", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.6/32", + "2001:db8::6/128", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 30, + }, + { + .hostname = "rt9", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt7", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x07}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.7", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.7/32", + "2001:db8::7/128", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 30, + }, + { + .hostname = "rt9", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt8", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x08}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.8", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.8/32", + "2001:db8::8/128", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 30, + }, + { + .hostname = "rt9", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt9", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x09}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.9", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.9/32", + "2001:db8::9/128", + }, + .adjacencies = { + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + { + .hostname = "rt7", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + }, + }, + { + .number = 10, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.1/32", + "2001:db8::1/128", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 20, + }, + { + .hostname = "rt4", + .metric = 20, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.2/32", + "2001:db8::2/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .srgb = { + .lower_bound = 20000, + .range_size = 8000, + }, + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.3/32", + "2001:db8::3/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 20, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.4/32", + "2001:db8::4/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 20, + }, + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.5/32", + "2001:db8::5/128", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.6/32", + "2001:db8::6/128", + }, + .adjacencies = { + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 50, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt7", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x07}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.7", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.7/32", + "2001:db8::7/128", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 50, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt8", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x08}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.8", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.8/32", + "2001:db8::8/128", + }, + .adjacencies = { + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 50, + }, + { + .hostname = "rt7", + .metric = 50, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + }, + }, + { + .number = 11, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.1/32", + "2001:db8::1/128", + }, + .adjacencies = { + { + .hostname = "rt2", + .pseudonode_id = 1, + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.2/32", + "2001:db8::2/128", + }, + .adjacencies = { + { + .hostname = "rt2", + .pseudonode_id = 1, + .metric = 50, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.3/32", + "2001:db8::3/128", + }, + .adjacencies = { + { + .hostname = "rt2", + .pseudonode_id = 1, + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.4/32", + "2001:db8::4/128", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.5/32", + "2001:db8::5/128", + }, + .adjacencies = { + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.6/32", + "2001:db8::6/128", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .pseudonode_id = 1, + .level = IS_LEVEL_1, + .adjacencies = { + { + .hostname = "rt1", + .metric = 0, + }, + { + .hostname = "rt2", + .metric = 0, + }, + { + .hostname = "rt3", + .metric = 0, + }, + }, + }, + }, + }, + { + .number = 12, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.1/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.2/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.3/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.4/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.5/32", + }, + .adjacencies = { + { + .hostname = "rt3", + .metric = 400, + }, + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.6/32", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt8", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt7", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x07}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.7", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.7/32", + }, + .adjacencies = { + { + .hostname = "rt5", + .metric = 200, + }, + { + .hostname = "rt8", + .metric = 100, + }, + { + .hostname = "rt9", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt8", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x08}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.8", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.8/32", + }, + .adjacencies = { + { + .hostname = "rt6", + .metric = 10, + }, + { + .hostname = "rt7", + .metric = 100, + }, + { + .hostname = "rt10", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt9", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x09}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.9", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.9/32", + }, + .adjacencies = { + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt10", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0a}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.10", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.10/32", + }, + .adjacencies = { + { + .hostname = "rt8", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + }, + }, + { + .number = 13, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.1/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.2/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.3/32", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.4/32", + }, + .adjacencies = { + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 100, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.5/32", + }, + .adjacencies = { + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt4", + .metric = 100, + }, + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt6", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.6", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.6/32", + }, + .adjacencies = { + { + .hostname = "rt3", + .metric = 10, + }, + { + .hostname = "rt7", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + { + .hostname = "rt7", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x07}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.7", + .protocols = { + .ipv4 = true, + }, + .networks = { + "10.0.255.7/32", + }, + .adjacencies = { + { + .hostname = "rt5", + .metric = 10, + }, + { + .hostname = "rt6", + .metric = 10, + }, + }, + .flags = F_ISIS_TEST_NODE_SR, + }, + }, + }, + { + /* sentinel */ + }, +}; diff --git a/tests/subdir.am b/tests/subdir.am index 04053a6f46..e54bfc4a35 100644 --- a/tests/subdir.am +++ b/tests/subdir.am @@ -23,6 +23,7 @@ else TESTS_ISISD = \ tests/isisd/test_fuzz_isis_tlv \ tests/isisd/test_isis_lspdb \ + tests/isisd/test_isis_spf \ tests/isisd/test_isis_vertex_queue \ # end endif @@ -111,6 +112,7 @@ noinst_HEADERS += \ tests/helpers/c/tests.h \ tests/lib/cli/common_cli.h \ tests/lib/test_typelist.h \ + tests/isisd/test_common.h \ # end # @@ -168,16 +170,21 @@ tests_bgpd_test_peer_attr_SOURCES = tests/bgpd/test_peer_attr.c tests_isisd_test_fuzz_isis_tlv_CFLAGS = $(TESTS_CFLAGS) -I$(top_builddir)/tests/isisd tests_isisd_test_fuzz_isis_tlv_CPPFLAGS = $(TESTS_CPPFLAGS) -I$(top_builddir)/tests/isisd tests_isisd_test_fuzz_isis_tlv_LDADD = $(ISISD_TEST_LDADD) -tests_isisd_test_fuzz_isis_tlv_SOURCES = tests/isisd/test_fuzz_isis_tlv.c +tests_isisd_test_fuzz_isis_tlv_SOURCES = tests/isisd/test_fuzz_isis_tlv.c tests/isisd/test_common.c nodist_tests_isisd_test_fuzz_isis_tlv_SOURCES = tests/isisd/test_fuzz_isis_tlv_tests.h tests_isisd_test_isis_lspdb_CFLAGS = $(TESTS_CFLAGS) tests_isisd_test_isis_lspdb_CPPFLAGS = $(TESTS_CPPFLAGS) tests_isisd_test_isis_lspdb_LDADD = $(ISISD_TEST_LDADD) -tests_isisd_test_isis_lspdb_SOURCES = tests/isisd/test_isis_lspdb.c +tests_isisd_test_isis_lspdb_SOURCES = tests/isisd/test_isis_lspdb.c tests/isisd/test_common.c +tests_isisd_test_isis_spf_CFLAGS = $(TESTS_CFLAGS) +tests_isisd_test_isis_spf_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_isisd_test_isis_spf_LDADD = $(ISISD_TEST_LDADD) +tests_isisd_test_isis_spf_SOURCES = tests/isisd/test_isis_spf.c tests/isisd/test_common.c tests/isisd/test_topologies.c +nodist_tests_isisd_test_isis_spf_SOURCES = yang/frr-isisd.yang.c tests_isisd_test_isis_vertex_queue_CFLAGS = $(TESTS_CFLAGS) tests_isisd_test_isis_vertex_queue_CPPFLAGS = $(TESTS_CPPFLAGS) tests_isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD) -tests_isisd_test_isis_vertex_queue_SOURCES = tests/isisd/test_isis_vertex_queue.c +tests_isisd_test_isis_vertex_queue_SOURCES = tests/isisd/test_isis_vertex_queue.c tests/isisd/test_common.c tests_lib_cxxcompat_CFLAGS = $(TESTS_CFLAGS) $(CXX_COMPAT_CFLAGS) $(WERROR) tests_lib_cxxcompat_CPPFLAGS = $(TESTS_CPPFLAGS) @@ -327,6 +334,9 @@ EXTRA_DIST += \ tests/isisd/test_fuzz_isis_tlv.py \ tests/isisd/test_fuzz_isis_tlv_tests.h.gz \ tests/isisd/test_isis_lspdb.py \ + tests/isisd/test_isis_spf.py \ + tests/isisd/test_isis_spf.in \ + tests/isisd/test_isis_spf.refout \ tests/isisd/test_isis_vertex_queue.py \ tests/lib/cli/test_commands.in \ tests/lib/cli/test_commands.py \ From 75aa7aa1352a06c2045c027dc792f14c925aa3a3 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Mon, 24 Aug 2020 15:27:15 -0300 Subject: [PATCH 9/9] isisd: add abiliy to compute the reverse shortest path tree RFC 7490 says: "The reverse SPF computes the cost from each remote node to root. This is achieved by running the normal SPF algorithm but using the link cost in the direction from the next hop back towards root in place of the link cost in the direction away from root towards the next hop". Support for reverse SPF will be necessary later as it's one of the algorithms used to compute R-LFA/TI-LFA repair paths. Signed-off-by: Renato Westphal --- isisd/fabricd.c | 7 +-- isisd/isis_spf.c | 85 ++++++++++++++++++++++++++++++-- isisd/isis_spf.h | 8 ++- isisd/isis_spf_private.h | 1 + tests/isisd/test_isis_spf.c | 32 ++++++++++-- tests/isisd/test_isis_spf.in | 3 ++ tests/isisd/test_isis_spf.refout | 84 +++++++++++++++++++++++++++++++ 7 files changed, 207 insertions(+), 13 deletions(-) diff --git a/isisd/fabricd.c b/isisd/fabricd.c index 2953ee681c..1a081bbea6 100644 --- a/isisd/fabricd.c +++ b/isisd/fabricd.c @@ -221,9 +221,10 @@ struct fabricd *fabricd_new(struct isis_area *area) rv->area = area; rv->initial_sync_state = FABRICD_SYNC_PENDING; - rv->spftree = isis_spftree_new(area, &area->lspdb[IS_LEVEL_2 - 1], - area->isis->sysid, ISIS_LEVEL2, - SPFTREE_IPV4, F_SPFTREE_HOPCOUNT_METRIC); + rv->spftree = + isis_spftree_new(area, &area->lspdb[IS_LEVEL_2 - 1], + area->isis->sysid, ISIS_LEVEL2, SPFTREE_IPV4, + SPF_TYPE_FORWARD, F_SPFTREE_HOPCOUNT_METRIC); rv->neighbors = skiplist_new(0, neighbor_entry_list_cmp, neighbor_entry_del_void); rv->neighbors_neighbors = hash_create(neighbor_entry_hash_key, diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 19a373791e..dd0a6ec824 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -276,7 +276,8 @@ static void isis_spf_adj_free(void *arg) struct isis_spftree *isis_spftree_new(struct isis_area *area, struct lspdb_head *lspdb, const uint8_t *sysid, int level, - enum spf_tree_id tree_id, uint8_t flags) + enum spf_tree_id tree_id, + enum spf_type type, uint8_t flags) { struct isis_spftree *tree; @@ -293,6 +294,7 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area, tree->last_run_monotime = 0; tree->last_run_duration = 0; tree->runcount = 0; + tree->type = type; memcpy(tree->sysid, sysid, ISIS_SYS_ID_LEN); tree->level = level; tree->tree_id = tree_id; @@ -336,9 +338,10 @@ void spftree_area_init(struct isis_area *area) if (area->spftree[tree][level - 1]) continue; - area->spftree[tree][level - 1] = isis_spftree_new( - area, &area->lspdb[level - 1], - area->isis->sysid, level, tree, 0); + area->spftree[tree][level - 1] = + isis_spftree_new(area, &area->lspdb[level - 1], + area->isis->sysid, level, tree, + SPF_TYPE_FORWARD, 0); } } } @@ -956,6 +959,76 @@ static void isis_spf_preload_tent(struct isis_spftree *spftree, } } +struct spf_adj_find_reverse_metric_args { + const uint8_t *id_self; + uint32_t reverse_metric; +}; + +static int spf_adj_find_reverse_metric_cb(const uint8_t *id, uint32_t metric, + bool oldmetric, + struct isis_ext_subtlvs *subtlvs, + void *arg) +{ + struct spf_adj_find_reverse_metric_args *args = arg; + + if (memcmp(id, args->id_self, ISIS_SYS_ID_LEN)) + return LSP_ITER_CONTINUE; + + args->reverse_metric = metric; + + return LSP_ITER_STOP; +} + +/* + * Change all SPF adjacencies to use the link cost in the direction from the + * next hop back towards root in place of the link cost in the direction away + * from root towards the next hop. + */ +static void spf_adj_get_reverse_metrics(struct isis_spftree *spftree) +{ + struct isis_spf_adj *sadj; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS(spftree->sadj_list, node, nnode, sadj)) { + uint8_t lspid[ISIS_SYS_ID_LEN + 2]; + struct isis_lsp *lsp_adj; + const uint8_t *id_self; + struct spf_adj_find_reverse_metric_args args; + + /* Skip pseudonodes. */ + if (LSP_PSEUDO_ID(sadj->id)) + continue; + + /* Find LSP of the corresponding adjacency. */ + memcpy(lspid, sadj->id, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID(lspid) = 0; + LSP_FRAGMENT(lspid) = 0; + lsp_adj = lsp_search(spftree->lspdb, lspid); + if (lsp_adj == NULL || lsp_adj->hdr.rem_lifetime == 0) { + /* Delete one-way adjacency. */ + listnode_delete(spftree->sadj_list, sadj); + continue; + } + + /* Find root node in the LSP of the adjacent router. */ + if (CHECK_FLAG(sadj->flags, F_ISIS_SPF_ADJ_BROADCAST)) + id_self = sadj->lan.desig_is_id; + else + id_self = spftree->sysid; + args.id_self = id_self; + args.reverse_metric = UINT32_MAX; + isis_lsp_iterate_is_reach(lsp_adj, spftree->mtid, + spf_adj_find_reverse_metric_cb, + &args); + if (args.reverse_metric == UINT32_MAX) { + /* Delete one-way adjacency. */ + listnode_delete(spftree->sadj_list, sadj); + continue; + } + sadj->metric = args.reverse_metric; + } +} + static void spf_adj_list_parse_tlv(struct isis_spftree *spftree, struct list *adj_list, const uint8_t *id, const uint8_t *desig_is_id, @@ -1092,6 +1165,9 @@ static void isis_spf_build_adj_list(struct isis_spftree *spftree, if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)) list_delete(&adj_list); + + if (spftree->type == SPF_TYPE_REVERSE) + spf_adj_get_reverse_metrics(spftree); } /* @@ -1181,6 +1257,7 @@ struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area, if (!spftree) spftree = isis_spftree_new(area, &area->lspdb[IS_LEVEL_2 - 1], sysid, ISIS_LEVEL2, SPFTREE_IPV4, + SPF_TYPE_FORWARD, F_SPFTREE_HOPCOUNT_METRIC); init_spt(spftree, ISIS_MT_IPV4_UNICAST); diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 61a107bea2..b2dc23496f 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -26,6 +26,11 @@ struct isis_spftree; +enum spf_type { + SPF_TYPE_FORWARD = 1, + SPF_TYPE_REVERSE, +}; + struct isis_spf_adj { uint8_t id[ISIS_SYS_ID_LEN + 1]; struct isis_adjacency *adj; @@ -43,7 +48,8 @@ struct isis_spf_adj { struct isis_spftree *isis_spftree_new(struct isis_area *area, struct lspdb_head *lspdb, const uint8_t *sysid, int level, - enum spf_tree_id tree_id, uint8_t flags); + enum spf_tree_id tree_id, + enum spf_type type, uint8_t flags); void isis_spf_invalidate_routes(struct isis_spftree *tree); void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees); diff --git a/isisd/isis_spf_private.h b/isisd/isis_spf_private.h index 6bdf900d1c..1e61bf0f48 100644 --- a/isisd/isis_spf_private.h +++ b/isisd/isis_spf_private.h @@ -314,6 +314,7 @@ struct isis_spftree { time_t last_run_monotime; /* last run as monotime for scheduling */ time_t last_run_duration; /* last run duration in msec */ + enum spf_type type; uint8_t sysid[ISIS_SYS_ID_LEN]; uint16_t mtid; int family; diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index 4e1d7b050f..dae906b956 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -38,6 +38,7 @@ enum test_type { TEST_SPF = 1, + TEST_REVERSE_SPF, }; #define F_DISPLAY_LSPDB 0x01 @@ -51,13 +52,15 @@ static struct isis *isis; static void test_run_spf(struct vty *vty, const struct isis_topology *topology, const struct isis_test_node *root, struct isis_area *area, struct lspdb_head *lspdb, - int level, int tree) + int level, int tree, bool reverse) { struct isis_spftree *spftree; + enum spf_type spf_type; /* Run SPF. */ + spf_type = reverse ? SPF_TYPE_REVERSE : SPF_TYPE_FORWARD; spftree = isis_spftree_new(area, lspdb, root->sysid, level, tree, - F_SPFTREE_NO_ADJACENCIES); + spf_type, F_SPFTREE_NO_ADJACENCIES); isis_run_spf(spftree); /* Print the SPT and the corresponding routing table. */ @@ -110,7 +113,12 @@ static int test_run(struct vty *vty, const struct isis_topology *topology, case TEST_SPF: test_run_spf(vty, topology, root, area, &area->lspdb[level - 1], level, - tree); + tree, false); + break; + case TEST_REVERSE_SPF: + test_run_spf(vty, topology, root, area, + &area->lspdb[level - 1], level, + tree, true); break; } } @@ -126,7 +134,11 @@ static int test_run(struct vty *vty, const struct isis_topology *topology, } DEFUN(test_isis, test_isis_cmd, - "test isis topology (1-13) root HOSTNAME spf\ + "test isis topology (1-13) root HOSTNAME\ + <\ + spf\ + |reverse-spf\ + >\ [display-lspdb] [] []", "Test command\n" "IS-IS routing protocol\n" @@ -135,6 +147,7 @@ DEFUN(test_isis, test_isis_cmd, "SPF root\n" "SPF root hostname\n" "Normal Shortest Path First\n" + "Reverse Shortest Path First\n" "Display the LSPDB\n" "Do IPv4 processing only\n" "Do IPv6 processing only\n" @@ -144,6 +157,7 @@ DEFUN(test_isis, test_isis_cmd, uint16_t topology_number; const struct isis_topology *topology; const struct isis_test_node *root; + enum test_type test_type; uint8_t flags = 0; int idx = 0; @@ -165,6 +179,14 @@ DEFUN(test_isis, test_isis_cmd, return CMD_WARNING; } + /* Parse test information. */ + if (argv_find(argv, argc, "spf", &idx)) + test_type = TEST_SPF; + else if (argv_find(argv, argc, "reverse-spf", &idx)) + test_type = TEST_REVERSE_SPF; + else + return CMD_WARNING; + /* Parse control flags. */ if (argv_find(argv, argc, "display-lspdb", &idx)) SET_FLAG(flags, F_DISPLAY_LSPDB); @@ -177,7 +199,7 @@ DEFUN(test_isis, test_isis_cmd, else if (argv_find(argv, argc, "level-2-only", &idx)) SET_FLAG(flags, F_LEVEL2_ONLY); - return test_run(vty, topology, root, TEST_SPF, flags); + return test_run(vty, topology, root, test_type, flags); } static void vty_do_exit(int isexit) diff --git a/tests/isisd/test_isis_spf.in b/tests/isisd/test_isis_spf.in index 28d3c59e1e..d9a61782e9 100644 --- a/tests/isisd/test_isis_spf.in +++ b/tests/isisd/test_isis_spf.in @@ -11,3 +11,6 @@ test isis topology 10 root rt1 spf test isis topology 11 root rt1 spf test isis topology 12 root rt1 spf ipv4-only test isis topology 13 root rt1 spf ipv4-only + +test isis topology 4 root rt1 reverse-spf ipv4-only +test isis topology 11 root rt1 reverse-spf diff --git a/tests/isisd/test_isis_spf.refout b/tests/isisd/test_isis_spf.refout index ee82926197..ed0569947c 100644 --- a/tests/isisd/test_isis_spf.refout +++ b/tests/isisd/test_isis_spf.refout @@ -615,5 +615,89 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 30 - rt3 - 10.0.255.7/32 40 - rt3 - +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) + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.2/32 20 - rt2 - + 10.0.255.3/32 20 - rt3 - + 10.0.255.4/32 30 - rt2 - + 10.0.255.5/32 30 - rt3 - + 10.0.255.6/32 40 - rt2 - + 10.0.255.7/32 40 - rt3 - + 10.0.255.8/32 50 - rt2 - + +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) + +IS-IS L1 IPv4 routing table: + + Prefix Metric Interface Nexthop Label(s) + ----------------------------------------------------- + 10.0.255.3/32 20 - rt3 - + 10.0.255.5/32 30 - rt3 - + 10.0.255.6/32 40 - 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 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: + + Prefix Metric Interface Nexthop Label(s) + ------------------------------------------------------- + 2001:db8::3/128 20 - rt3 - + 2001:db8::5/128 30 - rt3 - + 2001:db8::6/128 40 - rt3 - + test# end.