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 <mail@pascalmathis.com>
This commit is contained in:
Pascal Mathis 2018-05-21 12:09:25 +02:00
parent 598ce6bd70
commit 70ee29b4db
No known key found for this signature in database
GPG key ID: E208DBA7BFC9B28C
2 changed files with 400 additions and 247 deletions

View file

@ -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. */

View file

@ -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];