]> git.proxmox.com Git - mirror_frr.git/blame - tests/isisd/test_isis_spf.c
Merge pull request #7361 from wesleycoakley/alpine-build-fix
[mirror_frr.git] / tests / isisd / test_isis_spf.c
CommitLineData
52a7c25e
RW
1/*
2 * Copyright (C) 2020 NetDEF, Inc.
3 * Renato Westphal
4 *
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)
8 * any later version.
9 *
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
13 * more details.
14 *
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
18 */
19
20#include <zebra.h>
21
22#include <lib/version.h>
23#include "getopt.h"
24#include "thread.h"
25#include "vty.h"
26#include "command.h"
27#include "log.h"
28#include "vrf.h"
29#include "yang.h"
30
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"
36
37#include "test_common.h"
38
39enum test_type {
40 TEST_SPF = 1,
75aa7aa1 41 TEST_REVERSE_SPF,
ca74d663 42 TEST_TI_LFA,
52a7c25e
RW
43};
44
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
50
51static struct isis *isis;
52
53static 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,
75aa7aa1 56 int level, int tree, bool reverse)
52a7c25e
RW
57{
58 struct isis_spftree *spftree;
75aa7aa1 59 enum spf_type spf_type;
52a7c25e
RW
60
61 /* Run SPF. */
75aa7aa1 62 spf_type = reverse ? SPF_TYPE_REVERSE : SPF_TYPE_FORWARD;
52a7c25e 63 spftree = isis_spftree_new(area, lspdb, root->sysid, level, tree,
75aa7aa1 64 spf_type, F_SPFTREE_NO_ADJACENCIES);
52a7c25e
RW
65 isis_run_spf(spftree);
66
67 /* Print the SPT and the corresponding routing table. */
68 isis_print_spftree(vty, spftree);
d47d6089 69 isis_print_routes(vty, spftree, false, false);
52a7c25e
RW
70
71 /* Cleanup SPF tree. */
72 isis_spftree_del(spftree);
73}
74
ca74d663
RW
75static 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,
79 int level, int tree,
80 struct lfa_protected_resource *protected_resource)
81{
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;
86 uint8_t flags;
87
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);
93
94 /* Run reverse SPF in the root node. */
95 spftree_reverse = isis_spf_reverse_run(spftree_self);
96
97 /* Run forward SPF on all adjacent routers. */
98 isis_spf_run_neighbors(spftree_self);
99
100 /* Compute the TI-LFA repair paths. */
101 spftree_pc = isis_tilfa_compute(area, spftree_self, spftree_reverse,
102 protected_resource);
103
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));
108 vty_out(vty, "\n");
109 RB_FOREACH (spf_node, isis_spf_nodes, &spftree_self->adj_nodes) {
110 if (RB_EMPTY(isis_spf_nodes, &spf_node->lfa.p_space))
111 continue;
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));
116 vty_out(vty, "\n");
117 }
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));
121 vty_out(vty, "\n");
122
123 /* Print the post-convergence SPT and the correspoding routing table. */
124 isis_print_spftree(vty, spftree_pc);
d47d6089 125 isis_print_routes(vty, spftree_self, false, true);
ca74d663
RW
126
127 /* Cleanup everything. */
128 isis_spftree_del(spftree_self);
129 isis_spftree_del(spftree_reverse);
130 isis_spftree_del(spftree_pc);
131}
132
52a7c25e
RW
133static int test_run(struct vty *vty, const struct isis_topology *topology,
134 const struct isis_test_node *root, enum test_type test_type,
ca74d663
RW
135 uint8_t flags, enum lfa_protection_type protection_type,
136 const char *fail_sysid_str, uint8_t fail_pseudonode_id)
52a7c25e
RW
137{
138 struct isis_area *area;
ca74d663
RW
139 struct lfa_protected_resource protected_resource = {};
140 uint8_t fail_id[ISIS_SYS_ID_LEN] = {};
52a7c25e
RW
141
142 /* Init topology. */
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");
149 return CMD_WARNING;
150 }
151
ca74d663
RW
152 /* Parse failed link/node. */
153 if (fail_sysid_str) {
154 if (sysid2buff(fail_id, fail_sysid_str) == 0) {
155 struct isis_dynhn *dynhn;
156
157 dynhn = dynhn_find_by_name(fail_sysid_str);
158 if (dynhn == NULL) {
159 vty_out(vty, "Invalid system id %s\n",
160 fail_sysid_str);
161 return CMD_WARNING;
162 }
163 memcpy(fail_id, dynhn->id, ISIS_SYS_ID_LEN);
164 }
165
166 protected_resource.type = protection_type;
167 memcpy(protected_resource.adjacency, fail_id, ISIS_SYS_ID_LEN);
168 LSP_PSEUDO_ID(protected_resource.adjacency) =
169 fail_pseudonode_id;
170 }
171
52a7c25e
RW
172 for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
173 if (level == IS_LEVEL_1 && CHECK_FLAG(flags, F_LEVEL2_ONLY))
174 continue;
175 if (level == IS_LEVEL_2 && CHECK_FLAG(flags, F_LEVEL1_ONLY))
176 continue;
177 if ((root->level & level) == 0)
178 continue;
179
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);
185
186 for (int tree = SPFTREE_IPV4; tree <= SPFTREE_IPV6; tree++) {
187 if (tree == SPFTREE_IPV4
188 && CHECK_FLAG(flags, F_IPV6_ONLY))
189 continue;
190 if (tree == SPFTREE_IPV6
191 && CHECK_FLAG(flags, F_IPV4_ONLY))
192 continue;
193
194 switch (test_type) {
195 case TEST_SPF:
196 test_run_spf(vty, topology, root, area,
197 &area->lspdb[level - 1], level,
75aa7aa1
RW
198 tree, false);
199 break;
200 case TEST_REVERSE_SPF:
201 test_run_spf(vty, topology, root, area,
202 &area->lspdb[level - 1], level,
203 tree, true);
52a7c25e 204 break;
ca74d663
RW
205 case TEST_TI_LFA:
206 test_run_ti_lfa(vty, topology, root, area,
207 &area->lspdb[level - 1], level,
208 tree, &protected_resource);
209 break;
52a7c25e
RW
210 }
211 }
212 }
213
214 /* Cleanup IS-IS area. */
215 isis_area_destroy(area);
216
217 /* Cleanup hostnames. */
218 dyn_cache_cleanup_all();
219
220 return CMD_SUCCESS;
221}
222
223DEFUN(test_isis, test_isis_cmd,
75aa7aa1
RW
224 "test isis topology (1-13) root HOSTNAME\
225 <\
226 spf\
227 |reverse-spf\
ca74d663 228 |ti-lfa system-id WORD [pseudonode-id <1-255>] [node-protection]\
75aa7aa1 229 >\
52a7c25e
RW
230 [display-lspdb] [<ipv4-only|ipv6-only>] [<level-1-only|level-2-only>]",
231 "Test command\n"
232 "IS-IS routing protocol\n"
233 "Test topology\n"
234 "Test topology number\n"
235 "SPF root\n"
236 "SPF root hostname\n"
237 "Normal Shortest Path First\n"
75aa7aa1 238 "Reverse Shortest Path First\n"
ca74d663
RW
239 "Topology Independent LFA\n"
240 "System ID\n"
241 "System ID\n"
242 "Pseudonode-ID\n"
243 "Pseudonode-ID\n"
244 "Node protection\n"
52a7c25e
RW
245 "Display the LSPDB\n"
246 "Do IPv4 processing only\n"
247 "Do IPv6 processing only\n"
248 "Skip L2 LSPs\n"
249 "Skip L1 LSPs\n")
250{
251 uint16_t topology_number;
252 const struct isis_topology *topology;
253 const struct isis_test_node *root;
75aa7aa1 254 enum test_type test_type;
ca74d663
RW
255 enum lfa_protection_type protection_type = 0;
256 const char *fail_sysid_str = NULL;
257 uint8_t fail_pseudonode_id = 0;
52a7c25e
RW
258 uint8_t flags = 0;
259 int idx = 0;
260
261 /* Load topology. */
262 argv_find(argv, argc, "topology", &idx);
263 topology_number = atoi(argv[idx + 1]->arg);
264 topology = test_topology_find(test_topologies, topology_number);
265 if (!topology) {
266 vty_out(vty, "%% Topology \"%s\" not found\n",
267 argv[idx + 1]->arg);
268 return CMD_WARNING;
269 }
270
271 /* Find root node. */
272 argv_find(argv, argc, "root", &idx);
273 root = test_topology_find_node(topology, argv[idx + 1]->arg, 0);
274 if (!root) {
275 vty_out(vty, "%% Node \"%s\" not found\n", argv[idx + 1]->arg);
276 return CMD_WARNING;
277 }
278
75aa7aa1
RW
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;
ca74d663
RW
284 else if (argv_find(argv, argc, "ti-lfa", &idx)) {
285 test_type = TEST_TI_LFA;
286
287 fail_sysid_str = argv[idx + 2]->arg;
288 if (argv_find(argv, argc, "pseudonode-id", &idx))
289 fail_pseudonode_id =
290 strtoul(argv[idx + 1]->arg, NULL, 10);
291 if (argv_find(argv, argc, "node-protection", &idx))
292 protection_type = LFA_NODE_PROTECTION;
293 else
294 protection_type = LFA_LINK_PROTECTION;
295 } else
75aa7aa1
RW
296 return CMD_WARNING;
297
52a7c25e
RW
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);
309
ca74d663
RW
310 return test_run(vty, topology, root, test_type, flags, protection_type,
311 fail_sysid_str, fail_pseudonode_id);
52a7c25e
RW
312}
313
314static void vty_do_exit(int isexit)
315{
316 printf("\nend.\n");
317
318 isis_finish(isis);
319 cmd_terminate();
320 vty_terminate();
321 yang_terminate();
322 thread_master_free(master);
323
324 log_memstats(stderr, "test-isis-spf");
325 if (!isexit)
326 exit(0);
327}
328
329struct option longopts[] = {{"help", no_argument, NULL, 'h'},
330 {"debug", no_argument, NULL, 'd'},
331 {0}};
332
333/* Help information display. */
334static void usage(char *progname, int status)
335{
336 if (status != 0)
337 fprintf(stderr, "Try `%s --help' for more information.\n",
338 progname);
339 else {
340 printf("Usage : %s [OPTION...]\n\
341isisd SPF test program.\n\n\
342-u, --debug Enable debugging\n\
343-h, --help Display this help and exit\n\
344\n\
345Report bugs to %s\n",
346 progname, FRR_BUG_ADDRESS);
347 }
348 exit(status);
349}
350
351int main(int argc, char **argv)
352{
353 char *p;
354 char *progname;
355 struct thread thread;
356 bool debug = false;
357
358 /* Set umask before anything for security */
359 umask(0027);
360
361 /* get program name */
362 progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]);
363
364 while (1) {
365 int opt;
366
367 opt = getopt_long(argc, argv, "hd", longopts, 0);
368
369 if (opt == EOF)
370 break;
371
372 switch (opt) {
373 case 0:
374 break;
375 case 'd':
376 debug = true;
377 break;
378 case 'h':
379 usage(progname, 0);
380 break;
381 default:
382 usage(progname, 1);
383 break;
384 }
385 }
386
387 /* master init. */
388 master = thread_master_create(NULL);
389 isis_master_init(master);
390
391 /* Library inits. */
392 cmd_init(1);
393 cmd_hostname_set("test");
394 vty_init(master, false);
395 yang_init(true);
396 if (debug)
397 zlog_aux_init("NONE: ", LOG_DEBUG);
398 else
399 zlog_aux_init("NONE: ", ZLOG_DISABLED);
400
401 /* IS-IS inits. */
402 yang_module_load("frr-isisd");
65251ce8 403 isis = isis_new(VRF_DEFAULT_NAME);
52a7c25e
RW
404 listnode_add(im->isis, isis);
405 SET_FLAG(im->options, F_ISIS_UNIT_TEST);
406 debug_spf_events |= DEBUG_SPF_EVENTS;
ca74d663 407 debug_tilfa |= DEBUG_TILFA;
52a7c25e
RW
408 debug_events |= DEBUG_EVENTS;
409 debug_rte_events |= DEBUG_RTE_EVENTS;
410
411 /* Install test command. */
412 install_element(VIEW_NODE, &test_isis_cmd);
413
414 /* Read input from .in file. */
415 vty_stdio(vty_do_exit);
416
417 /* Fetch next active thread. */
418 while (thread_fetch(master, &thread))
419 thread_call(&thread);
420
421 /* Not reached. */
422 exit(0);
423}