2 * BGP Peer Attribute Unit Tests
3 * Copyright (C) 2018 Pascal Mathis
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)
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
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
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"
34 #include "bgpd/rfapi/rfapi_backend.h"
37 /* Required variables to link in libbgp */
38 struct zebra_privs_t bgpd_privs
= {0};
39 struct thread_master
*master
;
51 enum test_peer_attr_type
{
53 PEER_AT_AF_FILTER
= 1,
54 PEER_AT_AF_CUSTOM
= 2,
55 PEER_AT_GLOBAL_FLAG
= 3,
56 PEER_AT_GLOBAL_CUSTOM
= 4
60 enum test_state state
;
68 struct peer_group
*group
;
79 const char *peer_address
;
80 const char *peer_interface
;
81 const char *peer_group
;
84 struct test_peer_family
{
89 struct test_peer_attr
{
92 const char *group_cmd
;
94 enum test_peer_attr_type type
;
107 bool skip_xfer_cases
;
112 struct test_peer_family families
[AFI_MAX
* SAFI_MAX
];
114 void (*custom_handler
)(struct test
*test
, struct peer
*peer
,
115 struct peer
*group
, bool peer_set
,
119 #define OUT_SYMBOL_INFO "\u25ba"
120 #define OUT_SYMBOL_OK "\u2714"
121 #define OUT_SYMBOL_NOK "\u2716"
123 #define TEST_ASSERT_EQ(T, A, B) \
125 if ((T)->state != TEST_SUCCESS || ((A) == (B))) \
127 (T)->state = TEST_ASSERT_ERROR; \
128 (T)->error = str_printf( \
129 "assertion failed: %s[%d] == [%d]%s (%s:%d)", (#A), \
130 (A), (B), (#B), __FILE__, __LINE__); \
133 static struct test_config cfg
= {
136 .peer_address
= "1.1.1.1",
137 .peer_interface
= "IP-TEST",
138 .peer_group
= "PG-TEST",
141 static struct test_peer_family test_default_families
[] = {
142 {.afi
= AFI_IP
, .safi
= SAFI_UNICAST
},
143 {.afi
= AFI_IP
, .safi
= SAFI_MULTICAST
},
144 {.afi
= AFI_IP6
, .safi
= SAFI_UNICAST
},
145 {.afi
= AFI_IP6
, .safi
= SAFI_MULTICAST
},
148 static char *str_vprintf(const char *fmt
, va_list ap
)
157 ret
= vsnprintf(buf
, buf_size
, fmt
, apc
);
160 if (ret
>= 0 && ret
< buf_size
)
168 buf
= XREALLOC(MTYPE_TMP
, buf
, buf_size
);
174 static char *str_printf(const char *fmt
, ...)
180 buf
= str_vprintf(fmt
, ap
);
186 /* clang-format off */
187 static struct test_peer_attr test_peer_attrs
[] = {
188 /* Peer Attributes */
190 .cmd
= "advertisement-interval",
191 .peer_cmd
= "advertisement-interval 10",
192 .group_cmd
= "advertisement-interval 20",
193 .u
.flag
= PEER_FLAG_ROUTEADV
,
194 .type
= PEER_AT_GLOBAL_FLAG
,
197 .cmd
= "capability dynamic",
198 .u
.flag
= PEER_FLAG_DYNAMIC_CAPABILITY
,
199 .type
= PEER_AT_GLOBAL_FLAG
,
202 .cmd
= "capability extended-nexthop",
203 .u
.flag
= PEER_FLAG_CAPABILITY_ENHE
,
204 .type
= PEER_AT_GLOBAL_FLAG
,
207 .cmd
= "capability extended-nexthop",
208 .u
.flag
= PEER_FLAG_CAPABILITY_ENHE
,
209 .type
= PEER_AT_GLOBAL_FLAG
,
210 .o
.invert_peer
= true,
211 .o
.use_iface_peer
= true,
214 .cmd
= "description",
215 .peer_cmd
= "description FRR Peer",
216 .group_cmd
= "description FRR Group",
217 .type
= PEER_AT_GLOBAL_CUSTOM
,
220 .cmd
= "disable-connected-check",
221 .u
.flag
= PEER_FLAG_DISABLE_CONNECTED_CHECK
,
222 .type
= PEER_AT_GLOBAL_FLAG
,
225 .cmd
= "dont-capability-negotiate",
226 .u
.flag
= PEER_FLAG_DONT_CAPABILITY
,
227 .type
= PEER_AT_GLOBAL_FLAG
,
230 .cmd
= "enforce-first-as",
231 .u
.flag
= PEER_FLAG_ENFORCE_FIRST_AS
,
232 .type
= PEER_AT_GLOBAL_FLAG
,
236 .peer_cmd
= "local-as 1",
237 .group_cmd
= "local-as 2",
238 .type
= PEER_AT_GLOBAL_CUSTOM
,
241 .cmd
= "local-as 1 no-prepend",
242 .u
.flag
= PEER_FLAG_LOCAL_AS_NO_PREPEND
,
243 .type
= PEER_AT_GLOBAL_FLAG
,
246 .cmd
= "local-as 1 no-prepend replace-as",
247 .u
.flag
= PEER_FLAG_LOCAL_AS_REPLACE_AS
,
248 .type
= PEER_AT_GLOBAL_FLAG
,
251 .cmd
= "override-capability",
252 .u
.flag
= PEER_FLAG_OVERRIDE_CAPABILITY
,
253 .type
= PEER_AT_GLOBAL_FLAG
,
257 .u
.flag
= PEER_FLAG_PASSIVE
,
258 .type
= PEER_AT_GLOBAL_FLAG
,
262 .peer_cmd
= "password FRR-Peer",
263 .group_cmd
= "password FRR-Group",
264 .type
= PEER_AT_GLOBAL_CUSTOM
,
268 .u
.flag
= PEER_FLAG_SHUTDOWN
,
269 .type
= PEER_AT_GLOBAL_FLAG
,
272 .cmd
= "strict-capability-match",
273 .u
.flag
= PEER_FLAG_STRICT_CAP_MATCH
,
274 .type
= PEER_AT_GLOBAL_FLAG
,
278 .peer_cmd
= "timers 10 30",
279 .group_cmd
= "timers 20 60",
280 .u
.flag
= PEER_FLAG_TIMER
,
281 .type
= PEER_AT_GLOBAL_FLAG
,
284 .cmd
= "timers connect",
285 .peer_cmd
= "timers connect 10",
286 .group_cmd
= "timers connect 20",
287 .u
.flag
= PEER_FLAG_TIMER_CONNECT
,
288 .type
= PEER_AT_GLOBAL_FLAG
,
291 .cmd
= "update-source",
292 .peer_cmd
= "update-source 255.255.255.1",
293 .group_cmd
= "update-source 255.255.255.2",
294 .type
= PEER_AT_GLOBAL_CUSTOM
,
297 .cmd
= "update-source",
298 .peer_cmd
= "update-source IFACE-PEER",
299 .group_cmd
= "update-source IFACE-GROUP",
300 .type
= PEER_AT_GLOBAL_CUSTOM
,
303 /* Address Family Attributes */
305 .cmd
= "addpath-tx-all-paths",
306 .u
.flag
= PEER_FLAG_ADDPATH_TX_ALL_PATHS
,
309 .cmd
= "addpath-tx-bestpath-per-AS",
310 .u
.flag
= PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS
,
314 .peer_cmd
= "allowas-in 1",
315 .group_cmd
= "allowas-in 2",
316 .u
.flag
= PEER_FLAG_ALLOWAS_IN
,
319 .cmd
= "allowas-in origin",
320 .u
.flag
= PEER_FLAG_ALLOWAS_IN_ORIGIN
,
323 .cmd
= "as-override",
324 .u
.flag
= PEER_FLAG_AS_OVERRIDE
,
327 .cmd
= "attribute-unchanged as-path",
328 .u
.flag
= PEER_FLAG_AS_PATH_UNCHANGED
,
331 .cmd
= "attribute-unchanged next-hop",
332 .u
.flag
= PEER_FLAG_NEXTHOP_UNCHANGED
,
335 .cmd
= "attribute-unchanged med",
336 .u
.flag
= PEER_FLAG_MED_UNCHANGED
,
339 .cmd
= "attribute-unchanged as-path next-hop",
340 .u
.flag
= PEER_FLAG_AS_PATH_UNCHANGED
341 | PEER_FLAG_NEXTHOP_UNCHANGED
,
344 .cmd
= "attribute-unchanged as-path med",
345 .u
.flag
= PEER_FLAG_AS_PATH_UNCHANGED
346 | PEER_FLAG_MED_UNCHANGED
,
349 .cmd
= "attribute-unchanged as-path next-hop med",
350 .u
.flag
= PEER_FLAG_AS_PATH_UNCHANGED
351 | PEER_FLAG_NEXTHOP_UNCHANGED
352 | PEER_FLAG_MED_UNCHANGED
,
355 .cmd
= "capability orf prefix-list send",
356 .u
.flag
= PEER_FLAG_ORF_PREFIX_SM
,
359 .cmd
= "capability orf prefix-list receive",
360 .u
.flag
= PEER_FLAG_ORF_PREFIX_RM
,
363 .cmd
= "capability orf prefix-list both",
364 .u
.flag
= PEER_FLAG_ORF_PREFIX_SM
| PEER_FLAG_ORF_PREFIX_RM
,
367 .cmd
= "default-originate",
368 .u
.flag
= PEER_FLAG_DEFAULT_ORIGINATE
,
371 .cmd
= "default-originate route-map",
372 .peer_cmd
= "default-originate route-map RM-PEER",
373 .group_cmd
= "default-originate route-map RM-GROUP",
374 .u
.flag
= PEER_FLAG_DEFAULT_ORIGINATE
,
377 .cmd
= "distribute-list",
378 .peer_cmd
= "distribute-list FL-PEER in",
379 .group_cmd
= "distribute-list FL-GROUP in",
380 .type
= PEER_AT_AF_FILTER
,
381 .u
.filter
.flag
= PEER_FT_DISTRIBUTE_LIST
,
382 .u
.filter
.direct
= FILTER_IN
,
385 .cmd
= "distribute-list",
386 .peer_cmd
= "distribute-list FL-PEER out",
387 .group_cmd
= "distribute-list FL-GROUP out",
388 .type
= PEER_AT_AF_FILTER
,
389 .u
.filter
.flag
= PEER_FT_DISTRIBUTE_LIST
,
390 .u
.filter
.direct
= FILTER_OUT
,
393 .cmd
= "filter-list",
394 .peer_cmd
= "filter-list FL-PEER in",
395 .group_cmd
= "filter-list FL-GROUP in",
396 .type
= PEER_AT_AF_FILTER
,
397 .u
.filter
.flag
= PEER_FT_FILTER_LIST
,
398 .u
.filter
.direct
= FILTER_IN
,
401 .cmd
= "filter-list",
402 .peer_cmd
= "filter-list FL-PEER out",
403 .group_cmd
= "filter-list FL-GROUP out",
404 .type
= PEER_AT_AF_FILTER
,
405 .u
.filter
.flag
= PEER_FT_FILTER_LIST
,
406 .u
.filter
.direct
= FILTER_OUT
,
409 .cmd
= "maximum-prefix",
410 .peer_cmd
= "maximum-prefix 10",
411 .group_cmd
= "maximum-prefix 20",
412 .u
.flag
= PEER_FLAG_MAX_PREFIX
,
415 .cmd
= "maximum-prefix",
416 .peer_cmd
= "maximum-prefix 10 restart 100",
417 .group_cmd
= "maximum-prefix 20 restart 200",
418 .u
.flag
= PEER_FLAG_MAX_PREFIX
,
421 .cmd
= "maximum-prefix",
422 .peer_cmd
= "maximum-prefix 10 1 restart 100",
423 .group_cmd
= "maximum-prefix 20 2 restart 200",
424 .u
.flag
= PEER_FLAG_MAX_PREFIX
,
427 .cmd
= "maximum-prefix",
428 .peer_cmd
= "maximum-prefix 10 warning-only",
429 .group_cmd
= "maximum-prefix 20 warning-only",
430 .u
.flag
= PEER_FLAG_MAX_PREFIX
| PEER_FLAG_MAX_PREFIX_WARNING
,
433 .cmd
= "maximum-prefix",
434 .peer_cmd
= "maximum-prefix 10 1 warning-only",
435 .group_cmd
= "maximum-prefix 20 2 warning-only",
436 .u
.flag
= PEER_FLAG_MAX_PREFIX
| PEER_FLAG_MAX_PREFIX_WARNING
,
439 .cmd
= "next-hop-self",
440 .u
.flag
= PEER_FLAG_NEXTHOP_SELF
,
443 .cmd
= "next-hop-self force",
444 .u
.flag
= PEER_FLAG_FORCE_NEXTHOP_SELF
,
447 .cmd
= "prefix-list",
448 .peer_cmd
= "prefix-list PL-PEER in",
449 .group_cmd
= "prefix-list PL-GROUP in",
450 .type
= PEER_AT_AF_FILTER
,
451 .u
.filter
.flag
= PEER_FT_PREFIX_LIST
,
452 .u
.filter
.direct
= FILTER_IN
,
455 .cmd
= "prefix-list",
456 .peer_cmd
= "prefix-list PL-PEER out",
457 .group_cmd
= "prefix-list PL-GROUP out",
458 .type
= PEER_AT_AF_FILTER
,
459 .u
.filter
.flag
= PEER_FT_PREFIX_LIST
,
460 .u
.filter
.direct
= FILTER_OUT
,
463 .cmd
= "remove-private-AS",
464 .u
.flag
= PEER_FLAG_REMOVE_PRIVATE_AS
,
467 .cmd
= "remove-private-AS all",
468 .u
.flag
= PEER_FLAG_REMOVE_PRIVATE_AS
469 | PEER_FLAG_REMOVE_PRIVATE_AS_ALL
,
472 .cmd
= "remove-private-AS replace-AS",
473 .u
.flag
= PEER_FLAG_REMOVE_PRIVATE_AS
474 | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE
,
477 .cmd
= "remove-private-AS all replace-AS",
478 .u
.flag
= PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE
,
482 .peer_cmd
= "route-map RM-PEER in",
483 .group_cmd
= "route-map RM-GROUP in",
484 .type
= PEER_AT_AF_FILTER
,
485 .u
.filter
.flag
= PEER_FT_ROUTE_MAP
,
486 .u
.filter
.direct
= FILTER_IN
,
490 .peer_cmd
= "route-map RM-PEER out",
491 .group_cmd
= "route-map RM-GROUP out",
492 .type
= PEER_AT_AF_FILTER
,
493 .u
.filter
.flag
= PEER_FT_ROUTE_MAP
,
494 .u
.filter
.direct
= FILTER_OUT
,
497 .cmd
= "route-reflector-client",
498 .u
.flag
= PEER_FLAG_REFLECTOR_CLIENT
,
500 .o
.skip_xfer_cases
= true,
503 .cmd
= "route-server-client",
504 .u
.flag
= PEER_FLAG_RSERVER_CLIENT
,
507 .cmd
= "send-community",
508 .u
.flag
= PEER_FLAG_SEND_COMMUNITY
,
509 .o
.invert_peer
= true,
510 .o
.invert_group
= true,
513 .cmd
= "send-community extended",
514 .u
.flag
= PEER_FLAG_SEND_EXT_COMMUNITY
,
515 .o
.invert_peer
= true,
516 .o
.invert_group
= true,
519 .cmd
= "send-community large",
520 .u
.flag
= PEER_FLAG_SEND_LARGE_COMMUNITY
,
521 .o
.invert_peer
= true,
522 .o
.invert_group
= true,
525 .cmd
= "soft-reconfiguration inbound",
526 .u
.flag
= PEER_FLAG_SOFT_RECONFIG
,
529 .cmd
= "unsuppress-map",
530 .peer_cmd
= "unsuppress-map UM-PEER",
531 .group_cmd
= "unsuppress-map UM-GROUP",
532 .type
= PEER_AT_AF_FILTER
,
533 .u
.filter
.flag
= PEER_FT_UNSUPPRESS_MAP
,
534 .u
.filter
.direct
= 0,
538 .peer_cmd
= "weight 100",
539 .group_cmd
= "weight 200",
540 .u
.flag
= PEER_FLAG_WEIGHT
,
544 /* clang-format on */
546 static const char *str_from_afi(afi_t afi
)
554 return "<unknown AFI>";
558 static const char *str_from_safi(safi_t safi
)
566 return "<unknown SAFI>";
570 static const char *str_from_attr_type(enum test_peer_attr_type at
)
573 case PEER_AT_GLOBAL_FLAG
:
575 case PEER_AT_AF_FLAG
:
577 case PEER_AT_AF_FILTER
:
579 case PEER_AT_GLOBAL_CUSTOM
:
580 case PEER_AT_AF_CUSTOM
:
587 static bool is_attr_type_global(enum test_peer_attr_type at
)
589 return at
== PEER_AT_GLOBAL_FLAG
|| at
== PEER_AT_GLOBAL_CUSTOM
;
592 static void test_log(struct test
*test
, const char *fmt
, ...)
596 /* Skip logging if test instance has previously failed. */
597 if (test
->state
!= TEST_SUCCESS
)
600 /* Store formatted log message. */
602 listnode_add(test
->log
, str_vprintf(fmt
, ap
));
606 static void test_execute(struct test
*test
, const char *fmt
, ...)
613 /* Skip execution if test instance has previously failed. */
614 if (test
->state
!= TEST_SUCCESS
)
617 /* Format command string with variadic arguments. */
619 cmd
= str_vprintf(fmt
, ap
);
622 test
->state
= TEST_INTERNAL_ERROR
;
624 str_printf("could not format command string [%s]", fmt
);
628 /* Tokenize formatted command string. */
629 vline
= cmd_make_strvec(cmd
);
631 test
->state
= TEST_INTERNAL_ERROR
;
632 test
->error
= str_printf(
633 "tokenizing command string [%s] returned empty result",
635 XFREE(MTYPE_TMP
, cmd
);
640 /* Execute command (non-strict). */
641 ret
= cmd_execute_command(vline
, test
->vty
, NULL
, 0);
642 if (ret
!= CMD_SUCCESS
) {
643 test
->state
= TEST_COMMAND_ERROR
;
644 test
->error
= str_printf(
645 "execution of command [%s] has failed with code [%d]",
650 cmd_free_strvec(vline
);
651 XFREE(MTYPE_TMP
, cmd
);
654 static void test_config(struct test
*test
, const char *fmt
, bool invert
,
662 /* Skip execution if test instance has previously failed. */
663 if (test
->state
!= TEST_SUCCESS
)
666 /* Format matcher string with variadic arguments. */
668 matcher
= str_vprintf(fmt
, apc
);
671 test
->state
= TEST_INTERNAL_ERROR
;
673 str_printf("could not format matcher string [%s]", fmt
);
677 /* Fetch BGP configuration into buffer. */
678 bgp_config_write(test
->vty
);
679 config
= buffer_getstr(test
->vty
->obuf
);
680 buffer_reset(test
->vty
->obuf
);
682 /* Match config against matcher. */
683 matched
= !!strstr(config
, matcher
);
684 if (!matched
&& !invert
) {
685 test
->state
= TEST_CONFIG_ERROR
;
686 test
->error
= str_printf("expected config [%s] to be present",
688 } else if (matched
&& invert
) {
689 test
->state
= TEST_CONFIG_ERROR
;
690 test
->error
= str_printf("expected config [%s] to be absent",
694 /* Free memory and return. */
695 XFREE(MTYPE_TMP
, matcher
);
696 XFREE(MTYPE_TMP
, config
);
699 static void test_config_present(struct test
*test
, const char *fmt
, ...)
704 test_config(test
, fmt
, false, ap
);
708 static void test_config_absent(struct test
*test
, const char *fmt
, ...)
713 test_config(test
, fmt
, true, ap
);
717 static void test_initialize(struct test
*test
)
721 /* Skip execution if test instance has previously failed. */
722 if (test
->state
!= TEST_SUCCESS
)
725 /* Log message about (re)-initialization */
726 test_log(test
, "prepare: %sinitialize bgp test environment",
727 test
->bgp
? "re-" : "");
729 /* Attempt gracefully to purge previous BGP configuration. */
730 test_execute(test
, "no router bgp");
731 test
->state
= TEST_SUCCESS
;
733 /* Initialize BGP test environment. */
734 test_execute(test
, "router bgp %d", cfg
.local_asn
);
735 test_execute(test
, "no bgp default ipv4-unicast");
736 test_execute(test
, "neighbor %s peer-group", cfg
.peer_group
);
737 if (test
->o
.use_iface_peer
) {
738 test_execute(test
, "neighbor %s interface", cfg
.peer_interface
);
739 test_execute(test
, "neighbor %s remote-as %d",
741 test
->o
.use_ibgp
? cfg
.local_asn
: cfg
.peer_asn
);
743 test_execute(test
, "neighbor %s remote-as %d", cfg
.peer_address
,
744 test
->o
.use_ibgp
? cfg
.local_asn
: cfg
.peer_asn
);
747 if (test
->state
!= TEST_SUCCESS
)
750 /* Fetch default BGP instance. */
751 test
->bgp
= bgp_get_default();
753 test
->state
= TEST_INTERNAL_ERROR
;
755 str_printf("could not retrieve default bgp instance");
759 /* Fetch peer instance. */
760 if (test
->o
.use_iface_peer
) {
762 peer_lookup_by_conf_if(test
->bgp
, cfg
.peer_interface
);
764 str2sockunion(cfg
.peer_address
, &su
);
765 test
->peer
= peer_lookup(test
->bgp
, &su
);
768 test
->state
= TEST_INTERNAL_ERROR
;
769 test
->error
= str_printf(
770 "could not retrieve instance of bgp peer [%s]",
775 /* Fetch peer-group instance. */
776 test
->group
= peer_group_lookup(test
->bgp
, cfg
.peer_group
);
778 test
->state
= TEST_INTERNAL_ERROR
;
779 test
->error
= str_printf(
780 "could not retrieve instance of bgp peer-group [%s]",
786 static struct test
*test_new(const char *desc
, bool use_ibgp
,
791 test
= XCALLOC(MTYPE_TMP
, sizeof(struct test
));
792 test
->state
= TEST_SUCCESS
;
793 test
->desc
= XSTRDUP(MTYPE_TMP
, desc
);
794 test
->log
= list_new();
795 test
->o
.use_ibgp
= use_ibgp
;
796 test
->o
.use_iface_peer
= use_iface_peer
;
798 test
->vty
= vty_new();
799 test
->vty
->type
= VTY_TERM
;
800 test
->vty
->node
= CONFIG_NODE
;
802 test_initialize(test
);
807 static void test_finish(struct test
*test
)
810 struct listnode
*node
, *nnode
;
812 /* Print test output header. */
813 printf("%s [test] %s\n",
814 (test
->state
== TEST_SUCCESS
) ? OUT_SYMBOL_OK
: OUT_SYMBOL_NOK
,
817 /* Print test log messages. */
818 for (ALL_LIST_ELEMENTS(test
->log
, node
, nnode
, msg
)) {
819 printf("%s %s\n", OUT_SYMBOL_INFO
, msg
);
820 XFREE(MTYPE_TMP
, msg
);
823 /* Print test error message if available. */
824 if (test
->state
!= TEST_SUCCESS
&& test
->error
)
825 printf("%s error: %s\n", OUT_SYMBOL_INFO
, test
->error
);
827 /* Print machine-readable result of test. */
828 printf("%s\n", test
->state
== TEST_SUCCESS
? "OK" : "failed");
830 /* Cleanup allocated memory. */
832 vty_close(test
->vty
);
836 list_delete_and_null(&test
->log
);
838 XFREE(MTYPE_TMP
, test
->desc
);
840 XFREE(MTYPE_TMP
, test
->error
);
841 XFREE(MTYPE_TMP
, test
);
844 static void test_peer_flags(struct test
*test
, struct test_peer_attr
*pa
,
845 struct peer
*peer
, bool exp_val
, bool exp_ovrd
)
847 bool exp_inv
, cur_val
, cur_ovrd
, cur_inv
;
849 /* Skip execution if test instance has previously failed. */
850 if (test
->state
!= TEST_SUCCESS
)
853 /* Detect if flag is meant to be inverted. */
854 if (CHECK_FLAG(peer
->sflags
, PEER_STATUS_GROUP
))
855 exp_inv
= pa
->o
.invert_group
;
857 exp_inv
= pa
->o
.invert_peer
;
859 /* Flip expected value if flag is inverted. */
862 /* Fetch current state of value, override and invert flags. */
863 if (pa
->type
== PEER_AT_GLOBAL_FLAG
) {
864 cur_val
= !!CHECK_FLAG(peer
->flags
, pa
->u
.flag
);
865 cur_ovrd
= !!CHECK_FLAG(peer
->flags_override
, pa
->u
.flag
);
866 cur_inv
= !!CHECK_FLAG(peer
->flags_invert
, pa
->u
.flag
);
867 } else /* if (pa->type == PEER_AT_AF_FLAG) */ {
868 cur_val
= !!CHECK_FLAG(peer
->af_flags
[pa
->afi
][pa
->safi
],
870 cur_ovrd
= !!CHECK_FLAG(
871 peer
->af_flags_override
[pa
->afi
][pa
->safi
], pa
->u
.flag
);
872 cur_inv
= !!CHECK_FLAG(peer
->af_flags_invert
[pa
->afi
][pa
->safi
],
876 /* Assert expected flag states. */
877 TEST_ASSERT_EQ(test
, cur_val
, exp_val
);
878 TEST_ASSERT_EQ(test
, cur_ovrd
, exp_ovrd
);
879 TEST_ASSERT_EQ(test
, cur_inv
, exp_inv
);
882 static void test_af_filter(struct test
*test
, struct test_peer_attr
*pa
,
883 struct peer
*peer
, bool exp_state
, bool exp_ovrd
)
886 struct bgp_filter
*filter
;
888 /* Skip execution if test instance has previously failed. */
889 if (test
->state
!= TEST_SUCCESS
)
892 /* Fetch and assert current state of override flag. */
893 cur_ovrd
= !!CHECK_FLAG(
894 peer
->filter_override
[pa
->afi
][pa
->safi
][pa
->u
.filter
.direct
],
897 TEST_ASSERT_EQ(test
, cur_ovrd
, exp_ovrd
);
899 /* Assert that map/list matches expected state (set/unset). */
900 filter
= &peer
->filter
[pa
->afi
][pa
->safi
];
902 switch (pa
->u
.filter
.flag
) {
903 case PEER_FT_DISTRIBUTE_LIST
:
905 !!(filter
->dlist
[pa
->u
.filter
.direct
].name
),
908 case PEER_FT_FILTER_LIST
:
910 !!(filter
->aslist
[pa
->u
.filter
.direct
].name
),
913 case PEER_FT_PREFIX_LIST
:
915 !!(filter
->plist
[pa
->u
.filter
.direct
].name
),
918 case PEER_FT_ROUTE_MAP
:
919 TEST_ASSERT_EQ(test
, !!(filter
->map
[pa
->u
.filter
.direct
].name
),
922 case PEER_FT_UNSUPPRESS_MAP
:
923 TEST_ASSERT_EQ(test
, !!(filter
->usmap
.name
), exp_state
);
928 static void test_custom(struct test
*test
, struct test_peer_attr
*pa
,
929 struct peer
*peer
, struct peer
*group
, bool peer_set
,
934 /* Skip execution if test instance has previously failed. */
935 if (test
->state
!= TEST_SUCCESS
)
938 /* Skip execution if no custom handler is defined. */
939 if (!pa
->custom_handler
)
942 /* Execute custom handler. */
943 pa
->custom_handler(test
, peer
, group
, peer_set
, group_set
);
944 if (test
->state
!= TEST_SUCCESS
) {
945 test
->state
= TEST_CUSTOM_ERROR
;
946 handler_error
= test
->error
;
948 str_printf("custom handler failed: %s", handler_error
);
949 XFREE(MTYPE_TMP
, handler_error
);
954 static void test_process(struct test
*test
, struct test_peer_attr
*pa
,
955 struct peer
*peer
, struct peer
*group
, bool peer_set
,
959 case PEER_AT_GLOBAL_FLAG
:
960 case PEER_AT_AF_FLAG
:
961 test_peer_flags(test
, pa
, peer
, peer_set
|| group_set
,
963 test_peer_flags(test
, pa
, group
, group_set
, false);
966 case PEER_AT_AF_FILTER
:
967 test_af_filter(test
, pa
, peer
, peer_set
|| group_set
, peer_set
);
968 test_af_filter(test
, pa
, group
, group_set
, false);
971 case PEER_AT_GLOBAL_CUSTOM
:
972 case PEER_AT_AF_CUSTOM
:
974 * Do nothing here - a custom handler can be executed, but this
975 * is not required. This will allow defining peer attributes
976 * which shall not be checked for flag/filter/other internal
982 test
->state
= TEST_INTERNAL_ERROR
;
984 str_printf("invalid attribute type: %d", pa
->type
);
988 /* Attempt to call a custom handler if set for further processing. */
989 test_custom(test
, pa
, peer
, group
, peer_set
, group_set
);
992 static void test_peer_attr(struct test
*test
, struct test_peer_attr
*pa
)
996 const char *ecp
= pa
->o
.invert_peer
? "no " : "";
997 const char *dcp
= pa
->o
.invert_peer
? "" : "no ";
998 const char *ecg
= pa
->o
.invert_group
? "no " : "";
999 const char *dcg
= pa
->o
.invert_group
? "" : "no ";
1000 const char *peer_cmd
= pa
->peer_cmd
?: pa
->cmd
;
1001 const char *group_cmd
= pa
->group_cmd
?: pa
->cmd
;
1002 struct peer
*p
= test
->peer
;
1003 struct peer_group
*g
= test
->group
;
1005 /* Determine type and if test is address-family relevant */
1006 type
= str_from_attr_type(pa
->type
);
1008 test
->state
= TEST_INTERNAL_ERROR
;
1010 str_printf("invalid attribute type: %d", pa
->type
);
1014 /* Test Preparation: Switch and activate address-family. */
1015 if (!is_attr_type_global(pa
->type
)) {
1016 test_log(test
, "prepare: switch address-family to [%s]",
1017 afi_safi_print(pa
->afi
, pa
->safi
));
1018 test_execute(test
, "address-family %s %s",
1019 str_from_afi(pa
->afi
), str_from_safi(pa
->safi
));
1020 test_execute(test
, "neighbor %s activate", g
->name
);
1021 test_execute(test
, "neighbor %s activate", p
->host
);
1024 /* Skip peer-group to peer transfer test cases if requested. */
1025 if (pa
->o
.skip_xfer_cases
&& test
->state
== TEST_SUCCESS
)
1026 test
->state
= TEST_SKIPPING
;
1028 /* Test Case: Set flag on BGP peer. */
1029 test_log(test
, "case %02d: set %s [%s] on [%s]", tc
++, type
, peer_cmd
,
1031 test_execute(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1032 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1033 test_config_absent(test
, "neighbor %s %s", g
->name
, pa
->cmd
);
1034 test_process(test
, pa
, p
, g
->conf
, true, false);
1036 /* Test Case: Set flag on BGP peer-group. */
1037 test_log(test
, "case %02d: set %s [%s] on [%s]", tc
++, type
, group_cmd
,
1039 test_execute(test
, "%sneighbor %s %s", ecg
, g
->name
, group_cmd
);
1040 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1041 test_config_present(test
, "%sneighbor %s %s", ecg
, g
->name
, group_cmd
);
1042 test_process(test
, pa
, p
, g
->conf
, true, true);
1044 /* Test Case: Add BGP peer to peer-group. */
1045 test_log(test
, "case %02d: add peer [%s] to group [%s]", tc
++, p
->host
,
1047 test_execute(test
, "neighbor %s peer-group %s", p
->host
, g
->name
);
1048 test_config_present(test
, "neighbor %s %speer-group %s", p
->host
,
1049 p
->conf_if
? "interface " : "", g
->name
);
1050 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1051 test_config_present(test
, "%sneighbor %s %s", ecg
, g
->name
, group_cmd
);
1052 test_process(test
, pa
, p
, g
->conf
, true, true);
1054 /* Test Case: Unset flag on BGP peer-group. */
1055 test_log(test
, "case %02d: unset %s [%s] on [%s]", tc
++, type
,
1056 group_cmd
, g
->name
);
1057 test_execute(test
, "%sneighbor %s %s", dcg
, g
->name
, group_cmd
);
1058 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1059 test_config_absent(test
, "neighbor %s %s", g
->name
, pa
->cmd
);
1060 test_process(test
, pa
, p
, g
->conf
, true, false);
1062 /* Stop skipping test cases if previously enabled. */
1063 if (pa
->o
.skip_xfer_cases
&& test
->state
== TEST_SKIPPING
)
1064 test
->state
= TEST_SUCCESS
;
1066 /* Test Preparation: Re-initialize test environment. */
1067 test_initialize(test
);
1071 /* Test Preparation: Switch and activate address-family. */
1072 if (!is_attr_type_global(pa
->type
)) {
1073 test_log(test
, "prepare: switch address-family to [%s]",
1074 afi_safi_print(pa
->afi
, pa
->safi
));
1075 test_execute(test
, "address-family %s %s",
1076 str_from_afi(pa
->afi
), str_from_safi(pa
->safi
));
1077 test_execute(test
, "neighbor %s activate", g
->name
);
1078 test_execute(test
, "neighbor %s activate", p
->host
);
1081 /* Test Case: Set flag on BGP peer. */
1082 test_log(test
, "case %02d: set %s [%s] on [%s]", tc
++, type
, peer_cmd
,
1084 test_execute(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1085 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1086 test_config_absent(test
, "neighbor %s %s", g
->name
, pa
->cmd
);
1087 test_process(test
, pa
, p
, g
->conf
, true, false);
1089 /* Test Case: Add BGP peer to peer-group. */
1090 test_log(test
, "case %02d: add peer [%s] to group [%s]", tc
++, p
->host
,
1092 test_execute(test
, "neighbor %s peer-group %s", p
->host
, g
->name
);
1093 test_config_present(test
, "neighbor %s %speer-group %s", p
->host
,
1094 p
->conf_if
? "interface " : "", g
->name
);
1095 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1096 test_config_absent(test
, "neighbor %s %s", g
->name
, pa
->cmd
);
1097 test_process(test
, pa
, p
, g
->conf
, true, false);
1099 /* Test Case: Re-add BGP peer to peer-group. */
1100 test_log(test
, "case %02d: re-add peer [%s] to group [%s]", tc
++,
1102 test_execute(test
, "neighbor %s peer-group %s", p
->host
, g
->name
);
1103 test_config_present(test
, "neighbor %s %speer-group %s", p
->host
,
1104 p
->conf_if
? "interface " : "", g
->name
);
1105 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1106 test_config_absent(test
, "neighbor %s %s", g
->name
, pa
->cmd
);
1107 test_process(test
, pa
, p
, g
->conf
, true, false);
1109 /* Test Case: Set flag on BGP peer-group. */
1110 test_log(test
, "case %02d: set %s [%s] on [%s]", tc
++, type
, group_cmd
,
1112 test_execute(test
, "%sneighbor %s %s", ecg
, g
->name
, group_cmd
);
1113 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1114 test_config_present(test
, "%sneighbor %s %s", ecg
, g
->name
, group_cmd
);
1115 test_process(test
, pa
, p
, g
->conf
, true, true);
1117 /* Test Case: Unset flag on BGP peer-group. */
1118 test_log(test
, "case %02d: unset %s [%s] on [%s]", tc
++, type
,
1119 group_cmd
, g
->name
);
1120 test_execute(test
, "%sneighbor %s %s", dcg
, g
->name
, group_cmd
);
1121 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1122 test_config_absent(test
, "neighbor %s %s", g
->name
, pa
->cmd
);
1123 test_process(test
, pa
, p
, g
->conf
, true, false);
1125 /* Test Case: Set flag on BGP peer-group. */
1126 test_log(test
, "case %02d: set %s [%s] on [%s]", tc
++, type
, group_cmd
,
1128 test_execute(test
, "%sneighbor %s %s", ecg
, g
->name
, group_cmd
);
1129 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1130 test_config_present(test
, "%sneighbor %s %s", ecg
, g
->name
, group_cmd
);
1131 test_process(test
, pa
, p
, g
->conf
, true, true);
1133 /* Test Case: Re-set flag on BGP peer. */
1134 test_log(test
, "case %02d: re-set %s [%s] on [%s]", tc
++, type
,
1136 test_execute(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1137 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1138 test_config_present(test
, "%sneighbor %s %s", ecg
, g
->name
, group_cmd
);
1139 test_process(test
, pa
, p
, g
->conf
, true, true);
1141 /* Test Case: Unset flag on BGP peer. */
1142 test_log(test
, "case %02d: unset %s [%s] on [%s]", tc
++, type
, peer_cmd
,
1144 test_execute(test
, "%sneighbor %s %s", dcp
, p
->host
, peer_cmd
);
1145 test_config_absent(test
, "neighbor %s %s", p
->host
, pa
->cmd
);
1146 test_config_present(test
, "%sneighbor %s %s", ecg
, g
->name
, group_cmd
);
1147 test_process(test
, pa
, p
, g
->conf
, false, true);
1149 /* Test Case: Unset flag on BGP peer-group. */
1150 test_log(test
, "case %02d: unset %s [%s] on [%s]", tc
++, type
,
1151 group_cmd
, g
->name
);
1152 test_execute(test
, "%sneighbor %s %s", dcg
, g
->name
, group_cmd
);
1153 test_config_absent(test
, "neighbor %s %s", p
->host
, pa
->cmd
);
1154 test_config_absent(test
, "neighbor %s %s", g
->name
, pa
->cmd
);
1155 test_process(test
, pa
, p
, g
->conf
, false, false);
1157 /* Test Case: Set flag on BGP peer. */
1158 test_log(test
, "case %02d: set %s [%s] on [%s]", tc
++, type
, peer_cmd
,
1160 test_execute(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1161 test_config_present(test
, "%sneighbor %s %s", ecp
, p
->host
, peer_cmd
);
1162 test_config_absent(test
, "neighbor %s %s", g
->name
, pa
->cmd
);
1163 test_process(test
, pa
, p
, g
->conf
, true, false);
1166 static void bgp_startup(void)
1169 openzlog("testbgpd", "NONE", 0, LOG_CONS
| LOG_NDELAY
| LOG_PID
,
1171 zprivs_preinit(&bgpd_privs
);
1172 zprivs_init(&bgpd_privs
);
1174 master
= thread_master_create(NULL
);
1175 bgp_master_init(master
);
1176 bgp_option_set(BGP_OPT_NO_LISTEN
);
1177 vrf_init(NULL
, NULL
, NULL
, NULL
);
1182 static void bgp_shutdown(void)
1185 struct listnode
*node
, *nnode
;
1189 for (ALL_LIST_ELEMENTS(bm
->bgp
, node
, nnode
, bgp
))
1193 bgp_route_map_terminate();
1195 bgp_pthreads_finish();
1196 access_list_add_hook(NULL
);
1197 access_list_delete_hook(NULL
);
1198 access_list_reset();
1199 as_list_add_hook(NULL
);
1200 as_list_delete_hook(NULL
);
1202 prefix_list_add_hook(NULL
);
1203 prefix_list_delete_hook(NULL
);
1204 prefix_list_reset();
1205 community_list_terminate(bgp_clist
);
1207 #ifdef ENABLE_BGP_VNC
1208 vnc_zebra_destroy();
1210 bgp_zebra_destroy();
1212 bf_free(bm
->rd_idspace
);
1213 list_delete_and_null(&bm
->bgp
);
1214 memset(bm
, 0, sizeof(*bm
));
1218 zprivs_terminate(&bgpd_privs
);
1219 thread_master_free(master
);
1227 struct list
*pa_list
;
1228 struct test_peer_attr
*pa
, *pac
;
1229 struct listnode
*node
, *nnode
;
1233 pa_list
= list_new();
1235 while (test_peer_attrs
[i
].cmd
) {
1236 pa
= &test_peer_attrs
[i
++];
1238 /* Just copy the peer attribute structure for global flags. */
1239 if (is_attr_type_global(pa
->type
)) {
1240 pac
= XMALLOC(MTYPE_TMP
, sizeof(struct test_peer_attr
));
1241 memcpy(pac
, pa
, sizeof(struct test_peer_attr
));
1242 listnode_add(pa_list
, pac
);
1246 /* Fallback to default families if not specified. */
1247 if (!pa
->families
[0].afi
&& !pa
->families
[0].safi
)
1248 memcpy(&pa
->families
, test_default_families
,
1249 sizeof(test_default_families
));
1251 /* Add peer attribute definition for each address family. */
1253 while (pa
->families
[ii
].afi
&& pa
->families
[ii
].safi
) {
1254 pac
= XMALLOC(MTYPE_TMP
, sizeof(struct test_peer_attr
));
1255 memcpy(pac
, pa
, sizeof(struct test_peer_attr
));
1257 pac
->afi
= pa
->families
[ii
].afi
;
1258 pac
->safi
= pa
->families
[ii
].safi
;
1259 listnode_add(pa_list
, pac
);
1265 for (ALL_LIST_ELEMENTS(pa_list
, node
, nnode
, pa
)) {
1269 /* Build test description string. */
1270 if (pa
->afi
&& pa
->safi
)
1271 desc
= str_printf("peer\\%s-%s\\%s",
1272 str_from_afi(pa
->afi
),
1273 str_from_safi(pa
->safi
), pa
->cmd
);
1275 desc
= str_printf("peer\\%s", pa
->cmd
);
1277 /* Initialize new test instance. */
1278 test
= test_new(desc
, pa
->o
.use_ibgp
, pa
->o
.use_iface_peer
);
1279 XFREE(MTYPE_TMP
, desc
);
1281 /* Execute tests and finish test instance. */
1282 test_peer_attr(test
, pa
);
1285 /* Print empty line as spacer. */
1288 /* Free memory used for peer-attr declaration. */
1289 XFREE(MTYPE_TMP
, pa
);
1292 list_delete_and_null(&pa_list
);