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