1 /*
2  * BGP Multipath Unit Test
3  * Copyright (C) 2010 Google Inc.
4  *
5  * This file is part of Quagga
6  *
7  * Quagga is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation; either version 2, or (at your option) any
10  * later version.
11  *
12  * Quagga is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; see the file COPYING; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include <zebra.h>
23 
24 #include "qobj.h"
25 #include "vty.h"
26 #include "stream.h"
27 #include "privs.h"
28 #include "linklist.h"
29 #include "memory.h"
30 #include "zclient.h"
31 #include "queue.h"
32 #include "filter.h"
33 
34 #include "bgpd/bgpd.h"
35 #include "bgpd/bgp_table.h"
36 #include "bgpd/bgp_route.h"
37 #include "bgpd/bgp_attr.h"
38 #include "bgpd/bgp_nexthop.h"
39 #include "bgpd/bgp_mpath.h"
40 #include "bgpd/bgp_evpn.h"
41 #include "bgpd/bgp_network.h"
42 
43 #define VT100_RESET "\x1b[0m"
44 #define VT100_RED "\x1b[31m"
45 #define VT100_GREEN "\x1b[32m"
46 #define VT100_YELLOW "\x1b[33m"
47 #define OK VT100_GREEN "OK" VT100_RESET
48 #define FAILED VT100_RED "failed" VT100_RESET
49 
50 #define TEST_PASSED 0
51 #define TEST_FAILED -1
52 
53 #define EXPECT_TRUE(expr, res)                                                 \
54 	if (!(expr)) {                                                         \
55 		printf("Test failure in %s line %u: %s\n", __func__, __LINE__, \
56 		       #expr);                                                 \
57 		(res) = TEST_FAILED;                                           \
58 	}
59 
60 typedef struct testcase_t__ testcase_t;
61 
62 typedef int (*test_setup_func)(testcase_t *);
63 typedef int (*test_run_func)(testcase_t *);
64 typedef int (*test_cleanup_func)(testcase_t *);
65 
66 struct testcase_t__ {
67 	const char *desc;
68 	void *test_data;
69 	void *verify_data;
70 	void *tmp_data;
71 	test_setup_func setup;
72 	test_run_func run;
73 	test_cleanup_func cleanup;
74 };
75 
76 /* need these to link in libbgp */
77 struct thread_master *master = NULL;
78 extern struct zclient *zclient;
79 struct zebra_privs_t bgpd_privs = {
80 	.user = NULL,
81 	.group = NULL,
82 	.vty_group = NULL,
83 };
84 
85 static int tty = 0;
86 
87 /* Create fake bgp instance */
bgp_create_fake(as_t * as,const char * name)88 static struct bgp *bgp_create_fake(as_t *as, const char *name)
89 {
90 	struct bgp *bgp;
91 	afi_t afi;
92 	safi_t safi;
93 
94 	if ((bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp))) == NULL)
95 		return NULL;
96 
97 	bgp_lock(bgp);
98 	// bgp->peer_self = peer_new (bgp);
99 	// bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "Static
100 	// announcement");
101 
102 	bgp->peer = list_new();
103 	// bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp;
104 
105 	bgp->group = list_new();
106 	// bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp;
107 
108 	bgp_evpn_init(bgp);
109 	for (afi = AFI_IP; afi < AFI_MAX; afi++)
110 		for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
111 			bgp->route[afi][safi] = bgp_table_init(bgp, afi, safi);
112 			bgp->aggregate[afi][safi] = bgp_table_init(
113 				bgp, afi, safi);
114 			bgp->rib[afi][safi] = bgp_table_init(bgp, afi, safi);
115 			bgp->maxpaths[afi][safi].maxpaths_ebgp = MULTIPATH_NUM;
116 			bgp->maxpaths[afi][safi].maxpaths_ibgp = MULTIPATH_NUM;
117 		}
118 
119 	bgp_scan_init(bgp);
120 	bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
121 	bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
122 	bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
123 	bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
124 	bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
125 
126 	bgp->as = *as;
127 
128 	if (name)
129 		bgp->name = strdup(name);
130 
131 	return bgp;
132 }
133 
134 /*=========================================================
135  * Testcase for maximum-paths configuration
136  */
setup_bgp_cfg_maximum_paths(testcase_t * t)137 static int setup_bgp_cfg_maximum_paths(testcase_t *t)
138 {
139 	as_t asn = 1;
140 	t->tmp_data = bgp_create_fake(&asn, NULL);
141 	if (!t->tmp_data)
142 		return -1;
143 	return 0;
144 }
145 
run_bgp_cfg_maximum_paths(testcase_t * t)146 static int run_bgp_cfg_maximum_paths(testcase_t *t)
147 {
148 	afi_t afi;
149 	safi_t safi;
150 	struct bgp *bgp;
151 	int api_result;
152 	int test_result = TEST_PASSED;
153 
154 	bgp = t->tmp_data;
155 	for (afi = AFI_IP; afi < AFI_MAX; afi++)
156 		for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
157 			/* test bgp_maximum_paths_set */
158 			api_result = bgp_maximum_paths_set(
159 				bgp, afi, safi, BGP_PEER_EBGP, 10, 0);
160 			EXPECT_TRUE(api_result == 0, test_result);
161 			api_result = bgp_maximum_paths_set(
162 				bgp, afi, safi, BGP_PEER_IBGP, 10, 0);
163 			EXPECT_TRUE(api_result == 0, test_result);
164 			EXPECT_TRUE(bgp->maxpaths[afi][safi].maxpaths_ebgp
165 					    == 10,
166 				    test_result);
167 			EXPECT_TRUE(bgp->maxpaths[afi][safi].maxpaths_ibgp
168 					    == 10,
169 				    test_result);
170 
171 			/* test bgp_maximum_paths_unset */
172 			api_result = bgp_maximum_paths_unset(bgp, afi, safi,
173 							     BGP_PEER_EBGP);
174 			EXPECT_TRUE(api_result == 0, test_result);
175 			api_result = bgp_maximum_paths_unset(bgp, afi, safi,
176 							     BGP_PEER_IBGP);
177 			EXPECT_TRUE(api_result == 0, test_result);
178 			EXPECT_TRUE((bgp->maxpaths[afi][safi].maxpaths_ebgp
179 				     == MULTIPATH_NUM),
180 				    test_result);
181 			EXPECT_TRUE((bgp->maxpaths[afi][safi].maxpaths_ibgp
182 				     == MULTIPATH_NUM),
183 				    test_result);
184 		}
185 
186 	return test_result;
187 }
188 
cleanup_bgp_cfg_maximum_paths(testcase_t * t)189 static int cleanup_bgp_cfg_maximum_paths(testcase_t *t)
190 {
191 	return bgp_delete((struct bgp *)t->tmp_data);
192 }
193 
194 testcase_t test_bgp_cfg_maximum_paths = {
195 	.desc = "Test bgp maximum-paths config",
196 	.setup = setup_bgp_cfg_maximum_paths,
197 	.run = run_bgp_cfg_maximum_paths,
198 	.cleanup = cleanup_bgp_cfg_maximum_paths,
199 };
200 
201 /*=========================================================
202  * Testcase for bgp_mp_list
203  */
204 struct peer test_mp_list_peer[] = {
205 	{.local_as = 1, .as = 2}, {.local_as = 1, .as = 2},
206 	{.local_as = 1, .as = 2}, {.local_as = 1, .as = 2},
207 	{.local_as = 1, .as = 2},
208 };
209 int test_mp_list_peer_count = array_size(test_mp_list_peer);
210 struct attr test_mp_list_attr[4];
211 struct bgp_path_info test_mp_list_info[] = {
212 	{.peer = &test_mp_list_peer[0], .attr = &test_mp_list_attr[0]},
213 	{.peer = &test_mp_list_peer[1], .attr = &test_mp_list_attr[1]},
214 	{.peer = &test_mp_list_peer[2], .attr = &test_mp_list_attr[1]},
215 	{.peer = &test_mp_list_peer[3], .attr = &test_mp_list_attr[2]},
216 	{.peer = &test_mp_list_peer[4], .attr = &test_mp_list_attr[3]},
217 };
218 int test_mp_list_info_count = array_size(test_mp_list_info);
219 
setup_bgp_mp_list(testcase_t * t)220 static int setup_bgp_mp_list(testcase_t *t)
221 {
222 	test_mp_list_attr[0].nexthop.s_addr = 0x01010101;
223 	test_mp_list_attr[1].nexthop.s_addr = 0x02020202;
224 	test_mp_list_attr[2].nexthop.s_addr = 0x03030303;
225 	test_mp_list_attr[3].nexthop.s_addr = 0x04040404;
226 
227 	if ((test_mp_list_peer[0].su_remote = sockunion_str2su("1.1.1.1"))
228 	    == NULL)
229 		return -1;
230 	if ((test_mp_list_peer[1].su_remote = sockunion_str2su("2.2.2.2"))
231 	    == NULL)
232 		return -1;
233 	if ((test_mp_list_peer[2].su_remote = sockunion_str2su("3.3.3.3"))
234 	    == NULL)
235 		return -1;
236 	if ((test_mp_list_peer[3].su_remote = sockunion_str2su("4.4.4.4"))
237 	    == NULL)
238 		return -1;
239 	if ((test_mp_list_peer[4].su_remote = sockunion_str2su("5.5.5.5"))
240 	    == NULL)
241 		return -1;
242 
243 	return 0;
244 }
245 
run_bgp_mp_list(testcase_t * t)246 static int run_bgp_mp_list(testcase_t *t)
247 {
248 	struct list mp_list;
249 	struct listnode *mp_node;
250 	struct bgp_path_info *info;
251 	int i;
252 	int test_result = TEST_PASSED;
253 	bgp_mp_list_init(&mp_list);
254 	EXPECT_TRUE(listcount(&mp_list) == 0, test_result);
255 
256 	bgp_mp_list_add(&mp_list, &test_mp_list_info[1]);
257 	bgp_mp_list_add(&mp_list, &test_mp_list_info[4]);
258 	bgp_mp_list_add(&mp_list, &test_mp_list_info[2]);
259 	bgp_mp_list_add(&mp_list, &test_mp_list_info[3]);
260 	bgp_mp_list_add(&mp_list, &test_mp_list_info[0]);
261 
262 	for (i = 0, mp_node = mp_list.head; i < test_mp_list_info_count;
263 	     i++, mp_node = listnextnode(mp_node)) {
264 		info = listgetdata(mp_node);
265 		EXPECT_TRUE(info == &test_mp_list_info[i], test_result);
266 	}
267 
268 	bgp_mp_list_clear(&mp_list);
269 	EXPECT_TRUE(listcount(&mp_list) == 0, test_result);
270 
271 	return test_result;
272 }
273 
cleanup_bgp_mp_list(testcase_t * t)274 static int cleanup_bgp_mp_list(testcase_t *t)
275 {
276 	int i;
277 
278 	for (i = 0; i < test_mp_list_peer_count; i++)
279 		sockunion_free(test_mp_list_peer[i].su_remote);
280 
281 	return 0;
282 }
283 
284 testcase_t test_bgp_mp_list = {
285 	.desc = "Test bgp_mp_list",
286 	.setup = setup_bgp_mp_list,
287 	.run = run_bgp_mp_list,
288 	.cleanup = cleanup_bgp_mp_list,
289 };
290 
291 /*=========================================================
292  * Testcase for bgp_path_info_mpath_update
293  */
294 
295 struct bgp_node test_rn;
296 
setup_bgp_path_info_mpath_update(testcase_t * t)297 static int setup_bgp_path_info_mpath_update(testcase_t *t)
298 {
299 	int i;
300 	struct bgp *bgp;
301 	struct bgp_table *rt;
302 	struct route_node *rt_node;
303 	as_t asn = 1;
304 
305 	t->tmp_data = bgp_create_fake(&asn, NULL);
306 	if (!t->tmp_data)
307 		return -1;
308 
309 	bgp = t->tmp_data;
310 	rt = bgp->rib[AFI_IP][SAFI_UNICAST];
311 
312 	if (!rt)
313 		return -1;
314 
315 	str2prefix("42.1.1.0/24", &test_rn.p);
316 	rt_node = bgp_dest_to_rnode(&test_rn);
317 	memcpy((struct route_table *)&rt_node->table, &rt->route_table,
318 	       sizeof(struct route_table *));
319 	setup_bgp_mp_list(t);
320 	for (i = 0; i < test_mp_list_info_count; i++)
321 		bgp_path_info_add(&test_rn, &test_mp_list_info[i]);
322 	return 0;
323 }
324 
run_bgp_path_info_mpath_update(testcase_t * t)325 static int run_bgp_path_info_mpath_update(testcase_t *t)
326 {
327 	struct bgp_path_info *new_best, *old_best, *mpath;
328 	struct list mp_list;
329 	struct bgp_maxpaths_cfg mp_cfg = {3, 3};
330 	int test_result = TEST_PASSED;
331 	bgp_mp_list_init(&mp_list);
332 	bgp_mp_list_add(&mp_list, &test_mp_list_info[4]);
333 	bgp_mp_list_add(&mp_list, &test_mp_list_info[3]);
334 	bgp_mp_list_add(&mp_list, &test_mp_list_info[0]);
335 	bgp_mp_list_add(&mp_list, &test_mp_list_info[1]);
336 	new_best = &test_mp_list_info[3];
337 	old_best = NULL;
338 	bgp_path_info_mpath_update(&test_rn, new_best, old_best, &mp_list,
339 				   &mp_cfg);
340 	bgp_mp_list_clear(&mp_list);
341 	EXPECT_TRUE(bgp_path_info_mpath_count(new_best) == 2, test_result);
342 	mpath = bgp_path_info_mpath_first(new_best);
343 	EXPECT_TRUE(mpath == &test_mp_list_info[0], test_result);
344 	EXPECT_TRUE(CHECK_FLAG(mpath->flags, BGP_PATH_MULTIPATH), test_result);
345 	mpath = bgp_path_info_mpath_next(mpath);
346 	EXPECT_TRUE(mpath == &test_mp_list_info[1], test_result);
347 	EXPECT_TRUE(CHECK_FLAG(mpath->flags, BGP_PATH_MULTIPATH), test_result);
348 
349 	bgp_mp_list_add(&mp_list, &test_mp_list_info[0]);
350 	bgp_mp_list_add(&mp_list, &test_mp_list_info[1]);
351 	new_best = &test_mp_list_info[0];
352 	old_best = &test_mp_list_info[3];
353 	bgp_path_info_mpath_update(&test_rn, new_best, old_best, &mp_list,
354 				   &mp_cfg);
355 	bgp_mp_list_clear(&mp_list);
356 	EXPECT_TRUE(bgp_path_info_mpath_count(new_best) == 1, test_result);
357 	mpath = bgp_path_info_mpath_first(new_best);
358 	EXPECT_TRUE(mpath == &test_mp_list_info[1], test_result);
359 	EXPECT_TRUE(CHECK_FLAG(mpath->flags, BGP_PATH_MULTIPATH), test_result);
360 	EXPECT_TRUE(!CHECK_FLAG(test_mp_list_info[0].flags, BGP_PATH_MULTIPATH),
361 		    test_result);
362 
363 	return test_result;
364 }
365 
cleanup_bgp_path_info_mpath_update(testcase_t * t)366 static int cleanup_bgp_path_info_mpath_update(testcase_t *t)
367 {
368 	int i;
369 
370 	for (i = 0; i < test_mp_list_peer_count; i++)
371 		sockunion_free(test_mp_list_peer[i].su_remote);
372 
373 	return bgp_delete((struct bgp *)t->tmp_data);
374 }
375 
376 testcase_t test_bgp_path_info_mpath_update = {
377 	.desc = "Test bgp_path_info_mpath_update",
378 	.setup = setup_bgp_path_info_mpath_update,
379 	.run = run_bgp_path_info_mpath_update,
380 	.cleanup = cleanup_bgp_path_info_mpath_update,
381 };
382 
383 /*=========================================================
384  * Set up testcase vector
385  */
386 testcase_t *all_tests[] = {
387 	&test_bgp_cfg_maximum_paths, &test_bgp_mp_list,
388 	&test_bgp_path_info_mpath_update,
389 };
390 
391 int all_tests_count = array_size(all_tests);
392 
393 /*=========================================================
394  * Test Driver Functions
395  */
global_test_init(void)396 static int global_test_init(void)
397 {
398 	qobj_init();
399 	master = thread_master_create(NULL);
400 	zclient = zclient_new(master, &zclient_options_default);
401 	bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
402 	vrf_init(NULL, NULL, NULL, NULL, NULL);
403 	bgp_option_set(BGP_OPT_NO_LISTEN);
404 
405 	if (fileno(stdout) >= 0)
406 		tty = isatty(fileno(stdout));
407 	return 0;
408 }
409 
global_test_cleanup(void)410 static int global_test_cleanup(void)
411 {
412 	if (zclient != NULL)
413 		zclient_free(zclient);
414 	thread_master_free(master);
415 	return 0;
416 }
417 
display_result(testcase_t * test,int result)418 static void display_result(testcase_t *test, int result)
419 {
420 	if (tty)
421 		printf("%s: %s\n", test->desc,
422 		       result == TEST_PASSED ? OK : FAILED);
423 	else
424 		printf("%s: %s\n", test->desc,
425 		       result == TEST_PASSED ? "OK" : "FAILED");
426 }
427 
setup_test(testcase_t * t)428 static int setup_test(testcase_t *t)
429 {
430 	int res = 0;
431 	if (t->setup)
432 		res = t->setup(t);
433 	return res;
434 }
435 
cleanup_test(testcase_t * t)436 static int cleanup_test(testcase_t *t)
437 {
438 	int res = 0;
439 	if (t->cleanup)
440 		res = t->cleanup(t);
441 	return res;
442 }
443 
run_tests(testcase_t * tests[],int num_tests,int * pass_count,int * fail_count)444 static void run_tests(testcase_t *tests[], int num_tests, int *pass_count,
445 		      int *fail_count)
446 {
447 	int test_index, result;
448 	testcase_t *cur_test;
449 
450 	*pass_count = *fail_count = 0;
451 
452 	for (test_index = 0; test_index < num_tests; test_index++) {
453 		cur_test = tests[test_index];
454 		if (!cur_test->desc) {
455 			printf("error: test %d has no description!\n",
456 			       test_index);
457 			continue;
458 		}
459 		if (!cur_test->run) {
460 			printf("error: test %s has no run function!\n",
461 			       cur_test->desc);
462 			continue;
463 		}
464 		if (setup_test(cur_test) != 0) {
465 			printf("error: setup failed for test %s\n",
466 			       cur_test->desc);
467 			continue;
468 		}
469 		result = cur_test->run(cur_test);
470 		if (result == TEST_PASSED)
471 			*pass_count += 1;
472 		else
473 			*fail_count += 1;
474 		display_result(cur_test, result);
475 		if (cleanup_test(cur_test) != 0) {
476 			printf("error: cleanup failed for test %s\n",
477 			       cur_test->desc);
478 			continue;
479 		}
480 	}
481 }
482 
main(void)483 int main(void)
484 {
485 	int pass_count, fail_count;
486 	time_t cur_time;
487 
488 	time(&cur_time);
489 	printf("BGP Multipath Tests Run at %s", ctime(&cur_time));
490 	if (global_test_init() != 0) {
491 		printf("Global init failed. Terminating.\n");
492 		exit(1);
493 	}
494 	run_tests(all_tests, all_tests_count, &pass_count, &fail_count);
495 	global_test_cleanup();
496 	printf("Total pass/fail: %d/%d\n", pass_count, fail_count);
497 	return fail_count;
498 }
499