summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgpd.c553
-rw-r--r--bgpd/bgpd.h26
2 files changed, 366 insertions, 213 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,56 +5490,62 @@ int peer_distribute_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
int peer_distribute_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct bgp_filter *gfilter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != FILTER_IN && direct != FILTER_OUT)
return BGP_ERR_INVALID_VALUE;
- filter = &peer->filter[afi][safi];
+ /* Unset override-flag unconditionally. */
+ UNSET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_DISTRIBUTE_LIST);
- /* apply peer-group filter */
+ /* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- gfilter = &peer->group->conf->filter[afi][safi];
-
- if (gfilter->dlist[direct].name) {
- if (filter->dlist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- filter->dlist[direct].name);
- filter->dlist[direct].name =
- XSTRDUP(MTYPE_BGP_FILTER_NAME,
- gfilter->dlist[direct].name);
- filter->dlist[direct].alist =
- gfilter->dlist[direct].alist;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
+ PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
+ filter[afi][safi].dlist[direct].name);
+ PEER_ATTR_INHERIT(peer, filter[afi][safi].dlist[direct].alist);
+ } else {
+ /* Otherwise remove configuration from peer. */
+ filter = &peer->filter[afi][safi];
+ if (filter->dlist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->dlist[direct].name);
+ filter->dlist[direct].name = NULL;
+ filter->dlist[direct].alist = NULL;
}
- if (filter->dlist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[direct].name);
- filter->dlist[direct].name = NULL;
- filter->dlist[direct].alist = NULL;
-
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Process peer route updates. */
peer_on_policy_change(peer, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Remove configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_DISTRIBUTE_LIST))
+ continue;
+ /* Remove configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->dlist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME,
filter->dlist[direct].name);
filter->dlist[direct].name = NULL;
filter->dlist[direct].alist = NULL;
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
}
@@ -5568,98 +5615,120 @@ static void peer_distribute_update(struct access_list *access)
int peer_prefix_list_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != FILTER_IN && direct != FILTER_OUT)
return BGP_ERR_INVALID_VALUE;
+ /* Set configuration on peer. */
filter = &peer->filter[afi][safi];
-
if (filter->dlist[direct].name)
return BGP_ERR_PEER_FILTER_CONFLICT;
-
if (filter->plist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
filter->plist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->plist[direct].plist = prefix_list_lookup(afi, name);
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Set override-flag and process peer route updates. */
+ SET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_PREFIX_LIST);
peer_on_policy_change(peer, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Set configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_PREFIX_LIST))
+ continue;
+ /* Set configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->plist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME,
filter->plist[direct].name);
filter->plist[direct].name =
XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->plist[direct].plist = prefix_list_lookup(afi, name);
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
}
+
return 0;
}
int peer_prefix_list_unset(struct peer *peer, afi_t afi, safi_t safi,
int direct)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct bgp_filter *gfilter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != FILTER_IN && direct != FILTER_OUT)
return BGP_ERR_INVALID_VALUE;
- filter = &peer->filter[afi][safi];
+ /* Unset override-flag unconditionally. */
+ UNSET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_PREFIX_LIST);
- /* apply peer-group filter */
+ /* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- gfilter = &peer->group->conf->filter[afi][safi];
-
- if (gfilter->plist[direct].name) {
- if (filter->plist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- filter->plist[direct].name);
- filter->plist[direct].name =
- XSTRDUP(MTYPE_BGP_FILTER_NAME,
- gfilter->plist[direct].name);
- filter->plist[direct].plist =
- gfilter->plist[direct].plist;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
+ PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
+ filter[afi][safi].plist[direct].name);
+ PEER_ATTR_INHERIT(peer, filter[afi][safi].plist[direct].plist);
+ } else {
+ /* Otherwise remove configuration from peer. */
+ filter = &peer->filter[afi][safi];
+ if (filter->plist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->plist[direct].name);
+ filter->plist[direct].name = NULL;
+ filter->plist[direct].plist = NULL;
}
- if (filter->plist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
- filter->plist[direct].name = NULL;
- filter->plist[direct].plist = NULL;
-
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Process peer route updates. */
peer_on_policy_change(peer, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Remove configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_PREFIX_LIST))
+ continue;
+ /* Remove configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->plist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME,
filter->plist[direct].name);
filter->plist[direct].name = NULL;
filter->plist[direct].plist = NULL;
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
}
@@ -5730,94 +5799,118 @@ static void peer_prefix_list_update(struct prefix_list *plist)
int peer_aslist_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != FILTER_IN && direct != FILTER_OUT)
return BGP_ERR_INVALID_VALUE;
+ /* Set configuration on peer. */
filter = &peer->filter[afi][safi];
-
if (filter->aslist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[direct].name);
filter->aslist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->aslist[direct].aslist = as_list_lookup(name);
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Set override-flag and process peer route updates. */
+ SET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_FILTER_LIST);
peer_on_policy_change(peer, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Set configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_FILTER_LIST))
+ continue;
+ /* Set configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->aslist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME,
filter->aslist[direct].name);
filter->aslist[direct].name =
XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->aslist[direct].aslist = as_list_lookup(name);
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
}
+
return 0;
}
int peer_aslist_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
{
+ struct peer *member;
struct bgp_filter *filter;
- struct bgp_filter *gfilter;
- struct peer_group *group;
struct listnode *node, *nnode;
if (direct != FILTER_IN && direct != FILTER_OUT)
return BGP_ERR_INVALID_VALUE;
- filter = &peer->filter[afi][safi];
+ /* Unset override-flag unconditionally. */
+ UNSET_FLAG(peer->filter_override[afi][safi][direct],
+ PEER_FT_FILTER_LIST);
- /* apply peer-group filter */
+ /* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
- gfilter = &peer->group->conf->filter[afi][safi];
-
- if (gfilter->aslist[direct].name) {
- if (filter->aslist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- filter->aslist[direct].name);
- filter->aslist[direct].name =
- XSTRDUP(MTYPE_BGP_FILTER_NAME,
- gfilter->aslist[direct].name);
- filter->aslist[direct].aslist =
- gfilter->aslist[direct].aslist;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
+ PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
+ filter[afi][safi].aslist[direct].name);
+ PEER_ATTR_INHERIT(peer,
+ filter[afi][safi].aslist[direct].aslist);
+ } else {
+ /* Otherwise remove configuration from peer. */
+ filter = &peer->filter[afi][safi];
+ if (filter->aslist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->aslist[direct].name);
+ filter->aslist[direct].name = NULL;
+ filter->aslist[direct].aslist = NULL;
}
- if (filter->aslist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[direct].name);
- filter->aslist[direct].name = NULL;
- filter->aslist[direct].aslist = NULL;
-
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Process peer route updates. */
peer_on_policy_change(peer, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Remove configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_FILTER_LIST))
+ continue;
+ /* Remove configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->aslist[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME,
filter->aslist[direct].name);
filter->aslist[direct].name = NULL;
filter->aslist[direct].aslist = NULL;
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == FILTER_OUT) ? 1 : 0);
}
@@ -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;
- }
+ PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
+ filter[afi][safi].map[direct].name);
+ PEER_ATTR_INHERIT(peer, filter[afi][safi].map[direct].map);
+ } else {
+ /* Otherwise remove configuration from peer. */
+ filter = &peer->filter[afi][safi];
+ if (filter->map[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+ filter->map[direct].name = NULL;
+ filter->map[direct].map = NULL;
}
- if (filter->map[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
- filter->map[direct].name = NULL;
- filter->map[direct].map = NULL;
-
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Process peer route updates. */
peer_on_policy_change(peer, afi, safi,
(direct == RMAP_OUT) ? 1 : 0);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Remove configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][direct],
+ PEER_FT_ROUTE_MAP))
+ continue;
+ /* Remove configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->map[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
filter->map[direct].name = NULL;
filter->map[direct].map = NULL;
- peer_on_policy_change(peer, afi, safi,
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi,
(direct == RMAP_OUT) ? 1 : 0);
}
+
return 0;
}
@@ -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;
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ PEER_STR_ATTR_INHERIT(MTYPE_BGP_FILTER_NAME, peer,
+ filter[afi][safi].usmap.name);
+ PEER_ATTR_INHERIT(peer, filter[afi][safi].usmap.map);
+ } else {
+ /* Otherwise remove configuration from peer. */
+ filter = &peer->filter[afi][safi];
+ if (filter->usmap.name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+ filter->usmap.name = NULL;
+ filter->usmap.map = NULL;
+ }
+ /* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Process peer route updates. */
peer_on_policy_change(peer, afi, safi, 1);
+
+ /* Skip peer-group mechanics for regular peers. */
return 0;
}
- group = peer->group;
- for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- filter = &peer->filter[afi][safi];
+ /*
+ * Remove configuration on all peer-group members, unless they are
+ * explicitely overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][0],
+ PEER_FT_UNSUPPRESS_MAP))
+ continue;
+ /* Remove configuration on peer-group member. */
+ filter = &member->filter[afi][safi];
if (filter->usmap.name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
filter->usmap.name = NULL;
filter->usmap.map = NULL;
- peer_on_policy_change(peer, afi, safi, 1);
+
+ /* Process peer route updates. */
+ peer_on_policy_change(member, afi, safi, 1);
}
+
return 0;
}
@@ -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];