mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-15 01:37:53 +00:00
Merge pull request #7345 from opensourcerouting/bgp-aggr-suppress
bgpd: aggregate-address suppress-map
This commit is contained in:
commit
90a65457d1
265
bgpd/bgp_route.c
265
bgpd/bgp_route.c
@ -115,6 +115,14 @@ DEFINE_HOOK(bgp_process,
|
||||
struct peer *peer, bool 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,
|
||||
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. */
|
||||
if (pi->extra && pi->extra->suppress)
|
||||
if (!UNSUPPRESS_MAP_NAME(filter)) {
|
||||
if (bgp_path_suppressed(pi) && !UNSUPPRESS_MAP_NAME(filter))
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* 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_extra dummy_rmap_path_extra = {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);
|
||||
|
||||
if (pi->extra && pi->extra->suppress)
|
||||
if (bgp_path_suppressed(pi))
|
||||
ret = route_map_apply(UNSUPPRESS_MAP(filter), p,
|
||||
RMAP_BGP, &rmap_path);
|
||||
else
|
||||
@ -6176,11 +6182,119 @@ static struct bgp_aggregate *bgp_aggregate_new(void)
|
||||
|
||||
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);
|
||||
route_map_counter_decrement(aggregate->rmap.map);
|
||||
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,
|
||||
struct aspath *aspath,
|
||||
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
|
||||
* configuration.
|
||||
*/
|
||||
static void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate,
|
||||
struct bgp *bgp,
|
||||
const struct prefix *p, afi_t afi,
|
||||
safi_t safi, bool suppress)
|
||||
void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate,
|
||||
struct bgp *bgp, const struct prefix *p,
|
||||
afi_t afi, safi_t safi, bool suppress)
|
||||
{
|
||||
struct bgp_table *table = bgp->rib[afi][safi];
|
||||
struct bgp_path_info_extra *pie;
|
||||
const struct prefix *dest_p;
|
||||
struct bgp_dest *dest, *top;
|
||||
struct bgp_path_info *pi;
|
||||
@ -6402,33 +6514,18 @@ static void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate,
|
||||
if (pi->sub_type == BGP_ROUTE_AGGREGATE)
|
||||
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. */
|
||||
if (suppress) {
|
||||
pie = bgp_path_info_extra_get(pi);
|
||||
/* Suppress route if not suppressed already. */
|
||||
pie->suppress++;
|
||||
bgp_path_info_set_flag(dest, pi,
|
||||
BGP_PATH_ATTR_CHANGED);
|
||||
if (aggr_suppress_path(aggregate, pi))
|
||||
toggle_suppression = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
pie = pi->extra;
|
||||
assert(pie->suppress > 0);
|
||||
pie->suppress--;
|
||||
/* Install route if there is no more suppression. */
|
||||
if (pie->suppress == 0) {
|
||||
bgp_path_info_set_flag(dest, pi,
|
||||
BGP_PATH_ATTR_CHANGED);
|
||||
if (aggr_unsuppress_path(aggregate, pi))
|
||||
toggle_suppression = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (toggle_suppression)
|
||||
bgp_process(bgp, dest, afi, safi);
|
||||
@ -6514,6 +6611,17 @@ void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
|
||||
if (aggregate->match_med)
|
||||
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
|
||||
aggregated has ORIGIN with the value INCOMPLETE, then the
|
||||
aggregated route must have the ORIGIN attribute with the value
|
||||
@ -6558,9 +6666,23 @@ void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
|
||||
*/
|
||||
if (aggregate->summary_only
|
||||
&& AGGREGATE_MED_VALID(aggregate)) {
|
||||
(bgp_path_info_extra_get(pi))->suppress++;
|
||||
bgp_path_info_set_flag(dest, pi,
|
||||
BGP_PATH_ATTR_CHANGED);
|
||||
if (aggr_suppress_path(aggregate, pi))
|
||||
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++;
|
||||
}
|
||||
|
||||
@ -6701,15 +6823,17 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi,
|
||||
|
||||
if (aggregate->summary_only && pi->extra
|
||||
&& AGGREGATE_MED_VALID(aggregate)) {
|
||||
pi->extra->suppress--;
|
||||
|
||||
if (pi->extra->suppress == 0) {
|
||||
bgp_path_info_set_flag(
|
||||
dest, pi,
|
||||
BGP_PATH_ATTR_CHANGED);
|
||||
if (aggr_unsuppress_path(aggregate, pi))
|
||||
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--;
|
||||
|
||||
if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE)
|
||||
@ -6800,7 +6924,11 @@ static void bgp_add_route_to_aggregate(struct bgp *bgp,
|
||||
pinew, true);
|
||||
|
||||
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) {
|
||||
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)
|
||||
return;
|
||||
|
||||
if (aggregate->summary_only && pi->extra && pi->extra->suppress > 0
|
||||
&& AGGREGATE_MED_VALID(aggregate)) {
|
||||
pi->extra->suppress--;
|
||||
|
||||
if (pi->extra->suppress == 0) {
|
||||
bgp_path_info_set_flag(pi->net, pi,
|
||||
BGP_PATH_ATTR_CHANGED);
|
||||
if (aggregate->summary_only && AGGREGATE_MED_VALID(aggregate))
|
||||
if (aggr_unsuppress_path(aggregate, pi))
|
||||
match++;
|
||||
|
||||
if (aggregate->suppress_map_name && AGGREGATE_MED_VALID(aggregate)
|
||||
&& aggr_suppress_map_test(bgp, aggregate, pi))
|
||||
if (aggr_unsuppress_path(aggregate, pi))
|
||||
match++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This must be called after `summary` check to avoid
|
||||
* This must be called after `summary`, `suppress-map` check to avoid
|
||||
* "unsuppressing" twice.
|
||||
*/
|
||||
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,
|
||||
safi_t safi, const char *rmap,
|
||||
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);
|
||||
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;
|
||||
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. */
|
||||
ret = str2prefix(prefix_str, &p);
|
||||
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);
|
||||
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);
|
||||
|
||||
/* Aggregate address insert into BGP routing table. */
|
||||
@ -7266,6 +7411,7 @@ DEFPY(aggregate_addressv4, aggregate_addressv4_cmd,
|
||||
"|route-map WORD$rmap_name"
|
||||
"|origin <egp|igp|incomplete>$origin_s"
|
||||
"|matching-MED-only$match_med"
|
||||
"|suppress-map WORD$suppress_map"
|
||||
"}",
|
||||
NO_STR
|
||||
"Configure BGP aggregate entries\n"
|
||||
@ -7278,7 +7424,9 @@ DEFPY(aggregate_addressv4, aggregate_addressv4_cmd,
|
||||
"Remote EGP\n"
|
||||
"Local IGP\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;
|
||||
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,
|
||||
summary_only != NULL, as_set, origin,
|
||||
match_med != NULL);
|
||||
match_med != NULL, suppress_map);
|
||||
}
|
||||
|
||||
DEFPY(aggregate_addressv6, aggregate_addressv6_cmd,
|
||||
@ -7324,6 +7472,7 @@ DEFPY(aggregate_addressv6, aggregate_addressv6_cmd,
|
||||
"|route-map WORD$rmap_name"
|
||||
"|origin <egp|igp|incomplete>$origin_s"
|
||||
"|matching-MED-only$match_med"
|
||||
"|suppress-map WORD$suppress_map"
|
||||
"}",
|
||||
NO_STR
|
||||
"Configure BGP aggregate entries\n"
|
||||
@ -7336,7 +7485,9 @@ DEFPY(aggregate_addressv6, aggregate_addressv6_cmd,
|
||||
"Remote EGP\n"
|
||||
"Local IGP\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;
|
||||
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,
|
||||
rmap_name, summary_only != NULL, as_set,
|
||||
origin, match_med != NULL);
|
||||
origin, match_med != NULL, suppress_map);
|
||||
}
|
||||
|
||||
/* 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))
|
||||
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");
|
||||
|
||||
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");
|
||||
else if (CHECK_FLAG(path->flags, BGP_PATH_STALE))
|
||||
vty_out(vty, "S");
|
||||
else if (path->extra && path->extra->suppress)
|
||||
else if (bgp_path_suppressed(path))
|
||||
vty_out(vty, "s");
|
||||
else if (CHECK_FLAG(path->flags, BGP_PATH_VALID)
|
||||
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
|
||||
@ -10433,7 +10584,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
|
||||
count++;
|
||||
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
|
||||
best = count;
|
||||
if (pi->extra && pi->extra->suppress)
|
||||
if (bgp_path_suppressed(pi))
|
||||
suppress = 1;
|
||||
|
||||
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)
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
@ -110,8 +110,8 @@ struct bgp_path_info_extra {
|
||||
/* Pointer to dampening structure. */
|
||||
struct bgp_damp_info *damp_info;
|
||||
|
||||
/* This route is suppressed with aggregation. */
|
||||
int suppress;
|
||||
/** List of aggregations that suppress this path. */
|
||||
struct list *aggr_suppressors;
|
||||
|
||||
/* Nexthop reachability check. */
|
||||
uint32_t igpmetric;
|
||||
@ -398,6 +398,11 @@ struct bgp_aggregate {
|
||||
#define AGGREGATE_MED_VALID(aggregate) \
|
||||
(((aggregate)->match_med && !(aggregate)->med_mismatched) \
|
||||
|| !(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) \
|
||||
@ -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);
|
||||
extern int bgp_evpn_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
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 */
|
||||
|
@ -3746,6 +3746,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
|
||||
int route_update)
|
||||
{
|
||||
int i;
|
||||
bool matched;
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
struct peer *peer;
|
||||
@ -3845,16 +3846,35 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
|
||||
if (!aggregate)
|
||||
continue;
|
||||
|
||||
if (!aggregate->rmap.name
|
||||
|| (strcmp(rmap_name, aggregate->rmap.name) != 0))
|
||||
continue;
|
||||
matched = false;
|
||||
|
||||
if (!aggregate->rmap.map)
|
||||
/* Update suppress map pointer. */
|
||||
if (aggregate->suppress_map_name
|
||||
&& strmatch(aggregate->suppress_map_name,
|
||||
rmap_name)) {
|
||||
if (aggregate->rmap.map == NULL)
|
||||
route_map_counter_increment(map);
|
||||
|
||||
aggregate->suppress_map = map;
|
||||
|
||||
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;
|
||||
|
||||
if (route_update) {
|
||||
matched = true;
|
||||
}
|
||||
|
||||
if (matched && route_update) {
|
||||
const struct prefix *bn_p =
|
||||
bgp_dest_get_prefix(bn);
|
||||
|
||||
|
@ -1005,6 +1005,12 @@ Route Aggregation-IPv4 Address Family
|
||||
Configure the aggregated address to only be created when the routes MED
|
||||
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
|
||||
.. 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
|
||||
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
|
||||
.. clicmd:: no aggregate-address X:X::X:X/M
|
||||
|
@ -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.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.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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
no bgp ebgp-requires-policy
|
||||
neighbor 10.0.0.2 remote-as 65001
|
||||
@ -8,5 +25,6 @@ router bgp 65000
|
||||
redistribute connected
|
||||
aggregate-address 192.168.0.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
|
||||
!
|
||||
|
@ -85,6 +85,20 @@ def teardown_module(mod):
|
||||
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():
|
||||
"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
|
||||
|
||||
|
||||
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():
|
||||
"Run the memory leak test and report results."
|
||||
tgen = get_topogen()
|
||||
|
Loading…
Reference in New Issue
Block a user