]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Route attribute storage keeps the previous layers
authorMaria Matejka <mq@ucw.cz>
Thu, 16 Jun 2022 21:24:53 +0000 (23:24 +0200)
committerMaria Matejka <mq@ucw.cz>
Fri, 17 Jun 2022 08:55:23 +0000 (10:55 +0200)
lib/attrs.h
lib/route.h
nest/rt-attr.c
nest/rt-show.c
proto/bgp/attrs.c
proto/mrt/mrt.c

index 79b7b14a4f817ebb852f9a632f016f39a96ea1b5..a75abcd3081b7cb694a4c5d21332eaf7e6f93008 100644 (file)
@@ -42,7 +42,7 @@ lp_store_adata(struct linpool *pool, const void *buf, uint len)
 #define tmp_copy_adata(ad)       tmp_store_adata((ad)->data, (ad)->length)
 
 static inline int adata_same(const struct adata *a, const struct adata *b)
-{ return (a->length == b->length && !memcmp(a->data, b->data, a->length)); }
+{ return (!a && !b) || (a->length == b->length && !memcmp(a->data, b->data, a->length)); }
 
 
 
index 1b2f4de6e03b12317e47839e9ad6a24e2516da19..7e28b91e3d1488b4d966b4ce8839608464838695 100644 (file)
@@ -237,7 +237,7 @@ ea_list *ea_append(ea_list *to, ea_list *what);
 void ea_format_bitfield(const struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
 
 /* Normalize ea_list; allocates the result from tmp_linpool */
-ea_list *ea_normalize(const ea_list *e);
+ea_list *ea_normalize(ea_list *e, int overlay);
 
 uint ea_list_size(ea_list *);
 void ea_list_copy(ea_list *dest, ea_list *src, uint size);
@@ -414,7 +414,7 @@ static inline int rte_dest(const rte *r)
 
 void rta_init(void);
 ea_list *ea_lookup(ea_list *);         /* Get a cached (and normalized) variant of this attribute list */
-static inline int ea_is_cached(ea_list *r) { return r->flags & EALF_CACHED; }
+static inline int ea_is_cached(const ea_list *r) { return r->flags & EALF_CACHED; }
 static inline ea_list *ea_clone(ea_list *r) { r->uc++; return r; }
 void ea__free(ea_list *r);
 static inline void ea_free(ea_list *r) { if (r && !--r->uc) ea__free(r); }
index 31e2057e2adfa1aff90a795f72be7d96e1845418..c0f81b9d41bee27e2040e05831edf287af1749da 100644 (file)
@@ -726,8 +726,8 @@ ea_do_prune(ea_list *e)
        s++;
 
       /* Now s0 is the most recent version, s[-1] the oldest one */
-      /* Drop undefs */
-      if (s0->undef)
+      /* Drop undefs unless this is a true overlay */
+      if (s0->undef && !e->next)
        continue;
 
       /* Copy the newest version to destination */
@@ -760,18 +760,15 @@ ea_do_prune(ea_list *e)
 static void
 ea_sort(ea_list *e)
 {
-  while (e)
-    {
-      if (!(e->flags & EALF_SORTED))
-       {
-         ea_do_sort(e);
-         ea_do_prune(e);
-         e->flags |= EALF_SORTED;
-       }
-      if (e->count > 5)
-       e->flags |= EALF_BISECT;
-      e = e->next;
-    }
+  if (!(e->flags & EALF_SORTED))
+  {
+    ea_do_sort(e);
+    ea_do_prune(e);
+    e->flags |= EALF_SORTED;
+  }
+
+  if (e->count > 5)
+    e->flags |= EALF_BISECT;
 }
 
 /**
@@ -782,7 +779,7 @@ ea_sort(ea_list *e)
  * a given &ea_list after merging with ea_merge().
  */
 static unsigned
-ea_scan(const ea_list *e)
+ea_scan(const ea_list *e, int overlay)
 {
   unsigned cnt = 0;
 
@@ -790,6 +787,8 @@ ea_scan(const ea_list *e)
     {
       cnt += e->count;
       e = e->next;
+      if (e && overlay && ea_is_cached(e))
+       break;
     }
   return sizeof(ea_list) + sizeof(eattr)*cnt;
 }
@@ -809,27 +808,32 @@ ea_scan(const ea_list *e)
  * by calling ea_sort().
  */
 static void
-ea_merge(const ea_list *e, ea_list *t)
+ea_merge(ea_list *e, ea_list *t, int overlay)
 {
   eattr *d = t->attrs;
 
   t->flags = 0;
   t->count = 0;
-  t->next = NULL;
+
   while (e)
     {
       memcpy(d, e->attrs, sizeof(eattr)*e->count);
       t->count += e->count;
       d += e->count;
       e = e->next;
+
+      if (e && overlay && ea_is_cached(e))
+       break;
     }
+
+  t->next = e;
 }
 
 ea_list *
-ea_normalize(const ea_list *e)
+ea_normalize(ea_list *e, int overlay)
 {
-  ea_list *t = tmp_alloc(ea_scan(e));
-  ea_merge(e, t);
+  ea_list *t = tmp_alloc(ea_scan(e, overlay));
+  ea_merge(e, t, overlay);
   ea_sort(t);
 
   return t->count ? t : NULL;
@@ -850,7 +854,8 @@ ea_same(ea_list *x, ea_list *y)
 
   if (!x || !y)
     return x == y;
-  ASSERT(!x->next && !y->next);
+  if (x->next != y->next)
+    return 0;
   if (x->count != y->count)
     return 0;
   for(c=0; c<x->count; c++)
@@ -876,13 +881,12 @@ ea_list_size(ea_list *o)
   unsigned i, elen;
 
   ASSERT_DIE(o);
-  ASSERT_DIE(!o->next);
   elen = BIRD_CPU_ALIGN(sizeof(ea_list) + sizeof(eattr) * o->count);
 
   for(i=0; i<o->count; i++)
     {
       eattr *a = &o->attrs[i];
-      if (!(a->type & EAF_EMBEDDED))
+      if (!a->undef && !(a->type & EAF_EMBEDDED))
        elen += ADATA_SIZE(a->u.ptr->length);
     }
 
@@ -899,7 +903,7 @@ ea_list_copy(ea_list *n, ea_list *o, uint elen)
   for(uint i=0; i<o->count; i++)
     {
       eattr *a = &n->attrs[i];
-      if (!(a->type & EAF_EMBEDDED))
+      if (!a->undef && !(a->type & EAF_EMBEDDED))
        {
          unsigned size = ADATA_SIZE(a->u.ptr->length);
          ASSERT_DIE(adpos + size <= elen);
@@ -923,12 +927,21 @@ ea_list_ref(ea_list *l)
       eattr *a = &l->attrs[i];
       ASSERT_DIE(a->id < ea_class_max);
 
+      if (a->undef)
+       continue;
+
       struct ea_class *cl = ea_class_global[a->id];
       ASSERT_DIE(cl && cl->uc);
 
       CALL(cl->stored, a);
       cl->uc++;
     }
+
+  if (l->next)
+  {
+    ASSERT_DIE(ea_is_cached(l->next));
+    ea_clone(l->next);
+  }
 }
 
 static void
@@ -939,6 +952,9 @@ ea_list_unref(ea_list *l)
       eattr *a = &l->attrs[i];
       ASSERT_DIE(a->id < ea_class_max);
 
+      if (a->undef)
+       continue;
+
       struct ea_class *cl = ea_class_global[a->id];
       ASSERT_DIE(cl && cl->uc);
 
@@ -946,6 +962,9 @@ ea_list_unref(ea_list *l)
       if (!--cl->uc)
        ea_class_free(cl);
     }
+
+  if (l->next)
+    ea_free(l->next);
 }
 
 void
@@ -1183,11 +1202,13 @@ ea_hash(ea_list *e)
 
   if (e)                       /* Assuming chain of length 1 */
     {
-      ASSERT_DIE(!e->next);
+      h ^= mem_hash(&e->next, sizeof(e->next));
       for(i=0; i<e->count; i++)
        {
          struct eattr *a = &e->attrs[i];
          h ^= a->id; h *= mul;
+         if (a->undef)
+           continue;
          if (a->type & EAF_EMBEDDED)
            h ^= a->u.data;
          else
@@ -1295,7 +1316,7 @@ ea_lookup(ea_list *o)
   uint h;
 
   ASSERT(!ea_is_cached(o));
-  o = ea_normalize(o);
+  o = ea_normalize(o, 1);
   h = ea_hash(o);
 
   for(r=rta_hash_table[h & rta_cache_mask]; r; r=r->next_hash)
@@ -1328,7 +1349,6 @@ ea__free(ea_list *a)
   if (a->next_hash)
     a->next_hash->pprev_hash = a->pprev_hash;
 
-  ASSERT(!a->next);
   ea_list_unref(a);
   mb_free(a);
 }
index 35036fe6a0e85c2cbb34f43e33ea7decf49c5bb7..8bf74754f2553fb5e19be77224ae17613cec6756 100644 (file)
@@ -60,7 +60,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
 
   /* Need to normalize the extended attributes */
   if (d->verbose && !rta_is_cached(a) && a)
-    a = ea_normalize(a);
+    a = ea_normalize(a, 0);
 
   get_route_info = e->src->proto->proto->get_route_info;
   if (get_route_info)
index 6d33ef2e407ffacb0bf7fc52809fb3cd8a2ab90d..46e949bf5abb045e2796899628ca87ca3b91a7ea 100644 (file)
@@ -1253,10 +1253,10 @@ bgp_export_attr(struct bgp_export_state *s, eattr *a, ea_list *to)
  * Result: one sorted attribute list segment, or NULL if attributes are unsuitable.
  */
 static inline ea_list *
-bgp_export_attrs(struct bgp_export_state *s, const ea_list *a)
+bgp_export_attrs(struct bgp_export_state *s, ea_list *a)
 {
   /* Merge the attribute list */
-  ea_list *new = ea_normalize(a);
+  ea_list *new = ea_normalize(a, 0);
   ASSERT_DIE(new);
 
   uint i, count;
index fcc1dcfe4266a9fd3b66b96319013fd86f4f9800..fcbe317b4ffe95476cf51c445ab6b9241d4da28f 100644 (file)
@@ -431,7 +431,7 @@ mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r)
 
   /* Attribute list must be normalized for bgp_encode_attrs() */
   if (!rta_is_cached(r->attrs))
-    eattrs = ea_normalize(eattrs);
+    eattrs = ea_normalize(eattrs, 0);
 
   mrt_buffer_need(b, MRT_ATTR_BUFFER_SIZE);
   byte *pos = b->pos;