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 <value>)

- 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 <command>' on a peer will remove the peer-specific
configuration and make the peer inherit the configuration from the
peer-group again.

- Executing 'no <command>' 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 <command>' 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 <mail@pascalmathis.com>
This commit is contained in:
Pascal Mathis 2018-05-19 22:10:48 +02:00
parent f7fba3423b
commit 598ce6bd70
No known key found for this signature in database
GPG Key ID: E208DBA7BFC9B28C
2 changed files with 365 additions and 324 deletions

View File

@ -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 CHECK_FLAG(peer->af_flags[afi][safi], flag);
} }
/* Return true if flag is set for the peer but not the peer-group */ void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi,
static int peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint32_t flag)
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)) { /* Unset override flag to signal inheritance from peer-group. */
if (peer_group_active(peer)) { UNSET_FLAG(peer->af_flags_override[afi][safi], flag);
g_peer = peer->group->conf;
/* If this flag is not set for the peer's peer-group /* Inherit flag state from peer-group. */
* then return true */ if (CHECK_FLAG(peer->group->conf->af_flags[afi][safi], flag))
if (!peer_af_flag_check(g_peer, afi, safi, flag)) { SET_FLAG(peer->af_flags[afi][safi], flag);
return 1; else
} UNSET_FLAG(peer->af_flags[afi][safi], flag);
} }
/* peer is not in a peer-group but the flag is set to return static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
true */ uint32_t flag)
else { {
return 1; 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. */ /* 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_AS_PATH_UNCHANGED, 1, peer_change_reset_out},
{PEER_FLAG_NEXTHOP_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_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_REMOVE_PRIVATE_AS, 1, peer_change_reset_out},
{PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in}, {PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in},
{PEER_FLAG_ALLOWAS_IN_ORIGIN, 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_SM, 1, peer_change_reset},
{PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset}, {PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset},
// PEER_FLAG_MAX_PREFIX {PEER_FLAG_MAX_PREFIX, 0, peer_change_none},
// PEER_FLAG_MAX_PREFIX_WARNING {PEER_FLAG_MAX_PREFIX_WARNING, 0, peer_change_none},
{PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out}, {PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out},
{PEER_FLAG_FORCE_NEXTHOP_SELF, 1, 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}, {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. */ /* When current flag configuration is same as requested one. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { 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; 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; 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) if (set)
SET_FLAG(peer->af_flags[afi][safi], flag); SET_FLAG(peer->af_flags[afi][safi], flag);
else if (peer_group_active(peer))
peer_af_flag_inherit(peer, afi, safi, flag);
else else
UNSET_FLAG(peer->af_flags[afi][safi], flag); 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. */ /* Peer group member updates. */
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
group = peer->group; group = peer->group;
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) { for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
if (CHECK_FLAG(tmp_peer->af_flags_override[afi][safi],
flag))
continue;
if (set if (set
&& CHECK_FLAG(tmp_peer->af_flags[afi][safi], flag) && CHECK_FLAG(tmp_peer->af_flags[afi][safi], flag))
== flag)
continue; continue;
if (!set 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 */ /* 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, int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
const char *rmap) const char *rmap)
{ {
struct peer_group *group; struct peer *member;
struct listnode *node, *nnode; struct listnode *node, *nnode;
if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE) /* Set flag and configuration on peer. */
|| (rmap && !peer->default_rmap[afi][safi].name) peer_af_flag_set(peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE);
|| (rmap if (rmap) {
&& strcmp(rmap, peer->default_rmap[afi][safi].name) != 0)) { if (!peer->default_rmap[afi][safi].name
SET_FLAG(peer->af_flags[afi][safi], || strcmp(rmap, peer->default_rmap[afi][safi].name) != 0) {
PEER_FLAG_DEFAULT_ORIGINATE);
if (rmap) {
if (peer->default_rmap[afi][safi].name) if (peer->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME, XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].name);
peer->default_rmap[afi][safi].name = peer->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
peer->default_rmap[afi][safi].map = peer->default_rmap[afi][safi].map =
route_map_lookup_by_name(rmap); 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)) { if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
/* Update peer route announcements. */
if (peer->status == Established && peer->afc_nego[afi][safi]) { if (peer->status == Established && peer->afc_nego[afi][safi]) {
update_group_adjust_peer(peer_af_find(peer, afi, safi)); update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate(peer, afi, safi, 0); bgp_default_originate(peer, afi, safi, 0);
bgp_announce_route(peer, afi, safi); bgp_announce_route(peer, afi, safi);
} }
/* Skip peer-group mechanics for regular peers. */
return 0; return 0;
} }
/* peer-group member updates. */ /*
group = peer->group; * Set flag and configuration on all peer-group members, unless they are
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { * explicitely overriding peer-group configuration.
SET_FLAG(peer->af_flags[afi][safi], */
PEER_FLAG_DEFAULT_ORIGINATE); 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 (rmap) {
if (peer->default_rmap[afi][safi].name) if (member->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME, XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name); member->default_rmap[afi][safi].name);
peer->default_rmap[afi][safi].name =
member->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
peer->default_rmap[afi][safi].map = member->default_rmap[afi][safi].map =
route_map_lookup_by_name(rmap); route_map_lookup_by_name(rmap);
} }
if (peer->status == Established && peer->afc_nego[afi][safi]) { /* Update peer route announcements. */
update_group_adjust_peer(peer_af_find(peer, afi, safi)); if (member->status == Established
bgp_default_originate(peer, afi, safi, 0); && member->afc_nego[afi][safi]) {
bgp_announce_route(peer, 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; return 0;
} }
int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi) 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; struct listnode *node, *nnode;
if (CHECK_FLAG(peer->af_flags[afi][safi], /* Inherit configuration from peer-group if peer is member. */
PEER_FLAG_DEFAULT_ORIGINATE)) { if (peer_group_active(peer)) {
UNSET_FLAG(peer->af_flags[afi][safi], peer_af_flag_inherit(peer, afi, safi,
PEER_FLAG_DEFAULT_ORIGINATE); 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) if (peer->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME, XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].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; peer->default_rmap[afi][safi].map = NULL;
} }
/* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
/* Update peer route announcements. */
if (peer->status == Established && peer->afc_nego[afi][safi]) { if (peer->status == Established && peer->afc_nego[afi][safi]) {
update_group_adjust_peer(peer_af_find(peer, afi, safi)); update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate(peer, afi, safi, 1); bgp_default_originate(peer, afi, safi, 1);
bgp_announce_route(peer, afi, safi); bgp_announce_route(peer, afi, safi);
} }
/* Skip peer-group mechanics for regular peers. */
return 0; return 0;
} }
/* peer-group member updates. */ /*
group = peer->group; * Remove flag and configuration from all peer-group members, unless
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { * 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], UNSET_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_DEFAULT_ORIGINATE); PEER_FLAG_DEFAULT_ORIGINATE);
if (peer->default_rmap[afi][safi].name) if (peer->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME, XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].name);
peer->default_rmap[afi][safi].name = NULL; peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL; peer->default_rmap[afi][safi].map = NULL;
/* Update peer route announcements. */
if (peer->status == Established && peer->afc_nego[afi][safi]) { if (peer->status == Established && peer->afc_nego[afi][safi]) {
update_group_adjust_peer(peer_af_find(peer, afi, safi)); update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate(peer, afi, safi, 1); bgp_default_originate(peer, afi, safi, 1);
bgp_announce_route(peer, afi, safi); bgp_announce_route(peer, afi, safi);
} }
} }
return 0; return 0;
} }
@ -4696,81 +4750,87 @@ static void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
/* neighbor weight. */ /* neighbor weight. */
int peer_weight_set(struct peer *peer, afi_t afi, safi_t safi, uint16_t 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; 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) { if (peer->weight[afi][safi] != weight) {
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); peer_on_policy_change(peer, afi, safi, 0);
} }
/* Skip peer-group mechanics for regular peers. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
return 0; return 0;
/* peer-group member updates. */ /*
group = peer->group; * Set flag and configuration on all peer-group members, unless they are
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { * explicitely overriding peer-group configuration.
if (peer->weight[afi][safi] != weight) { */
peer->weight[afi][safi] = weight; for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_WEIGHT); /* Skip peers with overridden configuration. */
peer_on_policy_change(peer, afi, safi, 0); 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; return 0;
} }
int peer_weight_unset(struct peer *peer, afi_t afi, safi_t safi) int peer_weight_unset(struct peer *peer, afi_t afi, safi_t safi)
{ {
struct peer_group *group; struct peer *member;
struct listnode *node, *nnode; 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)) { 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 */ peer_on_policy_change(peer, afi, safi, 0);
if (CHECK_FLAG(group->conf->af_flags[afi][safi], return 0;
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);
}
}
} }
else { /* Remove flag and configuration from peer. */
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_WEIGHT)) { peer_af_flag_unset(peer, afi, safi, PEER_FLAG_WEIGHT);
peer->weight[afi][safi] = 0; 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);
}
/* peer-group member updates. */ /* Skip peer-group mechanics for regular peers. */
group = peer->group; if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
return 0;
if (group) { /*
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, * Remove flag and configuration from all peer-group members, unless
peer)) { * they are explicitely overriding peer-group configuration.
if (CHECK_FLAG(peer->af_flags[afi][safi], */
PEER_FLAG_WEIGHT)) { for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
peer->weight[afi][safi] = 0; /* Skip peers with overridden configuration. */
peer_af_flag_unset(peer, afi, safi, if (CHECK_FLAG(member->af_flags_override[afi][safi],
PEER_FLAG_WEIGHT); PEER_FLAG_WEIGHT))
peer_on_policy_change(peer, afi, safi, continue;
0);
} /* 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; 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 peer_allowas_in_set(struct peer *peer, afi_t afi, safi_t safi,
int allow_num, int origin) int allow_num, int origin)
{ {
struct peer_group *group; struct peer *member;
struct listnode *node, *nnode; 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 (origin) {
if (peer->allowas_in[afi][safi] if (peer->allowas_in[afi][safi] != 0
|| CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ALLOWAS_IN)
|| !CHECK_FLAG(peer->af_flags[afi][safi], || !CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ALLOWAS_IN_ORIGIN)) { 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_af_flag_set(peer, afi, safi,
PEER_FLAG_ALLOWAS_IN_ORIGIN); PEER_FLAG_ALLOWAS_IN_ORIGIN);
peer->allowas_in[afi][safi] = 0;
peer_on_policy_change(peer, 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 { } else {
if (allow_num < 1 || allow_num > 10)
return BGP_ERR_INVALID_VALUE;
if (peer->allowas_in[afi][safi] != allow_num if (peer->allowas_in[afi][safi] != allow_num
|| CHECK_FLAG(peer->af_flags[afi][safi], || CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ALLOWAS_IN_ORIGIN)) { 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_af_flag_unset(peer, afi, safi,
PEER_FLAG_ALLOWAS_IN_ORIGIN); PEER_FLAG_ALLOWAS_IN_ORIGIN);
peer->allowas_in[afi][safi] = allow_num;
peer_on_policy_change(peer, afi, safi, 0); peer_on_policy_change(peer, afi, safi, 0);
} }
}
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) /* Skip peer-group mechanics for regular peers. */
return 0; if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
return 0;
group = peer->group; /*
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { * Set flag and configuration on all peer-group members, unless
if (peer->allowas_in[afi][safi] != allow_num * they are explicitely overriding peer-group configuration.
|| CHECK_FLAG(peer->af_flags[afi][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))
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_FLAG_ALLOWAS_IN_ORIGIN)) {
peer->allowas_in[afi][safi] = allow_num; UNSET_FLAG(member->af_flags[afi][safi],
peer_af_flag_set(peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
PEER_FLAG_ALLOWAS_IN); member->allowas_in[afi][safi] = allow_num;
peer_af_flag_unset(peer, afi, safi,
PEER_FLAG_ALLOWAS_IN_ORIGIN);
peer_on_policy_change(peer, afi, safi, 0); 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) int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi)
{ {
struct peer_group *group; struct peer *member;
struct peer *tmp_peer;
struct listnode *node, *nnode; struct listnode *node, *nnode;
/* If this is a peer-group we must first clear the flags for all of the /* Skip peer if flag is already disabled. */
* peer-group members if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN))
*/ return 0;
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
group = peer->group; /* Inherit configuration from peer-group if peer is member. */
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) { if (peer_group_active(peer)) {
if (CHECK_FLAG(tmp_peer->af_flags[afi][safi], peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
PEER_FLAG_ALLOWAS_IN) peer_af_flag_inherit(peer, afi, safi,
|| CHECK_FLAG(tmp_peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN);
PEER_FLAG_ALLOWAS_IN_ORIGIN)) { PEER_ATTR_INHERIT(peer, allowas_in[afi][safi]);
tmp_peer->allowas_in[afi][safi] = 0; peer_on_policy_change(peer, afi, safi, 0);
peer_af_flag_unset(tmp_peer, afi, safi,
PEER_FLAG_ALLOWAS_IN); return 0;
peer_af_flag_unset(tmp_peer, afi, safi,
PEER_FLAG_ALLOWAS_IN_ORIGIN);
peer_on_policy_change(tmp_peer, afi, safi, 0);
}
}
} }
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN) /* Remove flag and configuration from peer. */
|| CHECK_FLAG(peer->af_flags[afi][safi], peer_af_flag_unset(peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
PEER_FLAG_ALLOWAS_IN_ORIGIN)) { peer_af_flag_unset(peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
peer->allowas_in[afi][safi] = 0; peer->allowas_in[afi][safi] = 0;
peer_af_flag_unset(peer, afi, safi, PEER_FLAG_ALLOWAS_IN); peer_on_policy_change(peer, afi, safi, 0);
peer_af_flag_unset(peer, afi, safi,
PEER_FLAG_ALLOWAS_IN_ORIGIN); /* Skip peer-group mechanics if handling a regular peer. */
peer_on_policy_change(peer, afi, safi, 0); 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; 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, uint32_t max, uint8_t threshold, int warning,
uint16_t restart) uint16_t restart)
{ {
struct peer_group *group; struct peer *member;
struct listnode *node, *nnode; struct listnode *node, *nnode;
/* apply configuration and set flags */ /* Set flags and configuration on peer. */
SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); peer_af_flag_set(peer, afi, safi, PEER_FLAG_MAX_PREFIX);
if (warning) if (warning)
SET_FLAG(peer->af_flags[afi][safi], peer_af_flag_set(peer, afi, safi, PEER_FLAG_MAX_PREFIX_WARNING);
PEER_FLAG_MAX_PREFIX_WARNING);
else else
UNSET_FLAG(peer->af_flags[afi][safi], peer_af_flag_unset(peer, afi, safi,
PEER_FLAG_MAX_PREFIX_WARNING); PEER_FLAG_MAX_PREFIX_WARNING);
peer->pmax[afi][safi] = max; peer->pmax[afi][safi] = max;
peer->pmax_threshold[afi][safi] = threshold; peer->pmax_threshold[afi][safi] = threshold;
peer->pmax_restart[afi][safi] = restart; peer->pmax_restart[afi][safi] = restart;
/* if handling a peer-group, apply to all children */ /* Check if handling a regular peer. */
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
group = peer->group; /* Re-check if peer violates maximum-prefix. */
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { if ((peer->status == Established) && (peer->afc[afi][safi])) {
/*
* 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]))
bgp_maximum_prefix_overflow(peer, afi, safi, 1); bgp_maximum_prefix_overflow(peer, afi, safi, 1);
}
SET_FLAG(peer->af_flags_override[afi][safi], /* Skip peer-group mechanics for regular peers. */
PEER_FLAG_MAX_PREFIX); 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) if (warning)
SET_FLAG(peer->af_flags_override[afi][safi], SET_FLAG(member->af_flags[afi][safi],
PEER_FLAG_MAX_PREFIX_WARNING); PEER_FLAG_MAX_PREFIX_WARNING);
else else
UNSET_FLAG(peer->af_flags_override[afi][safi], UNSET_FLAG(member->af_flags[afi][safi],
PEER_FLAG_MAX_PREFIX_WARNING); 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; 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) 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; struct listnode *node, *nnode;
UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); /* Inherit configuration from peer-group if peer is member. */
UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); if (peer_group_active(peer)) {
peer->pmax[afi][safi] = 0; peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_MAX_PREFIX);
peer->pmax_threshold[afi][safi] = 0; peer_af_flag_inherit(peer, afi, safi,
peer->pmax_restart[afi][safi] = 0; PEER_FLAG_MAX_PREFIX_WARNING);
PEER_ATTR_INHERIT(peer, pmax[afi][safi]);
/* if not handling a peer-group, unset override flags */ PEER_ATTR_INHERIT(peer, pmax_threshold[afi][safi]);
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { PEER_ATTR_INHERIT(peer, pmax_restart[afi][safi]);
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];
}
return 0; 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 * Remove flags and configuration from all peer-group members, unless
* have overrides for our config. * they are explicitely overriding peer-group configuration.
*/ */
group = peer->group; for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { /* Skip peers with overridden configuration. */
if (!CHECK_FLAG(peer->af_flags_override[afi][safi], if (CHECK_FLAG(member->af_flags_override[afi][safi],
PEER_FLAG_MAX_PREFIX_WARNING)) PEER_FLAG_MAX_PREFIX))
UNSET_FLAG(peer->af_flags[afi][safi], continue;
PEER_FLAG_MAX_PREFIX_WARNING);
if (!CHECK_FLAG(peer->af_flags_override[afi][safi], /* Remove flag and configuration on peer-group member. */
PEER_FLAG_MAX_PREFIX)) { UNSET_FLAG(member->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
UNSET_FLAG(peer->af_flags[afi][safi], UNSET_FLAG(member->af_flags[afi][safi],
PEER_FLAG_MAX_PREFIX); PEER_FLAG_MAX_PREFIX_WARNING);
peer->pmax[afi][safi] = 0; member->pmax[afi][safi] = 0;
peer->pmax_threshold[afi][safi] = 0; member->pmax_threshold[afi][safi] = 0;
peer->pmax_restart[afi][safi] = 0; member->pmax_restart[afi][safi] = 0;
}
} }
return 0; return 0;
} }
@ -7065,19 +7126,13 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
/* Default information */ /* Default information */
if (peergroup_af_flag_check(peer, afi, safi, if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_DEFAULT_ORIGINATE) 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))))) {
vty_out(vty, " neighbor %s default-originate", addr); vty_out(vty, " neighbor %s default-originate", addr);
if (peer->default_rmap[afi][safi].name) if (peer->default_rmap[afi][safi].name)
vty_out(vty, " route-map %s", vty_out(vty, " route-map %s",
peer->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].name);
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
@ -7088,29 +7143,22 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
} }
/* maximum-prefix. */ /* maximum-prefix. */
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MAX_PREFIX)) {
if (!peer_group_active(peer) vty_out(vty, " neighbor %s maximum-prefix %lu", addr,
|| g_peer->pmax[afi][safi] != peer->pmax[afi][safi] peer->pmax[afi][safi]);
|| g_peer->pmax_threshold[afi][safi]
!= peer->pmax_threshold[afi][safi] if (peer->pmax_threshold[afi][safi]
|| CHECK_FLAG(g_peer->af_flags[afi][safi], != MAXIMUM_PREFIX_THRESHOLD_DEFAULT)
PEER_FLAG_MAX_PREFIX_WARNING) vty_out(vty, " %u", peer->pmax_threshold[afi][safi]);
!= CHECK_FLAG(peer->af_flags[afi][safi], if (peer_af_flag_check(peer, 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],
PEER_FLAG_MAX_PREFIX_WARNING)) PEER_FLAG_MAX_PREFIX_WARNING))
vty_out(vty, " warning-only"); vty_out(vty, " warning-only");
if (peer->pmax_restart[afi][safi]) if (peer->pmax_restart[afi][safi])
vty_out(vty, " restart %u", vty_out(vty, " restart %u",
peer->pmax_restart[afi][safi]); peer->pmax_restart[afi][safi]);
vty_out(vty, "\n");
} vty_out(vty, "\n");
}
/* Route server client. */ /* Route server client. */
if (peergroup_af_flag_check(peer, afi, safi, 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> */ /* allowas-in <1-10> */
if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) { if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) {
if (!peer_group_active(peer) if (peer_af_flag_check(peer, afi, safi,
|| !peer_af_flag_check(g_peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
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)) {
vty_out(vty, " neighbor %s allowas-in origin\n", addr); 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 */ /* weight */
if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_WEIGHT)) if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_WEIGHT))
if (!peer_group_active(peer) vty_out(vty, " neighbor %s weight %lu\n", addr,
|| !peer_af_flag_check(g_peer, afi, safi, PEER_FLAG_WEIGHT) peer->weight[afi][safi]);
|| 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]);
}
}
/* Filter. */ /* Filter. */
bgp_config_write_filter(vty, peer, afi, safi); bgp_config_write_filter(vty, peer, afi, safi);

View File

@ -1108,6 +1108,18 @@ struct peer {
}; };
DECLARE_QOBJ_TYPE(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. */ /* Check if suppress start/restart of sessions to peer. */
#define BGP_PEER_START_SUPPRESSED(P) \ #define BGP_PEER_START_SUPPRESSED(P) \
(CHECK_FLAG((P)->flags, PEER_FLAG_SHUTDOWN) \ (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_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_unset(struct peer *, afi_t, safi_t, uint32_t);
extern int peer_af_flag_check(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_set(struct peer *, int);
extern int peer_ebgp_multihop_unset(struct peer *); extern int peer_ebgp_multihop_unset(struct peer *);