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