]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
ID Map allows max and min limits
authorJan Moskyto Matejka <mq@ucw.cz>
Mon, 25 Apr 2016 08:35:08 +0000 (10:35 +0200)
committerJan Moskyto Matejka <mq@ucw.cz>
Mon, 25 Apr 2016 08:35:08 +0000 (10:35 +0200)
lib/idm.c
lib/idm.h
nest/rt-attr.c
nest/rt-fib.c
proto/ospf/topology.c

index 16d0e855ef3a972c25ab93d2817a8613d8d8fd89..2f0fa2083fe5e956c941918046bd4a979a05ff2a 100644 (file)
--- a/lib/idm.c
+++ b/lib/idm.c
@@ -29,35 +29,131 @@ idm_init(struct idm *m, pool *p, uint size)
 
 static inline int u32_cto(uint x) { return ffs(~x) - 1; }
 
+static void
+idm_grow(struct idm *m, u32 size)
+{
+  m->data = mb_realloc(m->data, size * sizeof(u32));
+  memset(m->data + m->size, 0, (size - m->size) * sizeof(u32));
+  m->size = size;
+}
+
+int
+idm_alloc_given(struct idm *m, u32 val)
+{
+  uint i = val / 32, j = val % 32;
+  if (i >= m->size)
+    idm_grow(m, i+1);
+
+  if (m->data[i] & (1 << j))
+    return 0;
+
+  m->data[i] |= (1 << j);
+  m->used--;
+  return 1;
+}
+
+/**
+ * Allocate a new ID
+ * @m: the ID Map to be used
+ * @min: minimal value returned
+ * @max: maximal value returned
+ *
+ * Returns the allocated value. Returns 0 if allocation is impossible.
+ */
 u32
-idm_alloc(struct idm *m)
+idm_alloc(struct idm *m, u32 min, u32 max)
 {
+  uint mini = min / 32, maxi = max / 32;
+
+  u32 minmask = ~((1 << (min % 32)) - 1);
+  u32 maxmask = ((1ULL << ((max+1) % 32)) - 1);
+
+  u32 mask;
+
   uint i, j;
 
-  for (i = m->pos; i < m->size; i++)
-    if (m->data[i] != 0xffffffff)
+  /* Not even allocated data array at mini. */
+  if (mini >= m->size)
+  {
+    i = mini;
+    idm_grow(m, mini+1);
+    mask = minmask;
+    goto found;
+  }
+
+  /* Only one u32 contains all possible values. */
+  if (mini == maxi)
+  {
+    mask = (minmask & maxmask);
+    if ((m->data[mini] & mask) == (mask))
+      return 0;
+    i = mini;
+    goto found;
+  }
+
+  /*
+   * a)
+   *                   m->pos
+   *                    v
+   * u32's in m->data: ..............................
+   *                          ^           ^
+   *                         mini        maxi
+   *
+   * b)
+   *                               m->pos
+   *                                v
+   * u32's in m->data: ..............................
+   *                          ^           ^
+   *                         mini        maxi
+   *
+   * c)
+   *                                          m->pos
+   *                                           v
+   * u32's in m->data: ..............................
+   *                          ^           ^
+   *                         mini        maxi
+   *
+   */
+
+  /* Beginning at: mini+1 (a) or m->pos (b,c) m->pos
+   * End at last before: MIN(maxi, m->size) ... this skips loop at c)
+   */
+  for (i = MAX(mini+1, m->pos); i < MIN(maxi, m->size); i++)
+    if (m->data[i] != (mask = 0xffffffff))
       goto found;
 
-  /* If we are at least 7/8 full, expand */
-  if (m->used > (m->size * 28))
+  /* if maxi points to an allocated value */
+  if (maxi < m->size)
+    if ((m->data[i = maxi] & maxmask) != (mask = maxmask))
+      goto found;
+
+  /* If we have just hit m->size and we are at least 7/8 full, expand */
+  if ((i == m->size) && (m->used > (m->size * 28)))
   {
-    m->size *= 2;
-    m->data = mb_realloc(m->data, m->size * sizeof(u32));
-    memset(m->data + i, 0, (m->size - i) * sizeof(u32));
+    idm_grow(m, m->size * 2);
+    mask = 0xffffffff;
     goto found;
   }
 
-  for (i = 0; i < m->pos; i++)
-    if (m->data[i] != 0xffffffff)
+  /* Trying i == mini (skipped before) */
+  if ((m->data[i = mini] & minmask) != (mask = minmask))
+    goto found;
+
+  /* Beginning at mini+1 in all cases
+   * End before m->pos (a,b) or maxi (c), whatever comes earlier. This skips loop at a) */
+
+  for (i = mini+1; i < MIN(maxi, m->pos); i++)
+    if (m->data[i] != (mask = 0xffffffff))
       goto found;
 
-  ASSERT(0);
+  return 0;
 
  found:
-  ASSERT(i < 0x8000000);
+  if (i >= 0x8000000) // Too large value
+    return 0;
 
   m->pos = i;
-  j = u32_cto(m->data[i]);
+  j = u32_cto(m->data[i] | ~mask);
 
   m->data[i] |= (1 << j);
   m->used++;
@@ -74,3 +170,100 @@ idm_free(struct idm *m, u32 id)
   m->data[i] &= ~(1 << j);
   m->used--;
 }
+
+#ifdef TEST
+
+#include <stdio.h>
+#include <string.h>
+
+#include "sysdep/unix/unix.h"
+
+struct idm m;
+
+static void idm_dump(struct idm *m)
+{
+  int w = 0;
+  char b[90];
+  for (int i=0; i<m->size; i++) {
+    u32 val = m->data[i];
+    while (val) {
+      u32 n = ffs(val)-1;
+      w += sprintf(b + w, "%u,", i*32 + n);
+      if (w < 72) {
+       b[w++] = ' ';
+      }
+      else {
+       b[w++] = '\n';
+       b[w] = 0;
+       debug(b);
+       w = 0;
+      }
+      val &= ~(1U<<n);
+    }
+  }
+
+  if (w) {
+    b[w++] = '\n';
+    b[w] = 0;
+    debug(b);
+  }
+}
+
+static void bitdump(u32 val)
+{
+  for (int i=0;i<32;i++)
+    debug("%c", "01"[!!(val&(1<<i))]);
+}
+
+static void dump(const char *msg)
+{
+  debug(msg);
+  debug("Used: %u, Pos: %u, Size: %u\n", m.used, m.pos, m.size);
+  idm_dump(&m);
+#if 0
+  for (int i=0;i<m.size;i+=2) {
+    debug("%3d: ", i*32);
+    bitdump(m.data[i]);
+    bitdump(m.data[i+1]);
+    debug("\n");
+  }
+#endif
+}
+
+#define TA(min, max)  debug("Alloc from (%u, %u): %u\n", min, max, idm_alloc(&m, min, max)); dump("")
+#define TF(n)        debug("Free %u\n", n); idm_free(&m, n); dump("")
+
+int main(void)
+{
+  log_init_debug(NULL);
+  resource_init();
+  idm_init(&m, &root_pool, 4);
+
+  TA(20, 40);
+  TA(20, 40);
+  TA(20, 40);
+  TA(20, 40);
+  TA(10, 30);
+  TA(10, 20);
+  TF(10);
+  TA(10, 20);
+  TF(11);
+  TA(65, 65);
+  debug("Alloc enough to auto-grow\n");
+  for (int i=0; i<105; i++)
+    idm_alloc(&m, 0, 200);
+  dump("");
+  TA(0, 200);
+  TA(0, 200);
+
+  TA(513, 513);
+
+  TA(1000, 2000);
+  TA(256, 257);
+  TA(256, 257);
+  TA(256, 257);
+  TF(1000);
+
+}
+
+#endif
index e3380cceae8dc4e32fe77146cc342a10efd6da30..b8f33bc578b38ac194dec5b78bd85ef61a8388d8 100644 (file)
--- a/lib/idm.h
+++ b/lib/idm.h
@@ -19,7 +19,7 @@ struct idm
 };
 
 void idm_init(struct idm *m, pool *p, uint size);
-u32 idm_alloc(struct idm *m);
+u32 idm_alloc(struct idm *m, u32 min, u32 max);
 void idm_free(struct idm *m, u32 id);
 
 #endif
index 185cbf9cc01e9324fc186402494b3bb8c3dd486a..8cee99152987b675985f629231bbff0c0c3a65c8 100644 (file)
@@ -113,9 +113,11 @@ rt_get_source(struct proto *p, u32 id)
   src = sl_alloc(rte_src_slab);
   src->proto = p;
   src->private_id = id;
-  src->global_id = idm_alloc(&src_ids);
+  src->global_id = idm_alloc(&src_ids, 1, 0xffffffff);
   src->uc = 0;
 
+  ASSERT(src->global_id); /* Couldn't allocate new ID */
+
   HASH_INSERT2(src_hash, RSH, rta_pool, src);
 
   return src;
index 558b3ace127f2c469a8216de0b3f81d50d2d829e..f81506bc665b0c0dee35586c335294a67e54bb6a 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "nest/bird.h"
 #include "nest/route.h"
+#include "lib/idm.h"
 #include "lib/string.h"
 
 #define HASH_DEF_ORDER 10
index 9d0a93c7bd5081d14c0ac3d8556df4e82ba17622..41d2300751b9fd862e1a2e3e7e7cf1e121c62bdc 100644 (file)
@@ -548,7 +548,10 @@ ort_to_lsaid(struct ospf_proto *p, ort *nf)
   if (ospf_is_v3(p))
   {
     if (!nf->lsa_id)
-      nf->lsa_id = idm_alloc(&p->idm);
+      nf->lsa_id = idm_alloc(&p->idm, 0, 0xffffffff);
+
+    if (!nf->lsa_id)
+      log(L_FATAL "%s: LSA ID allocation failed, using 0 as fallback.", p->p.name);
 
     return nf->lsa_id;
   }