]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Route export: rejected by filter bitmap
authorMaria Matejka <mq@ucw.cz>
Mon, 9 Mar 2020 14:31:10 +0000 (15:31 +0100)
committerMaria Matejka <mq@ucw.cz>
Tue, 9 Nov 2021 18:20:41 +0000 (19:20 +0100)
If a route has been rejected by filter, store that information
to avoid repeated export filter runs on rejected routes.

nest/proto.c
nest/protocol.h
nest/rt-table.c

index 631e4b60b0a0e2a71c6a844cf8431f72530991b6..c7e2520924924ef41bd67427bff0fbb03d695e9f 100644 (file)
@@ -463,6 +463,7 @@ channel_stop_export(struct channel *c)
   c->export_state = ES_DOWN;
   c->export_stats.routes = 0;
   bmap_reset(&c->export_map, 1024);
+  bmap_reset(&c->export_reject_map, 1024);
 }
 
 
@@ -551,6 +552,7 @@ channel_do_start(struct channel *c)
   c->feed_event = ev_new_init(c->proto->pool, channel_feed_loop, c);
 
   bmap_init(&c->export_map, c->proto->pool, 1024);
+  bmap_init(&c->export_reject_map, c->proto->pool, 1024);
   memset(&c->export_stats, 0, sizeof(struct export_stats));
   memset(&c->import_stats, 0, sizeof(struct import_stats));
 
@@ -585,6 +587,7 @@ channel_do_flush(struct channel *c)
 
   /* This have to be done in here, as channel pool is freed before channel_do_down() */
   bmap_free(&c->export_map);
+  bmap_free(&c->export_reject_map);
   c->in_table = NULL;
   c->reload_event = NULL;
   c->out_table = NULL;
index 9be8e531feafcac8ae14b5284a891aaadcbb47f8..4c87c72d5b16a7504289cf989338770762f4970e 100644 (file)
@@ -511,7 +511,8 @@ struct channel {
   struct rtable *table;
   const struct filter *in_filter;      /* Input filter */
   const struct filter *out_filter;     /* Output filter */
-  struct bmap export_map;              /* Keeps track which routes passed export filter */
+  struct bmap export_map;              /* Keeps track which routes were really exported */
+  struct bmap export_reject_map;       /* Keeps track which routes were rejected by export filter */
   struct channel_limit rx_limit;       /* Receive limit (for in_keep_filtered) */
   struct channel_limit in_limit;       /* Input limit */
   struct channel_limit out_limit;      /* Output limit */
index 0b6351e963beccd7060d9b05def90a9ecd796817..280551aaf59d2f0cb942eaa9d00cee696ec3034f 100644 (file)
@@ -376,18 +376,22 @@ export_filter_(struct channel *c, rte *rt, linpool *pool, int silent)
   struct proto *p = c->proto;
   const struct filter *filter = c->out_filter;
   struct export_stats *stats = &c->export_stats;
-  int v;
 
-  v = p->preexport ? p->preexport(c, rt) : 0;
+  /* Do nothing if we have already rejected the route */
+  if (silent && bmap_test(&c->export_reject_map, rt->id))
+    goto reject_noset;
+
+  int v = p->preexport ? p->preexport(c, rt) : 0;
   if (v < 0)
     {
       if (silent)
-       goto reject;
+       goto reject_noset;
 
       stats->updates_rejected++;
       if (v == RIC_REJECT)
        rte_trace_out(D_FILTERS, c, rt, "rejected by protocol");
-      goto reject;
+      goto reject_noset;
+
     }
   if (v > 0)
     {
@@ -410,9 +414,16 @@ export_filter_(struct channel *c, rte *rt, linpool *pool, int silent)
     }
 
  accept:
+  /* We have accepted the route */
+  bmap_clear(&c->export_reject_map, rt->id);
   return rt;
 
  reject:
+  /* We have rejected the route by filter */
+  bmap_set(&c->export_reject_map, rt->id);
+
+reject_noset:
+  /* Invalidate the route */
   /* Discard temporary rte */
   return NULL;
 }
@@ -565,8 +576,14 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
   {
     /* Feed or old_best changed -> find first accepted by filters */
     for (struct rte_storage *r = net->routes; r && rte_is_valid(&r->rte); r = r->next)
+    {
+      /* Already rejected before */
+      if (!refeed && bmap_test(&c->export_reject_map, r->rte.id))
+       continue;
+
       if (new_best = export_filter(c, ((nb0 = r->rte), &nb0), 0))
        break;
+    }
   }
   else
   {
@@ -677,7 +694,6 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
 /**
  * rte_announce - announce a routing table change
  * @tab: table the route has been added to
- * @type: type of route announcement (RA_UNDEF or RA_ANY)
  * @net: network in question
  * @new: the new or changed route
  * @old: the previous route replaced by the new one
@@ -693,13 +709,6 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
  * and @new_best and @old_best describes best routes. Other routes are not
  * affected, but in sorted table the order of other routes might change.
  *
- * Second, There is a bulk change of multiple routes in @net, with shared best
- * route selection. In such case separate route changes are described using
- * @type of %RA_ANY, with @new and @old specifying the changed route, while
- * @new_best and @old_best are NULL. After that, another notification is done
- * where @new_best and @old_best are filled (may be the same), but @new and @old
- * are NULL.
- *
  * The function announces the change to all associated channels. For each
  * channel, an appropriate preprocessing is done according to channel &ra_mode.
  * For example, %RA_OPTIMAL channels receive just changes of best routes.
@@ -714,7 +723,7 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
  * done outside of scope of rte_announce().
  */
 static void
-rte_announce(rtable *tab, uint type, net *net, struct rte_storage *new, struct rte_storage *old,
+rte_announce(rtable *tab, net *net, struct rte_storage *new, struct rte_storage *old,
             struct rte_storage *new_best, struct rte_storage *old_best)
 {
   if (!new || !rte_is_valid(&new->rte))
@@ -751,9 +760,6 @@ rte_announce(rtable *tab, uint type, net *net, struct rte_storage *new, struct r
     if (c->export_state == ES_DOWN)
       continue;
 
-    if (type && (type != c->ra_mode))
-      continue;
-
     rte n0;
     switch (c->ra_mode)
     {
@@ -775,6 +781,11 @@ rte_announce(rtable *tab, uint type, net *net, struct rte_storage *new, struct r
       rt_notify_merged(c, net, RTE_OR_NULL(new), RTE_OR_NULL(old), RTE_OR_NULL(new_best), RTE_OR_NULL(old_best), 0);
       break;
     }
+
+    /* Drop the old stored rejection if applicable.
+     * new->id == old->id happens when updating hostentries. */
+    if (old && (!new || (new->rte.id != old->rte.id)))
+      bmap_clear(&c->export_reject_map, old->rte.id);
   }
 }
 
@@ -1083,7 +1094,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
     }
 
   /* Propagate the route change */
-  rte_announce(table, RA_UNDEF, net, new_stored, old_stored,
+  rte_announce(table, net, new_stored, old_stored,
       net->routes, old_best_stored);
 
   if (!net->routes &&
@@ -1208,11 +1219,11 @@ rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
 /* Independent call to rte_announce(), used from next hop
    recalculation, outside of rte_update(). new must be non-NULL */
 static inline void
-rte_announce_i(rtable *tab, uint type, net *net, struct rte_storage *new, struct rte_storage *old,
+rte_announce_i(rtable *tab, net *net, struct rte_storage *new, struct rte_storage *old,
               struct rte_storage *new_best, struct rte_storage *old_best)
 {
   rte_update_lock();
-  rte_announce(tab, type, net, new, old, new_best, old_best);
+  rte_announce(tab, net, new, old, new_best, old_best);
   rte_update_unlock();
 }
 
@@ -1938,7 +1949,7 @@ rt_next_hop_update_net(rtable *tab, net *n)
     _Bool nb = (new == updates[i].new), ob = (old_best == updates[i].old);
     const char *best_indicator[2][2] = { { "updated", "updated [-best]" }, { "updated [+best]", "updated [best]" } };
     rte_trace_in(D_ROUTES, new->rte.sender, &updates[i].new->rte, best_indicator[nb][ob]);
-    rte_announce_i(tab, RA_UNDEF, n, updates[i].new, updates[i].old, new, old_best);
+    rte_announce_i(tab, n, updates[i].new, updates[i].old, new, old_best);
   }
 
   for (int i=0; i<count; i++)