]> git.ipfire.org Git - thirdparty/bird.git/blobdiff - nest/rt-attr.c
Nest: Fix handling of ECMP next hop flags
[thirdparty/bird.git] / nest / rt-attr.c
index d3671a53857e7f51ba5384375c70a01405b43b74..d04ccfe9f86ce074e066200c269c2f08fe2cacc7 100644 (file)
 
 #include <stddef.h>
 
+const char * const rta_src_names[RTS_MAX] = {
+  [RTS_DUMMY]          = "",
+  [RTS_STATIC]         = "static",
+  [RTS_INHERIT]                = "inherit",
+  [RTS_DEVICE]         = "device",
+  [RTS_STATIC_DEVICE]  = "static-device",
+  [RTS_REDIRECT]       = "redirect",
+  [RTS_RIP]            = "RIP",
+  [RTS_OSPF]           = "OSPF",
+  [RTS_OSPF_IA]                = "OSPF-IA",
+  [RTS_OSPF_EXT1]      = "OSPF-E1",
+  [RTS_OSPF_EXT2]      = "OSPF-E2",
+  [RTS_BGP]            = "BGP",
+  [RTS_PIPE]           = "pipe",
+  [RTS_BABEL]          = "Babel",
+  [RTS_RPKI]           = "RPKI",
+};
+
+const char * rta_dest_names[RTD_MAX] = {
+  [RTD_NONE]           = "",
+  [RTD_UNICAST]                = "unicast",
+  [RTD_BLACKHOLE]      = "blackhole",
+  [RTD_UNREACHABLE]    = "unreachable",
+  [RTD_PROHIBIT]       = "prohibited",
+};
+
 pool *rta_pool;
 
 static slab *rta_slab_[4];
@@ -80,9 +106,6 @@ static struct idm src_ids;
 
 static HASH(struct rte_src) src_hash;
 
-struct protocol *attr_class_to_protocol[EAP_MAX];
-
-
 static void
 rte_src_init(void)
 {
@@ -150,7 +173,8 @@ nexthop_hash(struct nexthop *x)
   for (; x; x = x->next)
   {
     h ^= ipa_hash(x->gw) ^ (h << 5) ^ (h >> 9);
-    for (int i=0; i<x->labels; i++)
+
+    for (int i = 0; i < x->labels; i++)
       h ^= x->label[i] ^ (h << 6) ^ (h >> 7);
   }
 
@@ -162,14 +186,17 @@ nexthop__same(struct nexthop *x, struct nexthop *y)
 {
   for (; x && y; x = x->next, y = y->next)
   {
-    if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || (x->weight != y->weight) || (x->labels != y->labels))
+    if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) ||
+       (x->flags != y->flags) || (x->weight != y->weight) ||
+       (x->labels != y->labels))
       return 0;
-    for (int i=0; i<x->labels; i++)
+
+    for (int i = 0; i < x->labels; i++)
       if (x->label[i] != y->label[i])
        return 0;
   }
 
-  return 1;
+  return x == y;
 }
 
 static int
@@ -183,6 +210,8 @@ nexthop_compare_node(struct nexthop *x, struct nexthop *y)
   if (!y)
     return -1;
 
+  /* Should we also compare flags ? */
+
   r = ((int) y->weight) - ((int) x->weight);
   if (r)
     return r;
@@ -195,7 +224,7 @@ nexthop_compare_node(struct nexthop *x, struct nexthop *y)
   if (r)
     return r;
 
-  for (int i=0; i<y->labels; i++)
+  for (int i = 0; i < y->labels; i++)
   {
     r = ((int) y->label[i]) - ((int) x->label[i]);
     if (r)
@@ -271,34 +300,22 @@ nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, lin
 }
 
 void
-nexthop_insert(struct nexthop *n, struct nexthop *x)
+nexthop_insert(struct nexthop **n, struct nexthop *x)
 {
-  struct nexthop tmp;
-  memcpy(&tmp, n, sizeof(struct nexthop));
-  if (nexthop_compare_node(n, x) > 0) /* Insert to the included nexthop */
-  {
-    memcpy(n, x, sizeof(struct nexthop));
-    memcpy(x, &tmp, sizeof(struct nexthop));
-    n->next = x;
-    return;
-  }
-
-  for (struct nexthop **nn = &(n->next); *nn; nn = &((*nn)->next))
+  for (; *n; n = &((*n)->next))
   {
-    int cmp = nexthop_compare_node(*nn, x);
+    int cmp = nexthop_compare_node(*n, x);
 
     if (cmp < 0)
       continue;
-    
-    if (cmp > 0)
-    {
-      x->next = *nn;
-      *nn = x;
-    }
-    
-    return;
+    else if (cmp > 0)
+      break;
+    else
+      return;
   }
 
+  x->next = *n;
+  *n = x;
 }
 
 int
@@ -314,7 +331,7 @@ nexthop_is_sorted(struct nexthop *x)
 static inline slab *
 nexthop_slab(struct nexthop *nh)
 {
-  return nexthop_slab_[nh->labels > 2 ? 3 : nh->labels];
+  return nexthop_slab_[MIN(nh->labels, 3)];
 }
 
 static struct nexthop *
@@ -329,7 +346,11 @@ nexthop_copy(struct nexthop *o)
       n->gw = o->gw;
       n->iface = o->iface;
       n->next = NULL;
+      n->flags = o->flags;
       n->weight = o->weight;
+      n->labels = o->labels;
+      for (int i=0; i<o->labels; i++)
+       n->label[i] = o->label[i];
 
       *last = n;
       last = &(n->next);
@@ -548,29 +569,47 @@ ea_do_sort(ea_list *e)
   while (ss);
 }
 
+/**
+ * In place discard duplicates, undefs and temporary attributes in sorted
+ * ea_list. We use stable sort for this reason.
+ **/
 static inline void
 ea_do_prune(ea_list *e)
 {
   eattr *s, *d, *l, *s0;
   int i = 0;
 
-  /* Discard duplicates and undefs. Do you remember sorting was stable? */
-  s = d = e->attrs;
-  l = e->attrs + e->count;
+  s = d = e->attrs;        /* Beginning of the list. @s is source, @d is destination. */
+  l = e->attrs + e->count;  /* End of the list */
+
+  /* Walk from begin to end. */
   while (s < l)
     {
       s0 = s++;
+      /* Find a consecutive block of the same attribute */
       while (s < l && s->id == s[-1].id)
        s++;
-      /* s0 is the most recent version, s[-1] the oldest one */
-      if ((s0->type & EAF_TYPE_MASK) != EAF_TYPE_UNDEF)
-       {
-         *d = *s0;
-         d->type = (d->type & ~(EAF_ORIGINATED|EAF_FRESH)) | (s[-1].type & EAF_ORIGINATED);
-         d++;
-         i++;
-       }
+
+      /* Now s0 is the most recent version, s[-1] the oldest one */
+      /* Drop undefs */
+      if ((s0->type & EAF_TYPE_MASK) == EAF_TYPE_UNDEF)
+       continue;
+
+      /* Drop temporary attributes */
+      if (s0->type & EAF_TEMP)
+       continue;
+
+      /* Copy the newest version to destination */
+      *d = *s0;
+
+      /* Preserve info whether it originated locally */
+      d->type = (d->type & ~(EAF_ORIGINATED|EAF_FRESH)) | (s[-1].type & EAF_ORIGINATED);
+
+      /* Next destination */
+      d++;
+      i++;
     }
+
   e->count = i;
 }
 
@@ -846,7 +885,18 @@ ea_show(struct cli *c, eattr *e)
   byte buf[CLI_MSG_SIZE];
   byte *pos = buf, *end = buf + sizeof(buf);
 
-  if (p = attr_class_to_protocol[EA_PROTO(e->id)])
+  if (EA_IS_CUSTOM(e->id))
+    {
+      const char *name = ea_custom_name(e->id);
+      if (name)
+        {
+         pos += bsprintf(pos, "%s", name);
+         status = GA_NAME;
+       }
+      else
+       pos += bsprintf(pos, "%02x.", EA_PROTO(e->id));
+    }
+  else if (p = class_to_protocol[EA_PROTO(e->id)])
     {
       pos += bsprintf(pos, "%s.", p->name);
       if (p->get_attr)
@@ -1126,15 +1176,7 @@ rta_lookup(rta *o)
 
   ASSERT(!(o->aflags & RTAF_CACHED));
   if (o->eattrs)
-    {
-      if (o->eattrs->next)     /* Multiple ea_list's, need to merge them */
-       {
-         ea_list *ml = alloca(ea_scan(o->eattrs));
-         ea_merge(o->eattrs, ml);
-         o->eattrs = ml;
-       }
-      ea_sort(o->eattrs);
-    }
+    ea_normalize(o->eattrs);
 
   h = rta_hash(o);
   for(r=rta_hash_table[h & rta_cache_mask]; r; r=r->next)
@@ -1162,12 +1204,12 @@ rta__free(rta *a)
   *a->pprev = a->next;
   if (a->next)
     a->next->pprev = a->pprev;
-  a->aflags = 0;               /* Poison the entry */
   rt_unlock_hostentry(a->hostentry);
   rt_unlock_source(a->src);
   if (a->nh.next)
     nexthop_free(a->nh.next);
   ea_free(a->eattrs);
+  a->aflags = 0;               /* Poison the entry */
   sl_free(rta_slab(a), a);
 }
 
@@ -1176,6 +1218,12 @@ rta_do_cow(rta *o, linpool *lp)
 {
   rta *r = lp_alloc(lp, rta_size(o));
   memcpy(r, o, rta_size(o));
+  for (struct nexthop **nhn = &(r->nh.next), *nho = o->nh.next; nho; nho = nho->next)
+    {
+      *nhn = lp_alloc(lp, nexthop_size(nho));
+      memcpy(*nhn, nho, nexthop_size(nho));
+      nhn = &((*nhn)->next);
+    }
   r->aflags = 0;
   r->uc = 0;
   return r;
@@ -1193,7 +1241,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_PIPE", "RTS_BABEL" };
+                        "RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" };
   static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
 
   debug("p=%s uc=%d %s %s%s h=%04x",
@@ -1242,17 +1290,12 @@ rta_dump_all(void)
 }
 
 void
-rta_show(struct cli *c, rta *a, ea_list *eal)
+rta_show(struct cli *c, rta *a)
 {
-  static char *src_names[] = { "dummy", "static", "inherit", "device", "static-device", "redirect",
-                              "RIP", "OSPF", "OSPF-IA", "OSPF-E1", "OSPF-E2", "BGP", "pipe" };
-  int i;
+  cli_printf(c, -1008, "\tType: %s %s", rta_src_names[a->source], ip_scope_text(a->scope));
 
-  cli_printf(c, -1008, "\tType: %s %s", src_names[a->source], ip_scope_text(a->scope));
-  if (!eal)
-    eal = a->eattrs;
-  for(; eal; eal=eal->next)
-    for(i=0; i<eal->count; i++)
+  for(ea_list *eal = a->eattrs; eal; eal=eal->next)
+    for(int i=0; i<eal->count; i++)
       ea_show(c, &eal->attrs[i]);
 }
 
@@ -1270,12 +1313,12 @@ rta_init(void)
   rta_slab_[0] = sl_new(rta_pool, sizeof(rta));
   rta_slab_[1] = sl_new(rta_pool, sizeof(rta) + sizeof(u32));
   rta_slab_[2] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)*2);
-  rta_slab_[3] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)*NEXTHOP_MAX_LABEL_STACK);
+  rta_slab_[3] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)*MPLS_MAX_LABEL_STACK);
 
   nexthop_slab_[0] = sl_new(rta_pool, sizeof(struct nexthop));
   nexthop_slab_[1] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32));
   nexthop_slab_[2] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)*2);
-  nexthop_slab_[3] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)*NEXTHOP_MAX_LABEL_STACK);
+  nexthop_slab_[3] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK);
 
   rta_alloc_hash();
   rte_src_init();