2 * Copyright (C) 2020 NetDEF, Inc.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <lib/version.h>
31 #include "isisd/isisd.h"
32 #include "isisd/isis_dynhn.h"
33 #include "isisd/isis_misc.h"
34 #include "isisd/isis_spf.h"
35 #include "isisd/isis_spf_private.h"
37 #include "test_common.h"
45 #define F_DISPLAY_LSPDB 0x01
46 #define F_IPV4_ONLY 0x02
47 #define F_IPV6_ONLY 0x04
48 #define F_LEVEL1_ONLY 0x08
49 #define F_LEVEL2_ONLY 0x10
51 static struct isis
*isis
;
53 static void test_run_spf(struct vty
*vty
, const struct isis_topology
*topology
,
54 const struct isis_test_node
*root
,
55 struct isis_area
*area
, struct lspdb_head
*lspdb
,
56 int level
, int tree
, bool reverse
)
58 struct isis_spftree
*spftree
;
59 enum spf_type spf_type
;
62 spf_type
= reverse
? SPF_TYPE_REVERSE
: SPF_TYPE_FORWARD
;
63 spftree
= isis_spftree_new(area
, lspdb
, root
->sysid
, level
, tree
,
64 spf_type
, F_SPFTREE_NO_ADJACENCIES
);
65 isis_run_spf(spftree
);
67 /* Print the SPT and the corresponding routing table. */
68 isis_print_spftree(vty
, spftree
);
69 isis_print_routes(vty
, spftree
, false, false);
71 /* Cleanup SPF tree. */
72 isis_spftree_del(spftree
);
75 static void test_run_ti_lfa(struct vty
*vty
,
76 const struct isis_topology
*topology
,
77 const struct isis_test_node
*root
,
78 struct isis_area
*area
, struct lspdb_head
*lspdb
,
80 struct lfa_protected_resource
*protected_resource
)
82 struct isis_spftree
*spftree_self
;
83 struct isis_spftree
*spftree_reverse
;
84 struct isis_spftree
*spftree_pc
;
85 struct isis_spf_node
*spf_node
, *node
;
88 /* Run forward SPF in the root node. */
89 flags
= F_SPFTREE_NO_ADJACENCIES
;
90 spftree_self
= isis_spftree_new(area
, lspdb
, root
->sysid
, level
, tree
,
91 SPF_TYPE_FORWARD
, flags
);
92 isis_run_spf(spftree_self
);
94 /* Run reverse SPF in the root node. */
95 spftree_reverse
= isis_spf_reverse_run(spftree_self
);
97 /* Run forward SPF on all adjacent routers. */
98 isis_spf_run_neighbors(spftree_self
);
100 /* Compute the TI-LFA repair paths. */
101 spftree_pc
= isis_tilfa_compute(area
, spftree_self
, spftree_reverse
,
104 /* Print the extended P-space and Q-space. */
105 vty_out(vty
, "P-space (self):\n");
106 RB_FOREACH (node
, isis_spf_nodes
, &spftree_pc
->lfa
.p_space
)
107 vty_out(vty
, " %s\n", print_sys_hostname(node
->sysid
));
109 RB_FOREACH (spf_node
, isis_spf_nodes
, &spftree_self
->adj_nodes
) {
110 if (RB_EMPTY(isis_spf_nodes
, &spf_node
->lfa
.p_space
))
112 vty_out(vty
, "P-space (%s):\n",
113 print_sys_hostname(spf_node
->sysid
));
114 RB_FOREACH (node
, isis_spf_nodes
, &spf_node
->lfa
.p_space
)
115 vty_out(vty
, " %s\n", print_sys_hostname(node
->sysid
));
118 vty_out(vty
, "Q-space:\n");
119 RB_FOREACH (node
, isis_spf_nodes
, &spftree_pc
->lfa
.q_space
)
120 vty_out(vty
, " %s\n", print_sys_hostname(node
->sysid
));
123 /* Print the post-convergence SPT and the correspoding routing table. */
124 isis_print_spftree(vty
, spftree_pc
);
125 isis_print_routes(vty
, spftree_self
, false, true);
127 /* Cleanup everything. */
128 isis_spftree_del(spftree_self
);
129 isis_spftree_del(spftree_reverse
);
130 isis_spftree_del(spftree_pc
);
133 static int test_run(struct vty
*vty
, const struct isis_topology
*topology
,
134 const struct isis_test_node
*root
, enum test_type test_type
,
135 uint8_t flags
, enum lfa_protection_type protection_type
,
136 const char *fail_sysid_str
, uint8_t fail_pseudonode_id
)
138 struct isis_area
*area
;
139 struct lfa_protected_resource protected_resource
= {};
140 uint8_t fail_id
[ISIS_SYS_ID_LEN
] = {};
143 memcpy(isis
->sysid
, root
->sysid
, sizeof(isis
->sysid
));
144 area
= isis_area_create("1", NULL
);
145 area
->is_type
= IS_LEVEL_1_AND_2
;
146 area
->srdb
.enabled
= true;
147 if (test_topology_load(topology
, area
, area
->lspdb
) != 0) {
148 vty_out(vty
, "%% Failed to load topology\n");
152 /* Parse failed link/node. */
153 if (fail_sysid_str
) {
154 if (sysid2buff(fail_id
, fail_sysid_str
) == 0) {
155 struct isis_dynhn
*dynhn
;
157 dynhn
= dynhn_find_by_name(fail_sysid_str
);
159 vty_out(vty
, "Invalid system id %s\n",
163 memcpy(fail_id
, dynhn
->id
, ISIS_SYS_ID_LEN
);
166 protected_resource
.type
= protection_type
;
167 memcpy(protected_resource
.adjacency
, fail_id
, ISIS_SYS_ID_LEN
);
168 LSP_PSEUDO_ID(protected_resource
.adjacency
) =
172 for (int level
= IS_LEVEL_1
; level
<= IS_LEVEL_2
; level
++) {
173 if (level
== IS_LEVEL_1
&& CHECK_FLAG(flags
, F_LEVEL2_ONLY
))
175 if (level
== IS_LEVEL_2
&& CHECK_FLAG(flags
, F_LEVEL1_ONLY
))
177 if ((root
->level
& level
) == 0)
180 /* Print the LDPDB. */
181 if (CHECK_FLAG(flags
, F_DISPLAY_LSPDB
))
182 show_isis_database_lspdb(vty
, area
, level
- 1,
183 &area
->lspdb
[level
- 1], NULL
,
184 ISIS_UI_LEVEL_DETAIL
);
186 for (int tree
= SPFTREE_IPV4
; tree
<= SPFTREE_IPV6
; tree
++) {
187 if (tree
== SPFTREE_IPV4
188 && CHECK_FLAG(flags
, F_IPV6_ONLY
))
190 if (tree
== SPFTREE_IPV6
191 && CHECK_FLAG(flags
, F_IPV4_ONLY
))
196 test_run_spf(vty
, topology
, root
, area
,
197 &area
->lspdb
[level
- 1], level
,
200 case TEST_REVERSE_SPF
:
201 test_run_spf(vty
, topology
, root
, area
,
202 &area
->lspdb
[level
- 1], level
,
206 test_run_ti_lfa(vty
, topology
, root
, area
,
207 &area
->lspdb
[level
- 1], level
,
208 tree
, &protected_resource
);
214 /* Cleanup IS-IS area. */
215 isis_area_destroy(area
);
217 /* Cleanup hostnames. */
218 dyn_cache_cleanup_all();
223 DEFUN(test_isis
, test_isis_cmd
,
224 "test isis topology (1-13) root HOSTNAME\
228 |ti-lfa system-id WORD [pseudonode-id <1-255>] [node-protection]\
230 [display-lspdb] [<ipv4-only|ipv6-only>] [<level-1-only|level-2-only>]",
232 "IS-IS routing protocol\n"
234 "Test topology number\n"
236 "SPF root hostname\n"
237 "Normal Shortest Path First\n"
238 "Reverse Shortest Path First\n"
239 "Topology Independent LFA\n"
245 "Display the LSPDB\n"
246 "Do IPv4 processing only\n"
247 "Do IPv6 processing only\n"
251 uint16_t topology_number
;
252 const struct isis_topology
*topology
;
253 const struct isis_test_node
*root
;
254 enum test_type test_type
;
255 enum lfa_protection_type protection_type
= 0;
256 const char *fail_sysid_str
= NULL
;
257 uint8_t fail_pseudonode_id
= 0;
262 argv_find(argv
, argc
, "topology", &idx
);
263 topology_number
= atoi(argv
[idx
+ 1]->arg
);
264 topology
= test_topology_find(test_topologies
, topology_number
);
266 vty_out(vty
, "%% Topology \"%s\" not found\n",
271 /* Find root node. */
272 argv_find(argv
, argc
, "root", &idx
);
273 root
= test_topology_find_node(topology
, argv
[idx
+ 1]->arg
, 0);
275 vty_out(vty
, "%% Node \"%s\" not found\n", argv
[idx
+ 1]->arg
);
279 /* Parse test information. */
280 if (argv_find(argv
, argc
, "spf", &idx
))
281 test_type
= TEST_SPF
;
282 else if (argv_find(argv
, argc
, "reverse-spf", &idx
))
283 test_type
= TEST_REVERSE_SPF
;
284 else if (argv_find(argv
, argc
, "ti-lfa", &idx
)) {
285 test_type
= TEST_TI_LFA
;
287 fail_sysid_str
= argv
[idx
+ 2]->arg
;
288 if (argv_find(argv
, argc
, "pseudonode-id", &idx
))
290 strtoul(argv
[idx
+ 1]->arg
, NULL
, 10);
291 if (argv_find(argv
, argc
, "node-protection", &idx
))
292 protection_type
= LFA_NODE_PROTECTION
;
294 protection_type
= LFA_LINK_PROTECTION
;
298 /* Parse control flags. */
299 if (argv_find(argv
, argc
, "display-lspdb", &idx
))
300 SET_FLAG(flags
, F_DISPLAY_LSPDB
);
301 if (argv_find(argv
, argc
, "ipv4-only", &idx
))
302 SET_FLAG(flags
, F_IPV4_ONLY
);
303 else if (argv_find(argv
, argc
, "ipv6-only", &idx
))
304 SET_FLAG(flags
, F_IPV6_ONLY
);
305 if (argv_find(argv
, argc
, "level-1-only", &idx
))
306 SET_FLAG(flags
, F_LEVEL1_ONLY
);
307 else if (argv_find(argv
, argc
, "level-2-only", &idx
))
308 SET_FLAG(flags
, F_LEVEL2_ONLY
);
310 return test_run(vty
, topology
, root
, test_type
, flags
, protection_type
,
311 fail_sysid_str
, fail_pseudonode_id
);
314 static void vty_do_exit(int isexit
)
322 thread_master_free(master
);
324 log_memstats(stderr
, "test-isis-spf");
329 struct option longopts
[] = {{"help", no_argument
, NULL
, 'h'},
330 {"debug", no_argument
, NULL
, 'd'},
333 /* Help information display. */
334 static void usage(char *progname
, int status
)
337 fprintf(stderr
, "Try `%s --help' for more information.\n",
340 printf("Usage : %s [OPTION...]\n\
341 isisd SPF test program.\n\n\
342 -u, --debug Enable debugging\n\
343 -h, --help Display this help and exit\n\
345 Report bugs to %s\n",
346 progname
, FRR_BUG_ADDRESS
);
351 int main(int argc
, char **argv
)
355 struct thread thread
;
358 /* Set umask before anything for security */
361 /* get program name */
362 progname
= ((p
= strrchr(argv
[0], '/')) ? ++p
: argv
[0]);
367 opt
= getopt_long(argc
, argv
, "hd", longopts
, 0);
388 master
= thread_master_create(NULL
);
389 isis_master_init(master
);
393 cmd_hostname_set("test");
394 vty_init(master
, false);
397 zlog_aux_init("NONE: ", LOG_DEBUG
);
399 zlog_aux_init("NONE: ", ZLOG_DISABLED
);
402 yang_module_load("frr-isisd");
403 isis
= isis_new(VRF_DEFAULT_NAME
);
404 listnode_add(im
->isis
, isis
);
405 SET_FLAG(im
->options
, F_ISIS_UNIT_TEST
);
406 debug_spf_events
|= DEBUG_SPF_EVENTS
;
407 debug_tilfa
|= DEBUG_TILFA
;
408 debug_events
|= DEBUG_EVENTS
;
409 debug_rte_events
|= DEBUG_RTE_EVENTS
;
411 /* Install test command. */
412 install_element(VIEW_NODE
, &test_isis_cmd
);
414 /* Read input from .in file. */
415 vty_stdio(vty_do_exit
);
417 /* Fetch next active thread. */
418 while (thread_fetch(master
, &thread
))
419 thread_call(&thread
);