]> 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 761ba9fe8faaa6656323cb50a990c2a9564e72cb..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",
@@ -88,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)
 {
@@ -331,6 +346,7 @@ 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++)
@@ -553,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;
 }
 
@@ -851,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)
@@ -1131,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)
@@ -1204,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",
@@ -1253,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]);
 }