]> git.proxmox.com Git - mirror_frr.git/blob - tests/bgpd/test_peer_attr.c
tests: fix build warning
[mirror_frr.git] / tests / bgpd / test_peer_attr.c
1 /*
2 * BGP Peer Attribute Unit Tests
3 * Copyright (C) 2018 Pascal Mathis
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 #include <zebra.h>
20
21 #include "memory.h"
22 #include "plist.h"
23 #include "bgpd/bgpd.h"
24 #include "bgpd/bgp_attr.h"
25 #include "bgpd/bgp_regex.h"
26 #include "bgpd/bgp_clist.h"
27 #include "bgpd/bgp_dump.h"
28 #include "bgpd/bgp_filter.h"
29 #include "bgpd/bgp_route.h"
30 #include "bgpd/bgp_vty.h"
31 #include "bgpd/bgp_zebra.h"
32 #include "bgpd/bgp_network.h"
33 #include "lib/routing_nb.h"
34 #include "lib/northbound_cli.h"
35 #include "bgpd/bgp_nb.h"
36
37 #ifdef ENABLE_BGP_VNC
38 #include "bgpd/rfapi/rfapi_backend.h"
39 #endif
40
41 #define OUT_SYMBOL_INFO "\u25ba"
42 #define OUT_SYMBOL_OK "\u2714"
43 #define OUT_SYMBOL_NOK "\u2716"
44
45 #define TEST_ASSERT(T, C) \
46 do { \
47 if ((T)->state != TEST_SUCCESS || (C)) \
48 break; \
49 (T)->state = TEST_ASSERT_ERROR; \
50 (T)->error = str_printf("assertion failed: %s (%s:%d)", (#C), \
51 __FILE__, __LINE__); \
52 } while (0)
53
54 #define TEST_ASSERT_EQ(T, A, B) \
55 do { \
56 if ((T)->state != TEST_SUCCESS || ((A) == (B))) \
57 break; \
58 (T)->state = TEST_ASSERT_ERROR; \
59 (T)->error = str_printf( \
60 "assertion failed: %s[%d] == [%d]%s (%s:%d)", (#A), \
61 (A), (B), (#B), __FILE__, __LINE__); \
62 } while (0)
63
64 #define TEST_HANDLER_MAX 5
65 #define TEST_HANDLER(name) _test_handler_##name
66 #define TEST_HANDLER_DECL(name) \
67 static void _test_handler_##name( \
68 struct test *test, struct test_peer_attr *pa, \
69 struct peer *peer, struct peer *group, bool peer_set, \
70 bool group_set)
71
72 #define TEST_ATTR_HANDLER_DECL(name, attr, pval, gval) \
73 TEST_HANDLER_DECL(name) \
74 { \
75 if (peer_set) \
76 TEST_ASSERT_EQ(test, peer->attr, (pval)); \
77 else if (peer_group_active(peer) && group_set) \
78 TEST_ASSERT_EQ(test, peer->attr, (gval)); \
79 if (group_set) \
80 TEST_ASSERT_EQ(test, group->attr, (gval)); \
81 } \
82 TEST_HANDLER_DECL(name)
83
84 #define TEST_STR_ATTR_HANDLER_DECL(name, attr, pval, gval) \
85 TEST_HANDLER_DECL(name) \
86 { \
87 if (peer_set) { \
88 TEST_ASSERT(test, peer->attr != NULL); \
89 TEST_ASSERT(test, !strcmp(peer->attr, (pval))); \
90 } else if (peer_group_active(peer) && group_set) { \
91 TEST_ASSERT(test, peer->attr != NULL); \
92 TEST_ASSERT(test, !strcmp(peer->attr, (gval))); \
93 } \
94 if (group_set) { \
95 TEST_ASSERT(test, group->attr != NULL); \
96 TEST_ASSERT(test, !strcmp(group->attr, (gval))); \
97 } \
98 } \
99 TEST_HANDLER_DECL(name)
100
101 #define TEST_SU_ATTR_HANDLER_DECL(name, attr, pval, gval) \
102 TEST_HANDLER_DECL(name) \
103 { \
104 union sockunion su; \
105 if (peer_set) { \
106 str2sockunion(pval, &su); \
107 TEST_ASSERT(test, !sockunion_cmp(peer->attr, &su)); \
108 } else if (peer_group_active(peer) && group_set) { \
109 str2sockunion(gval, &su); \
110 TEST_ASSERT(test, !sockunion_cmp(group->attr, &su)); \
111 } \
112 if (group_set) { \
113 str2sockunion(gval, &su); \
114 TEST_ASSERT(test, !sockunion_cmp(group->attr, &su)); \
115 } \
116 } \
117 TEST_HANDLER_DECL(name)
118
119 /* Required variables to link in libbgp */
120 struct zebra_privs_t bgpd_privs = {0};
121 struct thread_master *master;
122
123 enum test_state {
124 TEST_SUCCESS,
125 TEST_SKIPPING,
126 TEST_COMMAND_ERROR,
127 TEST_CONFIG_ERROR,
128 TEST_ASSERT_ERROR,
129 TEST_CUSTOM_ERROR,
130 TEST_INTERNAL_ERROR,
131 };
132
133 enum test_peer_attr_type {
134 PEER_AT_AF_FLAG = 0,
135 PEER_AT_AF_FILTER = 1,
136 PEER_AT_AF_CUSTOM = 2,
137 PEER_AT_GLOBAL_FLAG = 3,
138 PEER_AT_GLOBAL_CUSTOM = 4
139 };
140
141 struct test {
142 enum test_state state;
143 char *desc;
144 char *error;
145 struct list *log;
146
147 struct vty *vty;
148 struct bgp *bgp;
149 struct peer *peer;
150 struct peer_group *group;
151
152 struct {
153 bool use_ibgp;
154 bool use_iface_peer;
155 } o;
156 };
157
158 struct test_config {
159 int local_asn;
160 int peer_asn;
161 const char *peer_address;
162 const char *peer_interface;
163 const char *peer_group;
164 };
165
166 struct test_peer_family {
167 afi_t afi;
168 safi_t safi;
169 };
170
171 struct test_peer_attr {
172 const char *cmd;
173 const char *peer_cmd;
174 const char *group_cmd;
175
176 enum test_peer_attr_type type;
177 union {
178 uint32_t flag;
179 struct {
180 uint32_t flag;
181 size_t direct;
182 } filter;
183 } u;
184 struct {
185 bool invert_peer;
186 bool invert_group;
187 bool use_ibgp;
188 bool use_iface_peer;
189 bool skip_xfer_cases;
190 } o;
191
192 afi_t afi;
193 safi_t safi;
194 struct test_peer_family families[AFI_MAX * SAFI_MAX];
195
196 void (*handlers[TEST_HANDLER_MAX])(struct test *test,
197 struct test_peer_attr *pa,
198 struct peer *peer,
199 struct peer *group, bool peer_set,
200 bool group_set);
201 };
202
203 static struct test_config cfg = {
204 .local_asn = 100,
205 .peer_asn = 200,
206 .peer_address = "1.1.1.1",
207 .peer_interface = "IP-TEST",
208 .peer_group = "PG-TEST",
209 };
210
211 static struct test_peer_family test_default_families[] = {
212 {.afi = AFI_IP, .safi = SAFI_UNICAST},
213 {.afi = AFI_IP, .safi = SAFI_MULTICAST},
214 {.afi = AFI_IP6, .safi = SAFI_UNICAST},
215 {.afi = AFI_IP6, .safi = SAFI_MULTICAST},
216 };
217
218 static char *str_vprintf(const char *fmt, va_list ap)
219 {
220 int ret;
221 int buf_size = 0;
222 char *buf = NULL;
223 va_list apc;
224
225 while (1) {
226 va_copy(apc, ap);
227 ret = vsnprintf(buf, buf_size, fmt, apc);
228 va_end(apc);
229
230 if (ret >= 0 && ret < buf_size)
231 break;
232
233 if (ret >= 0)
234 buf_size = ret + 1;
235 else
236 buf_size *= 2;
237
238 buf = XREALLOC(MTYPE_TMP, buf, buf_size);
239 }
240
241 return buf;
242 }
243
244 static char *str_printf(const char *fmt, ...)
245 {
246 char *buf;
247 va_list ap;
248
249 va_start(ap, fmt);
250 buf = str_vprintf(fmt, ap);
251 va_end(ap);
252
253 return buf;
254 }
255
256 TEST_ATTR_HANDLER_DECL(advertisement_interval, v_routeadv, 10, 20);
257 TEST_STR_ATTR_HANDLER_DECL(password, password, "FRR-Peer", "FRR-Group");
258 TEST_ATTR_HANDLER_DECL(local_as, change_local_as, 1, 2);
259 TEST_ATTR_HANDLER_DECL(timers_1, keepalive, 10, 20);
260 TEST_ATTR_HANDLER_DECL(timers_2, holdtime, 30, 60);
261 TEST_ATTR_HANDLER_DECL(addpath_types, addpath_type[pa->afi][pa->safi],
262 BGP_ADDPATH_ALL, BGP_ADDPATH_BEST_PER_AS);
263 TEST_SU_ATTR_HANDLER_DECL(update_source_su, update_source, "255.255.255.1",
264 "255.255.255.2");
265 TEST_STR_ATTR_HANDLER_DECL(update_source_if, update_if, "IF-PEER", "IF-GROUP");
266
267 TEST_ATTR_HANDLER_DECL(allowas_in, allowas_in[pa->afi][pa->safi], 1, 2);
268 TEST_STR_ATTR_HANDLER_DECL(default_originate_route_map,
269 default_rmap[pa->afi][pa->safi].name, "RM-PEER",
270 "RM-GROUP");
271 TEST_STR_ATTR_HANDLER_DECL(
272 distribute_list,
273 filter[pa->afi][pa->safi].dlist[pa->u.filter.direct].name, "DL-PEER",
274 "DL-GROUP");
275 TEST_STR_ATTR_HANDLER_DECL(
276 filter_list, filter[pa->afi][pa->safi].aslist[pa->u.filter.direct].name,
277 "FL-PEER", "FL-GROUP");
278 TEST_ATTR_HANDLER_DECL(maximum_prefix, pmax[pa->afi][pa->safi], 10, 20);
279 TEST_ATTR_HANDLER_DECL(maximum_prefix_threshold,
280 pmax_threshold[pa->afi][pa->safi], 1, 2);
281 TEST_ATTR_HANDLER_DECL(maximum_prefix_restart, pmax_restart[pa->afi][pa->safi],
282 100, 200);
283 TEST_STR_ATTR_HANDLER_DECL(
284 prefix_list, filter[pa->afi][pa->safi].plist[pa->u.filter.direct].name,
285 "PL-PEER", "PL-GROUP");
286 TEST_STR_ATTR_HANDLER_DECL(
287 route_map, filter[pa->afi][pa->safi].map[pa->u.filter.direct].name,
288 "RM-PEER", "RM-GROUP");
289 TEST_STR_ATTR_HANDLER_DECL(unsuppress_map, filter[pa->afi][pa->safi].usmap.name,
290 "UM-PEER", "UM-GROUP");
291 TEST_ATTR_HANDLER_DECL(weight, weight[pa->afi][pa->safi], 100, 200);
292
293 /* clang-format off */
294 static struct test_peer_attr test_peer_attrs[] = {
295 /* Peer Attributes */
296 {
297 .cmd = "advertisement-interval",
298 .peer_cmd = "advertisement-interval 10",
299 .group_cmd = "advertisement-interval 20",
300 .u.flag = PEER_FLAG_ROUTEADV,
301 .type = PEER_AT_GLOBAL_FLAG,
302 .handlers[0] = TEST_HANDLER(advertisement_interval),
303 },
304 {
305 .cmd = "capability dynamic",
306 .u.flag = PEER_FLAG_DYNAMIC_CAPABILITY,
307 .type = PEER_AT_GLOBAL_FLAG,
308 },
309 {
310 .cmd = "capability extended-nexthop",
311 .u.flag = PEER_FLAG_CAPABILITY_ENHE,
312 .type = PEER_AT_GLOBAL_FLAG,
313 },
314 {
315 .cmd = "capability extended-nexthop",
316 .u.flag = PEER_FLAG_CAPABILITY_ENHE,
317 .type = PEER_AT_GLOBAL_FLAG,
318 .o.invert_peer = true,
319 .o.use_iface_peer = true,
320 },
321 {
322 .cmd = "description",
323 .peer_cmd = "description FRR Peer",
324 .group_cmd = "description FRR Group",
325 .type = PEER_AT_GLOBAL_CUSTOM,
326 },
327 {
328 .cmd = "disable-connected-check",
329 .u.flag = PEER_FLAG_DISABLE_CONNECTED_CHECK,
330 .type = PEER_AT_GLOBAL_FLAG,
331 },
332 {
333 .cmd = "dont-capability-negotiate",
334 .u.flag = PEER_FLAG_DONT_CAPABILITY,
335 .type = PEER_AT_GLOBAL_FLAG,
336 },
337 {
338 .cmd = "enforce-first-as",
339 .u.flag = PEER_FLAG_ENFORCE_FIRST_AS,
340 .type = PEER_AT_GLOBAL_FLAG,
341 },
342 {
343 .cmd = "local-as",
344 .peer_cmd = "local-as 1",
345 .group_cmd = "local-as 2",
346 .u.flag = PEER_FLAG_LOCAL_AS,
347 .type = PEER_AT_GLOBAL_FLAG,
348 .handlers[0] = TEST_HANDLER(local_as),
349 },
350 {
351 .cmd = "local-as 1 no-prepend",
352 .u.flag = PEER_FLAG_LOCAL_AS | PEER_FLAG_LOCAL_AS_NO_PREPEND,
353 .type = PEER_AT_GLOBAL_FLAG,
354 },
355 {
356 .cmd = "local-as 1 no-prepend replace-as",
357 .u.flag = PEER_FLAG_LOCAL_AS | PEER_FLAG_LOCAL_AS_REPLACE_AS,
358 .type = PEER_AT_GLOBAL_FLAG,
359 },
360 {
361 .cmd = "override-capability",
362 .u.flag = PEER_FLAG_OVERRIDE_CAPABILITY,
363 .type = PEER_AT_GLOBAL_FLAG,
364 },
365 {
366 .cmd = "passive",
367 .u.flag = PEER_FLAG_PASSIVE,
368 .type = PEER_AT_GLOBAL_FLAG,
369 },
370 {
371 .cmd = "password",
372 .peer_cmd = "password FRR-Peer",
373 .group_cmd = "password FRR-Group",
374 .u.flag = PEER_FLAG_PASSWORD,
375 .type = PEER_AT_GLOBAL_FLAG,
376 .handlers[0] = TEST_HANDLER(password),
377 },
378 {
379 .cmd = "shutdown",
380 .u.flag = PEER_FLAG_SHUTDOWN,
381 .type = PEER_AT_GLOBAL_FLAG,
382 },
383 {
384 .cmd = "strict-capability-match",
385 .u.flag = PEER_FLAG_STRICT_CAP_MATCH,
386 .type = PEER_AT_GLOBAL_FLAG,
387 },
388 {
389 .cmd = "timers",
390 .peer_cmd = "timers 10 30",
391 .group_cmd = "timers 20 60",
392 .u.flag = PEER_FLAG_TIMER,
393 .type = PEER_AT_GLOBAL_FLAG,
394 .handlers[0] = TEST_HANDLER(timers_1),
395 .handlers[1] = TEST_HANDLER(timers_2),
396 },
397 {
398 .cmd = "timers connect",
399 .peer_cmd = "timers connect 10",
400 .group_cmd = "timers connect 20",
401 .u.flag = PEER_FLAG_TIMER_CONNECT,
402 .type = PEER_AT_GLOBAL_FLAG,
403 },
404 {
405 .cmd = "update-source",
406 .peer_cmd = "update-source 255.255.255.1",
407 .group_cmd = "update-source 255.255.255.2",
408 .u.flag = PEER_FLAG_UPDATE_SOURCE,
409 .type = PEER_AT_GLOBAL_FLAG,
410 .handlers[0] = TEST_HANDLER(update_source_su),
411 },
412 {
413 .cmd = "update-source",
414 .peer_cmd = "update-source IF-PEER",
415 .group_cmd = "update-source IF-GROUP",
416 .u.flag = PEER_FLAG_UPDATE_SOURCE,
417 .type = PEER_AT_GLOBAL_FLAG,
418 .handlers[0] = TEST_HANDLER(update_source_if),
419 },
420
421 /* Address Family Attributes */
422 {
423 .cmd = "addpath",
424 .peer_cmd = "addpath-tx-all-paths",
425 .group_cmd = "addpath-tx-bestpath-per-AS",
426 .type = PEER_AT_AF_CUSTOM,
427 .handlers[0] = TEST_HANDLER(addpath_types),
428 },
429 {
430 .cmd = "allowas-in",
431 .peer_cmd = "allowas-in 1",
432 .group_cmd = "allowas-in 2",
433 .u.flag = PEER_FLAG_ALLOWAS_IN,
434 .handlers[0] = TEST_HANDLER(allowas_in),
435 },
436 {
437 .cmd = "allowas-in origin",
438 .u.flag = PEER_FLAG_ALLOWAS_IN_ORIGIN,
439 },
440 {
441 .cmd = "as-override",
442 .u.flag = PEER_FLAG_AS_OVERRIDE,
443 },
444 {
445 .cmd = "attribute-unchanged as-path",
446 .u.flag = PEER_FLAG_AS_PATH_UNCHANGED,
447 },
448 {
449 .cmd = "attribute-unchanged next-hop",
450 .u.flag = PEER_FLAG_NEXTHOP_UNCHANGED,
451 },
452 {
453 .cmd = "attribute-unchanged med",
454 .u.flag = PEER_FLAG_MED_UNCHANGED,
455 },
456 {
457 .cmd = "attribute-unchanged as-path next-hop",
458 .u.flag = PEER_FLAG_AS_PATH_UNCHANGED
459 | PEER_FLAG_NEXTHOP_UNCHANGED,
460 },
461 {
462 .cmd = "attribute-unchanged as-path med",
463 .u.flag = PEER_FLAG_AS_PATH_UNCHANGED
464 | PEER_FLAG_MED_UNCHANGED,
465 },
466 {
467 .cmd = "attribute-unchanged as-path next-hop med",
468 .u.flag = PEER_FLAG_AS_PATH_UNCHANGED
469 | PEER_FLAG_NEXTHOP_UNCHANGED
470 | PEER_FLAG_MED_UNCHANGED,
471 },
472 {
473 .cmd = "capability orf prefix-list send",
474 .u.flag = PEER_FLAG_ORF_PREFIX_SM,
475 },
476 {
477 .cmd = "capability orf prefix-list receive",
478 .u.flag = PEER_FLAG_ORF_PREFIX_RM,
479 },
480 {
481 .cmd = "capability orf prefix-list both",
482 .u.flag = PEER_FLAG_ORF_PREFIX_SM | PEER_FLAG_ORF_PREFIX_RM,
483 },
484 {
485 .cmd = "default-originate",
486 .u.flag = PEER_FLAG_DEFAULT_ORIGINATE,
487 },
488 {
489 .cmd = "default-originate route-map",
490 .peer_cmd = "default-originate route-map RM-PEER",
491 .group_cmd = "default-originate route-map RM-GROUP",
492 .u.flag = PEER_FLAG_DEFAULT_ORIGINATE,
493 .handlers[0] = TEST_HANDLER(default_originate_route_map),
494 },
495 {
496 .cmd = "distribute-list",
497 .peer_cmd = "distribute-list DL-PEER in",
498 .group_cmd = "distribute-list DL-GROUP in",
499 .type = PEER_AT_AF_FILTER,
500 .u.filter.flag = PEER_FT_DISTRIBUTE_LIST,
501 .u.filter.direct = FILTER_IN,
502 .handlers[0] = TEST_HANDLER(distribute_list),
503 },
504 {
505 .cmd = "distribute-list",
506 .peer_cmd = "distribute-list DL-PEER out",
507 .group_cmd = "distribute-list DL-GROUP out",
508 .type = PEER_AT_AF_FILTER,
509 .u.filter.flag = PEER_FT_DISTRIBUTE_LIST,
510 .u.filter.direct = FILTER_OUT,
511 .handlers[0] = TEST_HANDLER(distribute_list),
512 },
513 {
514 .cmd = "filter-list",
515 .peer_cmd = "filter-list FL-PEER in",
516 .group_cmd = "filter-list FL-GROUP in",
517 .type = PEER_AT_AF_FILTER,
518 .u.filter.flag = PEER_FT_FILTER_LIST,
519 .u.filter.direct = FILTER_IN,
520 .handlers[0] = TEST_HANDLER(filter_list),
521 },
522 {
523 .cmd = "filter-list",
524 .peer_cmd = "filter-list FL-PEER out",
525 .group_cmd = "filter-list FL-GROUP out",
526 .type = PEER_AT_AF_FILTER,
527 .u.filter.flag = PEER_FT_FILTER_LIST,
528 .u.filter.direct = FILTER_OUT,
529 .handlers[0] = TEST_HANDLER(filter_list),
530 },
531 {
532 .cmd = "maximum-prefix",
533 .peer_cmd = "maximum-prefix 10",
534 .group_cmd = "maximum-prefix 20",
535 .u.flag = PEER_FLAG_MAX_PREFIX,
536 .handlers[0] = TEST_HANDLER(maximum_prefix),
537 },
538 {
539 .cmd = "maximum-prefix",
540 .peer_cmd = "maximum-prefix 10 restart 100",
541 .group_cmd = "maximum-prefix 20 restart 200",
542 .u.flag = PEER_FLAG_MAX_PREFIX,
543 .handlers[0] = TEST_HANDLER(maximum_prefix),
544 .handlers[1] = TEST_HANDLER(maximum_prefix_restart),
545 },
546 {
547 .cmd = "maximum-prefix",
548 .peer_cmd = "maximum-prefix 10 1 restart 100",
549 .group_cmd = "maximum-prefix 20 2 restart 200",
550 .u.flag = PEER_FLAG_MAX_PREFIX,
551 .handlers[0] = TEST_HANDLER(maximum_prefix),
552 .handlers[1] = TEST_HANDLER(maximum_prefix_threshold),
553 .handlers[2] = TEST_HANDLER(maximum_prefix_restart),
554 },
555 {
556 .cmd = "maximum-prefix",
557 .peer_cmd = "maximum-prefix 10 warning-only",
558 .group_cmd = "maximum-prefix 20 warning-only",
559 .u.flag = PEER_FLAG_MAX_PREFIX | PEER_FLAG_MAX_PREFIX_WARNING,
560 .handlers[0] = TEST_HANDLER(maximum_prefix),
561 },
562 {
563 .cmd = "maximum-prefix",
564 .peer_cmd = "maximum-prefix 10 1 warning-only",
565 .group_cmd = "maximum-prefix 20 2 warning-only",
566 .u.flag = PEER_FLAG_MAX_PREFIX | PEER_FLAG_MAX_PREFIX_WARNING,
567 .handlers[0] = TEST_HANDLER(maximum_prefix),
568 .handlers[1] = TEST_HANDLER(maximum_prefix_threshold),
569 },
570 {
571 .cmd = "next-hop-self",
572 .u.flag = PEER_FLAG_NEXTHOP_SELF,
573 },
574 {
575 .cmd = "next-hop-self force",
576 .u.flag = PEER_FLAG_FORCE_NEXTHOP_SELF,
577 },
578 {
579 .cmd = "prefix-list",
580 .peer_cmd = "prefix-list PL-PEER in",
581 .group_cmd = "prefix-list PL-GROUP in",
582 .type = PEER_AT_AF_FILTER,
583 .u.filter.flag = PEER_FT_PREFIX_LIST,
584 .u.filter.direct = FILTER_IN,
585 .handlers[0] = TEST_HANDLER(prefix_list),
586 },
587 {
588 .cmd = "prefix-list",
589 .peer_cmd = "prefix-list PL-PEER out",
590 .group_cmd = "prefix-list PL-GROUP out",
591 .type = PEER_AT_AF_FILTER,
592 .u.filter.flag = PEER_FT_PREFIX_LIST,
593 .u.filter.direct = FILTER_OUT,
594 .handlers[0] = TEST_HANDLER(prefix_list),
595 },
596 {
597 .cmd = "remove-private-AS",
598 .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS,
599 },
600 {
601 .cmd = "remove-private-AS all",
602 .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS
603 | PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
604 },
605 {
606 .cmd = "remove-private-AS replace-AS",
607 .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS
608 | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
609 },
610 {
611 .cmd = "remove-private-AS all replace-AS",
612 .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
613 },
614 {
615 .cmd = "route-map",
616 .peer_cmd = "route-map RM-PEER in",
617 .group_cmd = "route-map RM-GROUP in",
618 .type = PEER_AT_AF_FILTER,
619 .u.filter.flag = PEER_FT_ROUTE_MAP,
620 .u.filter.direct = FILTER_IN,
621 .handlers[0] = TEST_HANDLER(route_map),
622 },
623 {
624 .cmd = "route-map",
625 .peer_cmd = "route-map RM-PEER out",
626 .group_cmd = "route-map RM-GROUP out",
627 .type = PEER_AT_AF_FILTER,
628 .u.filter.flag = PEER_FT_ROUTE_MAP,
629 .u.filter.direct = FILTER_OUT,
630 .handlers[0] = TEST_HANDLER(route_map),
631 },
632 {
633 .cmd = "route-reflector-client",
634 .u.flag = PEER_FLAG_REFLECTOR_CLIENT,
635 .o.use_ibgp = true,
636 .o.skip_xfer_cases = true,
637 },
638 {
639 .cmd = "route-server-client",
640 .u.flag = PEER_FLAG_RSERVER_CLIENT,
641 },
642 {
643 .cmd = "send-community",
644 .u.flag = PEER_FLAG_SEND_COMMUNITY,
645 .o.invert_peer = true,
646 .o.invert_group = true,
647 },
648 {
649 .cmd = "send-community extended",
650 .u.flag = PEER_FLAG_SEND_EXT_COMMUNITY,
651 .o.invert_peer = true,
652 .o.invert_group = true,
653 },
654 {
655 .cmd = "send-community large",
656 .u.flag = PEER_FLAG_SEND_LARGE_COMMUNITY,
657 .o.invert_peer = true,
658 .o.invert_group = true,
659 },
660 {
661 .cmd = "soft-reconfiguration inbound",
662 .u.flag = PEER_FLAG_SOFT_RECONFIG,
663 },
664 {
665 .cmd = "unsuppress-map",
666 .peer_cmd = "unsuppress-map UM-PEER",
667 .group_cmd = "unsuppress-map UM-GROUP",
668 .type = PEER_AT_AF_FILTER,
669 .u.filter.flag = PEER_FT_UNSUPPRESS_MAP,
670 .u.filter.direct = 0,
671 .handlers[0] = TEST_HANDLER(unsuppress_map),
672 },
673 {
674 .cmd = "weight",
675 .peer_cmd = "weight 100",
676 .group_cmd = "weight 200",
677 .u.flag = PEER_FLAG_WEIGHT,
678 .handlers[0] = TEST_HANDLER(weight),
679 },
680 {NULL}
681 };
682 /* clang-format on */
683
684 static const char *str_from_afi(afi_t afi)
685 {
686 switch (afi) {
687 case AFI_IP:
688 return "ipv4";
689 case AFI_IP6:
690 return "ipv6";
691 default:
692 return "<unknown AFI>";
693 }
694 }
695
696 static const char *str_from_safi(safi_t safi)
697 {
698 switch (safi) {
699 case SAFI_UNICAST:
700 return "unicast";
701 case SAFI_MULTICAST:
702 return "multicast";
703 default:
704 return "<unknown SAFI>";
705 }
706 }
707
708 static const char *str_from_attr_type(enum test_peer_attr_type at)
709 {
710 switch (at) {
711 case PEER_AT_GLOBAL_FLAG:
712 return "peer-flag";
713 case PEER_AT_AF_FLAG:
714 return "af-flag";
715 case PEER_AT_AF_FILTER:
716 return "af-filter";
717 case PEER_AT_GLOBAL_CUSTOM:
718 case PEER_AT_AF_CUSTOM:
719 return "custom";
720 default:
721 return NULL;
722 }
723 }
724
725 static bool is_attr_type_global(enum test_peer_attr_type at)
726 {
727 return at == PEER_AT_GLOBAL_FLAG || at == PEER_AT_GLOBAL_CUSTOM;
728 }
729
730 static void test_log(struct test *test, const char *fmt, ...)
731 {
732 va_list ap;
733
734 /* Skip logging if test instance has previously failed. */
735 if (test->state != TEST_SUCCESS)
736 return;
737
738 /* Store formatted log message. */
739 va_start(ap, fmt);
740 listnode_add(test->log, str_vprintf(fmt, ap));
741 va_end(ap);
742 }
743
744 static void test_execute(struct test *test, const char *fmt, ...)
745 {
746 int ret;
747 char *cmd;
748 va_list ap;
749 vector vline;
750
751 /* Skip execution if test instance has previously failed. */
752 if (test->state != TEST_SUCCESS)
753 return;
754
755 /* Format command string with variadic arguments. */
756 va_start(ap, fmt);
757 cmd = str_vprintf(fmt, ap);
758 va_end(ap);
759 if (!cmd) {
760 test->state = TEST_INTERNAL_ERROR;
761 test->error =
762 str_printf("could not format command string [%s]", fmt);
763 return;
764 }
765
766 /* Tokenize formatted command string. */
767 vline = cmd_make_strvec(cmd);
768 if (vline == NULL) {
769 test->state = TEST_INTERNAL_ERROR;
770 test->error = str_printf(
771 "tokenizing command string [%s] returned empty result",
772 cmd);
773 XFREE(MTYPE_TMP, cmd);
774
775 return;
776 }
777
778 /* Execute command (non-strict). */
779 ret = cmd_execute_command(vline, test->vty, NULL, 0);
780 if (ret == CMD_SUCCESS) {
781 /* Commit any pending changes, irnore error */
782 ret = nb_cli_pending_commit_check(test->vty);
783 }
784 if (ret != CMD_SUCCESS) {
785 test->state = TEST_COMMAND_ERROR;
786 test->error = str_printf(
787 "execution of command [%s] has failed with code [%d]",
788 cmd, ret);
789 }
790
791 /* Free memory. */
792 cmd_free_strvec(vline);
793 XFREE(MTYPE_TMP, cmd);
794 }
795
796 static void test_config(struct test *test, const char *fmt, bool invert,
797 va_list ap)
798 {
799 char *matcher;
800 char *config;
801 bool matched;
802 va_list apc;
803
804 /* Skip execution if test instance has previously failed. */
805 if (test->state != TEST_SUCCESS)
806 return;
807
808 /* Format matcher string with variadic arguments. */
809 va_copy(apc, ap);
810 matcher = str_vprintf(fmt, apc);
811 va_end(apc);
812 if (!matcher) {
813 test->state = TEST_INTERNAL_ERROR;
814 test->error =
815 str_printf("could not format matcher string [%s]", fmt);
816 return;
817 }
818
819 /* Fetch BGP configuration into buffer. */
820 bgp_config_write(test->vty);
821 config = buffer_getstr(test->vty->obuf);
822 buffer_reset(test->vty->obuf);
823
824 /* Match config against matcher. */
825 matched = !!strstr(config, matcher);
826 if (!matched && !invert) {
827 test->state = TEST_CONFIG_ERROR;
828 test->error = str_printf("expected config [%s] to be present",
829 matcher);
830 } else if (matched && invert) {
831 test->state = TEST_CONFIG_ERROR;
832 test->error = str_printf("expected config [%s] to be absent",
833 matcher);
834 }
835
836 /* Free memory and return. */
837 XFREE(MTYPE_TMP, matcher);
838 XFREE(MTYPE_TMP, config);
839 }
840
841 static void test_config_present(struct test *test, const char *fmt, ...)
842 {
843 va_list ap;
844
845 va_start(ap, fmt);
846 test_config(test, fmt, false, ap);
847 va_end(ap);
848 }
849
850 static void test_config_absent(struct test *test, const char *fmt, ...)
851 {
852 va_list ap;
853
854 va_start(ap, fmt);
855 test_config(test, fmt, true, ap);
856 va_end(ap);
857 }
858
859 static void test_initialize(struct test *test)
860 {
861 union sockunion su;
862
863 /* Skip execution if test instance has previously failed. */
864 if (test->state != TEST_SUCCESS)
865 return;
866
867 /* Log message about (re)-initialization */
868 test_log(test, "prepare: %sinitialize bgp test environment",
869 test->bgp ? "re-" : "");
870
871 /* Attempt gracefully to purge previous BGP configuration. */
872 test_execute(test, "no router bgp");
873 test->state = TEST_SUCCESS;
874
875 /* Initialize BGP test environment. */
876 test_execute(test, "router bgp %d", cfg.local_asn);
877 test_execute(test, "no bgp default ipv4-unicast");
878 test_execute(test, "neighbor %s peer-group", cfg.peer_group);
879 if (test->o.use_iface_peer) {
880 test_execute(test, "neighbor %s interface", cfg.peer_interface);
881 test_execute(test, "neighbor %s remote-as %d",
882 cfg.peer_interface,
883 test->o.use_ibgp ? cfg.local_asn : cfg.peer_asn);
884 } else {
885 test_execute(test, "neighbor %s remote-as %d", cfg.peer_address,
886 test->o.use_ibgp ? cfg.local_asn : cfg.peer_asn);
887 }
888
889 if (test->state != TEST_SUCCESS)
890 return;
891
892 /* Fetch default BGP instance. */
893 test->bgp = bgp_get_default();
894 if (!test->bgp) {
895 test->state = TEST_INTERNAL_ERROR;
896 test->error =
897 str_printf("could not retrieve default bgp instance");
898 return;
899 }
900
901 /* Fetch peer instance. */
902 if (test->o.use_iface_peer) {
903 test->peer =
904 peer_lookup_by_conf_if(test->bgp, cfg.peer_interface);
905 } else {
906 str2sockunion(cfg.peer_address, &su);
907 test->peer = peer_lookup(test->bgp, &su);
908 }
909 if (!test->peer) {
910 test->state = TEST_INTERNAL_ERROR;
911 test->error = str_printf(
912 "could not retrieve instance of bgp peer [%s]",
913 cfg.peer_address);
914 return;
915 }
916
917 /* Fetch peer-group instance. */
918 test->group = peer_group_lookup(test->bgp, cfg.peer_group);
919 if (!test->group) {
920 test->state = TEST_INTERNAL_ERROR;
921 test->error = str_printf(
922 "could not retrieve instance of bgp peer-group [%s]",
923 cfg.peer_group);
924 return;
925 }
926 }
927
928 static struct test *test_new(const char *desc, bool use_ibgp,
929 bool use_iface_peer)
930 {
931 struct test *test;
932
933 test = XCALLOC(MTYPE_TMP, sizeof(struct test));
934 test->state = TEST_SUCCESS;
935 test->desc = XSTRDUP(MTYPE_TMP, desc);
936 test->log = list_new();
937 test->o.use_ibgp = use_ibgp;
938 test->o.use_iface_peer = use_iface_peer;
939
940 test->vty = vty_new();
941 test->vty->type = VTY_TERM;
942 vty_config_enter(test->vty, true, false);
943
944 test_initialize(test);
945
946 return test;
947 };
948
949 static void test_finish(struct test *test)
950 {
951 char *msg;
952 struct listnode *node, *nnode;
953
954 /* Print test output header. */
955 printf("%s [test] %s\n",
956 (test->state == TEST_SUCCESS) ? OUT_SYMBOL_OK : OUT_SYMBOL_NOK,
957 test->desc);
958
959 /* Print test log messages. */
960 for (ALL_LIST_ELEMENTS(test->log, node, nnode, msg)) {
961 printf("%s %s\n", OUT_SYMBOL_INFO, msg);
962 XFREE(MTYPE_TMP, msg);
963 }
964
965 /* Print test error message if available. */
966 if (test->state != TEST_SUCCESS && test->error)
967 printf("%s error: %s\n", OUT_SYMBOL_INFO, test->error);
968
969 /* Print machine-readable result of test. */
970 printf("%s\n", test->state == TEST_SUCCESS ? "OK" : "failed");
971
972 /* Cleanup allocated memory. */
973 if (test->vty) {
974 vty_close(test->vty);
975 test->vty = NULL;
976 }
977 if (test->log)
978 list_delete(&test->log);
979 if (test->desc)
980 XFREE(MTYPE_TMP, test->desc);
981 if (test->error)
982 XFREE(MTYPE_TMP, test->error);
983 XFREE(MTYPE_TMP, test);
984 }
985
986 static void test_peer_flags(struct test *test, struct test_peer_attr *pa,
987 struct peer *peer, bool exp_val, bool exp_ovrd)
988 {
989 bool exp_inv, cur_val, cur_ovrd, cur_inv;
990
991 /* Skip execution if test instance has previously failed. */
992 if (test->state != TEST_SUCCESS)
993 return;
994
995 /* Detect if flag is meant to be inverted. */
996 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
997 exp_inv = pa->o.invert_group;
998 else
999 exp_inv = pa->o.invert_peer;
1000
1001 /* Flip expected value if flag is inverted. */
1002 exp_val ^= exp_inv;
1003
1004 /* Fetch current state of value, override and invert flags. */
1005 if (pa->type == PEER_AT_GLOBAL_FLAG) {
1006 cur_val = !!CHECK_FLAG(peer->flags, pa->u.flag);
1007 cur_ovrd = !!CHECK_FLAG(peer->flags_override, pa->u.flag);
1008 cur_inv = !!CHECK_FLAG(peer->flags_invert, pa->u.flag);
1009 } else /* if (pa->type == PEER_AT_AF_FLAG) */ {
1010 cur_val = !!CHECK_FLAG(peer->af_flags[pa->afi][pa->safi],
1011 pa->u.flag);
1012 cur_ovrd = !!CHECK_FLAG(
1013 peer->af_flags_override[pa->afi][pa->safi], pa->u.flag);
1014 cur_inv = !!CHECK_FLAG(peer->af_flags_invert[pa->afi][pa->safi],
1015 pa->u.flag);
1016 }
1017
1018 /* Assert expected flag states. */
1019 TEST_ASSERT_EQ(test, cur_val, exp_val);
1020 TEST_ASSERT_EQ(test, cur_ovrd, exp_ovrd);
1021 TEST_ASSERT_EQ(test, cur_inv, exp_inv);
1022 }
1023
1024 static void test_af_filter(struct test *test, struct test_peer_attr *pa,
1025 struct peer *peer, bool exp_state, bool exp_ovrd)
1026 {
1027 bool cur_ovrd;
1028 struct bgp_filter *filter;
1029
1030 /* Skip execution if test instance has previously failed. */
1031 if (test->state != TEST_SUCCESS)
1032 return;
1033
1034 /* Fetch and assert current state of override flag. */
1035 cur_ovrd = !!CHECK_FLAG(
1036 peer->filter_override[pa->afi][pa->safi][pa->u.filter.direct],
1037 pa->u.filter.flag);
1038
1039 TEST_ASSERT_EQ(test, cur_ovrd, exp_ovrd);
1040
1041 /* Assert that map/list matches expected state (set/unset). */
1042 filter = &peer->filter[pa->afi][pa->safi];
1043
1044 switch (pa->u.filter.flag) {
1045 case PEER_FT_DISTRIBUTE_LIST:
1046 TEST_ASSERT_EQ(test,
1047 !!(filter->dlist[pa->u.filter.direct].name),
1048 exp_state);
1049 break;
1050 case PEER_FT_FILTER_LIST:
1051 TEST_ASSERT_EQ(test,
1052 !!(filter->aslist[pa->u.filter.direct].name),
1053 exp_state);
1054 break;
1055 case PEER_FT_PREFIX_LIST:
1056 TEST_ASSERT_EQ(test,
1057 !!(filter->plist[pa->u.filter.direct].name),
1058 exp_state);
1059 break;
1060 case PEER_FT_ROUTE_MAP:
1061 TEST_ASSERT_EQ(test, !!(filter->map[pa->u.filter.direct].name),
1062 exp_state);
1063 break;
1064 case PEER_FT_UNSUPPRESS_MAP:
1065 TEST_ASSERT_EQ(test, !!(filter->usmap.name), exp_state);
1066 break;
1067 }
1068 }
1069
1070 static void test_custom(struct test *test, struct test_peer_attr *pa,
1071 struct peer *peer, struct peer *group, bool peer_set,
1072 bool group_set)
1073 {
1074 int i;
1075 char *handler_error;
1076
1077 for (i = 0; i < TEST_HANDLER_MAX; i++) {
1078 /* Skip execution if test instance has previously failed. */
1079 if (test->state != TEST_SUCCESS)
1080 return;
1081
1082 /* Skip further execution if handler is undefined. */
1083 if (!pa->handlers[i])
1084 return;
1085
1086 /* Execute custom handler. */
1087 pa->handlers[i](test, pa, peer, group, peer_set, group_set);
1088 if (test->state != TEST_SUCCESS) {
1089 test->state = TEST_CUSTOM_ERROR;
1090 handler_error = test->error;
1091 test->error = str_printf("custom handler failed: %s",
1092 handler_error);
1093 XFREE(MTYPE_TMP, handler_error);
1094 }
1095 }
1096 }
1097
1098
1099 static void test_process(struct test *test, struct test_peer_attr *pa,
1100 struct peer *peer, struct peer *group, bool peer_set,
1101 bool group_set)
1102 {
1103 switch (pa->type) {
1104 case PEER_AT_GLOBAL_FLAG:
1105 case PEER_AT_AF_FLAG:
1106 test_peer_flags(
1107 test, pa, peer,
1108 peer_set || (peer_group_active(peer) && group_set),
1109 peer_set);
1110 test_peer_flags(test, pa, group, group_set, false);
1111 break;
1112
1113 case PEER_AT_AF_FILTER:
1114 test_af_filter(
1115 test, pa, peer,
1116 peer_set || (peer_group_active(peer) && group_set),
1117 peer_set);
1118 test_af_filter(test, pa, group, group_set, false);
1119 break;
1120
1121 case PEER_AT_GLOBAL_CUSTOM:
1122 case PEER_AT_AF_CUSTOM:
1123 /*
1124 * Do nothing here - a custom handler can be executed, but this
1125 * is not required. This will allow defining peer attributes
1126 * which shall not be checked for flag/filter/other internal
1127 * states.
1128 */
1129 break;
1130
1131 default:
1132 test->state = TEST_INTERNAL_ERROR;
1133 test->error =
1134 str_printf("invalid attribute type: %d", pa->type);
1135 break;
1136 }
1137
1138 /* Attempt to call a custom handler if set for further processing. */
1139 test_custom(test, pa, peer, group, peer_set, group_set);
1140 }
1141
1142 static void test_peer_attr(struct test *test, struct test_peer_attr *pa)
1143 {
1144 int tc = 1;
1145 const char *type;
1146 const char *ecp = pa->o.invert_peer ? "no " : "";
1147 const char *dcp = pa->o.invert_peer ? "" : "no ";
1148 const char *ecg = pa->o.invert_group ? "no " : "";
1149 const char *dcg = pa->o.invert_group ? "" : "no ";
1150 const char *peer_cmd = pa->peer_cmd ?: pa->cmd;
1151 const char *group_cmd = pa->group_cmd ?: pa->cmd;
1152 struct peer *p = test->peer;
1153 struct peer_group *g = test->group;
1154
1155 /* Determine type and if test is address-family relevant */
1156 type = str_from_attr_type(pa->type);
1157 if (!type) {
1158 test->state = TEST_INTERNAL_ERROR;
1159 test->error =
1160 str_printf("invalid attribute type: %d", pa->type);
1161 return;
1162 }
1163
1164 /*
1165 * =====================================================================
1166 * Test Case Suite 1: Config persistence after adding peer to group
1167 *
1168 * Example: If a peer attribute has value [1] and a group attribute has
1169 * value [2], the peer attribute value should be persisted when the peer
1170 * gets added to the peer-group.
1171 *
1172 * This test suite is meant to test the group2peer functions which can
1173 * be found inside bgpd/bgpd.c, which are related to initial peer-group
1174 * inheritance.
1175 * =====================================================================
1176 */
1177
1178 /* Test Preparation: Switch and activate address-family. */
1179 if (!is_attr_type_global(pa->type)) {
1180 test_log(test, "prepare: switch address-family to [%s]",
1181 get_afi_safi_str(pa->afi, pa->safi, false));
1182 test_execute(test, "address-family %s %s",
1183 str_from_afi(pa->afi), str_from_safi(pa->safi));
1184 test_execute(test, "neighbor %s activate", g->name);
1185 test_execute(test, "neighbor %s activate", p->host);
1186 }
1187
1188 /* Skip peer-group to peer transfer test cases if requested. */
1189 if (pa->o.skip_xfer_cases && test->state == TEST_SUCCESS)
1190 test->state = TEST_SKIPPING;
1191
1192 /* Test Case: Set flag on BGP peer. */
1193 test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd,
1194 p->host);
1195 test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1196 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1197 test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
1198 test_process(test, pa, p, g->conf, true, false);
1199
1200 /* Test Case: Set flag on BGP peer-group. */
1201 test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
1202 g->name);
1203 test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1204 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1205 test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1206 test_process(test, pa, p, g->conf, true, true);
1207
1208 /* Test Case: Add BGP peer to peer-group. */
1209 test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host,
1210 g->name);
1211 test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
1212 test_config_present(test, "neighbor %s %speer-group %s", p->host,
1213 p->conf_if ? "interface " : "", g->name);
1214 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1215 test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1216 test_process(test, pa, p, g->conf, true, true);
1217
1218 /* Test Case: Unset flag on BGP peer-group. */
1219 test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type,
1220 group_cmd, g->name);
1221 test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd);
1222 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1223 test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
1224 test_process(test, pa, p, g->conf, true, false);
1225
1226 /*
1227 * =====================================================================
1228 * Test Case Suite 2: Config inheritance after adding peer to group
1229 *
1230 * Example: If a peer attribute has not been set and a group attribute
1231 * has a value of [2], the group attribute should be inherited to the
1232 * peer without flagging the newly set value as overridden.
1233 *
1234 * This test suite is meant to test the group2peer functions which can
1235 * be found inside bgpd/bgpd.c, which are related to initial peer-group
1236 * inheritance.
1237 * =====================================================================
1238 */
1239
1240 /* Test Preparation: Re-initialize test environment. */
1241 test_initialize(test);
1242 p = test->peer;
1243 g = test->group;
1244
1245 /* Test Preparation: Switch and activate address-family. */
1246 if (!is_attr_type_global(pa->type)) {
1247 test_log(test, "prepare: switch address-family to [%s]",
1248 get_afi_safi_str(pa->afi, pa->safi, false));
1249 test_execute(test, "address-family %s %s",
1250 str_from_afi(pa->afi), str_from_safi(pa->safi));
1251 test_execute(test, "neighbor %s activate", g->name);
1252 test_execute(test, "neighbor %s activate", p->host);
1253 }
1254
1255 /* Test Case: Set flag on BGP peer-group. */
1256 test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
1257 g->name);
1258 test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1259 test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
1260 test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1261 test_process(test, pa, p, g->conf, false, true);
1262
1263 /* Test Case: Add BGP peer to peer-group. */
1264 test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host,
1265 g->name);
1266 test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
1267 test_config_present(test, "neighbor %s %speer-group %s", p->host,
1268 p->conf_if ? "interface " : "", g->name);
1269 test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
1270 test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1271 test_process(test, pa, p, g->conf, false, true);
1272
1273 /* Stop skipping test cases if previously enabled. */
1274 if (pa->o.skip_xfer_cases && test->state == TEST_SKIPPING)
1275 test->state = TEST_SUCCESS;
1276
1277 /*
1278 * =====================================================================
1279 * Test Case Suite 3: Miscellaneous flag checks
1280 *
1281 * This test suite does not focus on initial peer-group inheritance and
1282 * instead executes various different commands to set/unset attributes
1283 * on both peer- and group-level. These checks should always be executed
1284 * and must pass.
1285 * =====================================================================
1286 */
1287
1288 /* Test Preparation: Re-initialize test environment. */
1289 test_initialize(test);
1290 p = test->peer;
1291 g = test->group;
1292
1293 /* Test Preparation: Switch and activate address-family. */
1294 if (!is_attr_type_global(pa->type)) {
1295 test_log(test, "prepare: switch address-family to [%s]",
1296 get_afi_safi_str(pa->afi, pa->safi, false));
1297 test_execute(test, "address-family %s %s",
1298 str_from_afi(pa->afi), str_from_safi(pa->safi));
1299 test_execute(test, "neighbor %s activate", g->name);
1300 test_execute(test, "neighbor %s activate", p->host);
1301 }
1302
1303 /* Test Case: Set flag on BGP peer. */
1304 test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd,
1305 p->host);
1306 test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1307 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1308 test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
1309 test_process(test, pa, p, g->conf, true, false);
1310
1311 /* Test Case: Add BGP peer to peer-group. */
1312 test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host,
1313 g->name);
1314 test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
1315 test_config_present(test, "neighbor %s %speer-group %s", p->host,
1316 p->conf_if ? "interface " : "", g->name);
1317 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1318 test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
1319 test_process(test, pa, p, g->conf, true, false);
1320
1321 /* Test Case: Re-add BGP peer to peer-group. */
1322 test_log(test, "case %02d: re-add peer [%s] to group [%s]", tc++,
1323 p->host, g->name);
1324 test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
1325 test_config_present(test, "neighbor %s %speer-group %s", p->host,
1326 p->conf_if ? "interface " : "", g->name);
1327 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1328 test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
1329 test_process(test, pa, p, g->conf, true, false);
1330
1331 /* Test Case: Set flag on BGP peer-group. */
1332 test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
1333 g->name);
1334 test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1335 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1336 test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1337 test_process(test, pa, p, g->conf, true, true);
1338
1339 /* Test Case: Unset flag on BGP peer-group. */
1340 test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type,
1341 group_cmd, g->name);
1342 test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd);
1343 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1344 test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
1345 test_process(test, pa, p, g->conf, true, false);
1346
1347 /* Test Case: Set flag on BGP peer-group. */
1348 test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
1349 g->name);
1350 test_execute(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1351 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1352 test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1353 test_process(test, pa, p, g->conf, true, true);
1354
1355 /* Test Case: Re-set flag on BGP peer. */
1356 test_log(test, "case %02d: re-set %s [%s] on [%s]", tc++, type,
1357 peer_cmd, p->host);
1358 test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1359 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1360 test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1361 test_process(test, pa, p, g->conf, true, true);
1362
1363 /* Test Case: Unset flag on BGP peer. */
1364 test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type, peer_cmd,
1365 p->host);
1366 test_execute(test, "%sneighbor %s %s", dcp, p->host, peer_cmd);
1367 test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
1368 test_config_present(test, "%sneighbor %s %s", ecg, g->name, group_cmd);
1369 test_process(test, pa, p, g->conf, false, true);
1370
1371 /* Test Case: Unset flag on BGP peer-group. */
1372 test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type,
1373 group_cmd, g->name);
1374 test_execute(test, "%sneighbor %s %s", dcg, g->name, group_cmd);
1375 test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
1376 test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
1377 test_process(test, pa, p, g->conf, false, false);
1378
1379 /* Test Case: Set flag on BGP peer. */
1380 test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd,
1381 p->host);
1382 test_execute(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1383 test_config_present(test, "%sneighbor %s %s", ecp, p->host, peer_cmd);
1384 test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
1385 test_process(test, pa, p, g->conf, true, false);
1386 }
1387
1388 static const struct frr_yang_module_info *const bgpd_yang_modules[] = {
1389 &frr_bgp_info,
1390 &frr_filter_info,
1391 &frr_interface_info,
1392 &frr_route_map_info,
1393 &frr_routing_info,
1394 &frr_vrf_info,
1395 };
1396
1397 static void bgp_startup(void)
1398 {
1399 cmd_init(1);
1400 zlog_aux_init("NONE: ", LOG_DEBUG);
1401 zprivs_preinit(&bgpd_privs);
1402 zprivs_init(&bgpd_privs);
1403
1404 master = thread_master_create(NULL);
1405 nb_init(master, bgpd_yang_modules, array_size(bgpd_yang_modules), false);
1406 bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
1407 bgp_option_set(BGP_OPT_NO_LISTEN);
1408 vrf_init(NULL, NULL, NULL, NULL, NULL);
1409 frr_pthread_init();
1410 bgp_init(0);
1411 bgp_pthreads_run();
1412 }
1413
1414 static void bgp_shutdown(void)
1415 {
1416 struct bgp *bgp;
1417 struct listnode *node, *nnode;
1418
1419 bgp_terminate();
1420 bgp_close();
1421 for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
1422 bgp_delete(bgp);
1423 bgp_dump_finish();
1424 bgp_route_finish();
1425 bgp_route_map_terminate();
1426 bgp_attr_finish();
1427 bgp_pthreads_finish();
1428 access_list_add_hook(NULL);
1429 access_list_delete_hook(NULL);
1430 access_list_reset();
1431 as_list_add_hook(NULL);
1432 as_list_delete_hook(NULL);
1433 bgp_filter_reset();
1434 prefix_list_add_hook(NULL);
1435 prefix_list_delete_hook(NULL);
1436 prefix_list_reset();
1437 community_list_terminate(bgp_clist);
1438 vrf_terminate();
1439 #ifdef ENABLE_BGP_VNC
1440 vnc_zebra_destroy();
1441 #endif
1442 bgp_zebra_destroy();
1443
1444 bf_free(bm->rd_idspace);
1445 list_delete(&bm->bgp);
1446 memset(bm, 0, sizeof(*bm));
1447
1448 vty_terminate();
1449 cmd_terminate();
1450 nb_terminate();
1451 yang_terminate();
1452 zprivs_terminate(&bgpd_privs);
1453 thread_master_free(master);
1454 master = NULL;
1455 }
1456
1457 int main(void)
1458 {
1459 int i, ii;
1460 struct list *pa_list;
1461 struct test_peer_attr *pa, *pac;
1462 struct listnode *node, *nnode;
1463
1464 bgp_startup();
1465
1466 pa_list = list_new();
1467 i = 0;
1468 while (test_peer_attrs[i].cmd) {
1469 pa = &test_peer_attrs[i++];
1470
1471 /* Just copy the peer attribute structure for global flags. */
1472 if (is_attr_type_global(pa->type)) {
1473 pac = XMALLOC(MTYPE_TMP, sizeof(struct test_peer_attr));
1474 memcpy(pac, pa, sizeof(struct test_peer_attr));
1475 listnode_add(pa_list, pac);
1476 continue;
1477 }
1478
1479 /* Fallback to default families if not specified. */
1480 if (!pa->families[0].afi && !pa->families[0].safi)
1481 memcpy(&pa->families, test_default_families,
1482 sizeof(test_default_families));
1483
1484 /* Add peer attribute definition for each address family. */
1485 ii = 0;
1486 while (pa->families[ii].afi && pa->families[ii].safi) {
1487 pac = XMALLOC(MTYPE_TMP, sizeof(struct test_peer_attr));
1488 memcpy(pac, pa, sizeof(struct test_peer_attr));
1489
1490 pac->afi = pa->families[ii].afi;
1491 pac->safi = pa->families[ii].safi;
1492 listnode_add(pa_list, pac);
1493
1494 ii++;
1495 }
1496 }
1497
1498 for (ALL_LIST_ELEMENTS(pa_list, node, nnode, pa)) {
1499 char *desc;
1500 struct test *test;
1501
1502 /* Build test description string. */
1503 if (pa->afi && pa->safi)
1504 desc = str_printf("peer\\%s-%s\\%s",
1505 str_from_afi(pa->afi),
1506 str_from_safi(pa->safi), pa->cmd);
1507 else
1508 desc = str_printf("peer\\%s", pa->cmd);
1509
1510 /* Initialize new test instance. */
1511 test = test_new(desc, pa->o.use_ibgp, pa->o.use_iface_peer);
1512 XFREE(MTYPE_TMP, desc);
1513
1514 /* Execute tests and finish test instance. */
1515 test_peer_attr(test, pa);
1516 test_finish(test);
1517
1518 /* Print empty line as spacer. */
1519 printf("\n");
1520
1521 /* Free memory used for peer-attr declaration. */
1522 XFREE(MTYPE_TMP, pa);
1523 }
1524
1525 list_delete(&pa_list);
1526 bgp_shutdown();
1527
1528 return 0;
1529 }