]> git.proxmox.com Git - mirror_frr.git/blob - tests/isisd/test_isis_spf.c
Merge pull request #7037 from volta-networks/fix_traps_bgp
[mirror_frr.git] / tests / isisd / test_isis_spf.c
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
39 enum test_type {
40 TEST_SPF = 1,
41 TEST_REVERSE_SPF,
42 };
43
44 #define F_DISPLAY_LSPDB 0x01
45 #define F_IPV4_ONLY 0x02
46 #define F_IPV6_ONLY 0x04
47 #define F_LEVEL1_ONLY 0x08
48 #define F_LEVEL2_ONLY 0x10
49
50 static struct isis *isis;
51
52 static void test_run_spf(struct vty *vty, const struct isis_topology *topology,
53 const struct isis_test_node *root,
54 struct isis_area *area, struct lspdb_head *lspdb,
55 int level, int tree, bool reverse)
56 {
57 struct isis_spftree *spftree;
58 enum spf_type spf_type;
59
60 /* Run SPF. */
61 spf_type = reverse ? SPF_TYPE_REVERSE : SPF_TYPE_FORWARD;
62 spftree = isis_spftree_new(area, lspdb, root->sysid, level, tree,
63 spf_type, F_SPFTREE_NO_ADJACENCIES);
64 isis_run_spf(spftree);
65
66 /* Print the SPT and the corresponding routing table. */
67 isis_print_spftree(vty, spftree);
68 isis_print_routes(vty, spftree);
69
70 /* Cleanup SPF tree. */
71 isis_spftree_del(spftree);
72 }
73
74 static int test_run(struct vty *vty, const struct isis_topology *topology,
75 const struct isis_test_node *root, enum test_type test_type,
76 uint8_t flags)
77 {
78 struct isis_area *area;
79
80 /* Init topology. */
81 memcpy(isis->sysid, root->sysid, sizeof(isis->sysid));
82 area = isis_area_create("1", NULL);
83 area->is_type = IS_LEVEL_1_AND_2;
84 area->srdb.enabled = true;
85 if (test_topology_load(topology, area, area->lspdb) != 0) {
86 vty_out(vty, "%% Failed to load topology\n");
87 return CMD_WARNING;
88 }
89
90 for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
91 if (level == IS_LEVEL_1 && CHECK_FLAG(flags, F_LEVEL2_ONLY))
92 continue;
93 if (level == IS_LEVEL_2 && CHECK_FLAG(flags, F_LEVEL1_ONLY))
94 continue;
95 if ((root->level & level) == 0)
96 continue;
97
98 /* Print the LDPDB. */
99 if (CHECK_FLAG(flags, F_DISPLAY_LSPDB))
100 show_isis_database_lspdb(vty, area, level - 1,
101 &area->lspdb[level - 1], NULL,
102 ISIS_UI_LEVEL_DETAIL);
103
104 for (int tree = SPFTREE_IPV4; tree <= SPFTREE_IPV6; tree++) {
105 if (tree == SPFTREE_IPV4
106 && CHECK_FLAG(flags, F_IPV6_ONLY))
107 continue;
108 if (tree == SPFTREE_IPV6
109 && CHECK_FLAG(flags, F_IPV4_ONLY))
110 continue;
111
112 switch (test_type) {
113 case TEST_SPF:
114 test_run_spf(vty, topology, root, area,
115 &area->lspdb[level - 1], level,
116 tree, false);
117 break;
118 case TEST_REVERSE_SPF:
119 test_run_spf(vty, topology, root, area,
120 &area->lspdb[level - 1], level,
121 tree, true);
122 break;
123 }
124 }
125 }
126
127 /* Cleanup IS-IS area. */
128 isis_area_destroy(area);
129
130 /* Cleanup hostnames. */
131 dyn_cache_cleanup_all();
132
133 return CMD_SUCCESS;
134 }
135
136 DEFUN(test_isis, test_isis_cmd,
137 "test isis topology (1-13) root HOSTNAME\
138 <\
139 spf\
140 |reverse-spf\
141 >\
142 [display-lspdb] [<ipv4-only|ipv6-only>] [<level-1-only|level-2-only>]",
143 "Test command\n"
144 "IS-IS routing protocol\n"
145 "Test topology\n"
146 "Test topology number\n"
147 "SPF root\n"
148 "SPF root hostname\n"
149 "Normal Shortest Path First\n"
150 "Reverse Shortest Path First\n"
151 "Display the LSPDB\n"
152 "Do IPv4 processing only\n"
153 "Do IPv6 processing only\n"
154 "Skip L2 LSPs\n"
155 "Skip L1 LSPs\n")
156 {
157 uint16_t topology_number;
158 const struct isis_topology *topology;
159 const struct isis_test_node *root;
160 enum test_type test_type;
161 uint8_t flags = 0;
162 int idx = 0;
163
164 /* Load topology. */
165 argv_find(argv, argc, "topology", &idx);
166 topology_number = atoi(argv[idx + 1]->arg);
167 topology = test_topology_find(test_topologies, topology_number);
168 if (!topology) {
169 vty_out(vty, "%% Topology \"%s\" not found\n",
170 argv[idx + 1]->arg);
171 return CMD_WARNING;
172 }
173
174 /* Find root node. */
175 argv_find(argv, argc, "root", &idx);
176 root = test_topology_find_node(topology, argv[idx + 1]->arg, 0);
177 if (!root) {
178 vty_out(vty, "%% Node \"%s\" not found\n", argv[idx + 1]->arg);
179 return CMD_WARNING;
180 }
181
182 /* Parse test information. */
183 if (argv_find(argv, argc, "spf", &idx))
184 test_type = TEST_SPF;
185 else if (argv_find(argv, argc, "reverse-spf", &idx))
186 test_type = TEST_REVERSE_SPF;
187 else
188 return CMD_WARNING;
189
190 /* Parse control flags. */
191 if (argv_find(argv, argc, "display-lspdb", &idx))
192 SET_FLAG(flags, F_DISPLAY_LSPDB);
193 if (argv_find(argv, argc, "ipv4-only", &idx))
194 SET_FLAG(flags, F_IPV4_ONLY);
195 else if (argv_find(argv, argc, "ipv6-only", &idx))
196 SET_FLAG(flags, F_IPV6_ONLY);
197 if (argv_find(argv, argc, "level-1-only", &idx))
198 SET_FLAG(flags, F_LEVEL1_ONLY);
199 else if (argv_find(argv, argc, "level-2-only", &idx))
200 SET_FLAG(flags, F_LEVEL2_ONLY);
201
202 return test_run(vty, topology, root, test_type, flags);
203 }
204
205 static void vty_do_exit(int isexit)
206 {
207 printf("\nend.\n");
208
209 isis_finish(isis);
210 cmd_terminate();
211 vty_terminate();
212 yang_terminate();
213 thread_master_free(master);
214
215 log_memstats(stderr, "test-isis-spf");
216 if (!isexit)
217 exit(0);
218 }
219
220 struct option longopts[] = {{"help", no_argument, NULL, 'h'},
221 {"debug", no_argument, NULL, 'd'},
222 {0}};
223
224 /* Help information display. */
225 static void usage(char *progname, int status)
226 {
227 if (status != 0)
228 fprintf(stderr, "Try `%s --help' for more information.\n",
229 progname);
230 else {
231 printf("Usage : %s [OPTION...]\n\
232 isisd SPF test program.\n\n\
233 -u, --debug Enable debugging\n\
234 -h, --help Display this help and exit\n\
235 \n\
236 Report bugs to %s\n",
237 progname, FRR_BUG_ADDRESS);
238 }
239 exit(status);
240 }
241
242 int main(int argc, char **argv)
243 {
244 char *p;
245 char *progname;
246 struct thread thread;
247 bool debug = false;
248
249 /* Set umask before anything for security */
250 umask(0027);
251
252 /* get program name */
253 progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]);
254
255 while (1) {
256 int opt;
257
258 opt = getopt_long(argc, argv, "hd", longopts, 0);
259
260 if (opt == EOF)
261 break;
262
263 switch (opt) {
264 case 0:
265 break;
266 case 'd':
267 debug = true;
268 break;
269 case 'h':
270 usage(progname, 0);
271 break;
272 default:
273 usage(progname, 1);
274 break;
275 }
276 }
277
278 /* master init. */
279 master = thread_master_create(NULL);
280 isis_master_init(master);
281
282 /* Library inits. */
283 cmd_init(1);
284 cmd_hostname_set("test");
285 vty_init(master, false);
286 yang_init(true);
287 if (debug)
288 zlog_aux_init("NONE: ", LOG_DEBUG);
289 else
290 zlog_aux_init("NONE: ", ZLOG_DISABLED);
291
292 /* IS-IS inits. */
293 yang_module_load("frr-isisd");
294 isis = isis_new(VRF_DEFAULT_NAME);
295 listnode_add(im->isis, isis);
296 SET_FLAG(im->options, F_ISIS_UNIT_TEST);
297 debug_spf_events |= DEBUG_SPF_EVENTS;
298 debug_events |= DEBUG_EVENTS;
299 debug_rte_events |= DEBUG_RTE_EVENTS;
300
301 /* Install test command. */
302 install_element(VIEW_NODE, &test_isis_cmd);
303
304 /* Read input from .in file. */
305 vty_stdio(vty_do_exit);
306
307 /* Fetch next active thread. */
308 while (thread_fetch(master, &thread))
309 thread_call(&thread);
310
311 /* Not reached. */
312 exit(0);
313 }