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