summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_vty.c65
-rw-r--r--bgpd/bgpd.c1377
-rw-r--r--bgpd/bgpd.h51
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/bgpd/test_peer_attr.c1001
-rw-r--r--tests/bgpd/test_peer_attr.py172
7 files changed, 2031 insertions, 640 deletions
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 833de64c94..6209c1be20 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -4075,6 +4075,7 @@ DEFUN (neighbor_send_community,
"Send Community attribute to this neighbor\n")
{
int idx_peer = 1;
+
return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
bgp_node_safi(vty),
PEER_FLAG_SEND_COMMUNITY);
@@ -4094,6 +4095,7 @@ DEFUN (no_neighbor_send_community,
"Send Community attribute to this neighbor\n")
{
int idx_peer = 2;
+
return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
bgp_node_afi(vty), bgp_node_safi(vty),
PEER_FLAG_SEND_COMMUNITY);
@@ -4117,27 +4119,26 @@ DEFUN (neighbor_send_community_type,
"Send Standard Community attributes\n"
"Send Large Community attributes\n")
{
- int idx = 0;
+ int idx_peer = 1;
uint32_t flag = 0;
+ const char *type = argv[argc - 1]->text;
- char *peer = argv[1]->arg;
-
- if (argv_find(argv, argc, "standard", &idx))
+ if (strmatch(type, "standard")) {
SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY);
- else if (argv_find(argv, argc, "extended", &idx))
+ } else if (strmatch(type, "extended")) {
SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY);
- else if (argv_find(argv, argc, "large", &idx))
+ } else if (strmatch(type, "large")) {
SET_FLAG(flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
- else if (argv_find(argv, argc, "both", &idx)) {
+ } else if (strmatch(type, "both")) {
SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY);
SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY);
- } else {
+ } else { /* if (strmatch(type, "all")) */
SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY);
SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY);
SET_FLAG(flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
}
- return peer_af_flag_set_vty(vty, peer, bgp_node_afi(vty),
+ return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
bgp_node_safi(vty), flag);
}
@@ -4166,33 +4167,27 @@ DEFUN (no_neighbor_send_community_type,
"Send Large Community attributes\n")
{
int idx_peer = 2;
-
+ uint32_t flag = 0;
const char *type = argv[argc - 1]->text;
- if (strmatch(type, "standard"))
- return peer_af_flag_unset_vty(
- vty, argv[idx_peer]->arg, bgp_node_afi(vty),
- bgp_node_safi(vty), PEER_FLAG_SEND_COMMUNITY);
- if (strmatch(type, "extended"))
- return peer_af_flag_unset_vty(
- vty, argv[idx_peer]->arg, bgp_node_afi(vty),
- bgp_node_safi(vty), PEER_FLAG_SEND_EXT_COMMUNITY);
- if (strmatch(type, "large"))
- return peer_af_flag_unset_vty(
- vty, argv[idx_peer]->arg, bgp_node_afi(vty),
- bgp_node_safi(vty), PEER_FLAG_SEND_LARGE_COMMUNITY);
- if (strmatch(type, "both"))
- return peer_af_flag_unset_vty(
- vty, argv[idx_peer]->arg, bgp_node_afi(vty),
- bgp_node_safi(vty),
- PEER_FLAG_SEND_COMMUNITY
- | PEER_FLAG_SEND_EXT_COMMUNITY);
-
- /* if (strmatch (type, "all")) */
- return peer_af_flag_unset_vty(
- vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
- (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY
- | PEER_FLAG_SEND_LARGE_COMMUNITY));
+ if (strmatch(type, "standard")) {
+ SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY);
+ } else if (strmatch(type, "extended")) {
+ SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY);
+ } else if (strmatch(type, "large")) {
+ SET_FLAG(flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
+ } else if (strmatch(type, "both")) {
+ SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY);
+ } else { /* if (strmatch(type, "all")) */
+ SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG(flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
+ }
+
+ return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
+ bgp_node_afi(vty), bgp_node_safi(vty),
+ flag);
}
ALIAS_HIDDEN(
@@ -5362,8 +5357,8 @@ static int peer_prefix_list_set_vty(struct vty *vty, const char *ip_str,
const char *direct_str)
{
int ret;
- struct peer *peer;
int direct = FILTER_IN;
+ struct peer *peer;
peer = peer_and_group_lookup_vty(vty, ip_str);
if (!peer)
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index cc09d4991d..0c7b642438 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -787,31 +787,60 @@ int peer_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint32_t flag)
return CHECK_FLAG(peer->af_flags[afi][safi], flag);
}
-/* Return true if flag is set for the peer but not the peer-group */
-static int peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
- uint32_t flag)
+void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi,
+ uint32_t flag)
{
- struct peer *g_peer = NULL;
+ /* Skip if peer is not a peer-group member. */
+ if (!peer_group_active(peer))
+ return;
- if (peer_af_flag_check(peer, afi, safi, flag)) {
- if (peer_group_active(peer)) {
- g_peer = peer->group->conf;
+ /* Unset override flag to signal inheritance from peer-group. */
+ UNSET_FLAG(peer->af_flags_override[afi][safi], flag);
- /* If this flag is not set for the peer's peer-group
- * then return true */
- if (!peer_af_flag_check(g_peer, afi, safi, flag)) {
- return 1;
- }
- }
+ /* Inherit flag state from peer-group. */
+ if (CHECK_FLAG(peer->group->conf->af_flags[afi][safi], flag))
+ SET_FLAG(peer->af_flags[afi][safi], flag);
+ else
+ UNSET_FLAG(peer->af_flags[afi][safi], flag);
+}
- /* peer is not in a peer-group but the flag is set to return
- true */
- else {
- return 1;
- }
+static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
+ uint32_t flag)
+{
+ if (!peer_group_active(peer)) {
+ if (CHECK_FLAG(peer->af_flags_invert[afi][safi], flag))
+ return !peer_af_flag_check(peer, afi, safi, flag);
+ else
+ return !!peer_af_flag_check(peer, afi, safi, flag);
}
- return 0;
+ return !!CHECK_FLAG(peer->af_flags_override[afi][safi], flag);
+}
+
+static bool peergroup_filter_check(struct peer *peer, afi_t afi, safi_t safi,
+ uint8_t type, int direct)
+{
+ struct bgp_filter *filter;
+
+ if (peer_group_active(peer))
+ return !!CHECK_FLAG(peer->filter_override[afi][safi][direct],
+ type);
+
+ filter = &peer->filter[afi][safi];
+ switch (type) {
+ case PEER_FT_DISTRIBUTE_LIST:
+ return !!(filter->dlist[direct].name);
+ case PEER_FT_FILTER_LIST:
+ return !!(filter->aslist[direct].name);
+ case PEER_FT_PREFIX_LIST:
+ return !!(filter->plist[direct].name);
+ case PEER_FT_ROUTE_MAP:
+ return !!(filter->map[direct].name);
+ case PEER_FT_UNSUPPRESS_MAP:
+ return !!(filter->usmap.name);
+ default:
+ return false;
+ }
}
/* Reset all address family specific configuration. */
@@ -872,6 +901,13 @@ static void peer_af_flag_reset(struct peer *peer, afi_t afi, safi_t safi)
PEER_FLAG_SEND_EXT_COMMUNITY);
SET_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_SEND_LARGE_COMMUNITY);
+
+ SET_FLAG(peer->af_flags_invert[afi][safi],
+ PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG(peer->af_flags_invert[afi][safi],
+ PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG(peer->af_flags_invert[afi][safi],
+ PEER_FLAG_SEND_LARGE_COMMUNITY);
}
/* Clear neighbor default_originate_rmap */
@@ -1145,7 +1181,7 @@ struct peer *peer_new(struct bgp *bgp)
peer = peer_lock(peer); /* initial reference */
peer->password = NULL;
- /* Set default flags. */
+ /* Set default flags. */
FOREACH_AFI_SAFI (afi, safi) {
if (!bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
SET_FLAG(peer->af_flags[afi][safi],
@@ -1154,8 +1190,14 @@ struct peer *peer_new(struct bgp *bgp)
PEER_FLAG_SEND_EXT_COMMUNITY);
SET_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_SEND_LARGE_COMMUNITY);
+
+ SET_FLAG(peer->af_flags_invert[afi][safi],
+ PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG(peer->af_flags_invert[afi][safi],
+ PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG(peer->af_flags_invert[afi][safi],
+ PEER_FLAG_SEND_LARGE_COMMUNITY);
}
- peer->orf_plist[afi][safi] = NULL;
}
/* set nexthop-unchanged for l2vpn evpn by default */
@@ -1246,6 +1288,8 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
FOREACH_AFI_SAFI (afi, safi) {
peer_dst->afc[afi][safi] = peer_src->afc[afi][safi];
peer_dst->af_flags[afi][safi] = peer_src->af_flags[afi][safi];
+ peer_dst->af_flags_invert[afi][safi] =
+ peer_src->af_flags_invert[afi][safi];
peer_dst->allowas_in[afi][safi] =
peer_src->allowas_in[afi][safi];
peer_dst->weight[afi][safi] = peer_src->weight[afi][safi];
@@ -1741,6 +1785,7 @@ static void peer_group2peer_config_copy_af(struct peer_group *group,
/* peer af_flags apply */
peer->af_flags[afi][safi] = conf->af_flags[afi][safi];
+ peer->af_flags_invert[afi][safi] = conf->af_flags_invert[afi][safi];
/* maximum-prefix */
peer->pmax[afi][safi] = conf->pmax[afi][safi];
@@ -3790,14 +3835,14 @@ static const struct peer_flag_action peer_af_flag_action_list[] = {
{PEER_FLAG_AS_PATH_UNCHANGED, 1, peer_change_reset_out},
{PEER_FLAG_NEXTHOP_UNCHANGED, 1, peer_change_reset_out},
{PEER_FLAG_MED_UNCHANGED, 1, peer_change_reset_out},
- // PEER_FLAG_DEFAULT_ORIGINATE
+ {PEER_FLAG_DEFAULT_ORIGINATE, 0, peer_change_none},
{PEER_FLAG_REMOVE_PRIVATE_AS, 1, peer_change_reset_out},
{PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in},
{PEER_FLAG_ALLOWAS_IN_ORIGIN, 0, peer_change_reset_in},
{PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset},
{PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset},
- // PEER_FLAG_MAX_PREFIX
- // PEER_FLAG_MAX_PREFIX_WARNING
+ {PEER_FLAG_MAX_PREFIX, 0, peer_change_none},
+ {PEER_FLAG_MAX_PREFIX_WARNING, 0, peer_change_none},
{PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out},
{PEER_FLAG_FORCE_NEXTHOP_SELF, 1, peer_change_reset_out},
{PEER_FLAG_REMOVE_PRIVATE_AS_ALL, 1, peer_change_reset_out},
@@ -4005,21 +4050,23 @@ int peer_flag_unset(struct peer *peer, uint32_t flag)
}
static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
- uint32_t flag, int set)
+ uint32_t flag, bool set)
{
int found;
int size;
+ int addpath_tx_used;
+ bool invert;
struct listnode *node, *nnode;
struct peer_group *group;
struct peer_flag_action action;
struct peer *tmp_peer;
struct bgp *bgp;
- int addpath_tx_used;
memset(&action, 0, sizeof(struct peer_flag_action));
size = sizeof peer_af_flag_action_list
/ sizeof(struct peer_flag_action);
+ invert = CHECK_FLAG(peer->af_flags_invert[afi][safi], flag);
found = peer_flag_action_set(peer_af_flag_action_list, size, &action,
flag);
@@ -4043,10 +4090,25 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
/* When current flag configuration is same as requested one. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- if (set && CHECK_FLAG(peer->af_flags[afi][safi], flag) == flag)
+ if (set && CHECK_FLAG(peer->af_flags[afi][safi], flag)) {
+ if (invert)
+ UNSET_FLAG(peer->af_flags_override[afi][safi],
+ flag);
+ else
+ SET_FLAG(peer->af_flags_override[afi][safi],
+ flag);
return 0;
- if (!set && !CHECK_FLAG(peer->af_flags[afi][safi], flag))
+ }
+
+ if (!set && !CHECK_FLAG(peer->af_flags[afi][safi], flag)) {
+ if (invert)
+ SET_FLAG(peer->af_flags_override[afi][safi],
+ flag);
+ else
+ UNSET_FLAG(peer->af_flags_override[afi][safi],
+ flag);
return 0;
+ }
}
/*
@@ -4078,10 +4140,22 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
}
}
- if (set)
- SET_FLAG(peer->af_flags[afi][safi], flag);
- else
- UNSET_FLAG(peer->af_flags[afi][safi], flag);
+ /* Set/unset flag or inherit from peer-group if appropriate. */
+ if (invert) {
+ if (!set)
+ UNSET_FLAG(peer->af_flags[afi][safi], flag);
+ else if (peer_group_active(peer))
+ peer_af_flag_inherit(peer, afi, safi, flag);
+ else
+ SET_FLAG(peer->af_flags[afi][safi], flag);
+ } else {
+ if (set)
+ SET_FLAG(peer->af_flags[afi][safi], flag);
+ else if (peer_group_active(peer))
+ peer_af_flag_inherit(peer, afi, safi, flag);
+ else
+ UNSET_FLAG(peer->af_flags[afi][safi], flag);
+ }
/* Execute action when peer is established. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
@@ -4105,11 +4179,13 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
/* Peer group member updates. */
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
group = peer->group;
-
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
+ if (CHECK_FLAG(tmp_peer->af_flags_override[afi][safi],
+ flag))
+ continue;
+
if (set
- && CHECK_FLAG(tmp_peer->af_flags[afi][safi], flag)
- == flag)
+ && CHECK_FLAG(tmp_peer->af_flags[afi][safi], flag))
continue;
if (!set
@@ -4146,6 +4222,11 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
}
}
}
+ } else {
+ if (set != invert)
+ SET_FLAG(peer->af_flags_override[afi][safi], flag);
+ else
+ UNSET_FLAG(peer->af_flags_override[afi][safi], flag);
}
/* Track if addpath TX is in use */
@@ -4525,71 +4606,98 @@ int peer_update_source_unset(struct peer *peer)
int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
const char *rmap)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
- if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)
- || (rmap && !peer->default_rmap[afi][safi].name)
- || (rmap
- && strcmp(rmap, peer->default_rmap[afi][safi].name) != 0)) {
- SET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_DEFAULT_ORIGINATE);
-
- if (rmap) {
+ /* Set flag and configuration on peer. */
+ peer_af_flag_set(peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE);
+ if (rmap) {
+ if (!peer->default_rmap[afi][safi].name
+ || strcmp(rmap, peer->default_rmap[afi][safi].name) != 0) {
if (peer->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
+
peer->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
peer->default_rmap[afi][safi].map =
route_map_lookup_by_name(rmap);
}
+ } else if (!rmap) {
+ if (peer->default_rmap[afi][safi].name)
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ peer->default_rmap[afi][safi].name);
+
+ peer->default_rmap[afi][safi].name = NULL;
+ peer->default_rmap[afi][safi].map = NULL;
}
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Update peer route announcements. */
if (peer->status == Established && peer->afc_nego[afi][safi]) {
update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate(peer, afi, safi, 0);
bgp_announce_route(peer, afi, safi);
}
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- SET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_DEFAULT_ORIGINATE);
+ /*
+ * Set flag and configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->af_flags_override[afi][safi],
+ PEER_FLAG_DEFAULT_ORIGINATE))
+ continue;
+ /* Set flag and configuration on peer-group member. */
+ SET_FLAG(member->af_flags[afi][safi],
+ PEER_FLAG_DEFAULT_ORIGINATE);
if (rmap) {
- if (peer->default_rmap[afi][safi].name)
+ if (member->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME,
- peer->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].name =
+ member->default_rmap[afi][safi].name);
+
+ member->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
- peer->default_rmap[afi][safi].map =
+ member->default_rmap[afi][safi].map =
route_map_lookup_by_name(rmap);
}
- if (peer->status == Established && peer->afc_nego[afi][safi]) {
- update_group_adjust_peer(peer_af_find(peer, afi, safi));
- bgp_default_originate(peer, afi, safi, 0);
- bgp_announce_route(peer, afi, safi);
+ /* Update peer route announcements. */
+ if (member->status == Established
+ && member->afc_nego[afi][safi]) {
+ update_group_adjust_peer(
+ peer_af_find(member, afi, safi));
+ bgp_default_originate(member, afi, safi, 0);
+ bgp_announce_route(member, afi, safi);
}
}
+
return 0;
}
int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
- if (CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_DEFAULT_ORIGINATE)) {
- UNSET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_DEFAULT_ORIGINATE);
-
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ peer_af_flag_inherit(peer, afi, safi,
+ PEER_FLAG_DEFAULT_ORIGINATE);
+ PEER_STR_ATTR_INHERIT(MTYPE_ROUTE_MAP_NAME, peer,
+ default_rmap[afi][safi].name);
+ PEER_ATTR_INHERIT(peer, default_rmap[afi][safi].map);
+ } else {
+ /* Otherwise remove flag and configuration from peer. */
+ peer_af_flag_unset(peer, afi, safi,
+ PEER_FLAG_DEFAULT_ORIGINATE);
if (peer->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
@@ -4597,33 +4705,46 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
peer->default_rmap[afi][safi].map = NULL;
}
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Update peer route announcements. */
if (peer->status == Established && peer->afc_nego[afi][safi]) {
update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate(peer, afi, safi, 1);
bgp_announce_route(peer, afi, safi);
}
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ /*
+ * Remove flag and configuration from all peer-group members, unless
+ * they are explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->af_flags_override[afi][safi],
+ PEER_FLAG_DEFAULT_ORIGINATE))
+ continue;
+
+ /* Remove flag and configuration on peer-group member. */
UNSET_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_DEFAULT_ORIGINATE);
-
if (peer->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL;
+ /* Update peer route announcements. */
if (peer->status == Established && peer->afc_nego[afi][safi]) {
update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate(peer, afi, safi, 1);
bgp_announce_route(peer, afi, safi);
}
}
+
return 0;
}
@@ -4668,81 +4789,87 @@ static void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
/* neighbor weight. */
int peer_weight_set(struct peer *peer, afi_t afi, safi_t safi, uint16_t weight)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
+ /* Set flag and configuration on peer. */
+ peer_af_flag_set(peer, afi, safi, PEER_FLAG_WEIGHT);
if (peer->weight[afi][safi] != weight) {
peer->weight[afi][safi] = weight;
- SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_WEIGHT);
peer_on_policy_change(peer, afi, safi, 0);
}
+ /* Skip peer-group mechanics for regular peers. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
return 0;
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- if (peer->weight[afi][safi] != weight) {
- peer->weight[afi][safi] = weight;
- SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_WEIGHT);
- peer_on_policy_change(peer, afi, safi, 0);
+ /*
+ * Set flag and configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->af_flags_override[afi][safi],
+ PEER_FLAG_WEIGHT))
+ continue;
+
+ /* Set flag and configuration on peer-group member. */
+ SET_FLAG(member->af_flags[afi][safi], PEER_FLAG_WEIGHT);
+ if (member->weight[afi][safi] != weight) {
+ member->weight[afi][safi] = weight;
+ peer_on_policy_change(member, afi, safi, 0);
}
}
+
return 0;
}
int peer_weight_unset(struct peer *peer, afi_t afi, safi_t safi)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
- /* not the peer-group itself but a peer in a peer-group */
+ if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_WEIGHT))
+ return 0;
+
+ /* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- group = peer->group;
+ peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_WEIGHT);
+ PEER_ATTR_INHERIT(peer, weight[afi][safi]);
- /* inherit weight from the peer-group */
- if (CHECK_FLAG(group->conf->af_flags[afi][safi],
- PEER_FLAG_WEIGHT)) {
- peer->weight[afi][safi] =
- group->conf->weight[afi][safi];
- peer_af_flag_set(peer, afi, safi, PEER_FLAG_WEIGHT);
- peer_on_policy_change(peer, afi, safi, 0);
- } else {
- if (CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_WEIGHT)) {
- peer->weight[afi][safi] = 0;
- peer_af_flag_unset(peer, afi, safi,
- PEER_FLAG_WEIGHT);
- peer_on_policy_change(peer, afi, safi, 0);
- }
- }
+ peer_on_policy_change(peer, afi, safi, 0);
+ return 0;
}
- else {
- if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_WEIGHT)) {
- peer->weight[afi][safi] = 0;
- peer_af_flag_unset(peer, afi, safi, PEER_FLAG_WEIGHT);
- peer_on_policy_change(peer, afi, safi, 0);
- }
+ /* Remove flag and configuration from peer. */
+ peer_af_flag_unset(peer, afi, safi, PEER_FLAG_WEIGHT);
+ peer->weight[afi][safi] = 0;
+ peer_on_policy_change(peer, afi, safi, 0);
- /* peer-group member updates. */
- group = peer->group;
+ /* Skip peer-group mechanics for regular peers. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
- if (group) {
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode,
- peer)) {
- if (CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_WEIGHT)) {
- peer->weight[afi][safi] = 0;
- peer_af_flag_unset(peer, afi, safi,
- PEER_FLAG_WEIGHT);
- peer_on_policy_change(peer, afi, safi,
- 0);
- }
- }
- }
+ /*
+ * Remove flag and configuration from all peer-group members, unless
+ * they are explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->af_flags_override[afi][safi],
+ PEER_FLAG_WEIGHT))
+ continue;
+
+ /* Skip peers where flag is already disabled. */
+ if (!CHECK_FLAG(member->af_flags[afi][safi], PEER_FLAG_WEIGHT))
+ continue;
+
+ /* Remove flag and configuration on peer-group member. */
+ UNSET_FLAG(member->af_flags[afi][safi], PEER_FLAG_WEIGHT);
+ member->weight[afi][safi] = 0;
+ peer_on_policy_change(member, afi, safi, 0);
}
+
return 0;
}
@@ -4971,68 +5098,67 @@ void peer_interface_unset(struct peer *peer)
int peer_allowas_in_set(struct peer *peer, afi_t afi, safi_t safi,
int allow_num, int origin)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
+ if (!origin && (allow_num < 1 || allow_num > 10))
+ return BGP_ERR_INVALID_VALUE;
+
+ /* Set flag and configuration on peer. */
+ peer_af_flag_set(peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
if (origin) {
- if (peer->allowas_in[afi][safi]
- || CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_ALLOWAS_IN)
+ if (peer->allowas_in[afi][safi] != 0
|| !CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
- peer->allowas_in[afi][safi] = 0;
- peer_af_flag_unset(peer, afi, safi,
- PEER_FLAG_ALLOWAS_IN);
peer_af_flag_set(peer, afi, safi,
PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ peer->allowas_in[afi][safi] = 0;
peer_on_policy_change(peer, afi, safi, 0);
}
-
- if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- if (peer->allowas_in[afi][safi]
- || CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_ALLOWAS_IN)
- || !CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
- peer->allowas_in[afi][safi] = 0;
- peer_af_flag_unset(peer, afi, safi,
- PEER_FLAG_ALLOWAS_IN);
- peer_af_flag_set(peer, afi, safi,
- PEER_FLAG_ALLOWAS_IN_ORIGIN);
- peer_on_policy_change(peer, afi, safi, 0);
- }
- }
} else {
- if (allow_num < 1 || allow_num > 10)
- return BGP_ERR_INVALID_VALUE;
-
if (peer->allowas_in[afi][safi] != allow_num
|| CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
- peer->allowas_in[afi][safi] = allow_num;
- peer_af_flag_set(peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
+
peer_af_flag_unset(peer, afi, safi,
PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ peer->allowas_in[afi][safi] = allow_num;
peer_on_policy_change(peer, afi, safi, 0);
}
+ }
- if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ /* Skip peer-group mechanics for regular peers. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- if (peer->allowas_in[afi][safi] != allow_num
- || CHECK_FLAG(peer->af_flags[afi][safi],
+ /*
+ * Set flag and configuration on all peer-group members, unless
+ * they are explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->af_flags_override[afi][safi],
+ PEER_FLAG_ALLOWAS_IN))
+ continue;
+
+ /* Set flag and configuration on peer-group member. */
+ SET_FLAG(member->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN);
+ if (origin) {
+ if (member->allowas_in[afi][safi] != 0
+ || !CHECK_FLAG(member->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
+ SET_FLAG(member->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ member->allowas_in[afi][safi] = 0;
+ peer_on_policy_change(peer, afi, safi, 0);
+ }
+ } else {
+ if (member->allowas_in[afi][safi] != allow_num
+ || CHECK_FLAG(member->af_flags[afi][safi],
PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
- peer->allowas_in[afi][safi] = allow_num;
- peer_af_flag_set(peer, afi, safi,
- PEER_FLAG_ALLOWAS_IN);
- peer_af_flag_unset(peer, afi, safi,
- PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ UNSET_FLAG(member->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ member->allowas_in[afi][safi] = allow_num;
peer_on_policy_change(peer, afi, safi, 0);
}
}
@@ -5043,38 +5169,55 @@ int peer_allowas_in_set(struct peer *peer, afi_t afi, safi_t safi,
int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi)
{
- struct peer_group *group;
- struct peer *tmp_peer;
+ struct peer *member;
struct listnode *node, *nnode;
- /* If this is a peer-group we must first clear the flags for all of the
- * peer-group members
- */
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
- if (CHECK_FLAG(tmp_peer->af_flags[afi][safi],
- PEER_FLAG_ALLOWAS_IN)
- || CHECK_FLAG(tmp_peer->af_flags[afi][safi],
- PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
- tmp_peer->allowas_in[afi][safi] = 0;
- peer_af_flag_unset(tmp_peer, afi, safi,
- PEER_FLAG_ALLOWAS_IN);
- peer_af_flag_unset(tmp_peer, afi, safi,
- PEER_FLAG_ALLOWAS_IN_ORIGIN);
- peer_on_policy_change(tmp_peer, afi, safi, 0);
- }
- }
- }
+ /* Skip peer if flag is already disabled. */
+ if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN))
+ return 0;
- if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)
- || CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
- peer->allowas_in[afi][safi] = 0;
- peer_af_flag_unset(peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
- peer_af_flag_unset(peer, afi, safi,
- PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
+ peer_af_flag_inherit(peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ PEER_ATTR_INHERIT(peer, allowas_in[afi][safi]);
peer_on_policy_change(peer, afi, safi, 0);
+
+ return 0;
+ }
+
+ /* Remove flag and configuration from peer. */
+ peer_af_flag_unset(peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
+ peer_af_flag_unset(peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ peer->allowas_in[afi][safi] = 0;
+ peer_on_policy_change(peer, afi, safi, 0);
+
+ /* Skip peer-group mechanics if handling a regular peer. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ /*
+ * Remove flags and configuration from all peer-group members, unless
+ * they are explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->af_flags_override[afi][safi],
+ PEER_FLAG_ALLOWAS_IN))
+ continue;
+
+ /* Skip peers where flag is already disabled. */
+ if (!CHECK_FLAG(member->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN))
+ continue;
+
+ /* Remove flags and configuration on peer-group member. */
+ UNSET_FLAG(member->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN);
+ UNSET_FLAG(member->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ member->allowas_in[afi][safi] = 0;
+ peer_on_policy_change(member, afi, safi, 0);
}
return 0;
@@ -5302,40 +5445,55 @@ int peer_password_unset(struct peer *peer)
int peer_distribute_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != FILTER_IN && direct != FILTER_OUT)
return BGP_ERR_INVALID_VALUE;
+ /* Set configuration on peer. */
filter = &peer->filter[afi][safi];
-
if (filter->plist[direct].name)
return BGP_ERR_PEER_FILTER_CONFLICT;
-
if (filter->dlist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[direct].name);
filter->dlist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->dlist[direct].alist = access_list_lookup(afi, name);
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Set override-flag and process peer route updates. */
+ SET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_DISTRIBUTE_LIST);
peer_on_policy_change(peer, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Set configuration on all peer-group members, un less they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_DISTRIBUTE_LIST))
+ continue;
+ /* Set configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->dlist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME,
filter->dlist[direct].name);
filter->dlist[direct].name =
XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->dlist[direct].alist = access_list_lookup(afi, name);
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
}
@@ -5344,56 +5502,62 @@ int peer_distribute_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
int peer_distribute_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct bgp_filter *gfilter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != FILTER_IN && direct != FILTER_OUT)
return BGP_ERR_INVALID_VALUE;
- filter = &peer->filter[afi][safi];
+ /* Unset override-flag unconditionally. */
+ UNSET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_DISTRIBUTE_LIST);
- /* apply peer-group filter */
+ /* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- gfilter = &peer->group->conf->filter[afi][safi];
-
- if (gfilter->dlist[direct].name) {
- if (filter->dlist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- filter->dlist[direct].name);
- filter->dlist[direct].name =
- XSTRDUP(MTYPE_BGP_FILTER_NAME,
- gfilter->dlist[direct].name);
- filter->dlist[direct].alist =
- gfilter->dlist[direct].alist;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
+ PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
+ filter[afi][safi].dlist[direct].name);
+ PEER_ATTR_INHERIT(peer, filter[afi][safi].dlist[direct].alist);
+ } else {
+ /* Otherwise remove configuration from peer. */
+ filter = &peer->filter[afi][safi];
+ if (filter->dlist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->dlist[direct].name);
+ filter->dlist[direct].name = NULL;
+ filter->dlist[direct].alist = NULL;
}
- if (filter->dlist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[direct].name);
- filter->dlist[direct].name = NULL;
- filter->dlist[direct].alist = NULL;
-
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Process peer route updates. */
peer_on_policy_change(peer, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Remove configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_DISTRIBUTE_LIST))
+ continue;
+ /* Remove configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->dlist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME,
filter->dlist[direct].name);
filter->dlist[direct].name = NULL;
filter->dlist[direct].alist = NULL;
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
}
@@ -5463,98 +5627,120 @@ static void peer_distribute_update(struct access_list *access)
int peer_prefix_list_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != FILTER_IN && direct != FILTER_OUT)
return BGP_ERR_INVALID_VALUE;
+ /* Set configuration on peer. */
filter = &peer->filter[afi][safi];
-
if (filter->dlist[direct].name)
return BGP_ERR_PEER_FILTER_CONFLICT;
-
if (filter->plist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
filter->plist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->plist[direct].plist = prefix_list_lookup(afi, name);
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Set override-flag and process peer route updates. */
+ SET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_PREFIX_LIST);
peer_on_policy_change(peer, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Set configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_PREFIX_LIST))
+ continue;
+ /* Set configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->plist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME,
filter->plist[direct].name);
filter->plist[direct].name =
XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->plist[direct].plist = prefix_list_lookup(afi, name);
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
}
+
return 0;
}
int peer_prefix_list_unset(struct peer *peer, afi_t afi, safi_t safi,
int direct)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct bgp_filter *gfilter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != FILTER_IN && direct != FILTER_OUT)
return BGP_ERR_INVALID_VALUE;
- filter = &peer->filter[afi][safi];
+ /* Unset override-flag unconditionally. */
+ UNSET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_PREFIX_LIST);
- /* apply peer-group filter */
+ /* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- gfilter = &peer->group->conf->filter[afi][safi];
-
- if (gfilter->plist[direct].name) {
- if (filter->plist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- filter->plist[direct].name);
- filter->plist[direct].name =
- XSTRDUP(MTYPE_BGP_FILTER_NAME,
- gfilter->plist[direct].name);
- filter->plist[direct].plist =
- gfilter->plist[direct].plist;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
+ PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
+ filter[afi][safi].plist[direct].name);
+ PEER_ATTR_INHERIT(peer, filter[afi][safi].plist[direct].plist);
+ } else {
+ /* Otherwise remove configuration from peer. */
+ filter = &peer->filter[afi][safi];
+ if (filter->plist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->plist[direct].name);
+ filter->plist[direct].name = NULL;
+ filter->plist[direct].plist = NULL;
}
- if (filter->plist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
- filter->plist[direct].name = NULL;
- filter->plist[direct].plist = NULL;
-
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Process peer route updates. */
peer_on_policy_change(peer, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Remove configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_PREFIX_LIST))
+ continue;
+ /* Remove configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->plist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME,
filter->plist[direct].name);
filter->plist[direct].name = NULL;
filter->plist[direct].plist = NULL;
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
}
@@ -5625,94 +5811,118 @@ static void peer_prefix_list_update(struct prefix_list *plist)
int peer_aslist_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != FILTER_IN && direct != FILTER_OUT)
return BGP_ERR_INVALID_VALUE;
+ /* Set configuration on peer. */
filter = &peer->filter[afi][safi];
-
if (filter->aslist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[direct].name);
filter->aslist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->aslist[direct].aslist = as_list_lookup(name);
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Set override-flag and process peer route updates. */
+ SET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_FILTER_LIST);
peer_on_policy_change(peer, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Set configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_FILTER_LIST))
+ continue;
+ /* Set configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->aslist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME,
filter->aslist[direct].name);
filter->aslist[direct].name =
XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->aslist[direct].aslist = as_list_lookup(name);
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
}
+
return 0;
}
int peer_aslist_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct bgp_filter *gfilter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != FILTER_IN && direct != FILTER_OUT)
return BGP_ERR_INVALID_VALUE;
- filter = &peer->filter[afi][safi];
+ /* Unset override-flag unconditionally. */
+ UNSET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_FILTER_LIST);
- /* apply peer-group filter */
+ /* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- gfilter = &peer->group->conf->filter[afi][safi];
-
- if (gfilter->aslist[direct].name) {
- if (filter->aslist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- filter->aslist[direct].name);
- filter->aslist[direct].name =
- XSTRDUP(MTYPE_BGP_FILTER_NAME,
- gfilter->aslist[direct].name);
- filter->aslist[direct].aslist =
- gfilter->aslist[direct].aslist;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
+ PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
+ filter[afi][safi].aslist[direct].name);
+ PEER_ATTR_INHERIT(peer,
+ filter[afi][safi].aslist[direct].aslist);
+ } else {
+ /* Otherwise remove configuration from peer. */
+ filter = &peer->filter[afi][safi];
+ if (filter->aslist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->aslist[direct].name);
+ filter->aslist[direct].name = NULL;
+ filter->aslist[direct].aslist = NULL;
}
- if (filter->aslist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[direct].name);
- filter->aslist[direct].name = NULL;
- filter->aslist[direct].aslist = NULL;
-
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Process peer route updates. */
peer_on_policy_change(peer, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Remove configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_FILTER_LIST))
+ continue;
+ /* Remove configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->aslist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME,
filter->aslist[direct].name);
filter->aslist[direct].name = NULL;
filter->aslist[direct].aslist = NULL;
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
}
@@ -5789,36 +5999,51 @@ static void peer_aslist_del(const char *aslist_name)
int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != RMAP_IN && direct != RMAP_OUT)
return BGP_ERR_INVALID_VALUE;
+ /* Set configuration on peer. */
filter = &peer->filter[afi][safi];
-
if (filter->map[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
-
filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->map[direct].map = route_map_lookup_by_name(name);
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Set override-flag and process peer route updates. */
+ SET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_ROUTE_MAP);
peer_on_policy_change(peer, afi, safi,
(direct == RMAP_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Set configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_ROUTE_MAP))
+ continue;
+ /* Set configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->map[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->map[direct].map = route_map_lookup_by_name(name);
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == RMAP_OUT) ? 1 : 0);
}
return 0;
@@ -5827,56 +6052,62 @@ int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
/* Unset route-map from the peer. */
int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct bgp_filter *gfilter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != RMAP_IN && direct != RMAP_OUT)
return BGP_ERR_INVALID_VALUE;
- filter = &peer->filter[afi][safi];
+ /* Unset override-flag unconditionally. */
+ UNSET_FLAG(peer->filter_override[afi][safi][direct], PEER_FT_ROUTE_MAP);
- /* apply peer-group filter */
+ /* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- gfilter = &peer->group->conf->filter[afi][safi];
-
- if (gfilter->map[direct].name) {
- if (filter->map[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- filter->map[direct].name);
- filter->map[direct].name =
- XSTRDUP(MTYPE_BGP_FILTER_NAME,
- gfilter->map[direct].name);
- filter->map[direct].map = gfilter->map[direct].map;
- peer_on_policy_change(peer, afi, safi,
- (direct == RMAP_OUT) ? 1 : 0);
- return 0;
- }
+ PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
+ filter[afi][safi].map[direct].name);
+ PEER_ATTR_INHERIT(peer, filter[afi][safi].map[direct].map);
+ } else {
+ /* Otherwise remove configuration from peer. */
+ filter = &peer->filter[afi][safi];
+ if (filter->map[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+ filter->map[direct].name = NULL;
+ filter->map[direct].map = NULL;
}
- if (filter->map[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
- filter->map[direct].name = NULL;
- filter->map[direct].map = NULL;
-
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Process peer route updates. */
peer_on_policy_change(peer, afi, safi,
(direct == RMAP_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Remove configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_ROUTE_MAP))
+ continue;
+ /* Remove configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->map[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
filter->map[direct].name = NULL;
filter->map[direct].map = NULL;
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == RMAP_OUT) ? 1 : 0);
}
+
return 0;
}
@@ -5884,65 +6115,106 @@ int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi,
const char *name)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct peer_group *group;
struct listnode *node, *nnode;
+ /* Set configuration on peer. */
filter = &peer->filter[afi][safi];
-
if (filter->usmap.name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
-
filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->usmap.map = route_map_lookup_by_name(name);
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Set override-flag and process peer route updates. */
+ SET_FLAG(peer->filter_override[afi][safi][0],
+ PEER_FT_UNSUPPRESS_MAP);
peer_on_policy_change(peer, afi, safi, 1);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Set configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][0],
+ PEER_FT_UNSUPPRESS_MAP))
+ continue;
+ /* Set configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->usmap.name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->usmap.map = route_map_lookup_by_name(name);
- peer_on_policy_change(peer, afi, safi, 1);
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi, 1);
}
+
return 0;
}
/* Unset route-map from the peer. */
int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct peer_group *group;
struct listnode *node, *nnode;
- filter = &peer->filter[afi][safi];
+ /* Unset override-flag unconditionally. */
+ UNSET_FLAG(peer->filter_override[afi][safi][0], PEER_FT_UNSUPPRESS_MAP);
- if (filter->usmap.name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
- filter->usmap.name = NULL;
- filter->usmap.map = NULL;
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
+ filter[afi][safi].usmap.name);
+ PEER_ATTR_INHERIT(peer, filter[afi][safi].usmap.map);
+ } else {
+ /* Otherwise remove configuration from peer. */
+ filter = &peer->filter[afi][safi];
+ if (filter->usmap.name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+ filter->usmap.name = NULL;
+ filter->usmap.map = NULL;
+ }
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Process peer route updates. */
peer_on_policy_change(peer, afi, safi, 1);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Remove configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][0],
+ PEER_FT_UNSUPPRESS_MAP))
+ continue;
+ /* Remove configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->usmap.name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
filter->usmap.name = NULL;
filter->usmap.map = NULL;
- peer_on_policy_change(peer, afi, safi, 1);
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi, 1);
}
+
return 0;
}
@@ -5950,66 +6222,55 @@ int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi,
uint32_t max, uint8_t threshold, int warning,
uint16_t restart)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
- /* apply configuration and set flags */
- SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+ /* Set flags and configuration on peer. */
+ peer_af_flag_set(peer, afi, safi, PEER_FLAG_MAX_PREFIX);
if (warning)
- SET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING);
+ peer_af_flag_set(peer, afi, safi, PEER_FLAG_MAX_PREFIX_WARNING);
else
- UNSET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING);
+ peer_af_flag_unset(peer, afi, safi,
+ PEER_FLAG_MAX_PREFIX_WARNING);
+
peer->pmax[afi][safi] = max;
peer->pmax_threshold[afi][safi] = threshold;
peer->pmax_restart[afi][safi] = restart;
- /* if handling a peer-group, apply to all children */
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- /*
- * If peer configuration is user-set, it overrides
- * peer-group config.
- */
- if (!CHECK_FLAG(peer->af_flags_override[afi][safi],
- PEER_FLAG_MAX_PREFIX)) {
- SET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX);
- peer->pmax[afi][safi] = max;
- peer->pmax_threshold[afi][safi] = threshold;
- peer->pmax_restart[afi][safi] = restart;
- }
- if (!CHECK_FLAG(peer->af_flags_override[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING)) {
- if (warning)
- SET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING);
- else
- UNSET_FLAG(
- peer->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING);
- }
-
- if ((peer->status == Established)
- && (peer->afc[afi][safi]))
- bgp_maximum_prefix_overflow(peer, afi, safi, 1);
- }
- } else {
- /* if not handling a peer-group, set the override flags */
+ /* Check if handling a regular peer. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Re-check if peer violates maximum-prefix. */
if ((peer->status == Established) && (peer->afc[afi][safi]))
bgp_maximum_prefix_overflow(peer, afi, safi, 1);
- SET_FLAG(peer->af_flags_override[afi][safi],
- PEER_FLAG_MAX_PREFIX);
+ /* Skip peer-group mechanics for regular peers. */
+ return 0;
+ }
+ /*
+ * Set flags and configuration on all peer-group members, unless they
+ * are explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->af_flags_override[afi][safi],
+ PEER_FLAG_MAX_PREFIX))
+ continue;
+
+ /* Set flag and configuration on peer-group member. */
+ member->pmax[afi][safi] = max;
+ member->pmax_threshold[afi][safi] = threshold;
+ member->pmax_restart[afi][safi] = restart;
if (warning)
- SET_FLAG(peer->af_flags_override[afi][safi],
+ SET_FLAG(member->af_flags[afi][safi],
PEER_FLAG_MAX_PREFIX_WARNING);
else
- UNSET_FLAG(peer->af_flags_override[afi][safi],
+ UNSET_FLAG(member->af_flags[afi][safi],
PEER_FLAG_MAX_PREFIX_WARNING);
+
+ /* Re-check if peer violates maximum-prefix. */
+ if ((member->status == Established) && (member->afc[afi][safi]))
+ bgp_maximum_prefix_overflow(member, afi, safi, 1);
}
return 0;
@@ -6017,53 +6278,47 @@ int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi,
int peer_maximum_prefix_unset(struct peer *peer, afi_t afi, safi_t safi)
{
- struct peer_group *group;
+ struct peer *member;
struct listnode *node, *nnode;
- UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
- UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
- peer->pmax[afi][safi] = 0;
- peer->pmax_threshold[afi][safi] = 0;
- peer->pmax_restart[afi][safi] = 0;
-
- /* if not handling a peer-group, unset override flags */
- if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- UNSET_FLAG(peer->af_flags_override[afi][safi],
- PEER_FLAG_MAX_PREFIX);
- UNSET_FLAG(peer->af_flags_override[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING);
- /* if peer is part of a peer-group, apply peer-group config */
- if (peer_group_active(peer)) {
- peer->pmax[afi][safi] =
- peer->group->conf->pmax[afi][safi];
- peer->pmax_threshold[afi][safi] =
- peer->group->conf->pmax_threshold[afi][safi];
- peer->pmax_restart[afi][safi] =
- peer->group->conf->pmax_restart[afi][safi];
- }
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_MAX_PREFIX);
+ peer_af_flag_inherit(peer, afi, safi,
+ PEER_FLAG_MAX_PREFIX_WARNING);
+ PEER_ATTR_INHERIT(peer, pmax[afi][safi]);
+ PEER_ATTR_INHERIT(peer, pmax_threshold[afi][safi]);
+ PEER_ATTR_INHERIT(peer, pmax_restart[afi][safi]);
return 0;
}
+ /* Remove flags and configuration from peer. */
+ peer_af_flag_unset(peer, afi, safi, PEER_FLAG_MAX_PREFIX);
+ peer_af_flag_unset(peer, afi, safi, PEER_FLAG_MAX_PREFIX_WARNING);
+ peer->pmax[afi][safi] = 0;
+ peer->pmax_threshold[afi][safi] = 0;
+ peer->pmax_restart[afi][safi] = 0;
+
/*
- * If this peer is a peer-group, set all peers in the group unless they
- * have overrides for our config.
+ * Remove flags and configuration from all peer-group members, unless
+ * they are explicitely overriding peer-group configuration.
*/
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- if (!CHECK_FLAG(peer->af_flags_override[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING))
- UNSET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING);
- if (!CHECK_FLAG(peer->af_flags_override[afi][safi],
- PEER_FLAG_MAX_PREFIX)) {
- UNSET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX);
- peer->pmax[afi][safi] = 0;
- peer->pmax_threshold[afi][safi] = 0;
- peer->pmax_restart[afi][safi] = 0;
- }
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->af_flags_override[afi][safi],
+ PEER_FLAG_MAX_PREFIX))
+ continue;
+
+ /* Remove flag and configuration on peer-group member. */
+ UNSET_FLAG(member->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+ UNSET_FLAG(member->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING);
+ member->pmax[afi][safi] = 0;
+ member->pmax_threshold[afi][safi] = 0;
+ member->pmax_restart[afi][safi] = 0;
}
+
return 0;
}
@@ -6431,86 +6686,58 @@ static void bgp_config_write_filter(struct vty *vty, struct peer *peer,
afi_t afi, safi_t safi)
{
struct bgp_filter *filter;
- struct bgp_filter *gfilter = NULL;
char *addr;
- int in = FILTER_IN;
- int out = FILTER_OUT;
addr = peer->host;
filter = &peer->filter[afi][safi];
- if (peer_group_active(peer))
- gfilter = &peer->group->conf->filter[afi][safi];
-
/* distribute-list. */
- if (filter->dlist[in].name)
- if (!gfilter || !gfilter->dlist[in].name
- || strcmp(filter->dlist[in].name, gfilter->dlist[in].name)
- != 0) {
- vty_out(vty, " neighbor %s distribute-list %s in\n",
- addr, filter->dlist[in].name);
- }
+ if (peergroup_filter_check(peer, afi, safi, PEER_FT_DISTRIBUTE_LIST,
+ FILTER_IN))
+ vty_out(vty, " neighbor %s distribute-list %s in\n", addr,
+ filter->dlist[FILTER_IN].name);
- if (filter->dlist[out].name && !gfilter) {
+ if (peergroup_filter_check(peer, afi, safi, PEER_FT_DISTRIBUTE_LIST,
+ FILTER_OUT))
vty_out(vty, " neighbor %s distribute-list %s out\n", addr,
- filter->dlist[out].name);
- }
+ filter->dlist[FILTER_OUT].name);
/* prefix-list. */
- if (filter->plist[in].name)
- if (!gfilter || !gfilter->plist[in].name
- || strcmp(filter->plist[in].name, gfilter->plist[in].name)
- != 0) {
- vty_out(vty, " neighbor %s prefix-list %s in\n", addr,
- filter->plist[in].name);
- }
+ if (peergroup_filter_check(peer, afi, safi, PEER_FT_PREFIX_LIST,
+ FILTER_IN))
+ vty_out(vty, " neighbor %s prefix-list %s in\n", addr,
+ filter->plist[FILTER_IN].name);
- if (filter->plist[out].name)
- if (!gfilter || !gfilter->plist[out].name
- || strcmp(filter->plist[out].name, gfilter->plist[out].name)
- != 0) {
- vty_out(vty, " neighbor %s prefix-list %s out\n", addr,
- filter->plist[out].name);
- }
+ if (peergroup_filter_check(peer, afi, safi, PEER_FT_PREFIX_LIST,
+ FILTER_OUT))
+ vty_out(vty, " neighbor %s prefix-list %s out\n", addr,
+ filter->plist[FILTER_OUT].name);
/* route-map. */
- if (filter->map[RMAP_IN].name)
- if (!gfilter || !gfilter->map[RMAP_IN].name
- || strcmp(filter->map[RMAP_IN].name,
- gfilter->map[RMAP_IN].name)
- != 0) {
- vty_out(vty, " neighbor %s route-map %s in\n", addr,
- filter->map[RMAP_IN].name);
- }
+ if (peergroup_filter_check(peer, afi, safi, PEER_FT_ROUTE_MAP, RMAP_IN))
+ vty_out(vty, " neighbor %s route-map %s in\n", addr,
+ filter->map[RMAP_IN].name);
- if (filter->map[RMAP_OUT].name)
- if (!gfilter || !gfilter->map[RMAP_OUT].name
- || strcmp(filter->map[RMAP_OUT].name,
- gfilter->map[RMAP_OUT].name)
- != 0) {
- vty_out(vty, " neighbor %s route-map %s out\n", addr,
- filter->map[RMAP_OUT].name);
- }
+ if (peergroup_filter_check(peer, afi, safi, PEER_FT_ROUTE_MAP,
+ RMAP_OUT))
+ vty_out(vty, " neighbor %s route-map %s out\n", addr,
+ filter->map[RMAP_OUT].name);
/* unsuppress-map */
- if (filter->usmap.name && !gfilter) {
+ if (peergroup_filter_check(peer, afi, safi, PEER_FT_UNSUPPRESS_MAP, 0))
vty_out(vty, " neighbor %s unsuppress-map %s\n", addr,
filter->usmap.name);
- }
/* filter-list. */
- if (filter->aslist[in].name)
- if (!gfilter || !gfilter->aslist[in].name
- || strcmp(filter->aslist[in].name, gfilter->aslist[in].name)
- != 0) {
- vty_out(vty, " neighbor %s filter-list %s in\n", addr,
- filter->aslist[in].name);
- }
+ if (peergroup_filter_check(peer, afi, safi, PEER_FT_FILTER_LIST,
+ FILTER_IN))
+ vty_out(vty, " neighbor %s filter-list %s in\n", addr,
+ filter->aslist[FILTER_IN].name);
- if (filter->aslist[out].name && !gfilter) {
+ if (peergroup_filter_check(peer, afi, safi, PEER_FT_FILTER_LIST,
+ FILTER_OUT))
vty_out(vty, " neighbor %s filter-list %s out\n", addr,
- filter->aslist[out].name);
- }
+ filter->aslist[FILTER_OUT].name);
}
/* BGP peer configuration display function. */
@@ -6841,6 +7068,7 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
{
struct peer *g_peer = NULL;
char *addr;
+ bool flag_scomm, flag_secomm, flag_slcomm;
/* Skip dynamic neighbors. */
if (peer_dynamic_neighbor(peer))
@@ -6967,97 +7195,63 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
}
/* send-community print. */
- if (bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
- if (peergroup_af_flag_check(peer, afi, safi,
- PEER_FLAG_SEND_COMMUNITY)
- && peergroup_af_flag_check(peer, afi, safi,
- PEER_FLAG_SEND_EXT_COMMUNITY)
- && peergroup_af_flag_check(
- peer, afi, safi,
- PEER_FLAG_SEND_LARGE_COMMUNITY)) {
- vty_out(vty, " neighbor %s send-community all\n",
- addr);
- } else if (peergroup_af_flag_check(
- peer, afi, safi,
- PEER_FLAG_SEND_LARGE_COMMUNITY)) {
- vty_out(vty, " neighbor %s send-community large\n",
- addr);
- } else if (peergroup_af_flag_check(
- peer, afi, safi,
- PEER_FLAG_SEND_EXT_COMMUNITY)) {
- vty_out(vty, " neighbor %s send-community extended\n",
- addr);
- } else if (peergroup_af_flag_check(peer, afi, safi,
- PEER_FLAG_SEND_COMMUNITY)) {
- vty_out(vty, " neighbor %s send-community\n", addr);
- }
- } else {
- if (!peer_af_flag_check(peer, afi, safi,
- PEER_FLAG_SEND_COMMUNITY)
- && (!g_peer || peer_af_flag_check(g_peer, afi, safi,
- PEER_FLAG_SEND_COMMUNITY))
- && !peer_af_flag_check(peer, afi, safi,
- PEER_FLAG_SEND_EXT_COMMUNITY)
- && (!g_peer
- || peer_af_flag_check(g_peer, afi, safi,
- PEER_FLAG_SEND_EXT_COMMUNITY))
- && !peer_af_flag_check(peer, afi, safi,
- PEER_FLAG_SEND_LARGE_COMMUNITY)
- && (!g_peer || peer_af_flag_check(
- g_peer, afi, safi,
- PEER_FLAG_SEND_LARGE_COMMUNITY))) {
+ flag_scomm = peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_COMMUNITY);
+ flag_secomm = peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_EXT_COMMUNITY);
+ flag_slcomm = peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_LARGE_COMMUNITY);
+
+ if (!bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
+ if (flag_scomm && flag_secomm && flag_slcomm) {
vty_out(vty, " no neighbor %s send-community all\n",
addr);
} else {
- if (!peer_af_flag_check(peer, afi, safi,
- PEER_FLAG_SEND_LARGE_COMMUNITY)
- && (!g_peer
- || peer_af_flag_check(
- g_peer, afi, safi,
- PEER_FLAG_SEND_LARGE_COMMUNITY))) {
+ if (flag_scomm)
vty_out(vty,
- " no neighbor %s send-community large\n",
+ " no neighbor %s send-community\n",
addr);
- }
-
- if (!peer_af_flag_check(peer, afi, safi,
- PEER_FLAG_SEND_EXT_COMMUNITY)
- && (!g_peer
- || peer_af_flag_check(
- g_peer, afi, safi,
- PEER_FLAG_SEND_EXT_COMMUNITY))) {
+ if (flag_secomm)
vty_out(vty,
" no neighbor %s send-community extended\n",
addr);
- }
- if (!peer_af_flag_check(peer, afi, safi,
- PEER_FLAG_SEND_COMMUNITY)
- && (!g_peer || peer_af_flag_check(
- g_peer, afi, safi,
- PEER_FLAG_SEND_COMMUNITY))) {
+ if (flag_slcomm)
vty_out(vty,
- " no neighbor %s send-community\n",
+ " no neighbor %s send-community large\n",
+ addr);
+ }
+ } else {
+ if (flag_scomm && flag_secomm && flag_slcomm) {
+ vty_out(vty, " neighbor %s send-community all\n",
+ addr);
+ } else if (flag_scomm && flag_secomm) {
+ vty_out(vty, " neighbor %s send-community both\n",
+ addr);
+ } else {
+ if (flag_scomm)
+ vty_out(vty, " neighbor %s send-community\n",
+ addr);
+ if (flag_secomm)
+ vty_out(vty,
+ " neighbor %s send-community extended\n",
+ addr);
+ if (flag_slcomm)
+ vty_out(vty,
+ " neighbor %s send-community large\n",
addr);
- }
}
}
/* Default information */
if (peergroup_af_flag_check(peer, afi, safi,
- PEER_FLAG_DEFAULT_ORIGINATE)
- || (g_peer
- && ((peer->default_rmap[afi][safi].name
- && !g_peer->default_rmap[afi][safi].name)
- || (!peer->default_rmap[afi][safi].name
- && g_peer->default_rmap[afi][safi].name)
- || (peer->default_rmap[afi][safi].name
- && strcmp(peer->default_rmap[afi][safi].name,
- g_peer->default_rmap[afi][safi].name))))) {
+ PEER_FLAG_DEFAULT_ORIGINATE)) {
vty_out(vty, " neighbor %s default-originate", addr);
+
if (peer->default_rmap[afi][safi].name)
vty_out(vty, " route-map %s",
peer->default_rmap[afi][safi].name);
+
vty_out(vty, "\n");
}
@@ -7068,29 +7262,22 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
}
/* maximum-prefix. */
- if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))
- if (!peer_group_active(peer)
- || g_peer->pmax[afi][safi] != peer->pmax[afi][safi]
- || g_peer->pmax_threshold[afi][safi]
- != peer->pmax_threshold[afi][safi]
- || CHECK_FLAG(g_peer->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING)
- != CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING)) {
- vty_out(vty, " neighbor %s maximum-prefix %lu", addr,
- peer->pmax[afi][safi]);
- if (peer->pmax_threshold[afi][safi]
- != MAXIMUM_PREFIX_THRESHOLD_DEFAULT)
- vty_out(vty, " %u",
- peer->pmax_threshold[afi][safi]);
- if (CHECK_FLAG(peer->af_flags[afi][safi],
+ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MAX_PREFIX)) {
+ vty_out(vty, " neighbor %s maximum-prefix %lu", addr,
+ peer->pmax[afi][safi]);
+
+ if (peer->pmax_threshold[afi][safi]
+ != MAXIMUM_PREFIX_THRESHOLD_DEFAULT)
+ vty_out(vty, " %u", peer->pmax_threshold[afi][safi]);
+ if (peer_af_flag_check(peer, afi, safi,
PEER_FLAG_MAX_PREFIX_WARNING))
- vty_out(vty, " warning-only");
- if (peer->pmax_restart[afi][safi])
- vty_out(vty, " restart %u",
- peer->pmax_restart[afi][safi]);
- vty_out(vty, "\n");
- }
+ vty_out(vty, " warning-only");
+ if (peer->pmax_restart[afi][safi])
+ vty_out(vty, " restart %u",
+ peer->pmax_restart[afi][safi]);
+
+ vty_out(vty, "\n");
+ }
/* Route server client. */
if (peergroup_af_flag_check(peer, afi, safi,
@@ -7105,42 +7292,22 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
}
/* allowas-in <1-10> */
- if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) {
- if (!peer_group_active(peer)
- || !peer_af_flag_check(g_peer, afi, safi,
- PEER_FLAG_ALLOWAS_IN)
- || peer->allowas_in[afi][safi]
- != g_peer->allowas_in[afi][safi]) {
- if (peer->allowas_in[afi][safi] == 3) {
- vty_out(vty, " neighbor %s allowas-in\n",
- addr);
- } else {
- vty_out(vty, " neighbor %s allowas-in %d\n",
- addr, peer->allowas_in[afi][safi]);
- }
- }
- }
-
- /* allowas-in origin */
- else if (peer_af_flag_check(peer, afi, safi,
- PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
- if (!peer_group_active(peer)
- || !peer_af_flag_check(g_peer, afi, safi,
- PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
+ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) {
+ if (peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
vty_out(vty, " neighbor %s allowas-in origin\n", addr);
+ } else if (peer->allowas_in[afi][safi] == 3) {
+ vty_out(vty, " neighbor %s allowas-in\n", addr);
+ } else {
+ vty_out(vty, " neighbor %s allowas-in %d\n", addr,
+ peer->allowas_in[afi][safi]);
}
}
/* weight */
- if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_WEIGHT))
- if (!peer_group_active(peer)
- || !peer_af_flag_check(g_peer, afi, safi, PEER_FLAG_WEIGHT)
- || peer->weight[afi][safi] != g_peer->weight[afi][safi]) {
- if (peer->weight[afi][safi]) {
- vty_out(vty, " neighbor %s weight %lu\n", addr,
- peer->weight[afi][safi]);
- }
- }
+ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_WEIGHT))
+ vty_out(vty, " neighbor %s weight %lu\n", addr,
+ peer->weight[afi][safi]);
/* Filter. */
bgp_config_write_filter(vty, peer, afi, safi);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index a685411f6e..24d05c2e80 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -866,6 +866,17 @@ struct peer {
*/
uint32_t af_flags_override[AFI_MAX][SAFI_MAX];
/*
+ * Parallel array to af_flags that indicates whether each flag should
+ * be treated as regular (defaults to 0) or inverted (defaults to 1).
+ * If a flag is set to 1 by default, the same bit should be set here.
+ *
+ * Notes:
+ * - This does *not* contain the flag values, rather it contains
+ * whether the flag at the same position in af_flags is *regular* or
+ * *inverted*.
+ */
+ uint32_t af_flags_invert[AFI_MAX][SAFI_MAX];
+ /*
* Effective flags, computed by applying peer-group flags and then
* overriding with individual flags
*/
@@ -1038,6 +1049,32 @@ struct peer {
/* Filter structure. */
struct bgp_filter filter[AFI_MAX][SAFI_MAX];
+ /*
+ * Parallel array to filter that indicates whether each filter
+ * originates from a peer-group or if it is config that is specific to
+ * this individual peer. If a filter is set independent of the
+ * peer-group the appropriate bit should be set here. If this peer is a
+ * peer-group, this memory region should be all zeros. The assumption
+ * is that the default state for all flags is unset. Due to filters
+ * having a direction (e.g. in/out/...), this array has a third
+ * dimension for storing the overrides independently per direction.
+ *
+ * Notes:
+ * - if a filter for an individual peer is unset, the corresponding
+ * override flag is unset and the peer is considered to be back in
+ * sync with the peer-group.
+ * - This does *not* contain the filter values, rather it contains
+ * whether the filter in filter (struct bgp_filter) is peer-specific.
+ */
+ uint8_t filter_override[AFI_MAX][SAFI_MAX][(FILTER_MAX > RMAP_MAX)
+ ? FILTER_MAX
+ : RMAP_MAX];
+#define PEER_FT_DISTRIBUTE_LIST (1 << 0) /* distribute-list */
+#define PEER_FT_FILTER_LIST (1 << 1) /* filter-list */
+#define PEER_FT_PREFIX_LIST (1 << 2) /* prefix-list */
+#define PEER_FT_ROUTE_MAP (1 << 3) /* route-map */
+#define PEER_FT_UNSUPPRESS_MAP (1 << 4) /* unsuppress-map */
+
/* ORF Prefix-list */
struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX];
@@ -1115,6 +1152,18 @@ struct peer {
};
DECLARE_QOBJ_TYPE(peer)
+/* Inherit peer attribute from peer-group. */
+#define PEER_ATTR_INHERIT(peer, attr) ((peer)->attr = (peer)->group->conf->attr)
+#define PEER_STR_ATTR_INHERIT(mt, peer, attr) \
+ do { \
+ if ((peer)->attr) \
+ XFREE(mt, (peer)->attr); \
+ if ((peer)->group->conf->attr) \
+ (peer)->attr = XSTRDUP(mt, (peer)->group->conf->attr); \
+ else \
+ (peer)->attr = NULL; \
+ } while (0)
+
/* Check if suppress start/restart of sessions to peer. */
#define BGP_PEER_START_SUPPRESSED(P) \
(CHECK_FLAG((P)->flags, PEER_FLAG_SHUTDOWN) \
@@ -1513,6 +1562,8 @@ extern int peer_flag_unset(struct peer *, uint32_t);
extern int peer_af_flag_set(struct peer *, afi_t, safi_t, uint32_t);
extern int peer_af_flag_unset(struct peer *, afi_t, safi_t, uint32_t);
extern int peer_af_flag_check(struct peer *, afi_t, safi_t, uint32_t);
+extern void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi,
+ uint32_t flag);
extern int peer_ebgp_multihop_set(struct peer *, int);
extern int peer_ebgp_multihop_unset(struct peer *);
diff --git a/tests/.gitignore b/tests/.gitignore
index 1ff038573f..5b90b7046c 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -26,6 +26,7 @@ __pycache__
/bgpd/test_mp_attr
/bgpd/test_mpath
/bgpd/test_packet
+/bgpd/test_peer_attr
/isisd/test_fuzz_isis_tlv
/isisd/test_fuzz_isis_tlv_tests.h
/isisd/test_isis_vertex_queue
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6a19325927..aefe0d06ac 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -18,6 +18,7 @@ TESTS_BGPD = \
bgpd/test_aspath \
bgpd/test_capability \
bgpd/test_packet \
+ bgpd/test_peer_attr \
bgpd/test_ecommunity \
bgpd/test_mp_attr \
bgpd/test_mpath
@@ -140,6 +141,7 @@ lib_cli_test_commands_SOURCES = lib/cli/test_commands_defun.c \
bgpd_test_aspath_SOURCES = bgpd/test_aspath.c
bgpd_test_capability_SOURCES = bgpd/test_capability.c
bgpd_test_packet_SOURCES = bgpd/test_packet.c
+bgpd_test_peer_attr_SOURCES = bgpd/test_peer_attr.c
bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c
bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c
bgpd_test_mpath_SOURCES = bgpd/test_mpath.c
@@ -179,6 +181,7 @@ lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD)
bgpd_test_aspath_LDADD = $(BGP_TEST_LDADD)
bgpd_test_capability_LDADD = $(BGP_TEST_LDADD)
bgpd_test_packet_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_peer_attr_LDADD = $(BGP_TEST_LDADD)
bgpd_test_ecommunity_LDADD = $(BGP_TEST_LDADD)
bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD)
bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD)
@@ -193,6 +196,7 @@ EXTRA_DIST = \
bgpd/test_ecommunity.py \
bgpd/test_mp_attr.py \
bgpd/test_mpath.py \
+ bgpd/test_peer_attr.py \
helpers/python/frrsix.py \
helpers/python/frrtest.py \
isisd/test_fuzz_isis_tlv.py \
diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c
new file mode 100644
index 0000000000..67a6db849f
--- /dev/null
+++ b/tests/bgpd/test_peer_attr.c
@@ -0,0 +1,1001 @@
+/*
+ * BGP Peer Attribute Unit Tests
+ * Copyright (C) 2018 Pascal Mathis
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "memory.h"
+#include "plist.h"
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_clist.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_filter.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_zebra.h"
+
+#ifdef ENABLE_BGP_VNC
+#include "bgpd/rfapi/rfapi_backend.h"
+#endif
+
+/* Required variables to link in libbgp */
+struct zebra_privs_t bgpd_privs = {0};
+struct thread_master *master;
+
+enum test_state {
+ TEST_SUCCESS,
+ TEST_COMMAND_ERROR,
+ TEST_CONFIG_ERROR,
+ TEST_ASSERT_ERROR,
+ TEST_INTERNAL_ERROR,
+};
+
+struct test {
+ enum test_state state;
+ char *desc;
+ char *error;
+ struct list *log;
+
+ struct vty *vty;
+ struct bgp *bgp;
+ struct peer *peer;
+ struct peer_group *group;
+};
+
+struct test_config {
+ int local_asn;
+ int peer_asn;
+ const char *peer_address;
+ const char *peer_group;
+};
+
+struct test_peer_family {
+ afi_t afi;
+ safi_t safi;
+};
+
+struct test_peer_attr {
+ const char *cmd;
+ const char *peer_cmd;
+ const char *group_cmd;
+
+ enum { PEER_AT_AF_FLAG = 0,
+ PEER_AT_AF_FILTER = 1,
+ PEER_AT_GLOBAL_FLAG = 2 } type;
+ union {
+ uint32_t flag;
+ struct {
+ uint32_t flag;
+ size_t direct;
+ } filter;
+ } u;
+ struct {
+ bool invert;
+ bool use_ibgp;
+ } o;
+
+ afi_t afi;
+ safi_t safi;
+ struct test_peer_family families[AFI_MAX * SAFI_MAX];
+};
+
+#define OUT_SYMBOL_INFO "\u25ba"
+#define OUT_SYMBOL_OK "\u2714"
+#define OUT_SYMBOL_NOK "\u2716"
+
+#define TEST_ASSERT_EQ(T, A, B) \
+ do { \
+ if ((T)->state != TEST_SUCCESS || ((A) == (B))) \
+ break; \
+ (T)->state = TEST_ASSERT_ERROR; \
+ (T)->error = str_printf( \
+ "assertion failed: %s[%d] == [%d]%s (%s:%d)", (#A), \
+ (A), (B), (#B), __FILE__, __LINE__); \
+ } while (0)
+
+static struct test_config cfg = {
+ .local_asn = 100,
+ .peer_asn = 200,
+ .peer_address = "1.1.1.1",
+ .peer_group = "PG-TEST",
+};
+
+static struct test_peer_family test_default_families[] = {
+ {.afi = AFI_IP, .safi = SAFI_UNICAST},
+ {.afi = AFI_IP, .safi = SAFI_MULTICAST},
+ {.afi = AFI_IP6, .safi = SAFI_UNICAST},
+ {.afi = AFI_IP6, .safi = SAFI_MULTICAST},
+};
+
+/* clang-format off */
+static struct test_peer_attr test_peer_attrs[] = {
+ {
+ .cmd = "addpath-tx-all-paths",
+ .u.flag = PEER_FLAG_ADDPATH_TX_ALL_PATHS,
+ },
+ {
+ .cmd = "addpath-tx-bestpath-per-AS",
+ .u.flag = PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS,
+ },
+ {
+ .cmd = "allowas-in",
+ .peer_cmd = "allowas-in 1",
+ .group_cmd = "allowas-in 2",
+ .u.flag = PEER_FLAG_ALLOWAS_IN,
+ },
+ {
+ .cmd = "allowas-in origin",
+ .u.flag = PEER_FLAG_ALLOWAS_IN_ORIGIN,
+ },
+ {
+ .cmd = "as-override",
+ .u.flag = PEER_FLAG_AS_OVERRIDE,
+ },
+ {
+ .cmd = "attribute-unchanged as-path",
+ .u.flag = PEER_FLAG_AS_PATH_UNCHANGED,
+ },
+ {
+ .cmd = "attribute-unchanged next-hop",
+ .u.flag = PEER_FLAG_NEXTHOP_UNCHANGED,
+ },
+ {
+ .cmd = "attribute-unchanged med",
+ .u.flag = PEER_FLAG_MED_UNCHANGED,
+ },
+ {
+ .cmd = "attribute-unchanged as-path next-hop",
+ .u.flag = PEER_FLAG_AS_PATH_UNCHANGED
+ | PEER_FLAG_NEXTHOP_UNCHANGED,
+ },
+ {
+ .cmd = "attribute-unchanged as-path med",
+ .u.flag = PEER_FLAG_AS_PATH_UNCHANGED
+ | PEER_FLAG_MED_UNCHANGED,
+ },
+ {
+ .cmd = "attribute-unchanged as-path next-hop med",
+ .u.flag = PEER_FLAG_AS_PATH_UNCHANGED
+ | PEER_FLAG_NEXTHOP_UNCHANGED
+ | PEER_FLAG_MED_UNCHANGED,
+ },
+ {
+ .cmd = "capability orf prefix-list send",
+ .u.flag = PEER_FLAG_ORF_PREFIX_SM,
+ },
+ {
+ .cmd = "capability orf prefix-list receive",
+ .u.flag = PEER_FLAG_ORF_PREFIX_RM,
+ },
+ {
+ .cmd = "capability orf prefix-list both",
+ .u.flag = PEER_FLAG_ORF_PREFIX_SM | PEER_FLAG_ORF_PREFIX_RM,
+ },
+ {
+ .cmd = "default-originate",
+ .u.flag = PEER_FLAG_DEFAULT_ORIGINATE,
+ },
+ {
+ .cmd = "default-originate route-map",
+ .peer_cmd = "default-originate route-map RM-PEER",
+ .group_cmd = "default-originate route-map RM-GROUP",
+ .u.flag = PEER_FLAG_DEFAULT_ORIGINATE,
+ },
+ {
+ .cmd = "filter-list",
+ .peer_cmd = "filter-list FL-PEER in",
+ .group_cmd = "filter-list FL-GROUP in",
+ .type = PEER_AT_AF_FILTER,
+ .u.filter.flag = PEER_FT_FILTER_LIST,
+ .u.filter.direct = FILTER_IN,
+ },
+ {
+ .cmd = "filter-list",
+ .peer_cmd = "filter-list FL-PEER out",
+ .group_cmd = "filter-list FL-GROUP out",
+ .type = PEER_AT_AF_FILTER,
+ .u.filter.flag = PEER_FT_FILTER_LIST,
+ .u.filter.direct = FILTER_OUT,
+ },
+ {
+ .cmd = "maximum-prefix",
+ .peer_cmd = "maximum-prefix 10",
+ .group_cmd = "maximum-prefix 20",
+ .u.flag = PEER_FLAG_MAX_PREFIX,
+ },
+ {
+ .cmd = "maximum-prefix",
+ .peer_cmd = "maximum-prefix 10 restart 100",
+ .group_cmd = "maximum-prefix 20 restart 200",
+ .u.flag = PEER_FLAG_MAX_PREFIX,
+ },
+ {
+ .cmd = "maximum-prefix",
+ .peer_cmd = "maximum-prefix 10 1 restart 100",
+ .group_cmd = "maximum-prefix 20 2 restart 200",
+ .u.flag = PEER_FLAG_MAX_PREFIX,
+ },
+ {
+ .cmd = "maximum-prefix",
+ .peer_cmd = "maximum-prefix 10 warning-only",
+ .group_cmd = "maximum-prefix 20 warning-only",
+ .u.flag = PEER_FLAG_MAX_PREFIX | PEER_FLAG_MAX_PREFIX_WARNING,
+ },
+ {
+ .cmd = "maximum-prefix",
+ .peer_cmd = "maximum-prefix 10 1 warning-only",
+ .group_cmd = "maximum-prefix 20 2 warning-only",
+ .u.flag = PEER_FLAG_MAX_PREFIX | PEER_FLAG_MAX_PREFIX_WARNING,
+ },
+ {
+ .cmd = "next-hop-self",
+ .u.flag = PEER_FLAG_NEXTHOP_SELF,
+ },
+ {
+ .cmd = "next-hop-self force",
+ .u.flag = PEER_FLAG_FORCE_NEXTHOP_SELF,
+ },
+ {
+ .cmd = "prefix-list",
+ .peer_cmd = "prefix-list PL-PEER in",
+ .group_cmd = "prefix-list PL-GROUP in",
+ .type = PEER_AT_AF_FILTER,
+ .u.filter.flag = PEER_FT_PREFIX_LIST,
+ .u.filter.direct = FILTER_IN,
+ },
+ {
+ .cmd = "prefix-list",
+ .peer_cmd = "prefix-list PL-PEER out",
+ .group_cmd = "prefix-list PL-GROUP out",
+ .type = PEER_AT_AF_FILTER,
+ .u.filter.flag = PEER_FT_PREFIX_LIST,
+ .u.filter.direct = FILTER_OUT,
+ },
+ {
+ .cmd = "remove-private-AS",
+ .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS,
+ },
+ {
+ .cmd = "remove-private-AS all",
+ .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS
+ | PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+ },
+ {
+ .cmd = "remove-private-AS replace-AS",
+ .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS
+ | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+ },
+ {
+ .cmd = "remove-private-AS all replace-AS",
+ .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+ },
+ {
+ .cmd = "route-map",
+ .peer_cmd = "route-map RM-PEER in",
+ .group_cmd = "route-map RM-GROUP in",
+ .type = PEER_AT_AF_FILTER,
+ .u.filter.flag = PEER_FT_ROUTE_MAP,
+ .u.filter.direct = FILTER_IN,
+ },
+ {
+ .cmd = "route-map",
+ .peer_cmd = "route-map RM-PEER out",
+ .group_cmd = "route-map RM-GROUP out",
+ .type = PEER_AT_AF_FILTER,
+ .u.filter.flag = PEER_FT_ROUTE_MAP,
+ .u.filter.direct = FILTER_OUT,
+ },
+ {
+ .cmd = "route-reflector-client",
+ .u.flag = PEER_FLAG_REFLECTOR_CLIENT,
+ .o.use_ibgp = true,
+ },
+ {
+ .cmd = "route-server-client",
+ .u.flag = PEER_FLAG_RSERVER_CLIENT,
+ },
+ {
+ .cmd = "send-community",
+ .u.flag = PEER_FLAG_SEND_COMMUNITY,
+ .o.invert = true,
+ },
+ {
+ .cmd = "send-community extended",
+ .u.flag = PEER_FLAG_SEND_EXT_COMMUNITY,
+ .o.invert = true,
+ },
+ {
+ .cmd = "send-community large",
+ .u.flag = PEER_FLAG_SEND_LARGE_COMMUNITY,
+ .o.invert = true,
+ },
+ {
+ .cmd = "soft-reconfiguration inbound",
+ .u.flag = PEER_FLAG_SOFT_RECONFIG,
+ },
+ {
+ .cmd = "unsuppress-map",
+ .peer_cmd = "unsuppress-map UM-PEER",
+ .group_cmd = "unsuppress-map UM-GROUP",
+ .type = PEER_AT_AF_FILTER,
+ .u.filter.flag = PEER_FT_UNSUPPRESS_MAP,
+ .u.filter.direct = 0,
+ },
+ {
+ .cmd = "weight",
+ .peer_cmd = "weight 100",
+ .group_cmd = "weight 200",
+ .u.flag = PEER_FLAG_WEIGHT,
+ },
+ {NULL}
+};
+/* clang-format on */
+
+static char *str_vprintf(const char *fmt, va_list ap)
+{
+ int ret;
+ int buf_size = 0;
+ char *buf = NULL;
+ va_list apc;
+
+ while (1) {
+ va_copy(apc, ap);
+ ret = vsnprintf(buf, buf_size, fmt, apc);
+ va_end(apc);
+
+ if (ret >= 0 && ret < buf_size)
+ break;
+
+ if (ret >= 0)
+ buf_size = ret + 1;
+ else
+ buf_size *= 2;
+
+ buf = XREALLOC(MTYPE_TMP, buf, buf_size);
+ }
+
+ return buf;
+}
+
+static char *str_printf(const char *fmt, ...)
+{
+ char *buf;
+ va_list ap;
+
+ va_start(ap, fmt);
+ buf = str_vprintf(fmt, ap);
+ va_end(ap);
+
+ return buf;
+}
+
+static const char *str_from_afi(afi_t afi)
+{
+ switch (afi) {
+ case AFI_IP:
+ return "ipv4";
+ case AFI_IP6:
+ return "ipv6";
+ default:
+ return "<unknown AFI>";
+ }
+}
+
+static const char *str_from_safi(safi_t safi)
+{
+ switch (safi) {
+ case SAFI_UNICAST:
+ return "unicast";
+ case SAFI_MULTICAST:
+ return "multicast";
+ default:
+ return "<unknown SAFI>";
+ }
+}
+
+static void test_execute(struct test *test, const char *fmt, ...)
+{
+ int ret;
+ char *cmd;
+ va_list ap;
+ vector vline;
+
+ /* Skip execution if test instance has previously failed. */
+ if (test->state != TEST_SUCCESS)
+ return;
+
+ /* Format command string with variadic arguments. */
+ va_start(ap, fmt);
+ cmd = str_vprintf(fmt, ap);
+ va_end(ap);
+ if (!cmd) {
+ test->state = TEST_INTERNAL_ERROR;
+ test->error =
+ str_printf("could not format command string [%s]", fmt);
+ return;
+ }
+
+ /* Tokenize formatted command string. */
+ vline = cmd_make_strvec(cmd);
+ if (vline == NULL) {
+ test->state = TEST_INTERNAL_ERROR;
+ test->error = str_printf(
+ "tokenizing command string [%s] returned empty result",
+ cmd);
+ XFREE(MTYPE_TMP, cmd);
+
+ return;
+ }
+
+ /* Execute command (non-strict). */
+ ret = cmd_execute_command(vline, test->vty, NULL, 0);
+ if (ret != CMD_SUCCESS) {
+ test->state = TEST_COMMAND_ERROR;
+ test->error = str_printf(
+ "execution of command [%s] has failed with code [%d]",
+ cmd, ret);
+ }
+
+ /* Free memory. */
+ cmd_free_strvec(vline);
+ XFREE(MTYPE_TMP, cmd);
+}
+
+static void test_config(struct test *test, const char *fmt, bool invert,
+ va_list ap)
+{
+ char *matcher;
+ char *config;
+ bool matched;
+ va_list apc;
+
+ /* Skip execution if test instance has previously failed. */
+ if (test->state != TEST_SUCCESS)
+ return;
+
+ /* Format matcher string with variadic arguments. */
+ va_copy(apc, ap);
+ matcher = str_vprintf(fmt, apc);
+ va_end(apc);
+ if (!matcher) {
+ test->state = TEST_INTERNAL_ERROR;
+ test->error =
+ str_printf("could not format matcher string [%s]", fmt);
+ return;
+ }
+
+ /* Fetch BGP configuration into buffer. */
+ bgp_config_write(test->vty);
+ config = buffer_getstr(test->vty->obuf);
+ buffer_reset(test->vty->obuf);
+
+ /* Match config against matcher. */
+ matched = !!strstr(config, matcher);
+ if (!matched && !invert) {
+ test->state = TEST_CONFIG_ERROR;
+ test->error = str_printf("expected config [%s] to be present",
+ matcher);
+ } else if (matched && invert) {
+ test->state = TEST_CONFIG_ERROR;
+ test->error = str_printf("expected config [%s] to be absent",
+ matcher);
+ }
+
+ /* Free memory and return. */
+ XFREE(MTYPE_TMP, matcher);
+ XFREE(MTYPE_TMP, config);
+}
+
+static void test_config_present(struct test *test, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ test_config(test, fmt, false, ap);
+ va_end(ap);
+}
+
+static void test_config_absent(struct test *test, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ test_config(test, fmt, true, ap);
+ va_end(ap);
+}
+
+static struct test *test_new(const char *desc, bool use_ibgp)
+{
+ struct test *test;
+ union sockunion su;
+
+ test = XCALLOC(MTYPE_TMP, sizeof(struct test));
+ test->state = TEST_SUCCESS;
+ test->desc = XSTRDUP(MTYPE_TMP, desc);
+ test->log = list_new();
+
+ test->vty = vty_new();
+ test->vty->type = VTY_TERM;
+ test->vty->node = CONFIG_NODE;
+
+ /* Attempt gracefully to purge previous BGP configuration. */
+ test_execute(test, "no router bgp");
+ test->state = TEST_SUCCESS;
+
+ /* Initialize BGP test environment. */
+ test_execute(test, "router bgp %d", cfg.local_asn);
+ test_execute(test, "no bgp default ipv4-unicast");
+ test_execute(test, "neighbor %s peer-group", cfg.peer_group);
+ test_execute(test, "neighbor %s remote-as %d", cfg.peer_address,
+ use_ibgp ? cfg.local_asn : cfg.peer_asn);
+ if (test->state != TEST_SUCCESS)
+ return test;
+
+ /* Fetch default BGP instance. */
+ test->bgp = bgp_get_default();
+ if (!test->bgp) {
+ test->state = TEST_INTERNAL_ERROR;
+ test->error =
+ str_printf("could not retrieve default bgp instance");
+ return test;
+ }
+
+ /* Fetch peer instance. */
+ str2sockunion(cfg.peer_address, &su);
+ test->peer = peer_lookup(test->bgp, &su);
+ if (!test->peer) {
+ test->state = TEST_INTERNAL_ERROR;
+ test->error = str_printf(
+ "could not retrieve instance of bgp peer [%s]",
+ cfg.peer_address);
+ return test;
+ }
+
+ /* Fetch peer-group instance. */
+ test->group = peer_group_lookup(test->bgp, cfg.peer_group);
+ if (!test->group) {
+ test->state = TEST_INTERNAL_ERROR;
+ test->error = str_printf(
+ "could not retrieve instance of bgp peer-group [%s]",
+ cfg.peer_group);
+ return test;
+ }
+
+ return test;
+};
+
+static void test_log(struct test *test, const char *fmt, ...)
+{
+ va_list ap;
+
+ /* Skip logging if test instance has previously failed. */
+ if (test->state != TEST_SUCCESS)
+ return;
+
+ /* Store formatted log message. */
+ va_start(ap, fmt);
+ listnode_add(test->log, str_vprintf(fmt, ap));
+ va_end(ap);
+}
+
+static void test_finish(struct test *test)
+{
+ char *msg;
+ struct listnode *node, *nnode;
+
+ /* Print test output header. */
+ printf("%s [test] %s\n",
+ (test->state == TEST_SUCCESS) ? OUT_SYMBOL_OK : OUT_SYMBOL_NOK,
+ test->desc);
+
+ /* Print test log messages. */
+ for (ALL_LIST_ELEMENTS(test->log, node, nnode, msg)) {
+ printf("%s %s\n", OUT_SYMBOL_INFO, msg);
+ XFREE(MTYPE_TMP, msg);
+ }
+
+ /* Print test error message if available. */
+ if (test->state != TEST_SUCCESS && test->error)
+ printf("%s error: %s\n", OUT_SYMBOL_INFO, test->error);
+
+ /* Print machine-readable result of test. */
+ printf("%s\n", test->state == TEST_SUCCESS ? "OK" : "failed");
+
+ /* Cleanup allocated memory. */
+ if (test->vty) {
+ vty_close(test->vty);
+ test->vty = NULL;
+ }
+ if (test->log)
+ list_delete_and_null(&test->log);
+ if (test->desc)
+ XFREE(MTYPE_TMP, test->desc);
+ if (test->error)
+ XFREE(MTYPE_TMP, test->error);
+ XFREE(MTYPE_TMP, test);
+}
+
+static void test_af_flags(struct test *test, struct peer *peer,
+ struct test_peer_attr *attr, bool exp_val,
+ bool exp_ovrd)
+{
+ bool exp_inv, cur_val, cur_ovrd, cur_inv;
+
+ /* Flip expected values for inverted flags. */
+ exp_inv = attr->o.invert;
+ exp_val ^= exp_inv;
+
+ /* Fetch current state of value, override and invert flags. */
+ cur_val = !!CHECK_FLAG(peer->af_flags[attr->afi][attr->safi],
+ attr->u.flag);
+ cur_ovrd = !!CHECK_FLAG(peer->af_flags_override[attr->afi][attr->safi],
+ attr->u.flag);
+ cur_inv = !!CHECK_FLAG(peer->af_flags_invert[attr->afi][attr->safi],
+ attr->u.flag);
+
+ /* Assert expected flag states. */
+ TEST_ASSERT_EQ(test, cur_val, exp_val);
+ TEST_ASSERT_EQ(test, cur_ovrd, exp_ovrd);
+ TEST_ASSERT_EQ(test, cur_inv, exp_inv);
+}
+
+static void test_af_filter(struct test *test, struct peer *peer,
+ struct test_peer_attr *attr, bool exp_state,
+ bool exp_ovrd)
+{
+ bool cur_ovrd;
+ struct bgp_filter *filter;
+
+ /* Fetch and assert current state of override flag. */
+ cur_ovrd = !!CHECK_FLAG(peer->filter_override[attr->afi][attr->safi]
+ [attr->u.filter.direct],
+ attr->u.filter.flag);
+
+ TEST_ASSERT_EQ(test, cur_ovrd, exp_ovrd);
+
+ /* Assert that map/list matches expected state (set/unset). */
+ filter = &peer->filter[attr->afi][attr->safi];
+
+ switch (attr->u.filter.flag) {
+ case PEER_FT_DISTRIBUTE_LIST:
+ TEST_ASSERT_EQ(test,
+ !!(filter->dlist[attr->u.filter.direct].name),
+ exp_state);
+ break;
+ case PEER_FT_FILTER_LIST:
+ TEST_ASSERT_EQ(test,
+ !!(filter->aslist[attr->u.filter.direct].name),
+ exp_state);
+ break;
+ case PEER_FT_PREFIX_LIST:
+ TEST_ASSERT_EQ(test,
+ !!(filter->plist[attr->u.filter.direct].name),
+ exp_state);
+ break;
+ case PEER_FT_ROUTE_MAP:
+ TEST_ASSERT_EQ(test,
+ !!(filter->map[attr->u.filter.direct].name),
+ exp_state);
+ break;
+ case PEER_FT_UNSUPPRESS_MAP:
+ TEST_ASSERT_EQ(test, !!(filter->usmap.name), exp_state);
+ break;
+ }
+}
+
+static void test_peer_attr(struct test *test, struct test_peer_attr *pa)
+{
+ int tc = 1;
+ const char *type;
+ const char *ec = pa->o.invert ? "no " : "";
+ const char *dc = pa->o.invert ? "" : "no ";
+ const char *peer_cmd = pa->peer_cmd ?: pa->cmd;
+ const char *group_cmd = pa->group_cmd ?: pa->cmd;
+ struct peer *p = test->peer;
+ struct peer_group *g = test->group;
+
+ if (pa->type == PEER_AT_AF_FLAG)
+ type = "af-flag";
+ else /* if (pa->type == PEER_AT_AF_FILTER) */
+ type = "af-filter";
+
+ /* Test Case: Switch active address-family. */
+ if (pa->type == PEER_AT_AF_FLAG || pa->type == PEER_AT_AF_FILTER) {
+ test_log(test, "prepare: switch address-family to [%s]",
+ afi_safi_print(pa->afi, pa->safi));
+ test_execute(test, "address-family %s %s",
+ str_from_afi(pa->afi), str_from_safi(pa->safi));
+ }
+
+ /* Test Case: Set flag on BGP peer. */
+ test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd,
+ p->host);
+ test_execute(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
+ if (pa->type == PEER_AT_AF_FLAG) {
+ test_af_flags(test, p, pa, true, true);
+ test_af_flags(test, g->conf, pa, false, false);
+ } else if (pa->type == PEER_AT_AF_FILTER) {
+ test_af_filter(test, p, pa, true, true);
+ test_af_filter(test, g->conf, pa, false, false);
+ }
+
+ /* Test Case: Add BGP peer to peer-group. */
+ test_log(test, "case %02d: add peer [%s] to group [%s]", tc++, p->host,
+ g->name);
+ test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
+ test_config_present(test, "neighbor %s peer-group %s", p->host,
+ g->name);
+ test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
+ if (pa->type == PEER_AT_AF_FLAG) {
+ test_af_flags(test, p, pa, true, true);
+ test_af_flags(test, g->conf, pa, false, false);
+ } else if (pa->type == PEER_AT_AF_FILTER) {
+ test_af_filter(test, p, pa, true, true);
+ test_af_filter(test, g->conf, pa, false, false);
+ }
+
+ /* Test Case: Re-add BGP peer to peer-group. */
+ test_log(test, "case %02d: re-add peer [%s] to group [%s]", tc++,
+ p->host, g->name);
+ test_execute(test, "neighbor %s peer-group %s", p->host, g->name);
+ test_config_present(test, "neighbor %s peer-group %s", p->host,
+ g->name);
+ test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
+ if (pa->type == PEER_AT_AF_FLAG) {
+ test_af_flags(test, p, pa, true, true);
+ test_af_flags(test, g->conf, pa, false, false);
+ } else if (pa->type == PEER_AT_AF_FILTER) {
+ test_af_filter(test, p, pa, true, true);
+ test_af_filter(test, g->conf, pa, false, false);
+ }
+
+ /* Test Case: Set flag on BGP peer-group. */
+ test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
+ g->name);
+ test_execute(test, "%sneighbor %s %s", ec, g->name, group_cmd);
+ test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
+ if (pa->type == PEER_AT_AF_FLAG) {
+ test_af_flags(test, p, pa, true, true);
+ test_af_flags(test, g->conf, pa, true, false);
+ } else if (pa->type == PEER_AT_AF_FILTER) {
+ test_af_filter(test, p, pa, true, true);
+ test_af_filter(test, g->conf, pa, true, false);
+ }
+
+ /* Test Case: Unset flag on BGP peer-group. */
+ test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type,
+ group_cmd, g->name);
+ test_execute(test, "%sneighbor %s %s", dc, g->name, group_cmd);
+ test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
+ if (pa->type == PEER_AT_AF_FLAG) {
+ test_af_flags(test, p, pa, true, true);
+ test_af_flags(test, g->conf, pa, false, false);
+ } else if (pa->type == PEER_AT_AF_FILTER) {
+ test_af_filter(test, p, pa, true, true);
+ test_af_filter(test, g->conf, pa, false, false);
+ }
+
+ /* Test Case: Set flag on BGP peer-group. */
+ test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, group_cmd,
+ g->name);
+ test_execute(test, "%sneighbor %s %s", ec, g->name, group_cmd);
+ test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
+ if (pa->type == PEER_AT_AF_FLAG) {
+ test_af_flags(test, p, pa, true, true);
+ test_af_flags(test, g->conf, pa, true, false);
+ } else if (pa->type == PEER_AT_AF_FILTER) {
+ test_af_filter(test, p, pa, true, true);
+ test_af_filter(test, g->conf, pa, true, false);
+ }
+
+ /* Test Case: Re-set flag on BGP peer. */
+ test_log(test, "case %02d: re-set %s [%s] on [%s]", tc++, type,
+ peer_cmd, p->host);
+ test_execute(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
+ if (pa->type == PEER_AT_AF_FLAG) {
+ test_af_flags(test, p, pa, true, true);
+ test_af_flags(test, g->conf, pa, true, false);
+ } else if (pa->type == PEER_AT_AF_FILTER) {
+ test_af_filter(test, p, pa, true, true);
+ test_af_filter(test, g->conf, pa, true, false);
+ }
+
+ /* Test Case: Unset flag on BGP peer. */
+ test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type, peer_cmd,
+ p->host);
+ test_execute(test, "%sneighbor %s %s", dc, p->host, peer_cmd);
+ test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
+ test_config_present(test, "%sneighbor %s %s", ec, g->name, group_cmd);
+ if (pa->type == PEER_AT_AF_FLAG) {
+ test_af_flags(test, p, pa, true, false);
+ test_af_flags(test, g->conf, pa, true, false);
+ } else if (pa->type == PEER_AT_AF_FILTER) {
+ test_af_filter(test, p, pa, true, false);
+ test_af_filter(test, g->conf, pa, true, false);
+ }
+
+ /* Test Case: Unset flag on BGP peer-group. */
+ test_log(test, "case %02d: unset %s [%s] on [%s]", tc++, type,
+ group_cmd, g->name);
+ test_execute(test, "%sneighbor %s %s", dc, g->name, group_cmd);
+ test_config_absent(test, "neighbor %s %s", p->host, pa->cmd);
+ test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
+ if (pa->type == PEER_AT_AF_FLAG) {
+ test_af_flags(test, p, pa, false, false);
+ test_af_flags(test, g->conf, pa, false, false);
+ } else if (pa->type == PEER_AT_AF_FILTER) {
+ test_af_filter(test, p, pa, false, false);
+ test_af_filter(test, g->conf, pa, false, false);
+ }
+
+ /* Test Case: Set flag on BGP peer. */
+ test_log(test, "case %02d: set %s [%s] on [%s]", tc++, type, peer_cmd,
+ p->host);
+ test_execute(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_present(test, "%sneighbor %s %s", ec, p->host, peer_cmd);
+ test_config_absent(test, "neighbor %s %s", g->name, pa->cmd);
+ if (pa->type == PEER_AT_AF_FLAG) {
+ test_af_flags(test, p, pa, true, true);
+ test_af_flags(test, g->conf, pa, false, false);
+ } else if (pa->type == PEER_AT_AF_FILTER) {
+ test_af_filter(test, p, pa, true, true);
+ test_af_filter(test, g->conf, pa, false, false);
+ }
+}
+
+static void bgp_startup(void)
+{
+ cmd_init(1);
+ openzlog("testbgpd", "NONE", 0, LOG_CONS | LOG_NDELAY | LOG_PID,
+ LOG_DAEMON);
+ zprivs_preinit(&bgpd_privs);
+ zprivs_init(&bgpd_privs);
+
+ master = thread_master_create(NULL);
+ bgp_master_init(master);
+ bgp_option_set(BGP_OPT_NO_LISTEN);
+ vrf_init(NULL, NULL, NULL, NULL);
+ bgp_init();
+ bgp_pthreads_run();
+}
+
+static void bgp_shutdown(void)
+{
+ struct bgp *bgp;
+ struct listnode *node, *nnode;
+
+ bgp_terminate();
+ bgp_close();
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+ bgp_delete(bgp);
+ bgp_dump_finish();
+ bgp_route_finish();
+ bgp_route_map_terminate();
+ bgp_attr_finish();
+ bgp_pthreads_finish();
+ access_list_add_hook(NULL);
+ access_list_delete_hook(NULL);
+ access_list_reset();
+ as_list_add_hook(NULL);
+ as_list_delete_hook(NULL);
+ bgp_filter_reset();
+ prefix_list_add_hook(NULL);
+ prefix_list_delete_hook(NULL);
+ prefix_list_reset();
+ community_list_terminate(bgp_clist);
+ vrf_terminate();
+#ifdef ENABLE_BGP_VNC
+ vnc_zebra_destroy();
+#endif
+ bgp_zebra_destroy();
+
+ bf_free(bm->rd_idspace);
+ list_delete_and_null(&bm->bgp);
+ memset(bm, 0, sizeof(*bm));
+
+ vty_terminate();
+ cmd_terminate();
+ zprivs_terminate(&bgpd_privs);
+ thread_master_free(master);
+ master = NULL;
+ closezlog();
+}
+
+int main(void)
+{
+ int i, ii;
+ struct list *pa_list;
+ struct test_peer_attr *pa, *pac;
+ struct listnode *node, *nnode;
+
+ bgp_startup();
+
+ pa_list = list_new();
+ i = 0;
+ while (test_peer_attrs[i].cmd) {
+ pa = &test_peer_attrs[i++];
+
+ /* Just copy the peer attribute structure for global flags. */
+ if (pa->type == PEER_AT_GLOBAL_FLAG) {
+ pac = XMALLOC(MTYPE_TMP, sizeof(struct test_peer_attr));
+ memcpy(pac, pa, sizeof(struct test_peer_attr));
+ listnode_add(pa_list, pac);
+ continue;
+ }
+
+ /* Fallback to default families if not specified. */
+ if (!pa->families[0].afi && !pa->families[0].safi)
+ memcpy(&pa->families, test_default_families,
+ sizeof(test_default_families));
+
+ /* Add peer attribute definition for each address family. */
+ ii = 0;
+ while (pa->families[ii].afi && pa->families[ii].safi) {
+ pac = XMALLOC(MTYPE_TMP, sizeof(struct test_peer_attr));
+ memcpy(pac, pa, sizeof(struct test_peer_attr));
+
+ pac->afi = pa->families[ii].afi;
+ pac->safi = pa->families[ii].safi;
+ listnode_add(pa_list, pac);
+
+ ii++;
+ }
+ }
+
+ for (ALL_LIST_ELEMENTS(pa_list, node, nnode, pa)) {
+ char *desc;
+ struct test *test;
+
+ /* Build test description string. */
+ if (pa->afi && pa->safi)
+ desc = str_printf("peer\\%s-%s\\%s",
+ str_from_afi(pa->afi),
+ str_from_safi(pa->safi), pa->cmd);
+ else
+ desc = str_printf("peer\\%s", pa->cmd);
+
+ /* Initialize new test instance. */
+ test = test_new(desc, pa->o.use_ibgp);
+ XFREE(MTYPE_TMP, desc);
+
+ /* Execute tests and finish test instance. */
+ test_peer_attr(test, pa);
+ test_finish(test);
+
+ /* Print empty line as spacer. */
+ printf("\n");
+
+ /* Free memory used for peer-attr declaration. */
+ XFREE(MTYPE_TMP, pa);
+ }
+
+ list_delete_and_null(&pa_list);
+ bgp_shutdown();
+
+ return 0;
+}
diff --git a/tests/bgpd/test_peer_attr.py b/tests/bgpd/test_peer_attr.py
new file mode 100644
index 0000000000..d93dfc0050
--- /dev/null
+++ b/tests/bgpd/test_peer_attr.py
@@ -0,0 +1,172 @@
+import frrtest
+
+class TestFlag(frrtest.TestMultiOut):
+ program = './test_peer_attr'
+
+# List of tests can be generated by executing:
+# $> ./test_peer_attr 2>&1 | sed -n 's/\\/\\\\/g; s/\S\+ \[test\] \(.\+\)/TestFlag.okfail(\x27\1\x27)/pg'
+#
+TestFlag.okfail('peer\\ipv4-unicast\\addpath-tx-all-paths')
+TestFlag.okfail('peer\\ipv4-multicast\\addpath-tx-all-paths')
+TestFlag.okfail('peer\\ipv6-unicast\\addpath-tx-all-paths')
+TestFlag.okfail('peer\\ipv6-multicast\\addpath-tx-all-paths')
+TestFlag.okfail('peer\\ipv4-unicast\\addpath-tx-bestpath-per-AS')
+TestFlag.okfail('peer\\ipv4-multicast\\addpath-tx-bestpath-per-AS')
+TestFlag.okfail('peer\\ipv6-unicast\\addpath-tx-bestpath-per-AS')
+TestFlag.okfail('peer\\ipv6-multicast\\addpath-tx-bestpath-per-AS')
+TestFlag.okfail('peer\\ipv4-unicast\\allowas-in')
+TestFlag.okfail('peer\\ipv4-multicast\\allowas-in')
+TestFlag.okfail('peer\\ipv6-unicast\\allowas-in')
+TestFlag.okfail('peer\\ipv6-multicast\\allowas-in')
+TestFlag.okfail('peer\\ipv4-unicast\\allowas-in origin')
+TestFlag.okfail('peer\\ipv4-multicast\\allowas-in origin')
+TestFlag.okfail('peer\\ipv6-unicast\\allowas-in origin')
+TestFlag.okfail('peer\\ipv6-multicast\\allowas-in origin')
+TestFlag.okfail('peer\\ipv4-unicast\\as-override')
+TestFlag.okfail('peer\\ipv4-multicast\\as-override')
+TestFlag.okfail('peer\\ipv6-unicast\\as-override')
+TestFlag.okfail('peer\\ipv6-multicast\\as-override')
+TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged as-path')
+TestFlag.okfail('peer\\ipv4-multicast\\attribute-unchanged as-path')
+TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged as-path')
+TestFlag.okfail('peer\\ipv6-multicast\\attribute-unchanged as-path')
+TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged next-hop')
+TestFlag.okfail('peer\\ipv4-multicast\\attribute-unchanged next-hop')
+TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged next-hop')
+TestFlag.okfail('peer\\ipv6-multicast\\attribute-unchanged next-hop')
+TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged med')
+TestFlag.okfail('peer\\ipv4-multicast\\attribute-unchanged med')
+TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged med')
+TestFlag.okfail('peer\\ipv6-multicast\\attribute-unchanged med')
+TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged as-path next-hop')
+TestFlag.okfail('peer\\ipv4-multicast\\attribute-unchanged as-path next-hop')
+TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged as-path next-hop')
+TestFlag.okfail('peer\\ipv6-multicast\\attribute-unchanged as-path next-hop')
+TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged as-path med')
+TestFlag.okfail('peer\\ipv4-multicast\\attribute-unchanged as-path med')
+TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged as-path med')
+TestFlag.okfail('peer\\ipv6-multicast\\attribute-unchanged as-path med')
+TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged as-path next-hop med')
+TestFlag.okfail('peer\\ipv4-multicast\\attribute-unchanged as-path next-hop med')
+TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged as-path next-hop med')
+TestFlag.okfail('peer\\ipv6-multicast\\attribute-unchanged as-path next-hop med')
+TestFlag.okfail('peer\\ipv4-unicast\\capability orf prefix-list send')
+TestFlag.okfail('peer\\ipv4-multicast\\capability orf prefix-list send')
+TestFlag.okfail('peer\\ipv6-unicast\\capability orf prefix-list send')
+TestFlag.okfail('peer\\ipv6-multicast\\capability orf prefix-list send')
+TestFlag.okfail('peer\\ipv4-unicast\\capability orf prefix-list receive')
+TestFlag.okfail('peer\\ipv4-multicast\\capability orf prefix-list receive')
+TestFlag.okfail('peer\\ipv6-unicast\\capability orf prefix-list receive')
+TestFlag.okfail('peer\\ipv6-multicast\\capability orf prefix-list receive')
+TestFlag.okfail('peer\\ipv4-unicast\\capability orf prefix-list both')
+TestFlag.okfail('peer\\ipv4-multicast\\capability orf prefix-list both')
+TestFlag.okfail('peer\\ipv6-unicast\\capability orf prefix-list both')
+TestFlag.okfail('peer\\ipv6-multicast\\capability orf prefix-list both')
+TestFlag.okfail('peer\\ipv4-unicast\\default-originate')
+TestFlag.okfail('peer\\ipv4-multicast\\default-originate')
+TestFlag.okfail('peer\\ipv6-unicast\\default-originate')
+TestFlag.okfail('peer\\ipv6-multicast\\default-originate')
+TestFlag.okfail('peer\\ipv4-unicast\\default-originate route-map')
+TestFlag.okfail('peer\\ipv4-multicast\\default-originate route-map')
+TestFlag.okfail('peer\\ipv6-unicast\\default-originate route-map')
+TestFlag.okfail('peer\\ipv6-multicast\\default-originate route-map')
+TestFlag.okfail('peer\\ipv4-unicast\\filter-list')
+TestFlag.okfail('peer\\ipv4-multicast\\filter-list')
+TestFlag.okfail('peer\\ipv6-unicast\\filter-list')
+TestFlag.okfail('peer\\ipv6-multicast\\filter-list')
+TestFlag.okfail('peer\\ipv4-unicast\\filter-list')
+TestFlag.okfail('peer\\ipv4-multicast\\filter-list')
+TestFlag.okfail('peer\\ipv6-unicast\\filter-list')
+TestFlag.okfail('peer\\ipv6-multicast\\filter-list')
+TestFlag.okfail('peer\\ipv4-unicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv4-multicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv6-unicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv6-multicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv4-unicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv4-multicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv6-unicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv6-multicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv4-unicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv4-multicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv6-unicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv6-multicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv4-unicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv4-multicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv6-unicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv6-multicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv4-unicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv4-multicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv6-unicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv6-multicast\\maximum-prefix')
+TestFlag.okfail('peer\\ipv4-unicast\\next-hop-self')
+TestFlag.okfail('peer\\ipv4-multicast\\next-hop-self')
+TestFlag.okfail('peer\\ipv6-unicast\\next-hop-self')
+TestFlag.okfail('peer\\ipv6-multicast\\next-hop-self')
+TestFlag.okfail('peer\\ipv4-unicast\\next-hop-self force')
+TestFlag.okfail('peer\\ipv4-multicast\\next-hop-self force')
+TestFlag.okfail('peer\\ipv6-unicast\\next-hop-self force')
+TestFlag.okfail('peer\\ipv6-multicast\\next-hop-self force')
+TestFlag.okfail('peer\\ipv4-unicast\\prefix-list')
+TestFlag.okfail('peer\\ipv4-multicast\\prefix-list')
+TestFlag.okfail('peer\\ipv6-unicast\\prefix-list')
+TestFlag.okfail('peer\\ipv6-multicast\\prefix-list')
+TestFlag.okfail('peer\\ipv4-unicast\\prefix-list')
+TestFlag.okfail('peer\\ipv4-multicast\\prefix-list')
+TestFlag.okfail('peer\\ipv6-unicast\\prefix-list')
+TestFlag.okfail('peer\\ipv6-multicast\\prefix-list')
+TestFlag.okfail('peer\\ipv4-unicast\\remove-private-AS')
+TestFlag.okfail('peer\\ipv4-multicast\\remove-private-AS')
+TestFlag.okfail('peer\\ipv6-unicast\\remove-private-AS')
+TestFlag.okfail('peer\\ipv6-multicast\\remove-private-AS')
+TestFlag.okfail('peer\\ipv4-unicast\\remove-private-AS all')
+TestFlag.okfail('peer\\ipv4-multicast\\remove-private-AS all')
+TestFlag.okfail('peer\\ipv6-unicast\\remove-private-AS all')
+TestFlag.okfail('peer\\ipv6-multicast\\remove-private-AS all')
+TestFlag.okfail('peer\\ipv4-unicast\\remove-private-AS replace-AS')
+TestFlag.okfail('peer\\ipv4-multicast\\remove-private-AS replace-AS')
+TestFlag.okfail('peer\\ipv6-unicast\\remove-private-AS replace-AS')
+TestFlag.okfail('peer\\ipv6-multicast\\remove-private-AS replace-AS')
+TestFlag.okfail('peer\\ipv4-unicast\\remove-private-AS all replace-AS')
+TestFlag.okfail('peer\\ipv4-multicast\\remove-private-AS all replace-AS')
+TestFlag.okfail('peer\\ipv6-unicast\\remove-private-AS all replace-AS')
+TestFlag.okfail('peer\\ipv6-multicast\\remove-private-AS all replace-AS')
+TestFlag.okfail('peer\\ipv4-unicast\\route-map')
+TestFlag.okfail('peer\\ipv4-multicast\\route-map')
+TestFlag.okfail('peer\\ipv6-unicast\\route-map')
+TestFlag.okfail('peer\\ipv6-multicast\\route-map')
+TestFlag.okfail('peer\\ipv4-unicast\\route-map')
+TestFlag.okfail('peer\\ipv4-multicast\\route-map')
+TestFlag.okfail('peer\\ipv6-unicast\\route-map')
+TestFlag.okfail('peer\\ipv6-multicast\\route-map')
+TestFlag.okfail('peer\\ipv4-unicast\\route-reflector-client')
+TestFlag.okfail('peer\\ipv4-multicast\\route-reflector-client')
+TestFlag.okfail('peer\\ipv6-unicast\\route-reflector-client')
+TestFlag.okfail('peer\\ipv6-multicast\\route-reflector-client')
+TestFlag.okfail('peer\\ipv4-unicast\\route-server-client')
+TestFlag.okfail('peer\\ipv4-multicast\\route-server-client')
+TestFlag.okfail('peer\\ipv6-unicast\\route-server-client')
+TestFlag.okfail('peer\\ipv6-multicast\\route-server-client')
+TestFlag.okfail('peer\\ipv4-unicast\\send-community')
+TestFlag.okfail('peer\\ipv4-multicast\\send-community')
+TestFlag.okfail('peer\\ipv6-unicast\\send-community')
+TestFlag.okfail('peer\\ipv6-multicast\\send-community')
+TestFlag.okfail('peer\\ipv4-unicast\\send-community extended')
+TestFlag.okfail('peer\\ipv4-multicast\\send-community extended')
+TestFlag.okfail('peer\\ipv6-unicast\\send-community extended')
+TestFlag.okfail('peer\\ipv6-multicast\\send-community extended')
+TestFlag.okfail('peer\\ipv4-unicast\\send-community large')
+TestFlag.okfail('peer\\ipv4-multicast\\send-community large')
+TestFlag.okfail('peer\\ipv6-unicast\\send-community large')
+TestFlag.okfail('peer\\ipv6-multicast\\send-community large')
+TestFlag.okfail('peer\\ipv4-unicast\\soft-reconfiguration inbound')
+TestFlag.okfail('peer\\ipv4-multicast\\soft-reconfiguration inbound')
+TestFlag.okfail('peer\\ipv6-unicast\\soft-reconfiguration inbound')
+TestFlag.okfail('peer\\ipv6-multicast\\soft-reconfiguration inbound')
+TestFlag.okfail('peer\\ipv4-unicast\\unsuppress-map')
+TestFlag.okfail('peer\\ipv4-multicast\\unsuppress-map')
+TestFlag.okfail('peer\\ipv6-unicast\\unsuppress-map')
+TestFlag.okfail('peer\\ipv6-multicast\\unsuppress-map')
+TestFlag.okfail('peer\\ipv4-unicast\\weight')
+TestFlag.okfail('peer\\ipv4-multicast\\weight')
+TestFlag.okfail('peer\\ipv6-unicast\\weight')
+TestFlag.okfail('peer\\ipv6-multicast\\weight')