]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Changes pipes to transfer all routes between routing table, not just optimal routes.
authorOndrej Zajicek <santiago@crfreenet.org>
Sun, 31 May 2009 13:24:27 +0000 (15:24 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Sun, 31 May 2009 13:24:27 +0000 (15:24 +0200)
nest/proto-hooks.c
nest/protocol.h
nest/route.h
nest/rt-table.c
proto/bgp/bgp.c
proto/ospf/ospf.c
proto/pipe/pipe.c
proto/rip/rip.c
sysdep/unix/krt.c

index 82df5cb74ad464c05c83701e4997ef6ec72d6eef..9af6ef5f8cf4d3b7c454ac0f2c4e0af16f6d886d 100644 (file)
@@ -188,6 +188,8 @@ void ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
  * belonging to network @net being replaced by a new route @new with
  * extended attributes @attrs. Either @new or @old or both can be %NULL
  * if the corresponding route doesn't exist.
+ *
+ * FIXME documentation
  */
 void rt_notify(struct proto *p, net *net, rte *new, rte *old, ea_list *attrs)
 { DUMMY; }
index d681ae680d5517fccfc214611867d454bc6844e2..865b2b38776bd1066d7dcd8d65b4af4184f10cd8 100644 (file)
@@ -100,6 +100,7 @@ struct proto {
   unsigned debug;                      /* Debugging flags */
   unsigned preference;                 /* Default route preference */
   int min_scope;                       /* Minimal route scope accepted */
+  unsigned accept_ra_types;            /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */
   unsigned disabled;                   /* Manually disabled */
   unsigned proto_state;                        /* Protocol state machine (see below) */
   unsigned core_state;                 /* Core state machine (see below) */
index 43cfa9dd20dde2211fa0f5faaaa56c887a870a2e..e55ae1d102e87c11210e4352e1bc87ade64ad7d9 100644 (file)
@@ -146,6 +146,7 @@ typedef struct network {
 typedef struct rte {
   struct rte *next;
   net *net;                            /* Network this RTE belongs to */
+  struct proto *sender;                        /* Protocol instance that sent the route to the routing table */
   struct rta *attrs;                   /* Attributes of this route */
   byte flags;                          /* Flags (REF_...) */
   byte pflags;                         /* Protocol-specific flags */
@@ -178,6 +179,10 @@ typedef struct rte {
 
 #define REF_COW 1                      /* Copy this rte on write */
 
+/* Types of route announcement, also used as flags */
+#define RA_OPTIMAL 1                   /* Announcement of optimal route change */
+#define RA_ANY 2                       /* Announcement of any route change */
+
 struct config;
 
 void rt_init(void);
@@ -191,6 +196,7 @@ static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (ne
 rte *rte_find(net *net, struct proto *p);
 rte *rte_get_temp(struct rta *);
 void rte_update(rtable *tab, net *net, struct proto *p, rte *new);
+void rte_update2(rtable *tab, net *net, struct proto *p, struct proto *src, rte *new);
 void rte_discard(rtable *tab, rte *old);
 void rte_dump(rte *);
 void rte_free(rte *);
@@ -230,7 +236,7 @@ void rt_show(struct rt_show_data *);
 
 typedef struct rta {
   struct rta *next, **pprev;           /* Hash chain */
-  struct proto *proto;                 /* Protocol instance */
+  struct proto *proto;                 /* Protocol instance that originally created the route */
   unsigned uc;                         /* Use count */
   byte source;                         /* Route source (RTS_...) */
   byte scope;                          /* Route scope (SCOPE_... -- see ip.h) */
index b0781a33ec6f0773d5432baefb5cbd4122114d79..176e2deef826b20fcff84c43e30621f4e621eca6 100644 (file)
@@ -158,7 +158,7 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg)
 }
 
 static inline void
-do_rte_announce(struct announce_hook *a, net *net, rte *new, rte *old, ea_list *tmpa, int class)
+do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, ea_list *tmpa, int class)
 {
   struct proto *p = a->proto;
   rte *new0 = new;
@@ -234,14 +234,17 @@ do_rte_announce(struct announce_hook *a, net *net, rte *new, rte *old, ea_list *
 /**
  * rte_announce - announce a routing table change
  * @tab: table the route has been added to
+ * @type: type of route announcement (RA_OPTIMAL or RA_ANY)
  * @net: network in question
  * @new: the new route to be announced
- * @old: previous optimal route for the same network
+ * @old: the previous route for the same network
  * @tmpa: a list of temporary attributes belonging to the new route
  *
  * This function gets a routing table update and announces it
  * to all protocols connected to the same table by their announcement hooks.
  *
+ * previous optimal route for the same network FIXME
+ *
  * For each such protocol, we first call its import_control() hook which
  * performs basic checks on the route (each protocol has a right to veto
  * or force accept of the route before any filter is asked) and adds default
@@ -250,7 +253,7 @@ do_rte_announce(struct announce_hook *a, net *net, rte *new, rte *old, ea_list *
  * route, the rt_notify() hook of the protocol gets called.
  */
 static void
-rte_announce(rtable *tab, net *net, rte *new, rte *old, ea_list *tmpa)
+rte_announce(rtable *tab, int type, net *net, rte *new, rte *old, ea_list *tmpa)
 {
   struct announce_hook *a;
   int class = ipa_classify(net->n.prefix);
@@ -258,7 +261,8 @@ rte_announce(rtable *tab, net *net, rte *new, rte *old, ea_list *tmpa)
   WALK_LIST(a, tab->hooks)
     {
       ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING);
-      do_rte_announce(a, net, new, old, tmpa, class);
+      if (a->proto->accept_ra_types == type)
+       do_rte_announce(a, type, net, new, old, tmpa, class);
     }
 }
 
@@ -271,7 +275,7 @@ rte_validate(rte *e)
   if (ipa_nonzero(ipa_and(n->n.prefix, ipa_not(ipa_mkmask(n->n.pxlen)))))
     {
       log(L_BUG "Ignoring bogus prefix %I/%d received via %s",
-         n->n.prefix, n->n.pxlen, e->attrs->proto->name);
+         n->n.prefix, n->n.pxlen, e->sender->name);
       return 0;
     }
   if (n->n.pxlen)
@@ -290,14 +294,14 @@ rte_validate(rte *e)
                return 1;
            }
          log(L_WARN "Ignoring bogus route %I/%d received via %s",
-             n->n.prefix, n->n.pxlen, e->attrs->proto->name);
+             n->n.prefix, n->n.pxlen, e->sender->name);
          return 0;
        }
-      if ((c & IADDR_SCOPE_MASK) < e->attrs->proto->min_scope)
+      if ((c & IADDR_SCOPE_MASK) < e->sender->min_scope)
        {
          log(L_WARN "Ignoring %s scope route %I/%d received from %I via %s",
              ip_scope_text(c & IADDR_SCOPE_MASK),
-             n->n.prefix, n->n.pxlen, e->attrs->from, e->attrs->proto->name);
+             n->n.prefix, n->n.pxlen, e->attrs->from, e->sender->name);
          return 0;
        }
     }
@@ -337,7 +341,7 @@ rte_same(rte *x, rte *y)
 }
 
 static void
-rte_recalculate(rtable *table, net *net, struct proto *p, rte *new, ea_list *tmpa)
+rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte *new, ea_list *tmpa)
 {
   rte *old_best = net->routes;
   rte *old = NULL;
@@ -346,7 +350,7 @@ rte_recalculate(rtable *table, net *net, struct proto *p, rte *new, ea_list *tmp
   k = &net->routes;                    /* Find and remove original route from the same protocol */
   while (old = *k)
     {
-      if (old->attrs->proto == p)
+      if (old->attrs->proto == src)
        {
          if (new && rte_same(old, new))
            {
@@ -362,10 +366,14 @@ rte_recalculate(rtable *table, net *net, struct proto *p, rte *new, ea_list *tmp
       k = &old->next;
     }
 
+  log(L_WARN "ANNOUNCE %I/%d from %s (%s) %p", net->n.prefix, net->n.pxlen, p->name, src->name, old_best);
+
+  rte_announce(table, RA_ANY, net, new, old, tmpa);
+
   if (new && rte_better(new, old_best))        /* It's a new optimal route => announce and relink it */
     {
       rte_trace_in(D_ROUTES, p, new, "added [best]");
-      rte_announce(table, net, new, old_best, tmpa);
+      rte_announce(table, RA_OPTIMAL, net, new, old_best, tmpa);
       new->next = net->routes;
       net->routes = new;
     }
@@ -377,7 +385,7 @@ rte_recalculate(rtable *table, net *net, struct proto *p, rte *new, ea_list *tmp
          for(s=net->routes; s; s=s->next)
            if (rte_better(s, r))
              r = s;
-         rte_announce(table, net, r, old_best, tmpa);
+         rte_announce(table, RA_OPTIMAL, net, r, old_best, tmpa);
          if (r)                        /* Re-link the new optimal route */
            {
              k = &net->routes;
@@ -477,12 +485,19 @@ rte_update_unlock(void)
  */
 void
 rte_update(rtable *table, net *net, struct proto *p, rte *new)
+{
+  rte_update2(table, net, p, p, new);
+}
+
+void
+rte_update2(rtable *table, net *net, struct proto *p, struct proto *src, rte *new)
 {
   ea_list *tmpa = NULL;
 
   rte_update_lock();
   if (new)
     {
+      new->sender = p;
       struct filter *filter = p->in_filter;
 
        /* Do not filter routes going to the secondary side of the pipe, 
@@ -501,8 +516,8 @@ rte_update(rtable *table, net *net, struct proto *p, rte *new)
          rte_trace_in(D_FILTERS, p, new, "filtered out");
          goto drop;
        }
-      if (p->make_tmp_attrs)
-       tmpa = p->make_tmp_attrs(new, rte_update_pool);
+      if (src->make_tmp_attrs)
+       tmpa = src->make_tmp_attrs(new, rte_update_pool);
       if (filter)
        {
          ea_list *old_tmpa = tmpa;
@@ -512,14 +527,14 @@ rte_update(rtable *table, net *net, struct proto *p, rte *new)
              rte_trace_in(D_FILTERS, p, new, "filtered out");
              goto drop;
            }
-         if (tmpa != old_tmpa && p->store_tmp_attrs)
-           p->store_tmp_attrs(new, tmpa);
+         if (tmpa != old_tmpa && src->store_tmp_attrs)
+           src->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(table, net, p, new, tmpa);
+  rte_recalculate(table, net, p, src, new, tmpa);
   rte_update_unlock();
   return;
 
@@ -531,11 +546,8 @@ drop:
 void
 rte_discard(rtable *t, rte *old)       /* Non-filtered route deletion, used during garbage collection */
 {
-  net *n = old->net;
-  struct proto *p = old->attrs->proto;
-
   rte_update_lock();
-  rte_recalculate(t, n, p, NULL, NULL);
+  rte_recalculate(t, old->net, old->sender, old->attrs->proto, NULL, NULL);
   rte_update_unlock();
 }
 
@@ -673,8 +685,8 @@ again:
       ncnt++;
     rescan:
       for (e=n->routes; e; e=e->next, rcnt++)
-       if (e->attrs->proto->core_state != FS_HAPPY &&
-           e->attrs->proto->core_state != FS_FEEDING)
+       if (e->sender->core_state != FS_HAPPY &&
+           e->sender->core_state != FS_FEEDING)
          {
            rte_discard(tab, e);
            rdel++;
@@ -827,6 +839,18 @@ rt_commit(struct config *new, struct config *old)
   DBG("\tdone\n");
 }
 
+static inline void
+do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e)
+{
+  struct proto *q = e->attrs->proto;
+  ea_list *tmpa;
+
+  rte_update_lock();
+  tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL;
+  do_rte_announce(h, type, n, e, NULL, tmpa, ipa_classify(n->n.prefix));
+  rte_update_unlock();
+}
+
 /**
  * rt_feed_baby - advertise routes to a new protocol
  * @p: protocol to be fed
@@ -865,19 +889,24 @@ again:
          FIB_ITERATE_PUT(fit, fn);
          return 0;
        }
-      if (e)
-       {
-         struct proto *q = e->attrs->proto;
-         ea_list *tmpa;
-
-         if (p->core_state != FS_FEEDING)
-           return 1;  /* In the meantime, the protocol fell down. */
-         rte_update_lock();
-         tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL;
-         do_rte_announce(h, n, e, NULL, tmpa, ipa_classify(n->n.prefix));
-         rte_update_unlock();
-         max_feed--;
-       }
+
+      if (p->accept_ra_types == RA_OPTIMAL)
+       if (e)
+         {
+           if (p->core_state != FS_FEEDING)
+             return 1;  /* In the meantime, the protocol fell down. */
+           do_feed_baby(p, RA_OPTIMAL, h, n, e);
+           max_feed--;
+         }
+
+      if (p->accept_ra_types == RA_ANY)
+       for(e = n->routes; e != NULL; e = e->next)
+         {
+           if (p->core_state != FS_FEEDING)
+             return 1;  /* In the meantime, the protocol fell down. */
+           do_feed_baby(p, RA_ANY, h, n, e);
+           max_feed--;
+         }
     }
   FIB_ITERATE_END(fn);
   p->feed_ahook = h->next;
index cbc699bb357e6d4694749013d3e50a76fe5ae4e2..b42ea302c2d031b1703c7d45985bc4943cecd20f 100644 (file)
@@ -753,6 +753,7 @@ bgp_init(struct proto_config *C)
   struct proto *P = proto_new(C, sizeof(struct bgp_proto));
   struct bgp_proto *p = (struct bgp_proto *) P;
 
+  P->accept_ra_types = RA_OPTIMAL;
   P->rt_notify = bgp_rt_notify;
   P->rte_better = bgp_rte_better;
   P->import_control = bgp_import_control;
index 0cab1d7b9c85ab4d082d1ad6f603cf32af2975e9..69d3724134756e73ccc1b5a017eb7c335d9247ae 100644 (file)
@@ -224,6 +224,7 @@ ospf_init(struct proto_config *c)
   p->import_control = ospf_import_control;
   p->make_tmp_attrs = ospf_make_tmp_attrs;
   p->store_tmp_attrs = ospf_store_tmp_attrs;
+  p->accept_ra_types = RA_OPTIMAL;
   p->rt_notify = ospf_rt_notify;
   p->if_notify = ospf_iface_notify;
   p->rte_better = ospf_rte_better;
index d1d6bba995b23cedb7baaee7955410e0a4028e38..0240d16eae3bb07830f29858102f5d9a5a593f27 100644 (file)
 #include "pipe.h"
 
 static void
-pipe_send(struct pipe_proto *p, rtable *dest, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
+pipe_send(struct pipe_proto *p, rtable *dest, net *n, rte *new, rte *old, ea_list *attrs)
 {
+  struct proto *src;
   net *nn;
   rte *e;
   rta a;
 
+  if (!new && !old)
+    return;
+
   if (dest->pipe_busy)
     {
       log(L_ERR "Pipe loop detected when sending %I/%d to table %s",
@@ -47,17 +51,24 @@ pipe_send(struct pipe_proto *p, rtable *dest, net *n, rte *new, rte *old UNUSED,
   if (new)
     {
       memcpy(&a, new->attrs, sizeof(rta));
-      a.proto = &p->p;
-      a.source = RTS_PIPE;
       a.aflags = 0;
       a.eattrs = attrs;
       e = rte_get_temp(&a);
       e->net = nn;
+
+      /* Copy protocol specific embedded attributes. */
+      memcpy(&(e->u), &(new->u), sizeof(e->u));
+
+      src = new->attrs->proto;
     }
   else
-    e = NULL;
+    {
+      e = NULL;
+      src = old->attrs->proto;
+    }
+
   dest->pipe_busy = 1;
-  rte_update(dest, nn, &p->p, e);
+  rte_update2(dest, nn, &p->p, src, e);
   dest->pipe_busy = 0;
 }
 
@@ -82,7 +93,7 @@ pipe_rt_notify_sec(struct proto *P, net *net, rte *new, rte *old, ea_list *attrs
 static int
 pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED)
 {
-  struct proto *pp = (*ee)->attrs->proto;
+  struct proto *pp = (*ee)->sender;
 
   if (pp == P || pp == &((struct pipe_proto *) P)->phantom->p)
     return -1; /* Avoid local loops automatically */
@@ -106,6 +117,7 @@ pipe_start(struct proto *P)
   memcpy(ph, p, sizeof(struct pipe_proto));
   p->phantom = ph;
   ph->phantom = p;
+  ph->p.accept_ra_types = RA_ANY;
   ph->p.rt_notify = pipe_rt_notify_sec;
   ph->p.proto_state = PS_UP;
   ph->p.core_state = ph->p.core_goal = FS_HAPPY;
@@ -141,6 +153,7 @@ pipe_init(struct proto_config *C)
   struct pipe_proto *p = (struct pipe_proto *) P;
 
   p->peer = c->peer->table;
+  P->accept_ra_types = RA_ANY;
   P->rt_notify = pipe_rt_notify_pri;
   P->import_control = pipe_import_control;
   return P;
index 12cc8783b8f21fc72a53e5135913a3840def0c33..ab417f018a6353a9581e67feb6a2ed1ca087b98f 100644 (file)
@@ -946,6 +946,7 @@ rip_rte_remove(net *net UNUSED, rte *rte)
 void
 rip_init_instance(struct proto *p)
 {
+  p->accept_ra_types = RA_OPTIMAL;
   p->if_notify = rip_if_notify;
   p->rt_notify = rip_rt_notify;
   p->import_control = rip_import_control;
index a60e7f917d02a35d4cada228c312e413256b2299..0b55b40b887c0c2b5a415f458429aa758b29773a 100644 (file)
@@ -875,6 +875,7 @@ krt_init(struct proto_config *c)
 {
   struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
 
+  p->p.accept_ra_types = RA_OPTIMAL;
   p->p.rt_notify = krt_notify;
   p->p.min_scope = SCOPE_HOST;
   return &p->p;