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