]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixed attributes normalization with underlays in place
authorMaria Matejka <mq@ucw.cz>
Sun, 28 Jan 2024 12:09:48 +0000 (13:09 +0100)
committerMaria Matejka <mq@ucw.cz>
Sun, 28 Jan 2024 12:16:25 +0000 (13:16 +0100)
nest/rt-attr.c
nest/rt-table.c

index d8a91e39647cc2018a8b7045cbcc41432cc5da1b..e6f70ad8d86a70f39424bb2000f0fa722b449a9b 100644 (file)
@@ -899,6 +899,8 @@ ea_do_sort(ea_list *e)
   while (ss);
 }
 
+static _Bool eattr_same_value(const eattr *a, const eattr *b);
+
 /**
  * In place discard duplicates and undefs in sorted ea_list. We use stable sort
  * for this reason.
@@ -909,6 +911,30 @@ ea_do_prune(ea_list *e)
   eattr *s, *d, *l, *s0;
   int i = 0;
 
+#if 0
+  debug("[[prune]] ");
+  ea_dump(e);
+  debug(" ----> ");
+#endif
+
+  /* Prepare underlay stepper */
+  uint ulc = 0;
+  for (ea_list *u = e->next; u; u = u->next)
+    ulc++;
+
+  struct { eattr *cur, *end; } uls[ulc];
+  {
+    ea_list *u = e->next;
+    for (uint i = 0; i < ulc; i++)
+    {
+      ASSERT_DIE(u->flags & EALF_SORTED);
+      uls[i].cur = u->attrs;
+      uls[i].end = u->attrs + u->count;
+      u = u->next;
+      /* debug(" [[prev %d: %p to %p]] ", i, uls[i].cur, uls[i].end); */
+    }
+  }
+
   s = d = e->attrs;        /* Beginning of the list. @s is source, @d is destination. */
   l = e->attrs + e->count;  /* End of the list */
 
@@ -919,11 +945,38 @@ ea_do_prune(ea_list *e)
       /* Find a consecutive block of the same attribute */
       while (s < l && s->id == s[-1].id)
        s++;
-
       /* Now s0 is the most recent version, s[-1] the oldest one */
-      /* Drop undefs unless this is a true overlay */
-      if (s0->undef && (s[-1].undef || !e->next))
+
+      /* Find the attribute's underlay version */
+      eattr *prev = NULL;
+      for (uint i = 0; i < ulc; i++)
+      {
+       while ((uls[i].cur < uls[i].end) && (uls[i].cur->id < s0->id))
+       {
+         uls[i].cur++;
+         /* debug(" [[prev %d: %p (%s/%d)]] ", i, uls[i].cur, ea_class_global[uls[i].cur->id]->name, uls[i].cur->id); */
+       }
+
+       if ((uls[i].cur >= uls[i].end) || (uls[i].cur->id > s0->id))
+         continue;
+
+       prev = uls[i].cur;
+       break;
+      }
+
+      /* Drop identicals */
+      if (prev && eattr_same_value(s0, prev))
+      {
+       /* debug(" [[drop identical %s]] ", ea_class_global[s0->id]->name); */
+       continue;
+      }
+
+      /* Drop undefs (identical undefs already dropped before) */
+      if (!prev && s0->undef)
+      {
+       /* debug(" [[drop undef %s]] ", ea_class_global[s0->id]->name); */
        continue;
+      }
 
       /* Copy the newest version to destination */
       *d = *s0;
@@ -1027,13 +1080,52 @@ ea_merge(ea_list *e, ea_list *t, int overlay)
 ea_list *
 ea_normalize(ea_list *e, int overlay)
 {
+#if 0
+  debug("(normalize)");
+  ea_dump(e);
+  debug(" ----> ");
+#endif
   ea_list *t = tmp_alloc(ea_scan(e, overlay));
   ea_merge(e, t, overlay);
   ea_sort(t);
+#if 0
+  ea_dump(t);
+  debug("\n");
+#endif
 
   return t->count ? t : t->next;
 }
 
+static _Bool
+eattr_same_value(const eattr *a, const eattr *b)
+{
+  if (
+      a->id != b->id ||
+      a->flags != b->flags ||
+      a->type != b->type ||
+      a->undef != b->undef
+    )
+    return 0;
+
+  if (a->undef)
+    return 1;
+
+  if (a->type & EAF_EMBEDDED)
+    return a->u.data == b->u.data;
+  else
+    return adata_same(a->u.ptr, b->u.ptr);
+}
+
+static _Bool
+eattr_same(const eattr *a, const eattr *b)
+{
+  return
+    eattr_same_value(a, b) &&
+    a->originated == b->originated &&
+    a->fresh == b->fresh;
+}
+
+
 /**
  * ea_same - compare two &ea_list's
  * @x: attribute list
@@ -1054,19 +1146,8 @@ ea_same(ea_list *x, ea_list *y)
   if (x->count != y->count)
     return 0;
   for(c=0; c<x->count; c++)
-    {
-      eattr *a = &x->attrs[c];
-      eattr *b = &y->attrs[c];
-
-      if (a->id != b->id ||
-         a->flags != b->flags ||
-         a->type != b->type ||
-         a->originated != b->originated ||
-         a->fresh != b->fresh ||
-         a->undef != b->undef ||
-         ((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data : !adata_same(a->u.ptr, b->u.ptr)))
-       return 0;
-    }
+    if (!eattr_same(&x->attrs[c], &y->attrs[c]))
+      return 0;
   return 1;
 }
 
@@ -1421,14 +1502,22 @@ ea_dump(ea_list *e)
       for(i=0; i<e->count; i++)
        {
          eattr *a = &e->attrs[i];
-         debug(" %04x.%02x", a->id, a->flags);
+         struct ea_class *clp = (a->id < ea_class_max) ? ea_class_global[a->id] : NULL;
+         if (clp)
+           debug(" %s", clp->name);
+         else
+           debug(" 0x%x", a->id);
+
+         debug(".%02x", a->flags);
          debug("=%c",
              "?iO?IRP???S??pE?"
              "??L???N?????????"
              "?o???r??????????" [a->type]);
          if (a->originated)
            debug("o");
-         if (a->type & EAF_EMBEDDED)
+         if (a->undef)
+           debug(":undef");
+         else if (a->type & EAF_EMBEDDED)
            debug(":%08x", a->u.data);
          else if (a->id == ea_gen_nexthop.id)
            nexthop_dump(a->u.ptr);
@@ -1439,6 +1528,7 @@ ea_dump(ea_list *e)
              for(j=0; j<len; j++)
                debug("%02x", a->u.ptr->data[j]);
            }
+         debug(" ");
        }
       if (e = e->next)
        debug(" | ");
index ea0ab99b65f28d1c35f805e016eed5325db03651..ec1cd71c5de9d4feef19d9448db4c5984a80e76e 100644 (file)
@@ -503,6 +503,12 @@ rte_store(const rte *r, struct netindex *i, struct rtable_private *tab)
   else
     e->attrs = rta_lookup(e->attrs, 1);
 
+#if 0
+  debug("(store) %N ", i->addr);
+  ea_dump(e->attrs);
+  debug("\n");
+#endif
+
   return s;
 }
 
@@ -1769,6 +1775,13 @@ rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
       ea_clone(new->attrs) :
       ea_lookup(new->attrs, 0);
 
+#if 0
+  debug("%s.%s -(prefilter)-> %s: %N ", c->proto->name, c->name, c->table->name, n);
+  if (new) ea_dump(new->attrs);
+  else debug("withdraw");
+  debug("\n");
+#endif
+
   const struct filter *filter = c->in_filter;
   struct channel_import_stats *stats = &c->import_stats;
   struct mpls_fec *fec = NULL;
@@ -2351,7 +2364,9 @@ rt_refresh_trace(struct rtable_private *tab, struct rt_import_hook *ih, const ch
 void
 rte_dump(struct rte_storage *e)
 {
-  debug("%-1N ", e->rte.net);
+  debug("(%u) %-1N", NET_TO_INDEX(e->rte.net)->index, e->rte.net);
+  debug("ID=%d ", e->rte.id);
+  debug("SENDER=%s ", e->rte.sender->req->name);
   debug("PF=%02x ", e->rte.pflags);
   debug("SRC=%uG ", e->rte.src->global_id);
   ea_dump(e->rte.attrs);