]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Routing table core changes to support full route filtering:
authorMartin Mares <mj@ucw.cz>
Mon, 5 Apr 1999 20:25:03 +0000 (20:25 +0000)
committerMartin Mares <mj@ucw.cz>
Mon, 5 Apr 1999 20:25:03 +0000 (20:25 +0000)
o  Introduced rte_cow() which should be used for copying on write the
   rte's in filters. Each rte now carries a flag saying whether it's
   a real route (possessing table linkage and other insignia) or a local
   copy. This function can be expected to be fast since its fast-path
   is inlined.
o  Introduced rte_update_pool which is a linear memory pool used for
   all temporary data during rte_update. You should not reference it directly
   -- instead use a pool pointer passed to all related functions.
o  Split rte_update to three functions:

rte_update The front end: handles all checking, inbound
filtering and calls rte_recalculate() for the
final version of the route.
rte_recalculate Update the table according to already filtered route.
rte_announce Announce routing table changes to all protocols,
passing them through export filters and so on.

   The interface has _not_ changed -- still call rte_update() and it will
   do the rest for you automagically.
o  Use new filtering semantics to be explained in a separate mail.

nest/route.h
nest/rt-table.c

index 5fcae2bd3bc4de2a7f290b456b82abf34513fe7d..ebe10f1f4a759d56fd3a58ed10cc06dad265dc19 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     BIRD Internet Routing Daemon -- Routing Table
  *
- *     (c) 1998 Martin Mares <mj@ucw.cz>
+ *     (c) 1998--1999 Martin Mares <mj@ucw.cz>
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
@@ -150,6 +150,8 @@ typedef struct rte {
   } u;
 } rte;
 
+#define REF_COW 1                      /* Copy this rte on write */
+
 extern rtable master_table;
 
 void rt_init(void);
@@ -162,6 +164,8 @@ void rte_update(net *net, struct proto *p, rte *new);
 void rte_discard(rte *old);
 void rte_dump(rte *);
 void rte_free(rte *);
+rte *rte_do_cow(rte *);
+static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r) : r; }
 void rt_dump(rtable *);
 void rt_dump_all(void);
 void rt_feed_baby(struct proto *p);
index 8a5c5937ddf034a2751f246d079b607d7d34e66d..47b4bb72eb312aed21d1b5c4b95a084577c07ed8 100644 (file)
@@ -19,6 +19,7 @@
 
 rtable master_table;
 static slab *rte_slab;
+static linpool *rte_update_pool;
 
 #define RT_GC_MIN_TIME 5               /* FIXME: Make configurable */
 #define RT_GC_MIN_COUNT 100
@@ -95,6 +96,17 @@ rte_get_temp(rta *a)
   return e;
 }
 
+rte *
+rte_do_cow(rte *r)
+{
+  rte *e = sl_alloc(rte_slab);
+
+  memcpy(e, r, sizeof(rte));
+  e->attrs = rta_clone(r->attrs);
+  e->flags = 0;
+  return e;
+}
+
 static int                             /* Actually better or at least as good as */
 rte_better(rte *new, rte *old)
 {
@@ -114,21 +126,42 @@ rte_better(rte *new, rte *old)
 }
 
 static inline void
-do_rte_announce(struct proto *p, net *net, rte *new, rte *old)
+do_rte_announce(struct proto *p, net *net, rte *new, rte *old, ea_list *tmpa)
 {
-  if (p->out_filter)
+  rte *new0 = new;
+  rte *old0 = old;
+  if (new)
     {
-      if (old && f_run(p->out_filter, old, NULL) != F_ACCEPT)
-       old = NULL;
-      if (new && f_run(p->out_filter, new, NULL) != F_ACCEPT)
+      int ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0;
+      if (ok < 0 ||
+         (!ok && (p->out_filter == FILTER_REJECT ||
+                  p->out_filter && f_run(p->out_filter, &new, &tmpa, rte_update_pool) > F_MODIFY)
+         )
+        )
        new = NULL;
     }
+  if (old && p->out_filter)
+    {
+      /* FIXME: Do we really need to filter old routes? */
+      if (p->out_filter == FILTER_REJECT)
+       old = NULL;
+      else
+       {
+         ea_list *tmpb = p->make_tmp_attrs ? p->make_tmp_attrs(old, rte_update_pool) : NULL;
+         if (f_run(p->out_filter, &old, &tmpb, rte_update_pool) > F_MODIFY)
+           old = NULL;
+       }
+    }
   if (new || old)
     p->rt_notify(p, net, new, old);
+  if (new && new != new0)      /* Discard temporary rte's */
+    rte_free(new);
+  if (old && old != old0)
+    rte_free(old);
 }
 
-void
-rte_announce(net *net, rte *new, rte *old)
+static void
+rte_announce(net *net, rte *new, rte *old, ea_list *tmpa)
 {
   struct proto *p;
 
@@ -136,7 +169,7 @@ rte_announce(net *net, rte *new, rte *old)
     {
       ASSERT(p->core_state == FS_HAPPY);
       if (p->rt_notify)
-       do_rte_announce(p, net, new, old);
+       do_rte_announce(p, net, new, old, tmpa);
     }
 }
 
@@ -155,7 +188,12 @@ rt_feed_baby(struct proto *p)
          net *n = (net *) fn;
          rte *e;
          for(e=n->routes; e; e=e->next)
-           do_rte_announce(p, n, e, NULL);
+           {
+             struct proto *q = e->attrs->proto;
+             ea_list *tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL;
+             do_rte_announce(p, n, e, NULL, tmpa);
+             lp_flush(rte_update_pool);
+           }
        }
       FIB_WALK_END;
       t = t->sibling;
@@ -209,24 +247,13 @@ rte_free_quick(rte *e)
   sl_free(rte_slab, e);
 }
 
-void
-rte_update(net *net, struct proto *p, rte *new)
+static void
+rte_recalculate(net *net, struct proto *p, rte *new, ea_list *tmpa)
 {
   rte *old_best = net->routes;
   rte *old = NULL;
   rte **k, *r, *s;
 
-  if (new)
-    {
-      if (!rte_validate(new) || p->in_filter && f_run(p->in_filter, new, NULL) != F_ACCEPT)
-       {
-         rte_free(new);
-         return;
-       }
-      if (!(new->attrs->aflags & RTAF_CACHED)) /* Need to copy attributes */
-       new->attrs = rta_lookup(new->attrs);
-    }
-
   k = &net->routes;                    /* Find and remove original route from the same protocol */
   while (old = *k)
     {
@@ -240,7 +267,7 @@ rte_update(net *net, struct proto *p, rte *new)
 
   if (new && rte_better(new, old_best))        /* It's a new optimal route => announce and relink it */
     {
-      rte_announce(net, new, old_best);
+      rte_announce(net, new, old_best, tmpa);
       new->next = net->routes;
       net->routes = new;
     }
@@ -252,7 +279,7 @@ rte_update(net *net, struct proto *p, rte *new)
          for(s=net->routes; s; s=s->next)
            if (rte_better(s, r))
              r = s;
-         rte_announce(net, r, old_best);
+         rte_announce(net, r, old_best, tmpa);
          if (r)                        /* Re-link the new optimal route */
            {
              k = &net->routes;
@@ -291,10 +318,60 @@ rte_update(net *net, struct proto *p, rte *new)
     }
 }
 
+static int rte_update_nest_cnt;                /* Nesting counter to allow recursive updates */
+
+static inline void
+rte_update_lock(void)
+{
+  rte_update_nest_cnt++;
+}
+
+static inline void
+rte_update_unlock(void)
+{
+  if (!--rte_update_nest_cnt)
+    lp_flush(rte_update_pool);
+}
+
+void
+rte_update(net *net, struct proto *p, rte *new)
+{
+  ea_list *tmpa = NULL;
+
+  rte_update_lock();
+  if (new)
+    {
+      if (!rte_validate(new) || p->in_filter == FILTER_REJECT)
+       goto drop;
+      if (p->make_tmp_attrs)
+       tmpa = p->make_tmp_attrs(new, rte_update_pool);
+      if (p->in_filter)
+       {
+         int fr = f_run(p->in_filter, &new, &tmpa, rte_update_pool);
+         if (fr > F_MODIFY)
+           goto drop;
+         if (fr == F_MODIFY && p->store_tmp_attrs)
+           p->store_tmp_attrs(new, tmpa);
+       }
+      if (!(new->attrs->aflags & RTAF_CACHED)) /* Need to copy attributes */
+       new->attrs = rta_lookup(new->attrs);
+      new->flags |= REF_COW;
+    }
+  rte_recalculate(net, p, new, tmpa);
+  rte_update_unlock();
+  return;
+
+drop:
+  rte_free(new);
+  rte_update_unlock();
+}
+
 void
 rte_discard(rte *old)                  /* Non-filtered route deletion, used during garbage collection */
 {
-  rte_update(old->net, old->attrs->proto, NULL);
+  rte_update_lock();
+  rte_recalculate(old->net, old->attrs->proto, NULL, NULL);
+  rte_update_unlock();
 }
 
 void
@@ -357,6 +434,7 @@ rt_init(void)
 {
   rta_init();
   rt_table_pool = rp_new(&root_pool, "Routing tables");
+  rte_update_pool = lp_new(rt_table_pool, 4080);
   rt_setup(rt_table_pool, &master_table, "master");
   rte_slab = sl_new(rt_table_pool, sizeof(rte));
   rt_last_gc = now;