Merge pull request #7345 from opensourcerouting/bgp-aggr-suppress

bgpd: aggregate-address suppress-map
This commit is contained in:
Donatas Abraitis 2020-10-23 15:02:57 +03:00 committed by GitHub
commit 90a65457d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 372 additions and 68 deletions

View File

@ -115,6 +115,14 @@ DEFINE_HOOK(bgp_process,
struct peer *peer, bool withdraw), struct peer *peer, bool withdraw),
(bgp, afi, safi, bn, peer, withdraw)) (bgp, afi, safi, bn, peer, withdraw))
/** Test if path is suppressed. */
static bool bgp_path_suppressed(struct bgp_path_info *pi)
{
if (pi->extra == NULL || pi->extra->aggr_suppressors == NULL)
return false;
return listcount(pi->extra->aggr_suppressors) > 0;
}
struct bgp_dest *bgp_afi_node_get(struct bgp_table *table, afi_t afi, struct bgp_dest *bgp_afi_node_get(struct bgp_table *table, afi_t afi,
safi_t safi, const struct prefix *p, safi_t safi, const struct prefix *p,
@ -1704,10 +1712,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
} }
/* Aggregate-address suppress check. */ /* Aggregate-address suppress check. */
if (pi->extra && pi->extra->suppress) if (bgp_path_suppressed(pi) && !UNSUPPRESS_MAP_NAME(filter))
if (!UNSUPPRESS_MAP_NAME(filter)) { return false;
return false;
}
/* /*
* If we are doing VRF 2 VRF leaking via the import * If we are doing VRF 2 VRF leaking via the import
@ -1944,7 +1950,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
bgp_peer_as_override(bgp, afi, safi, peer, attr); bgp_peer_as_override(bgp, afi, safi, peer, attr);
/* Route map & unsuppress-map apply. */ /* Route map & unsuppress-map apply. */
if (ROUTE_MAP_OUT_NAME(filter) || (pi->extra && pi->extra->suppress)) { if (ROUTE_MAP_OUT_NAME(filter) || bgp_path_suppressed(pi)) {
struct bgp_path_info rmap_path = {0}; struct bgp_path_info rmap_path = {0};
struct bgp_path_info_extra dummy_rmap_path_extra = {0}; struct bgp_path_info_extra dummy_rmap_path_extra = {0};
struct attr dummy_attr = {0}; struct attr dummy_attr = {0};
@ -1969,7 +1975,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT); SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT);
if (pi->extra && pi->extra->suppress) if (bgp_path_suppressed(pi))
ret = route_map_apply(UNSUPPRESS_MAP(filter), p, ret = route_map_apply(UNSUPPRESS_MAP(filter), p,
RMAP_BGP, &rmap_path); RMAP_BGP, &rmap_path);
else else
@ -6176,11 +6182,119 @@ static struct bgp_aggregate *bgp_aggregate_new(void)
static void bgp_aggregate_free(struct bgp_aggregate *aggregate) static void bgp_aggregate_free(struct bgp_aggregate *aggregate)
{ {
XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->suppress_map_name);
route_map_counter_decrement(aggregate->suppress_map);
XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name); XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name);
route_map_counter_decrement(aggregate->rmap.map); route_map_counter_decrement(aggregate->rmap.map);
XFREE(MTYPE_BGP_AGGREGATE, aggregate); XFREE(MTYPE_BGP_AGGREGATE, aggregate);
} }
/**
* Helper function to avoid repeated code: prepare variables for a
* `route_map_apply` call.
*
* \returns `true` on route map match, otherwise `false`.
*/
static bool aggr_suppress_map_test(struct bgp *bgp,
struct bgp_aggregate *aggregate,
struct bgp_path_info *pi)
{
const struct prefix *p = bgp_dest_get_prefix(pi->net);
route_map_result_t rmr = RMAP_DENYMATCH;
struct bgp_path_info rmap_path = {};
struct attr attr = {};
/* No route map entries created, just don't match. */
if (aggregate->suppress_map == NULL)
return false;
/* Call route map matching and return result. */
attr.aspath = aspath_empty();
rmap_path.peer = bgp->peer_self;
rmap_path.attr = &attr;
SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_AGGREGATE);
rmr = route_map_apply(aggregate->suppress_map, p, RMAP_BGP, &rmap_path);
bgp->peer_self->rmap_type = 0;
bgp_attr_flush(&attr);
return rmr == RMAP_PERMITMATCH;
}
/** Test whether the aggregation has suppressed this path or not. */
static bool aggr_suppress_exists(struct bgp_aggregate *aggregate,
struct bgp_path_info *pi)
{
if (pi->extra == NULL || pi->extra->aggr_suppressors == NULL)
return false;
return listnode_lookup(pi->extra->aggr_suppressors, aggregate) != NULL;
}
/**
* Suppress this path and keep the reference.
*
* \returns `true` if needs processing otherwise `false`.
*/
static bool aggr_suppress_path(struct bgp_aggregate *aggregate,
struct bgp_path_info *pi)
{
struct bgp_path_info_extra *pie;
/* Path is already suppressed by this aggregation. */
if (aggr_suppress_exists(aggregate, pi))
return false;
pie = bgp_path_info_extra_get(pi);
/* This is the first suppression, allocate memory and list it. */
if (pie->aggr_suppressors == NULL)
pie->aggr_suppressors = list_new();
listnode_add(pie->aggr_suppressors, aggregate);
/* Only mark for processing if suppressed. */
if (listcount(pie->aggr_suppressors) == 1) {
if (BGP_DEBUG(update, UPDATE_OUT))
zlog_debug("aggregate-address suppressing: %pFX",
bgp_dest_get_prefix(pi->net));
bgp_path_info_set_flag(pi->net, pi, BGP_PATH_ATTR_CHANGED);
return true;
}
return false;
}
/**
* Unsuppress this path and remove the reference.
*
* \returns `true` if needs processing otherwise `false`.
*/
static bool aggr_unsuppress_path(struct bgp_aggregate *aggregate,
struct bgp_path_info *pi)
{
/* Path wasn't suppressed. */
if (!aggr_suppress_exists(aggregate, pi))
return false;
listnode_delete(pi->extra->aggr_suppressors, aggregate);
/* Unsuppress and free extra memory if last item. */
if (listcount(pi->extra->aggr_suppressors) == 0) {
if (BGP_DEBUG(update, UPDATE_OUT))
zlog_debug("aggregate-address unsuppressing: %pFX",
bgp_dest_get_prefix(pi->net));
list_delete(&pi->extra->aggr_suppressors);
bgp_path_info_set_flag(pi->net, pi, BGP_PATH_ATTR_CHANGED);
return true;
}
return false;
}
static bool bgp_aggregate_info_same(struct bgp_path_info *pi, uint8_t origin, static bool bgp_aggregate_info_same(struct bgp_path_info *pi, uint8_t origin,
struct aspath *aspath, struct aspath *aspath,
struct community *comm, struct community *comm,
@ -6375,13 +6489,11 @@ static bool bgp_aggregate_test_all_med(struct bgp_aggregate *aggregate,
* Toggles the route suppression status for this aggregate address * Toggles the route suppression status for this aggregate address
* configuration. * configuration.
*/ */
static void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate,
struct bgp *bgp, struct bgp *bgp, const struct prefix *p,
const struct prefix *p, afi_t afi, afi_t afi, safi_t safi, bool suppress)
safi_t safi, bool suppress)
{ {
struct bgp_table *table = bgp->rib[afi][safi]; struct bgp_table *table = bgp->rib[afi][safi];
struct bgp_path_info_extra *pie;
const struct prefix *dest_p; const struct prefix *dest_p;
struct bgp_dest *dest, *top; struct bgp_dest *dest, *top;
struct bgp_path_info *pi; struct bgp_path_info *pi;
@ -6402,32 +6514,17 @@ static void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate,
if (pi->sub_type == BGP_ROUTE_AGGREGATE) if (pi->sub_type == BGP_ROUTE_AGGREGATE)
continue; continue;
/*
* On installation it is possible that pi->extra is
* set to NULL, otherwise it must exists.
*/
assert(!suppress && pi->extra != NULL);
/* We are toggling suppression back. */ /* We are toggling suppression back. */
if (suppress) { if (suppress) {
pie = bgp_path_info_extra_get(pi);
/* Suppress route if not suppressed already. */ /* Suppress route if not suppressed already. */
pie->suppress++; if (aggr_suppress_path(aggregate, pi))
bgp_path_info_set_flag(dest, pi, toggle_suppression = true;
BGP_PATH_ATTR_CHANGED);
toggle_suppression = true;
continue; continue;
} }
pie = pi->extra;
assert(pie->suppress > 0);
pie->suppress--;
/* Install route if there is no more suppression. */ /* Install route if there is no more suppression. */
if (pie->suppress == 0) { if (aggr_unsuppress_path(aggregate, pi))
bgp_path_info_set_flag(dest, pi,
BGP_PATH_ATTR_CHANGED);
toggle_suppression = true; toggle_suppression = true;
}
} }
if (toggle_suppression) if (toggle_suppression)
@ -6514,6 +6611,17 @@ void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
if (aggregate->match_med) if (aggregate->match_med)
bgp_aggregate_test_all_med(aggregate, bgp, p, afi, safi); bgp_aggregate_test_all_med(aggregate, bgp, p, afi, safi);
/*
* Reset aggregate count: we might've been called from route map
* update so in that case we must retest all more specific routes.
*
* \see `bgp_route_map_process_update`.
*/
aggregate->count = 0;
aggregate->incomplete_origin_count = 0;
aggregate->incomplete_origin_count = 0;
aggregate->egp_origin_count = 0;
/* ORIGIN attribute: If at least one route among routes that are /* ORIGIN attribute: If at least one route among routes that are
aggregated has ORIGIN with the value INCOMPLETE, then the aggregated has ORIGIN with the value INCOMPLETE, then the
aggregated route must have the ORIGIN attribute with the value aggregated route must have the ORIGIN attribute with the value
@ -6558,10 +6666,24 @@ void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
*/ */
if (aggregate->summary_only if (aggregate->summary_only
&& AGGREGATE_MED_VALID(aggregate)) { && AGGREGATE_MED_VALID(aggregate)) {
(bgp_path_info_extra_get(pi))->suppress++; if (aggr_suppress_path(aggregate, pi))
bgp_path_info_set_flag(dest, pi, match++;
BGP_PATH_ATTR_CHANGED); }
match++;
/*
* Suppress more specific routes that match the route
* map results.
*
* MED matching:
* Don't suppress routes if MED matching is enabled and
* it mismatched otherwise we might end up with no
* routes for this path.
*/
if (aggregate->suppress_map_name
&& AGGREGATE_MED_VALID(aggregate)
&& aggr_suppress_map_test(bgp, aggregate, pi)) {
if (aggr_suppress_path(aggregate, pi))
match++;
} }
aggregate->count++; aggregate->count++;
@ -6701,15 +6823,17 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi,
if (aggregate->summary_only && pi->extra if (aggregate->summary_only && pi->extra
&& AGGREGATE_MED_VALID(aggregate)) { && AGGREGATE_MED_VALID(aggregate)) {
pi->extra->suppress--; if (aggr_unsuppress_path(aggregate, pi))
if (pi->extra->suppress == 0) {
bgp_path_info_set_flag(
dest, pi,
BGP_PATH_ATTR_CHANGED);
match++; match++;
}
} }
if (aggregate->suppress_map_name
&& AGGREGATE_MED_VALID(aggregate)
&& aggr_suppress_map_test(bgp, aggregate, pi)) {
if (aggr_unsuppress_path(aggregate, pi))
match++;
}
aggregate->count--; aggregate->count--;
if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE) if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE)
@ -6800,7 +6924,11 @@ static void bgp_add_route_to_aggregate(struct bgp *bgp,
pinew, true); pinew, true);
if (aggregate->summary_only && AGGREGATE_MED_VALID(aggregate)) if (aggregate->summary_only && AGGREGATE_MED_VALID(aggregate))
(bgp_path_info_extra_get(pinew))->suppress++; aggr_suppress_path(aggregate, pinew);
if (aggregate->suppress_map_name && AGGREGATE_MED_VALID(aggregate)
&& aggr_suppress_map_test(bgp, aggregate, pinew))
aggr_suppress_path(aggregate, pinew);
switch (pinew->attr->origin) { switch (pinew->attr->origin) {
case BGP_ORIGIN_INCOMPLETE: case BGP_ORIGIN_INCOMPLETE:
@ -6896,19 +7024,17 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi,
if (pi->sub_type == BGP_ROUTE_AGGREGATE) if (pi->sub_type == BGP_ROUTE_AGGREGATE)
return; return;
if (aggregate->summary_only && pi->extra && pi->extra->suppress > 0 if (aggregate->summary_only && AGGREGATE_MED_VALID(aggregate))
&& AGGREGATE_MED_VALID(aggregate)) { if (aggr_unsuppress_path(aggregate, pi))
pi->extra->suppress--; match++;
if (pi->extra->suppress == 0) { if (aggregate->suppress_map_name && AGGREGATE_MED_VALID(aggregate)
bgp_path_info_set_flag(pi->net, pi, && aggr_suppress_map_test(bgp, aggregate, pi))
BGP_PATH_ATTR_CHANGED); if (aggr_unsuppress_path(aggregate, pi))
match++; match++;
}
}
/* /*
* This must be called after `summary` check to avoid * This must be called after `summary`, `suppress-map` check to avoid
* "unsuppressing" twice. * "unsuppressing" twice.
*/ */
if (aggregate->match_med) if (aggregate->match_med)
@ -7171,7 +7297,8 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str,
static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
safi_t safi, const char *rmap, safi_t safi, const char *rmap,
uint8_t summary_only, uint8_t as_set, uint8_t summary_only, uint8_t as_set,
uint8_t origin, bool match_med) uint8_t origin, bool match_med,
const char *suppress_map)
{ {
VTY_DECLVAR_CONTEXT(bgp, bgp); VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret; int ret;
@ -7180,6 +7307,12 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
struct bgp_aggregate *aggregate; struct bgp_aggregate *aggregate;
uint8_t as_set_new = as_set; uint8_t as_set_new = as_set;
if (suppress_map && summary_only) {
vty_out(vty,
"'summary-only' and 'suppress-map' can't be used at the same time\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Convert string to prefix structure. */ /* Convert string to prefix structure. */
ret = str2prefix(prefix_str, &p); ret = str2prefix(prefix_str, &p);
if (!ret) { if (!ret) {
@ -7251,6 +7384,18 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
aggregate->rmap.map = route_map_lookup_by_name(rmap); aggregate->rmap.map = route_map_lookup_by_name(rmap);
route_map_counter_increment(aggregate->rmap.map); route_map_counter_increment(aggregate->rmap.map);
} }
if (suppress_map) {
XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->suppress_map_name);
route_map_counter_decrement(aggregate->suppress_map);
aggregate->suppress_map_name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, suppress_map);
aggregate->suppress_map =
route_map_lookup_by_name(aggregate->suppress_map_name);
route_map_counter_increment(aggregate->suppress_map);
}
bgp_dest_set_bgp_aggregate_info(dest, aggregate); bgp_dest_set_bgp_aggregate_info(dest, aggregate);
/* Aggregate address insert into BGP routing table. */ /* Aggregate address insert into BGP routing table. */
@ -7266,6 +7411,7 @@ DEFPY(aggregate_addressv4, aggregate_addressv4_cmd,
"|route-map WORD$rmap_name" "|route-map WORD$rmap_name"
"|origin <egp|igp|incomplete>$origin_s" "|origin <egp|igp|incomplete>$origin_s"
"|matching-MED-only$match_med" "|matching-MED-only$match_med"
"|suppress-map WORD$suppress_map"
"}", "}",
NO_STR NO_STR
"Configure BGP aggregate entries\n" "Configure BGP aggregate entries\n"
@ -7278,7 +7424,9 @@ DEFPY(aggregate_addressv4, aggregate_addressv4_cmd,
"Remote EGP\n" "Remote EGP\n"
"Local IGP\n" "Local IGP\n"
"Unknown heritage\n" "Unknown heritage\n"
"Only aggregate routes with matching MED\n") "Only aggregate routes with matching MED\n"
"Suppress the selected more specific routes\n"
"Route map with the route selectors\n")
{ {
const char *prefix_s = NULL; const char *prefix_s = NULL;
safi_t safi = bgp_node_safi(vty); safi_t safi = bgp_node_safi(vty);
@ -7314,7 +7462,7 @@ DEFPY(aggregate_addressv4, aggregate_addressv4_cmd,
return bgp_aggregate_set(vty, prefix_s, AFI_IP, safi, rmap_name, return bgp_aggregate_set(vty, prefix_s, AFI_IP, safi, rmap_name,
summary_only != NULL, as_set, origin, summary_only != NULL, as_set, origin,
match_med != NULL); match_med != NULL, suppress_map);
} }
DEFPY(aggregate_addressv6, aggregate_addressv6_cmd, DEFPY(aggregate_addressv6, aggregate_addressv6_cmd,
@ -7324,6 +7472,7 @@ DEFPY(aggregate_addressv6, aggregate_addressv6_cmd,
"|route-map WORD$rmap_name" "|route-map WORD$rmap_name"
"|origin <egp|igp|incomplete>$origin_s" "|origin <egp|igp|incomplete>$origin_s"
"|matching-MED-only$match_med" "|matching-MED-only$match_med"
"|suppress-map WORD$suppress_map"
"}", "}",
NO_STR NO_STR
"Configure BGP aggregate entries\n" "Configure BGP aggregate entries\n"
@ -7336,7 +7485,9 @@ DEFPY(aggregate_addressv6, aggregate_addressv6_cmd,
"Remote EGP\n" "Remote EGP\n"
"Local IGP\n" "Local IGP\n"
"Unknown heritage\n" "Unknown heritage\n"
"Only aggregate routes with matching MED\n") "Only aggregate routes with matching MED\n"
"Suppress the selected more specific routes\n"
"Route map with the route selectors\n")
{ {
uint8_t origin = BGP_ORIGIN_UNSPECIFIED; uint8_t origin = BGP_ORIGIN_UNSPECIFIED;
int as_set = AGGREGATE_AS_UNSET; int as_set = AGGREGATE_AS_UNSET;
@ -7360,7 +7511,7 @@ DEFPY(aggregate_addressv6, aggregate_addressv6_cmd,
return bgp_aggregate_set(vty, prefix_str, AFI_IP6, SAFI_UNICAST, return bgp_aggregate_set(vty, prefix_str, AFI_IP6, SAFI_UNICAST,
rmap_name, summary_only != NULL, as_set, rmap_name, summary_only != NULL, as_set,
origin, match_med != NULL); origin, match_med != NULL, suppress_map);
} }
/* Redistribute route treatment. */ /* Redistribute route treatment. */
@ -7668,7 +7819,7 @@ static void route_vty_short_status_out(struct vty *vty,
if (CHECK_FLAG(path->flags, BGP_PATH_STALE)) if (CHECK_FLAG(path->flags, BGP_PATH_STALE))
json_object_boolean_true_add(json_path, "stale"); json_object_boolean_true_add(json_path, "stale");
if (path->extra && path->extra->suppress) if (path->extra && bgp_path_suppressed(path))
json_object_boolean_true_add(json_path, "suppressed"); json_object_boolean_true_add(json_path, "suppressed");
if (CHECK_FLAG(path->flags, BGP_PATH_VALID) if (CHECK_FLAG(path->flags, BGP_PATH_VALID)
@ -7705,7 +7856,7 @@ static void route_vty_short_status_out(struct vty *vty,
vty_out(vty, "R"); vty_out(vty, "R");
else if (CHECK_FLAG(path->flags, BGP_PATH_STALE)) else if (CHECK_FLAG(path->flags, BGP_PATH_STALE))
vty_out(vty, "S"); vty_out(vty, "S");
else if (path->extra && path->extra->suppress) else if (bgp_path_suppressed(path))
vty_out(vty, "s"); vty_out(vty, "s");
else if (CHECK_FLAG(path->flags, BGP_PATH_VALID) else if (CHECK_FLAG(path->flags, BGP_PATH_VALID)
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
@ -10433,7 +10584,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
count++; count++;
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
best = count; best = count;
if (pi->extra && pi->extra->suppress) if (bgp_path_suppressed(pi))
suppress = 1; suppress = 1;
if (pi->attr->community == NULL) if (pi->attr->community == NULL)
@ -13998,6 +14149,10 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
if (bgp_aggregate->match_med) if (bgp_aggregate->match_med)
vty_out(vty, " matching-MED-only"); vty_out(vty, " matching-MED-only");
if (bgp_aggregate->suppress_map_name)
vty_out(vty, " suppress-map %s",
bgp_aggregate->suppress_map_name);
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
} }

View File

@ -110,8 +110,8 @@ struct bgp_path_info_extra {
/* Pointer to dampening structure. */ /* Pointer to dampening structure. */
struct bgp_damp_info *damp_info; struct bgp_damp_info *damp_info;
/* This route is suppressed with aggregation. */ /** List of aggregations that suppress this path. */
int suppress; struct list *aggr_suppressors;
/* Nexthop reachability check. */ /* Nexthop reachability check. */
uint32_t igpmetric; uint32_t igpmetric;
@ -398,6 +398,11 @@ struct bgp_aggregate {
#define AGGREGATE_MED_VALID(aggregate) \ #define AGGREGATE_MED_VALID(aggregate) \
(((aggregate)->match_med && !(aggregate)->med_mismatched) \ (((aggregate)->match_med && !(aggregate)->med_mismatched) \
|| !(aggregate)->match_med) || !(aggregate)->match_med)
/** Suppress map route map name (`NULL` when disabled). */
char *suppress_map_name;
/** Suppress map route map pointer. */
struct route_map *suppress_map;
}; };
#define BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen) \ #define BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen) \
@ -710,4 +715,8 @@ extern bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
struct attr *attr, struct bgp_dest *dest); struct attr *attr, struct bgp_dest *dest);
extern int bgp_evpn_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, extern int bgp_evpn_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
struct bgp_path_info *exist, int *paths_eq); struct bgp_path_info *exist, int *paths_eq);
extern void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate,
struct bgp *bgp,
const struct prefix *p, afi_t afi,
safi_t safi, bool suppress);
#endif /* _QUAGGA_BGP_ROUTE_H */ #endif /* _QUAGGA_BGP_ROUTE_H */

View File

@ -3746,6 +3746,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
int route_update) int route_update)
{ {
int i; int i;
bool matched;
afi_t afi; afi_t afi;
safi_t safi; safi_t safi;
struct peer *peer; struct peer *peer;
@ -3845,16 +3846,35 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
if (!aggregate) if (!aggregate)
continue; continue;
if (!aggregate->rmap.name matched = false;
|| (strcmp(rmap_name, aggregate->rmap.name) != 0))
continue;
if (!aggregate->rmap.map) /* Update suppress map pointer. */
route_map_counter_increment(map); if (aggregate->suppress_map_name
&& strmatch(aggregate->suppress_map_name,
rmap_name)) {
if (aggregate->rmap.map == NULL)
route_map_counter_increment(map);
aggregate->rmap.map = map; aggregate->suppress_map = map;
if (route_update) { bgp_aggregate_toggle_suppressed(
aggregate, bgp, bgp_dest_get_prefix(bn),
afi, safi, false);
matched = true;
}
if (aggregate->rmap.name
&& strmatch(rmap_name, aggregate->rmap.name)) {
if (aggregate->rmap.map == NULL)
route_map_counter_increment(map);
aggregate->rmap.map = map;
matched = true;
}
if (matched && route_update) {
const struct prefix *bn_p = const struct prefix *bn_p =
bgp_dest_get_prefix(bn); bgp_dest_get_prefix(bn);

View File

@ -1005,6 +1005,12 @@ Route Aggregation-IPv4 Address Family
Configure the aggregated address to only be created when the routes MED Configure the aggregated address to only be created when the routes MED
match, otherwise no aggregated route will be created. match, otherwise no aggregated route will be created.
.. index:: aggregate-address A.B.C.D/M suppress-map NAME
.. clicmd:: aggregate-address A.B.C.D/M suppress-map NAME
Similar to `summary-only`, but will only suppress more specific routes that
are matched by the selected route-map.
.. index:: no aggregate-address A.B.C.D/M .. index:: no aggregate-address A.B.C.D/M
.. clicmd:: no aggregate-address A.B.C.D/M .. clicmd:: no aggregate-address A.B.C.D/M
@ -1063,6 +1069,11 @@ Route Aggregation-IPv6 Address Family
Configure the aggregated address to only be created when the routes MED Configure the aggregated address to only be created when the routes MED
match, otherwise no aggregated route will be created. match, otherwise no aggregated route will be created.
.. index:: aggregate-address X:X::X:X/M suppress-map NAME
.. clicmd:: aggregate-address X:X::X:X/M suppress-map NAME
Similar to `summary-only`, but will only suppress more specific routes that
are matched by the selected route-map.
.. index:: no aggregate-address X:X::X:X/M .. index:: no aggregate-address X:X::X:X/M
.. clicmd:: no aggregate-address X:X::X:X/M .. clicmd:: no aggregate-address X:X::X:X/M

View File

@ -13,5 +13,9 @@ neighbor 10.0.0.1 {
route 192.168.1.1/32 next-hop 10.0.0.2 med 10; route 192.168.1.1/32 next-hop 10.0.0.2 med 10;
route 192.168.1.2/32 next-hop 10.0.0.2 med 10; route 192.168.1.2/32 next-hop 10.0.0.2 med 10;
route 192.168.1.3/32 next-hop 10.0.0.2 med 20; route 192.168.1.3/32 next-hop 10.0.0.2 med 20;
route 192.168.2.1/32 next-hop 10.0.0.2;
route 192.168.2.2/32 next-hop 10.0.0.2;
route 192.168.2.3/32 next-hop 10.0.0.2;
} }
} }

View File

@ -1,3 +1,20 @@
debug bgp updates
!
access-list acl-sup-one seq 5 permit 192.168.2.1/32
access-list acl-sup-one seq 10 deny any
!
access-list acl-sup-two seq 5 permit 192.168.2.2/32
access-list acl-sup-two seq 10 deny any
!
access-list acl-sup-three seq 5 permit 192.168.2.3/32
access-list acl-sup-three seq 10 deny any
!
route-map rm-sup-one permit 10
match ip address acl-sup-one
!
route-map rm-sup-two permit 10
match ip address acl-sup-two
!
router bgp 65000 router bgp 65000
no bgp ebgp-requires-policy no bgp ebgp-requires-policy
neighbor 10.0.0.2 remote-as 65001 neighbor 10.0.0.2 remote-as 65001
@ -8,5 +25,6 @@ router bgp 65000
redistribute connected redistribute connected
aggregate-address 192.168.0.0/24 matching-MED-only aggregate-address 192.168.0.0/24 matching-MED-only
aggregate-address 192.168.1.0/24 matching-MED-only aggregate-address 192.168.1.0/24 matching-MED-only
aggregate-address 192.168.2.0/24 suppress-map rm-sup-one
exit-address-family exit-address-family
! !

View File

@ -85,6 +85,20 @@ def teardown_module(mod):
tgen.stop_topology() tgen.stop_topology()
def expect_route(router_name, routes_expected):
"Helper function to avoid repeated code."
tgen = get_topogen()
test_func = functools.partial(
topotest.router_json_cmp,
tgen.gears[router_name],
"show ip route json",
routes_expected,
)
_, result = topotest.run_and_expect(test_func, None, count=120, wait=1)
assertmsg = '"{}" BGP convergence failure'.format(router_name)
assert result is None, assertmsg
def test_expect_convergence(): def test_expect_convergence():
"Test that BGP protocol converged." "Test that BGP protocol converged."
@ -185,6 +199,79 @@ aggregate-address 192.168.1.0/24 matching-MED-only summary-only
assert result is None, assertmsg assert result is None, assertmsg
def test_bgp_aggregate_address_suppress_map():
"Test that the command suppress-map works."
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
expect_route('r2', {
"192.168.2.0/24": [{"protocol": "bgp"}],
"192.168.2.1/32": None,
"192.168.2.2/32": [{"protocol": "bgp"}],
"192.168.2.3/32": [{"protocol": "bgp"}],
})
# Change route map and test again.
tgen.gears["r1"].vtysh_multicmd(
"""
configure terminal
router bgp 65000
address-family ipv4 unicast
no aggregate-address 192.168.2.0/24 suppress-map rm-sup-one
aggregate-address 192.168.2.0/24 suppress-map rm-sup-two
"""
)
expect_route('r2', {
"192.168.2.0/24": [{"protocol": "bgp"}],
"192.168.2.1/32": [{"protocol": "bgp"}],
"192.168.2.2/32": None,
"192.168.2.3/32": [{"protocol": "bgp"}],
})
def test_bgp_aggregate_address_suppress_map_update_route_map():
"Test that the suppress-map late route map creation works."
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
tgen.gears["r1"].vtysh_multicmd(
"""
configure terminal
router bgp 65000
address-family ipv4 unicast
no aggregate-address 192.168.2.0/24 suppress-map rm-sup-two
aggregate-address 192.168.2.0/24 suppress-map rm-sup-three
"""
)
expect_route('r2', {
"192.168.2.0/24": [{"protocol": "bgp"}],
"192.168.2.1/32": [{"protocol": "bgp"}],
"192.168.2.2/32": [{"protocol": "bgp"}],
"192.168.2.3/32": [{"protocol": "bgp"}],
})
# Create missing route map and test again.
tgen.gears["r1"].vtysh_multicmd(
"""
configure terminal
route-map rm-sup-three permit 10
match ip address acl-sup-three
"""
)
expect_route('r2', {
"192.168.2.0/24": [{"protocol": "bgp"}],
"192.168.2.1/32": [{"protocol": "bgp"}],
"192.168.2.2/32": [{"protocol": "bgp"}],
"192.168.2.3/32": None,
})
def test_memory_leak(): def test_memory_leak():
"Run the memory leak test and report results." "Run the memory leak test and report results."
tgen = get_topogen() tgen = get_topogen()