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