]> 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>
Sat, 20 Mar 2021 22:24:12 +0000 (23:24 +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/route.h
nest/rt-table.c
proto/radv/radv.c

index 1c27e63812cacab19e53d5cae43b47d06c2b17dc..b3b048193f99d3dd9968cdb7bd4c46c7ea42e24d 100644 (file)
@@ -463,6 +463,7 @@ channel_stop_export(struct channel *c)
   c->export_state = ES_DOWN;
   c->stats.exp_routes = 0;
   bmap_reset(&c->export_map, 1024);
+  bmap_reset(&c->export_reject_map, 1024);
 }
 
 
@@ -550,6 +551,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->stats, 0, sizeof(struct proto_stats));
 
   channel_reset_limit(&c->rx_limit);
@@ -583,6 +585,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 7bc7d728f9421f8ea38eed36d24f92fcaa054376..ea063326c7cb5aa2b0b6b02f9ad514a6bb5d973f 100644 (file)
@@ -506,7 +506,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 3d4a01f01d6b65823a2977cd04d590371d0543d7..2759bc172c0288ad327273dc403679cf26e5457d 100644 (file)
@@ -337,7 +337,7 @@ static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) f
 void *net_route(rtable *tab, const net_addr *n);
 int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
 rte *rte_find(net *net, struct rte_src *src);
-int rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter);
+int rt_examine(struct channel *c, net_addr *a);
 rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent);
 void rt_refresh_begin(rtable *t, struct channel *c);
 void rt_refresh_end(rtable *t, struct channel *c);
index 5e5fa22bcaee26e32fb50fafa8474d958afbcf93..92160805634db087dd0c9660167ce57ec99ebfcb 100644 (file)
@@ -442,33 +442,36 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
   const struct filter *filter = c->out_filter;
   struct proto_stats *stats = &c->stats;
   rte *rt;
-  int v;
 
   rt = rt0;
   *rt_free = NULL;
 
-  v = p->preexport ? p->preexport(p, &rt, pool) : 0;
-  if (v < 0)
+  /* Do nothing if we have already rejected the route */
+  if (silent && bmap_test(&c->export_reject_map, rt0->id))
+    return NULL;
+
+  int pv = p->preexport ? p->preexport(p, &rt, pool) : 0;
+  if (pv < 0)
     {
       if (silent)
        goto reject;
 
       stats->exp_updates_rejected++;
-      if (v == RIC_REJECT)
+      if (pv == RIC_REJECT)
        rte_trace_out(D_FILTERS, c, rt, "rejected by protocol");
       goto reject;
     }
-  if (v > 0)
+  if (pv > 0)
     {
       if (!silent)
        rte_trace_out(D_FILTERS, c, rt, "forced accept by protocol");
       goto accept;
     }
 
-  v = filter && ((filter == FILTER_REJECT) ||
+  int fv = filter && ((filter == FILTER_REJECT) ||
                 (f_run(filter, &rt, pool,
                        (silent ? FF_SILENT : 0)) > F_ACCEPT));
-  if (v)
+  if (fv)
     {
       if (silent)
        goto reject;
@@ -479,11 +482,19 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
     }
 
  accept:
+  /* We have accepted the route */
+  bmap_clear(&c->export_reject_map, rt0->id);
+
+  /* Discard temporary rte */
   if (rt != rt0)
     *rt_free = rt;
   return rt;
 
  reject:
+  /* We have rejected the route by filter */
+  if (pv == 0)
+    bmap_set(&c->export_reject_map, rt0->id);
+
   /* Discard temporary rte */
   if (rt != rt0)
     rte_free(rt);
@@ -839,7 +850,16 @@ rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old,
       continue;
 
     if (type && (type != c->ra_mode))
+    {
+      /* If skipping other means of announcement,
+       * drop the rejection bit anyway
+       * as we won't get this route as old any more.
+       * This happens when updating hostentries. */
+      if (old)
+       bmap_clear(&c->export_reject_map, old->id);
+
       continue;
+    }
 
     struct rte_export_internal e = {
       .pub = {
@@ -890,6 +910,11 @@ next_channel:
     /* Discard temporary rte */
     if (e.rt_free)
       rte_free(e.rt_free);
+
+    /* Drop the old stored rejection if applicable.
+     * new->id == old->id happens when updating hostentries. */
+    if (old && (!new || (new->id != old->id)))
+      bmap_clear(&c->export_reject_map, old->id);
   }
 }
 
@@ -1402,22 +1427,26 @@ rte_modify(rte *old)
   rte_update_unlock();
 }
 
-/* Check rtable for best route to given net whether it would be exported do p */
+/* Check channel for best route to given net whether it would be exported */
 int
-rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter)
+rt_examine(struct channel *c, net_addr *a)
 {
-  net *n = net_find(t, a);
+  net *n = net_find(c->table, a);
   rte *rt = n ? n->routes : NULL;
 
   if (!rte_is_valid(rt))
     return 0;
 
+  if (bmap_test(&c->export_reject_map, rt->id))
+    return 0;
+
   rte_update_lock();
 
+  struct proto *p = c->proto;
   /* Rest is stripped down export_filter() */
   int v = p->preexport ? p->preexport(p, &rt, rte_update_pool) : 0;
   if (v == RIC_PROCESS)
-    v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT);
+    v = (f_run(c->out_filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT);
 
   /* Discard temporary rte */
   if (rt != n->routes)
index 042d37696494e81613d87078edd6148c6de9d435..2f95a0bbce76e612cf0dd18d6cf7127f79cb2731 100644 (file)
@@ -555,7 +555,7 @@ radv_check_active(struct radv_proto *p)
     return 1;
 
   struct channel *c = p->p.main_channel;
-  return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter);
+  return rt_examine(c, &cf->trigger);
 }
 
 static void