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,
}
/* Aggregate-address suppress check. */
- if (pi->extra && pi->extra->suppress)
- if (!UNSUPPRESS_MAP_NAME(filter)) {
- return false;
- }
+ if (bgp_path_suppressed(pi) && !UNSUPPRESS_MAP_NAME(filter))
+ return false;
/*
* If we are doing VRF 2 VRF leaking via the import
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};
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
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) {
+ 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) {
+ 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,
* 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;
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);
- toggle_suppression = true;
+ 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)
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
*/
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);
- match++;
+ if (aggr_suppress_path(aggregate, pi))
+ match++;
}
/*
if (aggregate->suppress_map_name
&& AGGREGATE_MED_VALID(aggregate)
&& aggr_suppress_map_test(bgp, aggregate, pi)) {
- (bgp_path_info_extra_get(pi))->suppress++;
- bgp_path_info_set_flag(dest, pi,
- BGP_PATH_ATTR_CHANGED);
- match++;
+ if (aggr_suppress_path(aggregate, pi))
+ match++;
}
aggregate->count++;
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)) {
- /*
- * We can only get here if we were suppressed
- * before: it is a failure to not have
- * `pi->extra`.
- */
- assert(pi->extra != NULL);
- /*
- * If we suppressed before then the value must
- * be greater than zero.
- */
- assert(pi->extra->suppress > 0);
-
- pi->extra->suppress--;
- /* Unsuppress route if we reached `0`. */
- if (pi->extra->suppress == 0) {
- bgp_path_info_set_flag(
- dest, pi,
- BGP_PATH_ATTR_CHANGED);
+ if (aggr_unsuppress_path(aggregate, pi))
match++;
- }
}
aggregate->count--;
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))
- (bgp_path_info_extra_get(pinew))->suppress++;
+ aggr_suppress_path(aggregate, pinew);
switch (pinew->attr->origin) {
case BGP_ORIGIN_INCOMPLETE:
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)) {
- /*
- * We can only get here if we were suppressed before:
- * it is a failure to not have `pi->extra`.
- */
- assert(pi->extra != NULL);
- /*
- * If we suppressed before then the value must be
- * greater than zero.
- */
- assert(pi->extra->suppress > 0);
-
- pi->extra->suppress--;
- /* Unsuppress when we reached `0`. */
- if (pi->extra->suppress == 0) {
- bgp_path_info_set_flag(pi->net, pi,
- BGP_PATH_ATTR_CHANGED);
+ && aggr_suppress_map_test(bgp, aggregate, pi))
+ if (aggr_unsuppress_path(aggregate, pi))
match++;
- }
- }
/*
* This must be called after `summary`, `suppress-map` check to avoid
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)
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))
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)