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