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