]> git.ipfire.org Git - thirdparty/bird.git/blobdiff - nest/rt-attr.c
Doc: Remove some superfluous slashes
[thirdparty/bird.git] / nest / rt-attr.c
index 0fb7c8204126dcbf047f5319983aaa8c4bb00e03..edf27d4457e30d4d1efd9da02d1f9feee12f74bb 100644 (file)
@@ -51,6 +51,7 @@
 #include "nest/cli.h"
 #include "nest/attrs.h"
 #include "lib/alloca.h"
+#include "lib/hash.h"
 #include "lib/resource.h"
 #include "lib/string.h"
 
@@ -63,14 +64,20 @@ static slab *rte_src_slab;
 /* rte source ID bitmap */
 static u32 *src_ids;
 static u32 src_id_size, src_id_used, src_id_pos;
-#define SRC_ID_SIZE_DEF 4
+#define SRC_ID_INIT_SIZE 4
 
 /* rte source hash */
-static struct rte_src **src_table;
-static u32 src_hash_order, src_hash_size, src_hash_count;
-#define SRC_HASH_ORDER_DEF 6
-#define SRC_HASH_ORDER_MAX 18
-#define SRC_HASH_ORDER_MIN 10
+
+#define RSH_KEY(n)             n->proto, n->private_id
+#define RSH_NEXT(n)            n->next
+#define RSH_EQ(p1,n1,p2,n2)    p1 == p2 && n1 == n2
+#define RSH_FN(p,n)            p->hash_key ^ u32_hash(n)
+
+#define RSH_REHASH             rte_src_rehash
+#define RSH_PARAMS             /2, *2, 1, 1, 8, 20
+#define RSH_INIT_ORDER         6
+
+static HASH(struct rte_src) src_hash;
 
 struct protocol *attr_class_to_protocol[EAP_MAX];
 
@@ -81,25 +88,22 @@ rte_src_init(void)
   rte_src_slab = sl_new(rta_pool, sizeof(struct rte_src));
 
   src_id_pos = 0;
-  src_id_size = SRC_ID_SIZE_DEF;
+  src_id_size = SRC_ID_INIT_SIZE;
   src_ids = mb_allocz(rta_pool, src_id_size * sizeof(u32));
 
  /* ID 0 is reserved */
   src_ids[0] = 1;
   src_id_used = 1;
 
-  src_hash_count = 0;
-  src_hash_order = SRC_HASH_ORDER_DEF;
-  src_hash_size = 1 << src_hash_order;
-  src_table = mb_allocz(rta_pool, src_hash_size * sizeof(struct rte_src *));
+  HASH_INIT(src_hash, rta_pool, RSH_INIT_ORDER);
 }
 
-static inline int u32_cto(unsigned int x) { return ffs(~x) - 1; }
+static inline int u32_cto(uint x) { return ffs(~x) - 1; }
 
 static inline u32
 rte_src_alloc_id(void)
 {
-  int i, j;
+  uint i, j;
   for (i = src_id_pos; i < src_id_size; i++)
     if (src_ids[i] != 0xffffffff)
       goto found;
@@ -141,56 +145,22 @@ rte_src_free_id(u32 id)
   src_id_used--;
 }
 
-static inline u32 rte_src_hash(struct proto *p, u32 x, u32 order)
-{ return (x * 2902958171u) >> (32 - order); }
-
-static void
-rte_src_rehash(int step)
-{
-  struct rte_src **old_tab, *src, *src_next;
-  u32 old_size, hash, i;
-
-  old_tab = src_table;
-  old_size = src_hash_size;
-
-  src_hash_order += step;
-  src_hash_size = 1 << src_hash_order;
-  src_table = mb_allocz(rta_pool, src_hash_size * sizeof(struct rte_src *));
-  
-  for (i = 0; i < old_size; i++)
-    for (src = old_tab[i]; src; src = src_next)
-      {
-       src_next = src->next;
-       hash = rte_src_hash(src->proto, src->private_id, src_hash_order);
-       src->next = src_table[hash];
-       src_table[hash] = src;
-      }
 
-  mb_free(old_tab);
-}
+HASH_DEFINE_REHASH_FN(RSH, struct rte_src)
 
 struct rte_src *
 rt_find_source(struct proto *p, u32 id)
 {
-  struct rte_src *src;
-  u32 hash = rte_src_hash(p, id, src_hash_order);
-
-  for (src = src_table[hash]; src; src = src->next)
-    if ((src->proto == p) && (src->private_id == id))
-      return src;
-
-  return NULL;
+  return HASH_FIND(src_hash, RSH, p, id);
 }
 
 struct rte_src *
 rt_get_source(struct proto *p, u32 id)
 {
-  struct rte_src *src;
-  u32 hash = rte_src_hash(p, id, src_hash_order);
+  struct rte_src *src = rt_find_source(p, id);
 
-  for (src = src_table[hash]; src; src = src->next)
-    if ((src->proto == p) && (src->private_id == id))
-      return src;
+  if (src)
+    return src;
 
   src = sl_alloc(rte_src_slab);
   src->proto = p;
@@ -198,47 +168,26 @@ rt_get_source(struct proto *p, u32 id)
   src->global_id = rte_src_alloc_id();
   src->uc = 0;
 
-  src->next = src_table[hash];
-  src_table[hash] = src;
-
-  src_hash_count++;
-  if ((src_hash_count > src_hash_size) && (src_hash_order < SRC_HASH_ORDER_MAX))
-    rte_src_rehash(1);
+  HASH_INSERT2(src_hash, RSH, rta_pool, src);
 
   return src;
 }
 
-static inline void
-rt_remove_source(struct rte_src **sp)
-{
-  struct rte_src *src = *sp;
-
-  *sp = src->next;
-  rte_src_free_id(src->global_id);
-  sl_free(rte_src_slab, src);
-  src_hash_count--;
-}
-
 void
 rt_prune_sources(void)
 {
-  struct rte_src **sp;
-  int i;
-  
-  for (i = 0; i < src_hash_size; i++)
+  HASH_WALK_FILTER(src_hash, next, src, sp)
+  {
+    if (src->uc == 0)
     {
-      sp = &src_table[i];
-      while (*sp)
-       {
-         if ((*sp)->uc == 0)
-           rt_remove_source(sp);
-         else
-           sp = &(*sp)->next;
-       }
+      HASH_DO_REMOVE(src_hash, RSH, sp);
+      rte_src_free_id(src->global_id);
+      sl_free(rte_src_slab, src);
     }
+  }
+  HASH_WALK_FILTER_END;
 
-  while ((src_hash_count < (src_hash_size / 4)) && (src_hash_order > SRC_HASH_ORDER_MIN))
-    rte_src_rehash(-1);
+  HASH_MAY_RESIZE_DOWN(src_hash, RSH, rta_pool);
 }
 
 
@@ -246,10 +195,10 @@ rt_prune_sources(void)
  *     Multipath Next Hop
  */
 
-static inline unsigned int
+static inline uint
 mpnh_hash(struct mpnh *x)
 {
-  unsigned int h = 0;
+  uint h = 0;
   for (; x; x = x->next)
     h ^= ipa_hash(x->gw);
 
@@ -266,6 +215,122 @@ mpnh__same(struct mpnh *x, struct mpnh *y)
   return x == y;
 }
 
+static int
+mpnh_compare_node(struct mpnh *x, struct mpnh *y)
+{
+  int r;
+
+  if (!x)
+    return 1;
+
+  if (!y)
+    return -1;
+
+  r = ((int) y->weight) - ((int) x->weight);
+  if (r)
+    return r;
+
+  r = ipa_compare(x->gw, y->gw);
+  if (r)
+    return r;
+
+  return ((int) x->iface->index) - ((int) y->iface->index);
+}
+
+static inline struct mpnh *
+mpnh_copy_node(const struct mpnh *src, linpool *lp)
+{
+  struct mpnh *n = lp_alloc(lp, sizeof(struct mpnh));
+  n->gw = src->gw;
+  n->iface = src->iface;
+  n->next = NULL;
+  n->weight = src->weight;
+  return n;
+}
+
+/**
+ * mpnh_merge - merge nexthop lists
+ * @x: list 1
+ * @y: list 2
+ * @rx: reusability of list @x
+ * @ry: reusability of list @y
+ * @max: max number of nexthops
+ * @lp: linpool for allocating nexthops
+ *
+ * The mpnh_merge() function takes two nexthop lists @x and @y and merges them,
+ * eliminating possible duplicates. The input lists must be sorted and the
+ * result is sorted too. The number of nexthops in result is limited by @max.
+ * New nodes are allocated from linpool @lp.
+ *
+ * The arguments @rx and @ry specify whether corresponding input lists may be
+ * consumed by the function (i.e. their nodes reused in the resulting list), in
+ * that case the caller should not access these lists after that. To eliminate
+ * issues with deallocation of these lists, the caller should use some form of
+ * bulk deallocation (e.g. stack or linpool) to free these nodes when the
+ * resulting list is no longer needed. When reusability is not set, the
+ * corresponding lists are not modified nor linked from the resulting list.
+ */
+struct mpnh *
+mpnh_merge(struct mpnh *x, struct mpnh *y, int rx, int ry, int max, linpool *lp)
+{
+  struct mpnh *root = NULL;
+  struct mpnh **n = &root;
+
+  while ((x || y) && max--)
+  {
+    int cmp = mpnh_compare_node(x, y);
+    if (cmp < 0)
+    {
+      *n = rx ? x : mpnh_copy_node(x, lp);
+      x = x->next;
+    }
+    else if (cmp > 0)
+    {
+      *n = ry ? y : mpnh_copy_node(y, lp);
+      y = y->next;
+    }
+    else
+    {
+      *n = rx ? x : (ry ? y : mpnh_copy_node(x, lp));
+      x = x->next;
+      y = y->next;
+    }
+    n = &((*n)->next);
+  }
+  *n = NULL;
+
+  return root;
+}
+
+void
+mpnh_insert(struct mpnh **n, struct mpnh *x)
+{
+  for (; *n; n = &((*n)->next))
+  {
+    int cmp = mpnh_compare_node(*n, x);
+
+    if (cmp < 0)
+      continue;
+    else if (cmp > 0)
+      break;
+    else
+      return;
+  }
+
+  x->next = *n;
+  *n = x;
+}
+
+int
+mpnh_is_sorted(struct mpnh *x)
+{
+  for (; x && x->next; x = x->next)
+    if (mpnh_compare_node(x, x->next) >= 0)
+      return 0;
+
+  return 1;
+}
+
 static struct mpnh *
 mpnh_copy(struct mpnh *o)
 {
@@ -358,6 +423,82 @@ ea_find(ea_list *e, unsigned id)
   return a;
 }
 
+/**
+ * ea_walk - walk through extended attributes
+ * @s: walk state structure
+ * @id: start of attribute ID interval
+ * @max: length of attribute ID interval
+ *
+ * Given an extended attribute list, ea_walk() walks through the list looking
+ * for first occurrences of attributes with ID in specified interval from @id to
+ * (@id + @max - 1), returning pointers to found &eattr structures, storing its
+ * walk state in @s for subsequent calls.
+ *
+ * The function ea_walk() is supposed to be called in a loop, with initially
+ * zeroed walk state structure @s with filled the initial extended attribute
+ * list, returning one found attribute in each call or %NULL when no other
+ * attribute exists. The extended attribute list or the arguments should not be
+ * modified between calls. The maximum value of @max is 128.
+ */
+eattr *
+ea_walk(struct ea_walk_state *s, uint id, uint max)
+{
+  ea_list *e = s->eattrs;
+  eattr *a = s->ea;
+  eattr *a_max;
+
+  max = id + max;
+
+  if (a)
+    goto step;
+
+  for (; e; e = e->next)
+  {
+    if (e->flags & EALF_BISECT)
+    {
+      int l, r, m;
+
+      l = 0;
+      r = e->count - 1;
+      while (l < r)
+      {
+       m = (l+r) / 2;
+       if (e->attrs[m].id < id)
+         l = m + 1;
+       else
+         r = m;
+      }
+      a = e->attrs + l;
+    }
+    else
+      a = e->attrs;
+
+  step:
+    a_max = e->attrs + e->count;
+    for (; a < a_max; a++)
+      if ((a->id >= id) && (a->id < max))
+      {
+       int n = a->id - id;
+
+       if (BIT32_TEST(s->visited, n))
+         continue;
+
+       BIT32_SET(s->visited, n);
+
+       if ((a->type & EAF_TYPE_MASK) == EAF_TYPE_UNDEF)
+         continue;
+
+       s->eattrs = e;
+       s->ea = a;
+       return a;
+      }
+      else if (e->flags & EALF_BISECT)
+       break;
+  }
+
+  return NULL;
+}
+
 /**
  * ea_get_int - fetch an integer attribute
  * @e: attribute list
@@ -610,15 +751,41 @@ get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
       *buf += bsprintf(*buf, "igp_metric");
       return GA_NAME;
     }
+
   return GA_UNKNOWN;
 }
 
+void
+ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max)
+{
+  byte *bound = buf + bufsize - 32;
+  u32 data = a->u.data;
+  int i;
+
+  for (i = min; i < max; i++)
+    if ((data & (1u << i)) && names[i])
+    {
+      if (buf > bound)
+      {
+       strcpy(buf, " ...");
+       return;
+      }
+
+      buf += bsprintf(buf, " %s", names[i]);
+      data &= ~(1u << i);
+    }
+
+  if (data)
+    bsprintf(buf, " %08x", data);
+
+  return;
+}
+
 static inline void
-opaque_format(struct adata *ad, byte *buf, unsigned int size)
+opaque_format(struct adata *ad, byte *buf, uint size)
 {
   byte *bound = buf + size - 10;
-  int i;
+  uint i;
 
   for(i = 0; i < ad->length; i++)
     {
@@ -661,6 +828,18 @@ ea_show_ec_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end)
     }
 }
 
+static inline void
+ea_show_lc_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end)
+{
+  int i = lc_set_format(ad, 0, pos, end - pos);
+  cli_printf(c, -1012, "\t%s", buf);
+  while (i)
+    {
+      i = lc_set_format(ad, i, buf, end - buf - 1);
+      cli_printf(c, -1012, "\t\t%s", buf);
+    }
+}
+
 /**
  * ea_show - print an &eattr to CLI
  * @c: destination CLI
@@ -690,7 +869,7 @@ ea_show(struct cli *c, eattr *e)
     }
   else if (EA_PROTO(e->id))
     pos += bsprintf(pos, "%02x.", EA_PROTO(e->id));
-  else 
+  else
     status = get_generic_attr(e, &pos, end - pos);
 
   if (status < GA_NAME)
@@ -716,12 +895,18 @@ ea_show(struct cli *c, eattr *e)
        case EAF_TYPE_AS_PATH:
          as_path_format(ad, pos, end - pos);
          break;
+       case EAF_TYPE_BITFIELD:
+         bsprintf(pos, "%08x", e->u.data);
+         break;
        case EAF_TYPE_INT_SET:
          ea_show_int_set(c, ad, 1, pos, buf, end);
          return;
        case EAF_TYPE_EC_SET:
          ea_show_ec_set(c, ad, pos, buf, end);
          return;
+       case EAF_TYPE_LC_SET:
+         ea_show_lc_set(c, ad, pos, buf, end);
+         return;
        case EAF_TYPE_UNDEF:
        default:
          bsprintf(pos, "<type %02x>", e->type);
@@ -784,7 +969,7 @@ ea_dump(ea_list *e)
  * ea_hash() takes an extended attribute list and calculated a hopefully
  * uniformly distributed hash value from its contents.
  */
-inline unsigned int
+inline uint
 ea_hash(ea_list *e)
 {
   u32 h = 0;
@@ -846,10 +1031,10 @@ ea_append(ea_list *to, ea_list *what)
  *     rta's
  */
 
-static unsigned int rta_cache_count;
-static unsigned int rta_cache_size = 32;
-static unsigned int rta_cache_limit;
-static unsigned int rta_cache_mask;
+static uint rta_cache_count;
+static uint rta_cache_size = 32;
+static uint rta_cache_limit;
+static uint rta_cache_mask;
 static rta **rta_hash_table;
 
 static void
@@ -863,10 +1048,10 @@ rta_alloc_hash(void)
   rta_cache_mask = rta_cache_size - 1;
 }
 
-static inline unsigned int
+static inline uint
 rta_hash(rta *a)
 {
-  return (((unsigned) a->src) ^ ipa_hash(a->gw) ^
+  return (((uint) (uintptr_t) a->src) ^ ipa_hash(a->gw) ^
          mpnh_hash(a->nexthops) ^ ea_hash(a->eattrs)) & 0xffff;
 }
 
@@ -903,7 +1088,7 @@ rta_copy(rta *o)
 static inline void
 rta_insert(rta *r)
 {
-  unsigned int h = r->hash_key & rta_cache_mask;
+  uint h = r->hash_key & rta_cache_mask;
   r->next = rta_hash_table[h];
   if (r->next)
     r->next->pprev = &r->next;
@@ -914,8 +1099,8 @@ rta_insert(rta *r)
 static void
 rta_rehash(void)
 {
-  unsigned int ohs = rta_cache_size;
-  unsigned int h;
+  uint ohs = rta_cache_size;
+  uint h;
   rta *r, *n;
   rta **oht = rta_hash_table;
 
@@ -948,7 +1133,7 @@ rta *
 rta_lookup(rta *o)
 {
   rta *r;
-  unsigned int h;
+  uint h;
 
   ASSERT(!(o->aflags & RTAF_CACHED));
   if (o->eattrs)
@@ -996,6 +1181,16 @@ rta__free(rta *a)
   sl_free(rta_slab, a);
 }
 
+rta *
+rta_do_cow(rta *o, linpool *lp)
+{
+  rta *r = lp_alloc(lp, sizeof(rta));
+  memcpy(r, o, sizeof(rta));
+  r->aflags = 0;
+  r->uc = 0;
+  return r;
+}
+
 /**
  * rta_dump - dump route attributes
  * @a: attribute structure to dump
@@ -1008,7 +1203,7 @@ rta_dump(rta *a)
   static char *rts[] = { "RTS_DUMMY", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE",
                         "RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP",
                         "RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1",
-                         "RTS_OSPF_EXT2", "RTS_BGP" };
+                         "RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" };
   static char *rtc[] = { "", " BC", " MC", " AC" };
   static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
 
@@ -1039,7 +1234,7 @@ void
 rta_dump_all(void)
 {
   rta *a;
-  unsigned int h;
+  uint h;
 
   debug("Route attribute cache (%d entries, rehash at %d):\n", rta_cache_count, rta_cache_limit);
   for(h=0; h<rta_cache_size; h++)