]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Changes OSPF to generate stub networks for non-primary addresses.
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 10 Jun 2009 21:45:08 +0000 (23:45 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 10 Jun 2009 21:45:08 +0000 (23:45 +0200)
Also does some reorganization in RT LSA announcement.

lib/resource.c
lib/resource.h
lib/xmalloc.c
proto/ospf/ospf.c
proto/ospf/ospf.h
proto/ospf/topology.c

index 9e6268157665c41458119810224bb2c82681b548..289af9332e94a1d1b38526cf4ee322e2df1fa935 100644 (file)
@@ -327,6 +327,42 @@ mb_allocz(pool *p, unsigned size)
   return x;
 }
 
+/**
+ * mb_realloc - reallocate a memory block
+ * @p: pool
+ * @m: memory block
+ * @size: new size of the block
+ *
+ * mb_realloc() changes the size of the memory block @m to a given size.
+ * The contents will be unchanged to the minimum of the old and new sizes;
+ * newly allocated memory will be uninitialized. If @m is NULL, the call
+ * is equivalent to mb_alloc(@p, @size).
+ *
+ * Like mb_alloc(), mb_realloc() also returns a pointer to the memory
+ * chunk , not to the resource, hence you have to free it using
+ * mb_free(), not rfree().
+ */
+void *
+mb_realloc(pool *p, void *m, unsigned size)
+{
+  struct mblock *ob = NULL;
+
+  if (m)
+    {
+      ob = SKIP_BACK(struct mblock, data, m);
+      if (ob->r.n.next)
+       rem_node(&ob->r.n);
+    }
+
+  struct mblock *b = xrealloc(ob, sizeof(struct mblock) + size);
+
+  b->r.class = &mb_class;
+  add_tail(&p->inside, &b->r.n);
+  b->size = size;
+  return b->data;
+}
+
+
 /**
  * mb_free - free a memory block
  * @m: memory block
@@ -339,3 +375,4 @@ mb_free(void *m)
   struct mblock *b = SKIP_BACK(struct mblock, data, m);
   rfree(b);
 }
+
index 42ed26ed65f53311a58fdcea0016957864fe6c38..8dd441f0f75f0200cebdafe5a0ef272232c64d65 100644 (file)
@@ -47,6 +47,7 @@ extern pool root_pool;
 
 void *mb_alloc(pool *, unsigned size);
 void *mb_allocz(pool *, unsigned size);
+void *mb_realloc(pool *p, void *m, unsigned size);
 void mb_free(void *);
 
 /* Memory pools with linear allocation */
@@ -75,12 +76,13 @@ void sl_free(slab *, void *);
 #ifdef HAVE_LIBDMALLOC
 /*
  * The standard dmalloc macros tend to produce lots of namespace
- * conflicts and we use only xmalloc and xfree, so we can define
- * the stubs ourselves.
+ * conflicts and we use only xmalloc, xrealloc and xfree, so we
+ * can define the stubs ourselves.
  */
 #define DMALLOC_DISABLE
 #include <dmalloc.h>
 #define xmalloc(size) _xmalloc_leap(__FILE__, __LINE__, size)
+#define xrealloc(size) _xrealloc_leap(__FILE__, __LINE__, size)
 #define xfree(ptr) _xfree_leap(__FILE__, __LINE__, ptr)
 #else
 /*
@@ -89,7 +91,9 @@ void sl_free(slab *, void *);
  * the renaming.
  */
 #define xmalloc bird_xmalloc
+#define xrealloc bird_xrealloc
 void *xmalloc(unsigned);
+void *xrealloc(void *, unsigned);
 #define xfree(x) free(x)
 #endif
 
index bc386c83634731104aefb9acdfce16e091afeb7f..da2f09419fea800d17901ae7cbad572deb0fcdc8 100644 (file)
@@ -32,4 +32,24 @@ xmalloc(unsigned size)
   die("Unable to allocate %d bytes of memory", size);
 }
 
+/**
+ * xrealloc - realloc with checking
+ * @ptr: original memory block
+ * @size: block size
+ *
+ * This function is equivalent to realloc() except that in case of
+ * failure it calls die() to quit the program instead of returning
+ * a %NULL pointer.
+ *
+ * Wherever possible, please use the memory resources instead.
+ */
+void *
+xrealloc(void *ptr, unsigned size)
+{
+  void *p = realloc(ptr, size);
+  if (p)
+    return p;
+  die("Unable to allocate %d bytes of memory", size);
+}
+
 #endif
index 69d3724134756e73ccc1b5a017eb7c335d9247ae..4ad6ef46187addb4e717f1f78890503c8d367e84 100644 (file)
@@ -76,6 +76,9 @@
 #include <stdlib.h>
 #include "ospf.h"
 
+
+static void ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED, ea_list * attrs);
+static void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
 static int ospf_rte_better(struct rte *new, struct rte *old);
 static int ospf_rte_same(struct rte *new, struct rte *old);
 static void ospf_disp(timer *timer);
@@ -124,6 +127,9 @@ ospf_start(struct proto *p)
   po->disp_timer->hook = ospf_disp;
   po->disp_timer->recurrent = po->tick;
   tm_start(po->disp_timer, 1);
+  po->lsab_size = 256;
+  po->lsab_used = 0;
+  po->lsab = mb_alloc(p->pool, po->lsab_size);
   init_list(&(po->iface_list));
   init_list(&(po->area_list));
   fib_init(&po->rtf, p->pool, sizeof(ort), 16, ospf_rt_initort);
@@ -227,6 +233,7 @@ ospf_init(struct proto_config *c)
   p->accept_ra_types = RA_OPTIMAL;
   p->rt_notify = ospf_rt_notify;
   p->if_notify = ospf_iface_notify;
+  p->ifa_notify = ospf_ifa_notify;
   p->rte_better = ospf_rte_better;
   p->rte_same = ospf_rte_same;
 
@@ -429,7 +436,7 @@ ospf_shutdown(struct proto *p)
   return PS_DOWN;
 }
 
-void
+static void
 ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED,
               ea_list * attrs)
 {
@@ -473,6 +480,25 @@ ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED,
   }
 }
 
+static void
+ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
+{
+  struct proto_ospf *po = (struct proto_ospf *) p;
+  struct ospf_iface *ifa;
+  
+  if ((a->flags & IA_SECONDARY) || (a->flags & IA_UNNUMBERED))
+    return;
+
+  WALK_LIST(ifa, po->iface_list)
+    {
+      if (ifa->iface == a->iface)
+       {
+         schedule_rt_lsa(ifa->oa);
+         return;
+       }
+    }
+}
+
 static void
 ospf_get_status(struct proto *p, byte * buf)
 {
index fb78af4e4f14f1df0dfb2a36e614d1b5f9e7ae4a..71f99d34a108b70b0d0d2d38b82dd2370d8eb7bb 100644 (file)
@@ -550,6 +550,8 @@ struct proto_ospf
   int rfc1583;                 /* RFC1583 compatibility */
   int ebit;                    /* Did I originate any ext lsa? */
   struct ospf_area *backbone;  /* If exists */
+  void *lsab;                  /* LSA buffer used when originating router LSAs */
+  int lsab_size, lsab_used;
 };
 
 struct ospf_iface_patt
@@ -585,8 +587,6 @@ int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
                        struct linpool *pool);
 struct ea_list *ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool);
 void ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs);
-void ospf_rt_notify(struct proto *p, net *n, rte *new, rte *old,
-                   ea_list * attrs);
 void schedule_rt_lsa(struct ospf_area *oa);
 void schedule_rtcalc(struct proto_ospf *po);
 void schedule_net_lsa(struct ospf_iface *ifa);
index a15d2e35ce6f1575388532bf98807ac0744f1b05..18100f7eedb315807c812321fa3418e8fa83d4c8 100644 (file)
 
 int ptp_unnumbered_stub_lsa = 0;
 
+static void *
+lsab_alloc(struct proto_ospf *po, unsigned size)
+{
+  unsigned offset = po->lsab_used;
+  po->lsab_used += size;
+  if (po->lsab_used > po->lsab_size)
+    {
+      po->lsab_size = MAX(po->lsab_used, 2 * po->lsab_size);
+      po->lsab = mb_realloc(po->proto.pool, po->lsab, po->lsab_size);
+    }
+  return ((byte *) po->lsab) + offset;
+}
+
+static inline void *
+lsab_allocz(struct proto_ospf *po, unsigned size)
+{
+  void *r = lsab_alloc(po, size);
+  bzero(r, size);
+  return r;
+}
+
+static inline void *
+lsab_flush(struct proto_ospf *po)
+{
+  void *r = mb_alloc(po->proto.pool, po->lsab_size);
+  memcpy(r, po->lsab, po->lsab_used);
+  po->lsab_used = 0;
+  return r;
+}
+
+
 static void *
 originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
 {
   struct proto_ospf *po = oa->po;
   struct ospf_iface *ifa;
-  int j = 0, k = 0;
-  u16 i = 0;
+  int i = 0, j = 0, k = 0, bitv = 0;
   struct ospf_lsa_rt *rt;
-  struct ospf_lsa_rt_link *ln, *ln_after;
+  struct ospf_lsa_rt_link *ln;
   struct ospf_neighbor *neigh;
 
   DBG("%s: Originating RT_lsa body for area \"%I\".\n", po->proto.name,
       oa->areaid);
-
-  WALK_LIST(ifa, po->iface_list)
-  {
-    if ((ifa->oa == oa) && (ifa->state != OSPF_IS_DOWN))
-    {
-      i++;
-      if ((ifa->type == OSPF_IT_PTP) && (ifa->state == OSPF_IS_PTP) &&
-         (ptp_unnumbered_stub_lsa || !(ifa->iface->addr->flags & IA_UNNUMBERED)))
-        i++;
-    }
-  }
-  rt = mb_allocz(po->proto.pool, sizeof(struct ospf_lsa_rt) +
-                i * sizeof(struct ospf_lsa_rt_link));
+    
+  ASSERT(po->lsab_used == 0);
+  rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt));
   if (po->areano > 1)
     rt->veb.bit.b = 1;
   if ((po->ebit) && (!oa->stub))
     rt->veb.bit.e = 1;
-  ln = (struct ospf_lsa_rt_link *) (rt + 1);
-  ln_after = ln + i;
+  rt = NULL; /* buffer might be reallocated later */
 
   WALK_LIST(ifa, po->iface_list)
   {
-    if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) && (!EMPTY_LIST(ifa->neigh_list)))
+    int master = 0;
+
+    if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) &&
+       (!EMPTY_LIST(ifa->neigh_list)))
     {
       neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
       if ((neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
-        rt->veb.bit.v = 1;
+       bitv = 1;
     }
 
     if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN))
       continue;
 
-    if (ln == ln_after)
-      die("LSA space overflow");
+    /* BIRD does not support interface loops */
+    ASSERT(ifa->state != OSPF_IS_LOOP);
 
-    if (ifa->state == OSPF_IS_LOOP)
-    {
-      ln->type = 3;
-      ln->id = ipa_to_u32(ifa->iface->addr->ip);
-      ln->data = 0xffffffff;
-      ln->metric = 0;
-      ln->notos = 0;
-    }
-    else
-    {
-      switch (ifa->type)
+    switch (ifa->type)
       {
-      case OSPF_IT_PTP:        /* rfc2328 - pg126 */
+      case OSPF_IT_PTP:        /* RFC2328 - 12.4.1.1 */
        neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
        if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL))
        {
+         ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
          ln->type = LSART_PTP;
          ln->id = neigh->rid;
+         ln->data = (ifa->iface->addr->flags & IA_UNNUMBERED) ?
+           ifa->iface->index : ipa_to_u32(ifa->iface->addr->ip);
          ln->metric = ifa->cost;
          ln->notos = 0;
-         if (ifa->iface->addr->flags & IA_UNNUMBERED)
-         {
-           ln->data = ifa->iface->index;
-         }
-         else
-         {
-           ln->data = ipa_to_u32(ifa->iface->addr->ip);
-         }
-       }
-       else
-       {
-          ln--;
-         i--;          /* No link added */
-        }
-
-       if ((ifa->state == OSPF_IS_PTP) && 
-           (ptp_unnumbered_stub_lsa || !(ifa->iface->addr->flags & IA_UNNUMBERED)))
-       {
-         ln++;
-         if (ln == ln_after)
-            die("LSA space overflow");
-
-         ln->type = LSART_STUB;
-         ln->metric = ifa->cost;
-         ln->notos = 0;
-         if (ifa->iface->addr->flags & IA_UNNUMBERED)
-         {
-           ln->id = ipa_to_u32(ifa->iface->addr->opposite);
-           ln->data = 0xffffffff;
-         }
-         else
-         {
-           ln->data = ipa_to_u32(ipa_mkmask(ifa->iface->addr->pxlen));
-           ln->id = ipa_to_u32(ifa->iface->addr->prefix) & ln->data;
-         }
+         i++;
+         master = 1;
        }
        break;
-      case OSPF_IT_BCAST:
+
+      case OSPF_IT_BCAST: /* RFC2328 - 12.4.1.2 */
       case OSPF_IT_NBMA:
        if (ifa->state == OSPF_IS_WAITING)
-       {
-         ln->type = LSART_STUB;
-         ln->data = ipa_to_u32(ipa_mkmask(ifa->iface->addr->pxlen));
-         ln->id = ipa_to_u32(ifa->iface->addr->prefix) & ln->data;
-         ln->metric = ifa->cost;
-         ln->notos = 0;
-       }
-       else
-       {
-         j = 0, k = 0;
-         WALK_LIST(neigh, ifa->neigh_list)
+         break;
+
+       j = 0, k = 0;
+       WALK_LIST(neigh, ifa->neigh_list)
          {
            if ((neigh->rid == ifa->drid) && (neigh->state == NEIGHBOR_FULL))
              k = 1;
            if (neigh->state == NEIGHBOR_FULL)
              j = 1;
          }
-         if (((ifa->state == OSPF_IS_DR) && (j == 1)) || (k == 1))
+
+       if (((ifa->state == OSPF_IS_DR) && (j == 1)) || (k == 1))
          {
+           ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
            ln->type = LSART_NET;
            ln->id = ipa_to_u32(ifa->drip);
            ln->data = ipa_to_u32(ifa->iface->addr->ip);
            ln->metric = ifa->cost;
            ln->notos = 0;
+           i++;
+           master = 1;
          }
-         else
-         {
-           ln->type = LSART_STUB;
-           ln->data = ipa_to_u32(ipa_mkmask(ifa->iface->addr->pxlen));
-           ln->id = ipa_to_u32(ifa->iface->addr->prefix) & ln->data;
-           ln->metric = ifa->cost;
-           ln->notos = 0;
-         }
-       }
        break;
-      case OSPF_IT_VLINK:
+
+      case OSPF_IT_VLINK: /* RFC2328 - 12.4.1.3 */
        neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
        if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
        {
+         ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
          ln->type = LSART_VLNK;
          ln->id = neigh->rid;
+         ln->data = ipa_to_u32(ifa->iface->addr->ip);
          ln->metric = ifa->cost;
          ln->notos = 0;
-        }
-       else
-        {
-          ln--;
-         i--;          /* No link added */
+         i++;
+         master = 1;
         }
         break;
+
       default:
-        ln--;
-       i--;            /* No link added */
         log("Unknown interface type %s", ifa->iface->name);
         break;
       }
-    }
-    ln++;
+
+    /* Now we will originate stub areas for interfaces addresses */
+    struct ifa *a;
+    WALK_LIST(a, ifa->iface->addrs)
+      {
+       if (((a == ifa->iface->addr) && master) ||
+           (a->flags & IA_SECONDARY) ||
+           (a->flags & IA_UNNUMBERED))
+         continue;
+
+       ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
+       ln->type = LSART_STUB;
+       ln->id = ipa_to_u32(a->prefix);
+       ln->data = ipa_to_u32(ipa_mkmask(a->pxlen));
+       ln->metric = ifa->cost;
+       ln->notos = 0;
+       i++;
+      }
   }
+
+  rt = po->lsab;
   rt->links = i;
-  *length = i * sizeof(struct ospf_lsa_rt_link) + sizeof(struct ospf_lsa_rt) +
-    sizeof(struct ospf_lsa_header);
-  return rt;
+  rt->veb.bit.v = bitv;
+  *length = po->lsab_used + sizeof(struct ospf_lsa_header);
+  return lsab_flush(po);
 }
 
 /**