From 598ce6bd70427129b61f417f87be93d830496c7f Mon Sep 17 00:00:00 2001 From: Pascal Mathis Date: Sat, 19 May 2018 22:10:48 +0200 Subject: [PATCH 1/7] bgpd: Improve group overrides for AF flags The current implementation for overriding peer-group configuration on a peer member consists of several bandaids, which introduce more issues than they fix. A generic approach for implementing peer-group overrides for address-family flags is clearly missing. This commit implements a generic and sane approach to overriding peer-group configuration on a peer-member. A separate peer attribute called 'af_flags_override' which was introduced in 04e1c5b is being used to keep track of all address-family flags, storing whether the configuration is being inherited from the parent-group or overridden. All address-family flags are being supported by this implementation (note: flags, not filters/maps) except 'send-community', which currently breaks due to having the three flags enabled by default, which is not being properly handled within this commit; all flags are supposed to have an 'off'/'false' state by default. In the interest of readability and comprehensibility, the flag 'send-community' is being fixed in a separate commit. The following rules apply when looking at the new peer-group override implementation this commit provides: - Each peer-group can enable every flag (except the limitations noted above), which gets automatically inherited to all members. - Each peer can enable each flag independently and/or modify their value, if available. (e.g.: weight ) - Each command executed on a neighbor/peer gets explicitely set as an override, so even when the peer-group has the same kind of configuration, both will show up in 'show running-configuration'. - Executing 'no ' on a peer will remove the peer-specific configuration and make the peer inherit the configuration from the peer-group again. - Executing 'no ' on a peer-group will only remove the flag from the peer-group, however not from peers explicitely setting that flag. This guarantees a clean implementation which does not break, even when constantly messing with the flags of a peer-group. The same behavior is present in Cisco devices, so people familiar with those should feel safe when dealing with FRRs peer-groups. The only restriction that now applies is that single peer cannot disable a flag which was set by a peer-group, because 'no ' is already being used for disabling a peer-specific override. This is not supported by any known vendor though, would require many specific edge-cases and magic comparisons and will most likely only end up confusing the user. Additionally, peer-groups should only contain flags which are being used by all peer members. Signed-off-by: Pascal Mathis --- bgpd/bgpd.c | 676 +++++++++++++++++++++++++++------------------------- bgpd/bgpd.h | 13 + 2 files changed, 365 insertions(+), 324 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 71707b6afa..16cca278ac 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -804,31 +804,30 @@ 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)) + return !!peer_af_flag_check(peer, afi, safi, flag); - return 0; + return !!CHECK_FLAG(peer->af_flags_override[afi][safi], flag); } /* Reset all address family specific configuration. */ @@ -3818,14 +3817,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}, @@ -4071,10 +4070,15 @@ 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)) { + 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)) { + UNSET_FLAG(peer->af_flags_override[afi][safi], flag); return 0; + } } /* @@ -4106,8 +4110,11 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, } } + /* Set/unset flag or inherit from peer-group if appropriate. */ 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); @@ -4133,11 +4140,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 @@ -4174,6 +4183,11 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, } } } + } else { + if (set) + 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 */ @@ -4553,71 +4567,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); @@ -4625,33 +4666,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; } @@ -4696,81 +4750,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; } @@ -4999,68 +5059,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_ORIGIN)) + 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); } } @@ -5071,38 +5130,56 @@ 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; + + /* 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; } - 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); - peer_on_policy_change(peer, afi, safi, 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; @@ -5978,66 +6055,56 @@ 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 */ - if ((peer->status == Established) && (peer->afc[afi][safi])) + /* 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; @@ -6045,53 +6112,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; } @@ -7065,19 +7126,13 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, /* 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"); } @@ -7088,29 +7143,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, @@ -7125,42 +7173,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 340851e8d9..334c73d2d0 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1108,6 +1108,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) \ @@ -1506,6 +1518,7 @@ 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 *, afi_t, safi_t, uint32_t); extern int peer_ebgp_multihop_set(struct peer *, int); extern int peer_ebgp_multihop_unset(struct peer *); From 70ee29b4db0465ce58da486d80aba5615fa04b2c Mon Sep 17 00:00:00 2001 From: Pascal Mathis Date: Mon, 21 May 2018 12:09:25 +0200 Subject: [PATCH 2/7] bgpd: Improve group overrides for AF filters This commit adds the same peer-group override capabilites as d122d7cf7 for all filter/map options that can be enabled/disabled on each address-family of a BGP peer. All currently existing filter/map options are being supported: filter-list, distribute-list, prefix-list, route-map and unsuppress-map To implement this behavior, a new peer attribute 'filter_override' has been added together with various PEER_FT_ (filter type) constants for tracking the state of each filter in the same way as it is being done with 'af_flags_override'. Signed-off-by: Pascal Mathis --- bgpd/bgpd.c | 621 +++++++++++++++++++++++++++++++--------------------- bgpd/bgpd.h | 26 +++ 2 files changed, 400 insertions(+), 247 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 16cca278ac..7299654d25 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -830,6 +830,32 @@ static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, 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. */ static void peer_af_flag_reset(struct peer *peer, afi_t afi, safi_t safi) { @@ -5407,40 +5433,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); } @@ -5449,57 +5490,63 @@ 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; - } - } - - 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 (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - peer_on_policy_change(peer, afi, safi, - (direct == FILTER_OUT) ? 1 : 0); - return 0; - } - - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { + 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; + } + + /* 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; + } + + /* + * 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; + + /* Process peer route updates. */ + peer_on_policy_change(member, afi, safi, + (direct == FILTER_OUT) ? 1 : 0); } return 0; @@ -5568,99 +5615,121 @@ 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; - } - } - - 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 (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - peer_on_policy_change(peer, afi, safi, - (direct == FILTER_OUT) ? 1 : 0); - return 0; - } - - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { + 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; + } + + /* 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; + } + + /* + * 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; + + /* Process peer route updates. */ + peer_on_policy_change(member, afi, safi, + (direct == FILTER_OUT) ? 1 : 0); } return 0; @@ -5730,95 +5799,119 @@ 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; - } - } - - 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 (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - peer_on_policy_change(peer, afi, safi, - (direct == FILTER_OUT) ? 1 : 0); - return 0; - } - - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { + 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; + } + + /* 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; + } + + /* + * 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; + + /* Process peer route updates. */ + peer_on_policy_change(member, afi, safi, + (direct == FILTER_OUT) ? 1 : 0); } return 0; @@ -5894,36 +5987,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; @@ -5932,56 +6040,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; - } - } - - 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 (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - peer_on_policy_change(peer, afi, safi, - (direct == RMAP_OUT) ? 1 : 0); - return 0; - } - - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { + 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; + } + + /* 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; } + + /* + * 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; + + /* Process peer route updates. */ + peer_on_policy_change(member, afi, safi, + (direct == RMAP_OUT) ? 1 : 0); + } + return 0; } @@ -5989,65 +6103,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(peer->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; - - if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - peer_on_policy_change(peer, afi, safi, 1); - return 0; - } - - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { + /* 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; - peer_on_policy_change(peer, afi, safi, 1); } + + /* 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; + } + + /* + * 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; + + /* Process peer route updates. */ + peer_on_policy_change(member, afi, safi, 1); + } + return 0; } @@ -6520,86 +6675,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. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 334c73d2d0..bfa80c3ce2 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1031,6 +1031,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]; From 27c05d4d43d14464b15582c700a511156c4ea2af Mon Sep 17 00:00:00 2001 From: Pascal Mathis Date: Sun, 27 May 2018 17:39:45 +0200 Subject: [PATCH 3/7] bgpd: Fix group overrides for inverted AF flags This commit fixes peer-group overrides for inverted AF flags. This implementation is currently only being used by the three 'send-community' flags. Commit 70ee29b4d introduced generic support for overriding AF flags, but did not support inverted flags. By introducing an additional array on the BGP peer structure called 'af_flags_invert' all current and future flags which should work in an inverted way can now also be properly overridden. The CLI commands will work exactly the same way as before, just that 'no ' now sets the flag and override whereas '' will unset the flag and remove the override. Signed-off-by: Pascal Mathis --- bgpd/bgp_vty.c | 61 ++++++++--------- bgpd/bgpd.c | 178 ++++++++++++++++++++++++++----------------------- bgpd/bgpd.h | 11 +++ 3 files changed, 135 insertions(+), 115 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 257adda3f3..f83f357e53 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4073,6 +4073,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); @@ -4092,6 +4093,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); @@ -4115,27 +4117,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); } @@ -4164,33 +4165,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, "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); + } - /* 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)); + return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg, + bgp_node_afi(vty), bgp_node_safi(vty), + flag); } ALIAS_HIDDEN( diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 7299654d25..8dd756bec0 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -824,8 +824,12 @@ void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi, static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint32_t flag) { - if (!peer_group_active(peer)) - return !!peer_af_flag_check(peer, afi, safi, 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 !!CHECK_FLAG(peer->af_flags_override[afi][safi], flag); } @@ -914,6 +918,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 */ @@ -1187,7 +1198,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], @@ -1196,8 +1207,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 */ @@ -1288,6 +1305,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]; @@ -1776,6 +1795,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]; @@ -4058,21 +4078,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); @@ -4097,12 +4119,22 @@ 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)) { - SET_FLAG(peer->af_flags_override[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)) { - UNSET_FLAG(peer->af_flags_override[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; } } @@ -4137,12 +4169,21 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, } /* Set/unset flag or inherit from peer-group if appropriate. */ - 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); + 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) @@ -4210,7 +4251,7 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, } } } else { - if (set) + if (set != invert) SET_FLAG(peer->af_flags_override[afi][safi], flag); else UNSET_FLAG(peer->af_flags_override[afi][safi], flag); @@ -7049,6 +7090,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)) @@ -7175,79 +7217,51 @@ 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))) { - vty_out(vty, - " no neighbor %s send-community large\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))) { - 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_scomm) vty_out(vty, " no neighbor %s send-community\n", addr); - } + if (flag_secomm) + vty_out(vty, + " no neighbor %s send-community extended\n", + addr); + + if (flag_slcomm) + vty_out(vty, + " 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); } } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index bfa80c3ce2..97061681f0 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -858,6 +858,17 @@ struct peer { * *peer-specific*. */ 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 From 9d4f56237a22ff8f9f21912f1632e0279f4d7ec8 Mon Sep 17 00:00:00 2001 From: Pascal Mathis Date: Sun, 27 May 2018 17:52:19 +0200 Subject: [PATCH 4/7] tests: Add tests for overriding BGP peer attrs This commit introduces unit tests for BGP peer attributes and checks all three involved components, which are: - CLI Configuration Input: The appropriate commands to configure the attribute on either a peer or peer-group are being executed the same way an end user would do it. - CLI Configuration Output: The output of 'show running-config' is being checked for presence/absence of expected configuration strings. - Internal Data Structures: The internal data structures for maintaining flag/filter states (value + override + invert) are being checked after each operation to ensure the override has been implemented properly. All attributes to be tested must be defined within the 'peer_attrs' structure, which contains all peer attributes as of today and checks them with both IPv4 Unicast and IPv6 Unicast. More address families are supposed to be introduced at a later point in time. Each attribute is being checked in its own 'clean' BGP environment, so everything gets reset after each attribute to avoid any weird edge cases. The 'correct' BGP startup and shutdown routine was taken from 'bgp_main.c' to ensure that we are not leaking any memory or acting different than the real 'bgpd' would do. Signed-off-by: Pascal Mathis --- tests/.gitignore | 1 + tests/Makefile.am | 4 + tests/bgpd/test_peer_attr.c | 1144 ++++++++++++++++++++++++++++++++++ tests/bgpd/test_peer_attr.py | 94 +++ 4 files changed, 1243 insertions(+) create mode 100644 tests/bgpd/test_peer_attr.c create mode 100644 tests/bgpd/test_peer_attr.py diff --git a/tests/.gitignore b/tests/.gitignore index 1708a4b7b0..d136cae482 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -25,6 +25,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..bb965a3344 --- /dev/null +++ b/tests/bgpd/test_peer_attr.c @@ -0,0 +1,1144 @@ +/* + * 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 + +#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 = NULL; + +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, + } 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" + +/* clang-format off */ +#define TEST_ASSERT(T, C) \ + do { \ + if ((T)->state != TEST_SUCCESS || (C)) \ + break; \ + \ + (T)->state = TEST_ASSERT_ERROR; \ + (T)->error = str_printf("assertion failed: %s", (#C)); \ + } while (0) + +#define TEST_AF_FLAGS(T, P, A, V, O) \ + do { \ + if ((T)->state != TEST_SUCCESS) \ + break; \ + \ + TEST_ASSERT((T), !!CHECK_FLAG((P)->af_flags[(A)->afi][(A)->safi], (A)->u.flag) == ((V) ^ (A)->o.invert)); \ + TEST_ASSERT((T), !!CHECK_FLAG((P)->af_flags_override[(A)->afi][(A)->safi], (A)->u.flag) == (O)); \ + TEST_ASSERT((T), !!CHECK_FLAG((P)->af_flags_invert[(A)->afi][(A)->safi], (A)->u.flag) == (A)->o.invert); \ + } while (0) + +#define TEST_AF_FILTER(T, P, A, S, O) \ + do { \ + if ((T)->state != TEST_SUCCESS) \ + break; \ + \ + TEST_ASSERT((T), !!CHECK_FLAG((P)->filter_override[(A)->afi][(A)->safi][(A)->u.filter.direct], (A)->u.filter.flag) == (O)); \ + switch ((A)->u.filter.flag) { \ + case PEER_FT_DISTRIBUTE_LIST: \ + TEST_ASSERT((T), !!((P)->filter[(A)->afi][(A)->safi].dlist[(A)->u.filter.direct].name) == (S)); \ + break; \ + case PEER_FT_FILTER_LIST: \ + TEST_ASSERT((T), !!((P)->filter[(A)->afi][(A)->safi].aslist[(A)->u.filter.direct].name) == (S)); \ + break; \ + case PEER_FT_PREFIX_LIST: \ + TEST_ASSERT((T), !!((P)->filter[(A)->afi][(A)->safi].plist[(A)->u.filter.direct].name) == (S)); \ + break; \ + case PEER_FT_ROUTE_MAP: \ + TEST_ASSERT((T), !!((P)->filter[(A)->afi][(A)->safi].map[(A)->u.filter.direct].name) == (S)); \ + break; \ + case PEER_FT_UNSUPPRESS_MAP: \ + TEST_ASSERT((T), !!((P)->filter[(A)->afi][(A)->safi].usmap.name) == (S)); \ + break; \ + } \ + } while (0) +/* clang-format on */ + +static struct test_config cfg = { + .local_asn = 100, + .peer_asn = 200, + .peer_address = "1.1.1.1", + .peer_group = "PG-TEST", +}; + +/* clang-format off */ +static struct test_peer_attr test_peer_attrs[] = { + { + .cmd = "addpath-tx-all-paths", + .u.flag = PEER_FLAG_ADDPATH_TX_ALL_PATHS, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "addpath-tx-bestpath-per-AS", + .u.flag = PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "allowas-in", + .peer_cmd = "allowas-in 1", + .group_cmd = "allowas-in 2", + .u.flag = PEER_FLAG_ALLOWAS_IN, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "allowas-in origin", + .u.flag = PEER_FLAG_ALLOWAS_IN_ORIGIN, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "as-override", + .u.flag = PEER_FLAG_AS_OVERRIDE, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "attribute-unchanged as-path", + .u.flag = PEER_FLAG_AS_PATH_UNCHANGED, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "attribute-unchanged next-hop", + .u.flag = PEER_FLAG_NEXTHOP_UNCHANGED, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "attribute-unchanged med", + .u.flag = PEER_FLAG_MED_UNCHANGED, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "attribute-unchanged as-path next-hop", + .u.flag = PEER_FLAG_AS_PATH_UNCHANGED + | PEER_FLAG_NEXTHOP_UNCHANGED, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "attribute-unchanged as-path med", + .u.flag = PEER_FLAG_AS_PATH_UNCHANGED + | PEER_FLAG_MED_UNCHANGED, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "attribute-unchanged as-path next-hop med", + .u.flag = PEER_FLAG_AS_PATH_UNCHANGED + | PEER_FLAG_NEXTHOP_UNCHANGED + | PEER_FLAG_MED_UNCHANGED, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "capability orf prefix-list send", + .u.flag = PEER_FLAG_ORF_PREFIX_SM, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "capability orf prefix-list receive", + .u.flag = PEER_FLAG_ORF_PREFIX_RM, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "capability orf prefix-list both", + .u.flag = PEER_FLAG_ORF_PREFIX_SM | PEER_FLAG_ORF_PREFIX_RM, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "default-originate", + .u.flag = PEER_FLAG_DEFAULT_ORIGINATE, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .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, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "distribute-list", + .peer_cmd = "distribute-list DL-PEER in", + .group_cmd = "distribute-list DL-GROUP in", + .type = PEER_AT_AF_FILTER, + .u.filter.flag = PEER_FT_DISTRIBUTE_LIST, + .u.filter.direct = FILTER_IN, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "distribute-list", + .peer_cmd = "distribute-list DL-PEER out", + .group_cmd = "distribute-list DL-GROUP out", + .type = PEER_AT_AF_FILTER, + .u.filter.flag = PEER_FT_DISTRIBUTE_LIST, + .u.filter.direct = FILTER_OUT, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .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, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .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, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "maximum-prefix", + .peer_cmd = "maximum-prefix 10", + .group_cmd = "maximum-prefix 20", + .u.flag = PEER_FLAG_MAX_PREFIX, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "maximum-prefix", + .peer_cmd = "maximum-prefix 10 restart 100", + .group_cmd = "maximum-prefix 20 restart 200", + .u.flag = PEER_FLAG_MAX_PREFIX, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .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, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .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, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .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, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "next-hop-self", + .u.flag = PEER_FLAG_NEXTHOP_SELF, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "next-hop-self force", + .u.flag = PEER_FLAG_FORCE_NEXTHOP_SELF, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .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, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .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, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "remove-private-AS", + .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "remove-private-AS all", + .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS + | PEER_FLAG_REMOVE_PRIVATE_AS_ALL, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "remove-private-AS replace-AS", + .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS + | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "remove-private-AS all replace-AS", + .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .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, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .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, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "route-reflector-client", + .u.flag = PEER_FLAG_REFLECTOR_CLIENT, + .o.use_ibgp = true, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "route-server-client", + .u.flag = PEER_FLAG_RSERVER_CLIENT, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "send-community", + .u.flag = PEER_FLAG_SEND_COMMUNITY, + .o.invert = true, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "send-community extended", + .u.flag = PEER_FLAG_SEND_EXT_COMMUNITY, + .o.invert = true, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "send-community large", + .u.flag = PEER_FLAG_SEND_LARGE_COMMUNITY, + .o.invert = true, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "soft-reconfiguration inbound", + .u.flag = PEER_FLAG_SOFT_RECONFIG, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .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, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + { + .cmd = "weight", + .peer_cmd = "weight 100", + .group_cmd = "weight 200", + .u.flag = PEER_FLAG_WEIGHT, + .families = { + { .afi = AFI_IP, .safi = SAFI_UNICAST }, + { .afi = AFI_IP6, .safi = SAFI_UNICAST }, + } + }, + {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 ""; + } +} + +static const char *str_from_safi(safi_t safi) +{ + switch (safi) { + case SAFI_UNICAST: + return "unicast"; + case SAFI_MULTICAST: + return "multicast"; + case SAFI_MPLS_VPN: + return "labeled-unicast"; + case SAFI_FLOWSPEC: + return "flowspec"; + default: + return ""; + } +} + +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 and return. */ + cmd_free_strvec(vline); + XFREE(MTYPE_TMP, cmd); + return; +} + +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); + return; +} + +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_peer_attr(struct test *test, struct test_peer_attr *pa) +{ + int tc = 1; + 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; + + /* 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 af-flag [%s] on [%s]", tc++, 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 af-flag [%s] on [%s]", tc++, 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 af-flag [%s] on [%s]", tc++, 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 af-flag [%s] on [%s]", tc++, 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 af-flag [%s] on [%s]", tc++, 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 af-flag [%s] on [%s]", tc++, 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 af-flag [%s] on [%s]", tc++, 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 af-flag [%s] on [%s]", tc++, 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() +{ + 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() +{ + 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++]; + + if (pa->families[0].afi && pa->families[0].safi) { + 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++; + } + } else { + pac = XMALLOC(MTYPE_TMP, sizeof(struct test_peer_attr)); + memcpy(pac, pa, sizeof(struct test_peer_attr)); + listnode_add(pa_list, pac); + } + } + + 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..17c6598382 --- /dev/null +++ b/tests/bgpd/test_peer_attr.py @@ -0,0 +1,94 @@ +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\\ipv6-unicast\\addpath-tx-all-paths') +TestFlag.okfail('peer\\ipv4-unicast\\addpath-tx-bestpath-per-AS') +TestFlag.okfail('peer\\ipv6-unicast\\addpath-tx-bestpath-per-AS') +TestFlag.okfail('peer\\ipv4-unicast\\allowas-in') +TestFlag.okfail('peer\\ipv6-unicast\\allowas-in') +TestFlag.okfail('peer\\ipv4-unicast\\allowas-in origin') +TestFlag.okfail('peer\\ipv6-unicast\\allowas-in origin') +TestFlag.okfail('peer\\ipv4-unicast\\as-override') +TestFlag.okfail('peer\\ipv6-unicast\\as-override') +TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged as-path') +TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged as-path') +TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged next-hop') +TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged next-hop') +TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged med') +TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged med') +TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged as-path next-hop') +TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged as-path next-hop') +TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged as-path med') +TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged as-path med') +TestFlag.okfail('peer\\ipv4-unicast\\attribute-unchanged as-path next-hop med') +TestFlag.okfail('peer\\ipv6-unicast\\attribute-unchanged as-path next-hop med') +TestFlag.okfail('peer\\ipv4-unicast\\capability orf prefix-list send') +TestFlag.okfail('peer\\ipv6-unicast\\capability orf prefix-list send') +TestFlag.okfail('peer\\ipv4-unicast\\capability orf prefix-list receive') +TestFlag.okfail('peer\\ipv6-unicast\\capability orf prefix-list receive') +TestFlag.okfail('peer\\ipv4-unicast\\capability orf prefix-list both') +TestFlag.okfail('peer\\ipv6-unicast\\capability orf prefix-list both') +TestFlag.okfail('peer\\ipv4-unicast\\default-originate') +TestFlag.okfail('peer\\ipv6-unicast\\default-originate') +TestFlag.okfail('peer\\ipv4-unicast\\default-originate route-map') +TestFlag.okfail('peer\\ipv6-unicast\\default-originate route-map') +TestFlag.okfail('peer\\ipv4-unicast\\distribute-list') +TestFlag.okfail('peer\\ipv6-unicast\\distribute-list') +TestFlag.okfail('peer\\ipv4-unicast\\distribute-list') +TestFlag.okfail('peer\\ipv6-unicast\\distribute-list') +TestFlag.okfail('peer\\ipv4-unicast\\filter-list') +TestFlag.okfail('peer\\ipv6-unicast\\filter-list') +TestFlag.okfail('peer\\ipv4-unicast\\filter-list') +TestFlag.okfail('peer\\ipv6-unicast\\filter-list') +TestFlag.okfail('peer\\ipv4-unicast\\maximum-prefix') +TestFlag.okfail('peer\\ipv6-unicast\\maximum-prefix') +TestFlag.okfail('peer\\ipv4-unicast\\maximum-prefix') +TestFlag.okfail('peer\\ipv6-unicast\\maximum-prefix') +TestFlag.okfail('peer\\ipv4-unicast\\maximum-prefix') +TestFlag.okfail('peer\\ipv6-unicast\\maximum-prefix') +TestFlag.okfail('peer\\ipv4-unicast\\maximum-prefix') +TestFlag.okfail('peer\\ipv6-unicast\\maximum-prefix') +TestFlag.okfail('peer\\ipv4-unicast\\maximum-prefix') +TestFlag.okfail('peer\\ipv6-unicast\\maximum-prefix') +TestFlag.okfail('peer\\ipv4-unicast\\next-hop-self') +TestFlag.okfail('peer\\ipv6-unicast\\next-hop-self') +TestFlag.okfail('peer\\ipv4-unicast\\next-hop-self force') +TestFlag.okfail('peer\\ipv6-unicast\\next-hop-self force') +TestFlag.okfail('peer\\ipv4-unicast\\prefix-list') +TestFlag.okfail('peer\\ipv6-unicast\\prefix-list') +TestFlag.okfail('peer\\ipv4-unicast\\prefix-list') +TestFlag.okfail('peer\\ipv6-unicast\\prefix-list') +TestFlag.okfail('peer\\ipv4-unicast\\remove-private-AS') +TestFlag.okfail('peer\\ipv6-unicast\\remove-private-AS') +TestFlag.okfail('peer\\ipv4-unicast\\remove-private-AS all') +TestFlag.okfail('peer\\ipv6-unicast\\remove-private-AS all') +TestFlag.okfail('peer\\ipv4-unicast\\remove-private-AS replace-AS') +TestFlag.okfail('peer\\ipv6-unicast\\remove-private-AS replace-AS') +TestFlag.okfail('peer\\ipv4-unicast\\remove-private-AS all replace-AS') +TestFlag.okfail('peer\\ipv6-unicast\\remove-private-AS all replace-AS') +TestFlag.okfail('peer\\ipv4-unicast\\route-map') +TestFlag.okfail('peer\\ipv6-unicast\\route-map') +TestFlag.okfail('peer\\ipv4-unicast\\route-map') +TestFlag.okfail('peer\\ipv6-unicast\\route-map') +TestFlag.okfail('peer\\ipv4-unicast\\route-reflector-client') +TestFlag.okfail('peer\\ipv6-unicast\\route-reflector-client') +TestFlag.okfail('peer\\ipv4-unicast\\route-server-client') +TestFlag.okfail('peer\\ipv6-unicast\\route-server-client') +TestFlag.okfail('peer\\ipv4-unicast\\send-community') +TestFlag.okfail('peer\\ipv6-unicast\\send-community') +TestFlag.okfail('peer\\ipv4-unicast\\send-community extended') +TestFlag.okfail('peer\\ipv6-unicast\\send-community extended') +TestFlag.okfail('peer\\ipv4-unicast\\send-community large') +TestFlag.okfail('peer\\ipv6-unicast\\send-community large') +TestFlag.okfail('peer\\ipv4-unicast\\soft-reconfiguration inbound') +TestFlag.okfail('peer\\ipv6-unicast\\soft-reconfiguration inbound') +TestFlag.okfail('peer\\ipv4-unicast\\unsuppress-map') +TestFlag.okfail('peer\\ipv6-unicast\\unsuppress-map') +TestFlag.okfail('peer\\ipv4-unicast\\weight') +TestFlag.okfail('peer\\ipv6-unicast\\weight') From 246bb5f07a3c491fdf67572f05b4f8d4a43e6abf Mon Sep 17 00:00:00 2001 From: Pascal Mathis Date: Sun, 27 May 2018 19:23:57 +0200 Subject: [PATCH 5/7] bgpd: Fix group overrides for AF flags/filters The previous commit introduced very strict unit tests which check all three involved components (config input, config output, internal data structures) which revealed two more bugs in the peer-group override implementation. This commit fixes overrides for 'allowas-in ' and 'unsuppress-map', which both had a small mistake/typo causing those issues. Signed-off-by: Pascal Mathis --- bgpd/bgpd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 8dd756bec0..fa13299a23 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5166,7 +5166,7 @@ int peer_allowas_in_set(struct peer *peer, afi_t afi, safi_t safi, 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_ORIGIN)) + PEER_FLAG_ALLOWAS_IN)) continue; /* Set flag and configuration on peer-group member. */ @@ -6172,7 +6172,7 @@ int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi, */ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) { /* Skip peers with overridden configuration. */ - if (CHECK_FLAG(peer->filter_override[afi][safi][0], + if (CHECK_FLAG(member->filter_override[afi][safi][0], PEER_FT_UNSUPPRESS_MAP)) continue; From cf9ac8bfb04288a9befd0c38de2259e5f7ee4544 Mon Sep 17 00:00:00 2001 From: Pascal Mathis Date: Sun, 27 May 2018 19:36:48 +0200 Subject: [PATCH 6/7] bgpd: Fix style issues for peer-group overrides This commit fixes all outstanding style/formatting issues as detected by 'git clang-format' or 'checkpath' for the new peer-group override implementation, which spanned across several commits. Signed-off-by: Pascal Mathis --- bgpd/bgp_vty.c | 2 +- bgpd/bgpd.c | 26 ++++++++++++-------------- bgpd/bgpd.h | 3 ++- tests/bgpd/test_peer_attr.c | 10 ++++------ 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index f83f357e53..ec652e626d 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5325,8 +5325,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 fa13299a23..e1d915f449 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5174,9 +5174,9 @@ int peer_allowas_in_set(struct peer *peer, afi_t afi, safi_t safi, if (origin) { if (member->allowas_in[afi][safi] != 0 || !CHECK_FLAG(member->af_flags[afi][safi], - PEER_FLAG_ALLOWAS_IN_ORIGIN)) { + PEER_FLAG_ALLOWAS_IN_ORIGIN)) { SET_FLAG(member->af_flags[afi][safi], - PEER_FLAG_ALLOWAS_IN_ORIGIN); + PEER_FLAG_ALLOWAS_IN_ORIGIN); member->allowas_in[afi][safi] = 0; peer_on_policy_change(peer, afi, safi, 0); } @@ -5208,7 +5208,7 @@ int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi) 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_FLAG_ALLOWAS_IN_ORIGIN); PEER_ATTR_INHERIT(peer, allowas_in[afi][safi]); peer_on_policy_change(peer, afi, safi, 0); @@ -5232,19 +5232,18 @@ int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi) 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)) + PEER_FLAG_ALLOWAS_IN)) continue; /* Skip peers where flag is already disabled. */ if (!CHECK_FLAG(member->af_flags[afi][safi], - PEER_FLAG_ALLOWAS_IN)) + 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); - UNSET_FLAG(member->af_flags[afi][safi], - PEER_FLAG_ALLOWAS_IN_ORIGIN); + PEER_FLAG_ALLOWAS_IN_ORIGIN); member->allowas_in[afi][safi] = 0; peer_on_policy_change(member, afi, safi, 0); } @@ -6269,9 +6268,8 @@ int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi, /* 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])) { + if ((peer->status == Established) && (peer->afc[afi][safi])) bgp_maximum_prefix_overflow(peer, afi, safi, 1); - } /* Skip peer-group mechanics for regular peers. */ return 0; @@ -7218,11 +7216,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, /* send-community print. */ flag_scomm = peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_SEND_COMMUNITY); + PEER_FLAG_SEND_COMMUNITY); flag_secomm = peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_SEND_EXT_COMMUNITY); + PEER_FLAG_SEND_EXT_COMMUNITY); flag_slcomm = peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_SEND_LARGE_COMMUNITY); + PEER_FLAG_SEND_LARGE_COMMUNITY); if (!bgp_option_check(BGP_OPT_CONFIG_CISCO)) { if (flag_scomm && flag_secomm && flag_slcomm) { @@ -7322,7 +7320,7 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, 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]); + peer->allowas_in[afi][safi]); } } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 97061681f0..13fed9ac0d 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1555,7 +1555,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 *, 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/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index bb965a3344..d779655233 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -36,7 +36,7 @@ /* Required variables to link in libbgp */ struct zebra_privs_t bgpd_privs = {0}; -struct thread_master *master = NULL; +struct thread_master *master; enum test_state { TEST_SUCCESS, @@ -673,10 +673,9 @@ static void test_execute(struct test *test, const char *fmt, ...) cmd, ret); } - /* Free memory and return. */ + /* Free memory. */ cmd_free_strvec(vline); XFREE(MTYPE_TMP, cmd); - return; } static void test_config(struct test *test, const char *fmt, bool invert, @@ -722,7 +721,6 @@ static void test_config(struct test *test, const char *fmt, bool invert, /* Free memory and return. */ XFREE(MTYPE_TMP, matcher); XFREE(MTYPE_TMP, config); - return; } static void test_config_present(struct test *test, const char *fmt, ...) @@ -1017,7 +1015,7 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa) } } -static void bgp_startup() +static void bgp_startup(void) { cmd_init(1); openzlog("testbgpd", "NONE", 0, LOG_CONS | LOG_NDELAY | LOG_PID, @@ -1033,7 +1031,7 @@ static void bgp_startup() bgp_pthreads_run(); } -static void bgp_shutdown() +static void bgp_shutdown(void) { struct bgp *bgp; struct listnode *node, *nnode; From f9067479617fa6237abd9dc0391ae6ea14aa16a7 Mon Sep 17 00:00:00 2001 From: Pascal Mathis Date: Mon, 28 May 2018 18:50:52 +0200 Subject: [PATCH 7/7] tests: Improve test suite for peer attributes This commit improves the previous implementation of the peer attribute test suite by getting rid of some really ugly macros and replacing them with sane functions. Additionally, the macro TEST_ASSERT was changed to TEST_ASSERT_EQ (== comparison) which now also prints the line where the assertion has been infringend. This should make it way more clear where a specific issue has been spotted. Last but not least, the multicast families for both IPv4 and IPv6 had been added as they are working without any further changes or special cases for all currently existing peer attributes. Other AFI/SAFI references have been removed to keep the code clean. Signed-off-by: Pascal Mathis --- tests/bgpd/test_peer_attr.c | 459 ++++++++++++----------------------- tests/bgpd/test_peer_attr.py | 86 ++++++- 2 files changed, 241 insertions(+), 304 deletions(-) diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index d779655233..67a6db849f 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -77,7 +77,7 @@ struct test_peer_attr { enum { PEER_AT_AF_FLAG = 0, PEER_AT_AF_FILTER = 1, - } type; + PEER_AT_GLOBAL_FLAG = 2 } type; union { uint32_t flag; struct { @@ -99,52 +99,16 @@ struct test_peer_attr { #define OUT_SYMBOL_OK "\u2714" #define OUT_SYMBOL_NOK "\u2716" -/* clang-format off */ -#define TEST_ASSERT(T, C) \ +#define TEST_ASSERT_EQ(T, A, B) \ do { \ - if ((T)->state != TEST_SUCCESS || (C)) \ + if ((T)->state != TEST_SUCCESS || ((A) == (B))) \ break; \ - \ (T)->state = TEST_ASSERT_ERROR; \ - (T)->error = str_printf("assertion failed: %s", (#C)); \ + (T)->error = str_printf( \ + "assertion failed: %s[%d] == [%d]%s (%s:%d)", (#A), \ + (A), (B), (#B), __FILE__, __LINE__); \ } while (0) -#define TEST_AF_FLAGS(T, P, A, V, O) \ - do { \ - if ((T)->state != TEST_SUCCESS) \ - break; \ - \ - TEST_ASSERT((T), !!CHECK_FLAG((P)->af_flags[(A)->afi][(A)->safi], (A)->u.flag) == ((V) ^ (A)->o.invert)); \ - TEST_ASSERT((T), !!CHECK_FLAG((P)->af_flags_override[(A)->afi][(A)->safi], (A)->u.flag) == (O)); \ - TEST_ASSERT((T), !!CHECK_FLAG((P)->af_flags_invert[(A)->afi][(A)->safi], (A)->u.flag) == (A)->o.invert); \ - } while (0) - -#define TEST_AF_FILTER(T, P, A, S, O) \ - do { \ - if ((T)->state != TEST_SUCCESS) \ - break; \ - \ - TEST_ASSERT((T), !!CHECK_FLAG((P)->filter_override[(A)->afi][(A)->safi][(A)->u.filter.direct], (A)->u.filter.flag) == (O)); \ - switch ((A)->u.filter.flag) { \ - case PEER_FT_DISTRIBUTE_LIST: \ - TEST_ASSERT((T), !!((P)->filter[(A)->afi][(A)->safi].dlist[(A)->u.filter.direct].name) == (S)); \ - break; \ - case PEER_FT_FILTER_LIST: \ - TEST_ASSERT((T), !!((P)->filter[(A)->afi][(A)->safi].aslist[(A)->u.filter.direct].name) == (S)); \ - break; \ - case PEER_FT_PREFIX_LIST: \ - TEST_ASSERT((T), !!((P)->filter[(A)->afi][(A)->safi].plist[(A)->u.filter.direct].name) == (S)); \ - break; \ - case PEER_FT_ROUTE_MAP: \ - TEST_ASSERT((T), !!((P)->filter[(A)->afi][(A)->safi].map[(A)->u.filter.direct].name) == (S)); \ - break; \ - case PEER_FT_UNSUPPRESS_MAP: \ - TEST_ASSERT((T), !!((P)->filter[(A)->afi][(A)->safi].usmap.name) == (S)); \ - break; \ - } \ - } while (0) -/* clang-format on */ - static struct test_config cfg = { .local_asn = 100, .peer_asn = 200, @@ -152,167 +116,86 @@ static struct test_config cfg = { .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, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "addpath-tx-bestpath-per-AS", .u.flag = PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "allowas-in", .peer_cmd = "allowas-in 1", .group_cmd = "allowas-in 2", .u.flag = PEER_FLAG_ALLOWAS_IN, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "allowas-in origin", .u.flag = PEER_FLAG_ALLOWAS_IN_ORIGIN, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "as-override", .u.flag = PEER_FLAG_AS_OVERRIDE, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "attribute-unchanged as-path", .u.flag = PEER_FLAG_AS_PATH_UNCHANGED, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "attribute-unchanged next-hop", .u.flag = PEER_FLAG_NEXTHOP_UNCHANGED, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "attribute-unchanged med", .u.flag = PEER_FLAG_MED_UNCHANGED, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "attribute-unchanged as-path next-hop", .u.flag = PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_NEXTHOP_UNCHANGED, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "attribute-unchanged as-path med", .u.flag = PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_MED_UNCHANGED, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "attribute-unchanged as-path next-hop med", .u.flag = PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_NEXTHOP_UNCHANGED | PEER_FLAG_MED_UNCHANGED, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "capability orf prefix-list send", .u.flag = PEER_FLAG_ORF_PREFIX_SM, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "capability orf prefix-list receive", .u.flag = PEER_FLAG_ORF_PREFIX_RM, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "capability orf prefix-list both", .u.flag = PEER_FLAG_ORF_PREFIX_SM | PEER_FLAG_ORF_PREFIX_RM, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "default-originate", .u.flag = PEER_FLAG_DEFAULT_ORIGINATE, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .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, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } - }, - { - .cmd = "distribute-list", - .peer_cmd = "distribute-list DL-PEER in", - .group_cmd = "distribute-list DL-GROUP in", - .type = PEER_AT_AF_FILTER, - .u.filter.flag = PEER_FT_DISTRIBUTE_LIST, - .u.filter.direct = FILTER_IN, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } - }, - { - .cmd = "distribute-list", - .peer_cmd = "distribute-list DL-PEER out", - .group_cmd = "distribute-list DL-GROUP out", - .type = PEER_AT_AF_FILTER, - .u.filter.flag = PEER_FT_DISTRIBUTE_LIST, - .u.filter.direct = FILTER_OUT, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "filter-list", @@ -321,10 +204,6 @@ static struct test_peer_attr test_peer_attrs[] = { .type = PEER_AT_AF_FILTER, .u.filter.flag = PEER_FT_FILTER_LIST, .u.filter.direct = FILTER_IN, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "filter-list", @@ -333,76 +212,44 @@ static struct test_peer_attr test_peer_attrs[] = { .type = PEER_AT_AF_FILTER, .u.filter.flag = PEER_FT_FILTER_LIST, .u.filter.direct = FILTER_OUT, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "maximum-prefix", .peer_cmd = "maximum-prefix 10", .group_cmd = "maximum-prefix 20", .u.flag = PEER_FLAG_MAX_PREFIX, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "maximum-prefix", .peer_cmd = "maximum-prefix 10 restart 100", .group_cmd = "maximum-prefix 20 restart 200", .u.flag = PEER_FLAG_MAX_PREFIX, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .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, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .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, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .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, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "next-hop-self", .u.flag = PEER_FLAG_NEXTHOP_SELF, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "next-hop-self force", .u.flag = PEER_FLAG_FORCE_NEXTHOP_SELF, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "prefix-list", @@ -411,10 +258,6 @@ static struct test_peer_attr test_peer_attrs[] = { .type = PEER_AT_AF_FILTER, .u.filter.flag = PEER_FT_PREFIX_LIST, .u.filter.direct = FILTER_IN, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "prefix-list", @@ -423,44 +266,24 @@ static struct test_peer_attr test_peer_attrs[] = { .type = PEER_AT_AF_FILTER, .u.filter.flag = PEER_FT_PREFIX_LIST, .u.filter.direct = FILTER_OUT, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "remove-private-AS", .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "remove-private-AS all", .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS | PEER_FLAG_REMOVE_PRIVATE_AS_ALL, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "remove-private-AS replace-AS", .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "remove-private-AS all replace-AS", .u.flag = PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "route-map", @@ -469,10 +292,6 @@ static struct test_peer_attr test_peer_attrs[] = { .type = PEER_AT_AF_FILTER, .u.filter.flag = PEER_FT_ROUTE_MAP, .u.filter.direct = FILTER_IN, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "route-map", @@ -481,62 +300,34 @@ static struct test_peer_attr test_peer_attrs[] = { .type = PEER_AT_AF_FILTER, .u.filter.flag = PEER_FT_ROUTE_MAP, .u.filter.direct = FILTER_OUT, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "route-reflector-client", .u.flag = PEER_FLAG_REFLECTOR_CLIENT, .o.use_ibgp = true, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "route-server-client", .u.flag = PEER_FLAG_RSERVER_CLIENT, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "send-community", .u.flag = PEER_FLAG_SEND_COMMUNITY, .o.invert = true, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "send-community extended", .u.flag = PEER_FLAG_SEND_EXT_COMMUNITY, .o.invert = true, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "send-community large", .u.flag = PEER_FLAG_SEND_LARGE_COMMUNITY, .o.invert = true, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "soft-reconfiguration inbound", .u.flag = PEER_FLAG_SOFT_RECONFIG, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "unsuppress-map", @@ -545,20 +336,12 @@ static struct test_peer_attr test_peer_attrs[] = { .type = PEER_AT_AF_FILTER, .u.filter.flag = PEER_FT_UNSUPPRESS_MAP, .u.filter.direct = 0, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, { .cmd = "weight", .peer_cmd = "weight 100", .group_cmd = "weight 200", .u.flag = PEER_FLAG_WEIGHT, - .families = { - { .afi = AFI_IP, .safi = SAFI_UNICAST }, - { .afi = AFI_IP6, .safi = SAFI_UNICAST }, - } }, {NULL} }; @@ -621,10 +404,6 @@ static const char *str_from_safi(safi_t safi) return "unicast"; case SAFI_MULTICAST: return "multicast"; - case SAFI_MPLS_VPN: - return "labeled-unicast"; - case SAFI_FLOWSPEC: - return "flowspec"; default: return ""; } @@ -852,9 +631,78 @@ static void test_finish(struct test *test) 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; @@ -862,6 +710,11 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa) 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]", @@ -871,17 +724,17 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa) } /* Test Case: Set flag on BGP peer. */ - test_log(test, "case %02d: set af-flag [%s] on [%s]", tc++, peer_cmd, + 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); + 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_af_filter(test, p, pa, true, true); + test_af_filter(test, g->conf, pa, false, false); } /* Test Case: Add BGP peer to peer-group. */ @@ -893,11 +746,11 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa) 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); + 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_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. */ @@ -909,109 +762,109 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa) 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); + 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_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 af-flag [%s] on [%s]", tc++, group_cmd, + 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); + 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_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 af-flag [%s] on [%s]", tc++, group_cmd, - g->name); + 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); + 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_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 af-flag [%s] on [%s]", tc++, group_cmd, + 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); + 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_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 af-flag [%s] on [%s]", tc++, peer_cmd, - p->host); + 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); + 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_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 af-flag [%s] on [%s]", tc++, peer_cmd, + 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); + 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_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 af-flag [%s] on [%s]", tc++, group_cmd, - g->name); + 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); + 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_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 af-flag [%s] on [%s]", tc++, peer_cmd, + 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); + 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_af_filter(test, p, pa, true, true); + test_af_filter(test, g->conf, pa, false, false); } } @@ -1087,24 +940,30 @@ int main(void) while (test_peer_attrs[i].cmd) { pa = &test_peer_attrs[i++]; - if (pa->families[0].afi && pa->families[0].safi) { - 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++; - } - } else { + /* 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++; } } diff --git a/tests/bgpd/test_peer_attr.py b/tests/bgpd/test_peer_attr.py index 17c6598382..d93dfc0050 100644 --- a/tests/bgpd/test_peer_attr.py +++ b/tests/bgpd/test_peer_attr.py @@ -7,88 +7,166 @@ class TestFlag(frrtest.TestMultiOut): # $> ./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\\ipv4-unicast\\distribute-list') -TestFlag.okfail('peer\\ipv6-unicast\\distribute-list') -TestFlag.okfail('peer\\ipv4-unicast\\distribute-list') -TestFlag.okfail('peer\\ipv6-unicast\\distribute-list') +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')