summaryrefslogtreecommitdiffstats
path: root/isisd
diff options
context:
space:
mode:
authorRenato Westphal <renato@opensourcerouting.org>2020-08-24 19:46:36 +0200
committerRenato Westphal <renato@opensourcerouting.org>2020-08-27 01:16:19 +0200
commit52a7c25e63a3d62072aa4fb1ed415fe478ce2ef9 (patch)
tree1c5275b3da3fac27e478dd03781f183b870f21b5 /isisd
parentisisd: make the SPF code more modular (diff)
downloadfrr-52a7c25e63a3d62072aa4fb1ed415fe478ce2ef9.tar.xz
frr-52a7c25e63a3d62072aa4fb1ed415fe478ce2ef9.zip
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 <renato@opensourcerouting.org>
Diffstat (limited to 'isisd')
-rw-r--r--isisd/isis_dynhn.c16
-rw-r--r--isisd/isis_dynhn.h1
-rw-r--r--isisd/isis_misc.c2
-rw-r--r--isisd/isis_route.c20
-rw-r--r--isisd/isis_spf.c7
-rw-r--r--isisd/isis_spf.h2
-rw-r--r--isisd/isisd.c93
-rw-r--r--isisd/isisd.h4
8 files changed, 95 insertions, 50 deletions
diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c
index e34c59be1..244f388c2 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 2cfc43fc1..973fde830 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 27425f24a..6e9cbaf98 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 c12f9fd33..c83a7c04b 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 72f2beaaf..19a373791 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 e3c0fbc8b..61a107bea 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 1ce382954..aca98bf65 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 2314cc262..0c0a1eed1 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"