]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixing a refeed inconsistency
authorMaria Matejka <mq@ucw.cz>
Mon, 17 Feb 2025 20:37:46 +0000 (21:37 +0100)
committerKaterina Kubecova <katerina.kubecova@nic.cz>
Mon, 24 Feb 2025 09:52:53 +0000 (10:52 +0100)
On refeed, the table should not resend any obsolete routes
which have already been seen by the recipient, nor the appropriate
journal items.

nest/route.h
nest/rt-export.c
nest/rt-table.c
proto/bgp/attrs.c

index fd46b04297aae9e756b808d035da688c664a57db..196e78b01de3c0315f66955e77270c375a1c88c6 100644 (file)
@@ -222,7 +222,7 @@ struct rt_exporter {
   netindex_hash *netindex;                     /* Table for net <-> id conversion */
   void (*stopped)(struct rt_exporter *);       /* Callback when exporter can stop */
   void (*cleanup_done)(struct rt_exporter *, u64 end); /* Callback when cleanup has been done */
-  struct rt_export_feed *(*feed_net)(struct rt_exporter *, struct rcu_unwinder *, u32, bool (*)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *, const struct rt_export_item *first);
+  struct rt_export_feed *(*feed_net)(struct rt_exporter *, struct rcu_unwinder *, u32, struct bmap *, bool (*)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *, const struct rt_export_item *first);
   void (*feed_cleanup)(struct rt_exporter *, struct rt_export_feeder *);
 };
 
@@ -243,9 +243,9 @@ void rt_feeder_subscribe(struct rt_exporter *, struct rt_export_feeder *);
 void rt_feeder_unsubscribe(struct rt_export_feeder *);
 void rt_export_refeed_feeder(struct rt_export_feeder *, struct rt_feeding_request *);
 
-struct rt_export_feed *rt_export_next_feed(struct rt_export_feeder *);
+struct rt_export_feed *rt_export_next_feed(struct rt_export_feeder *, struct bmap *seen);
 #define RT_FEED_WALK(_feeder, _f)      \
-  for (const struct rt_export_feed *_f; _f = rt_export_next_feed(_feeder); ) \
+  for (const struct rt_export_feed *_f; _f = rt_export_next_feed(_feeder, NULL); ) \
 
 static inline bool rt_export_feed_active(struct rt_export_feeder *f)
 { return !!atomic_load_explicit(&f->exporter, memory_order_acquire); }
index 7d51e54cfd96862a6bc9acdd817230cd0d14984f..b5e7facbd1c2a58389acd7f4f123c496f9340d26 100644 (file)
@@ -100,7 +100,7 @@ rt_export_get(struct rt_export_request *r)
        rtex_trace(r, D_ROUTES, "Export drained");
        return NULL;
       }
-      else if (feed = rt_export_next_feed(&r->feeder))
+      else if (feed = rt_export_next_feed(&r->feeder, &r->seq_map))
       {
        /* Feeding more */
        rtex_trace(r, D_ROUTES, "Feeding %N", feed->ni->addr);
@@ -147,13 +147,13 @@ rt_export_get(struct rt_export_request *r)
       if (r->feeder.domain.rtable)
       {
        LOCK_DOMAIN(rtable, r->feeder.domain);
-       feed = e->feed_net(e, NULL, ni->index, NULL, NULL, update);
+       feed = e->feed_net(e, NULL, ni->index, &r->seq_map, NULL, NULL, update);
        UNLOCK_DOMAIN(rtable, r->feeder.domain);
       }
       else
       {
        RCU_ANCHOR(u);
-       feed = e->feed_net(e, u, ni->index, NULL, NULL, update);
+       feed = e->feed_net(e, u, ni->index, &r->seq_map, NULL, NULL, update);
       }
 
       ASSERT_DIE(feed && (feed != &rt_feed_index_out_of_range));
@@ -249,7 +249,7 @@ rt_alloc_feed(uint routes, uint exports)
 }
 
 static struct rt_export_feed *
-rt_export_get_next_feed(struct rt_export_feeder *f, struct rcu_unwinder *u)
+rt_export_get_next_feed(struct rt_export_feeder *f, struct rcu_unwinder *u, struct bmap *seen)
 {
   for (uint retry = 0; retry < (u ? 1024 : ~0U); retry++)
   {
@@ -262,7 +262,7 @@ rt_export_get_next_feed(struct rt_export_feeder *f, struct rcu_unwinder *u)
       return NULL;
     }
 
-    struct rt_export_feed *feed = e->feed_net(e, u, f->feed_index,
+    struct rt_export_feed *feed = e->feed_net(e, u, f->feed_index, seen,
        rt_net_is_feeding_feeder, f, NULL);
     if (feed == &rt_feed_index_out_of_range)
     {
@@ -290,7 +290,7 @@ rt_export_get_next_feed(struct rt_export_feeder *f, struct rcu_unwinder *u)
 }
 
 struct rt_export_feed *
-rt_export_next_feed(struct rt_export_feeder *f)
+rt_export_next_feed(struct rt_export_feeder *f, struct bmap *seen)
 {
   ASSERT_DIE(f);
 
@@ -298,13 +298,13 @@ rt_export_next_feed(struct rt_export_feeder *f)
   if (f->domain.rtable)
   {
     LOCK_DOMAIN(rtable, f->domain);
-    feed = rt_export_get_next_feed(f, NULL);
+    feed = rt_export_get_next_feed(f, NULL, seen);
     UNLOCK_DOMAIN(rtable, f->domain);
   }
   else
   {
     RCU_ANCHOR(u);
-    feed = rt_export_get_next_feed(f, u);
+    feed = rt_export_get_next_feed(f, u, seen);
   }
 
   if (feed)
@@ -342,7 +342,7 @@ rt_export_next_feed(struct rt_export_feeder *f)
 
   f->feeding = f->feed_pending;
   f->feed_pending = NULL;
-  return rt_export_next_feed(f);
+  return rt_export_next_feed(f, seen);
 }
 
 static void
index 27c8c2c6e5bbafcfbff4eb8546c93f0ad6f937d5..a2082e620d718a7368edc002f7c13f0e7c48e7b8 100644 (file)
@@ -2445,7 +2445,7 @@ rt_net_feed_validate_first(
 }
 
 static struct rt_export_feed *
-rt_net_feed_index(struct rtable_reading *tr, net *n, bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_pending_export *first)
+rt_net_feed_index(struct rtable_reading *tr, net *n, struct bmap *seen, bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_pending_export *first)
 {
   /* Get the feed itself. It may change under our hands tho. */
   struct rt_pending_export *first_in_net, *last_in_net;
@@ -2460,11 +2460,12 @@ rt_net_feed_index(struct rtable_reading *tr, net *n, bool (*prefilter)(struct rt
   uint ocnt = 0;
   for (const struct rt_pending_export *rpe = first; rpe;
       rpe = atomic_load_explicit(&rpe->next, memory_order_acquire))
-  {
-    ecnt++;
-    if (rpe->it.old)
-      ocnt++;
-  }
+    if (!seen || !bmap_test(seen, rpe->it.seq))
+    {
+      ecnt++;
+      if (rpe->it.old)
+       ocnt++;
+    }
 
   if (ecnt) {
     const net_addr *a = (first->it.new ?: first->it.old)->net;
@@ -2492,7 +2493,7 @@ rt_net_feed_index(struct rtable_reading *tr, net *n, bool (*prefilter)(struct rt
          rpe = atomic_load_explicit(&rpe->next, memory_order_acquire))
        if (e >= ecnt)
          RT_READ_RETRY(tr);
-       else
+       else if (!seen || !bmap_test(seen, rpe->it.seq))
        {
          feed->exports[e++] = rpe->it.seq;
 
@@ -2521,13 +2522,13 @@ rt_net_feed_index(struct rtable_reading *tr, net *n, bool (*prefilter)(struct rt
 }
 
 static struct rt_export_feed *
-rt_net_feed_internal(struct rtable_reading *tr, u32 index, bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_pending_export *first)
+rt_net_feed_internal(struct rtable_reading *tr, u32 index, struct bmap *seen, bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_pending_export *first)
 {
   net *n = rt_net_feed_get_net(tr, index);
   if (!n)
     return &rt_feed_index_out_of_range;
 
-  return rt_net_feed_index(tr, n, prefilter, f, first);
+  return rt_net_feed_index(tr, n, seen, prefilter, f, first);
 }
 
 struct rt_export_feed *
@@ -2535,14 +2536,14 @@ rt_net_feed(rtable *t, const net_addr *a, const struct rt_pending_export *first)
 {
   RT_READ(t, tr);
   const struct netindex *ni = net_find_index(tr->t->netindex, a);
-  return ni ? rt_net_feed_internal(tr, ni->index, NULL, NULL, first) : NULL;
+  return ni ? rt_net_feed_internal(tr, ni->index, NULL, NULL, NULL, first) : NULL;
 }
 
 static struct rt_export_feed *
-rt_feed_net_all(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_export_item *_first)
+rt_feed_net_all(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, struct bmap *seen, bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_export_item *_first)
 {
   RT_READ_ANCHORED(SKIP_BACK(rtable, export_all, e), tr, u);
-  return rt_net_feed_internal(tr, index, prefilter, f, SKIP_BACK(const struct rt_pending_export, it, _first));
+  return rt_net_feed_internal(tr, index, seen, prefilter, f, SKIP_BACK(const struct rt_pending_export, it, _first));
 }
 
 rte
@@ -2567,7 +2568,7 @@ rt_net_best(rtable *t, const net_addr *a)
 }
 
 static struct rt_export_feed *
-rt_feed_net_best(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_export_item *_first)
+rt_feed_net_best(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, struct bmap *seen, bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_export_item *_first)
 {
   SKIP_BACK_DECLARE(rtable, t, export_best, e);
   SKIP_BACK_DECLARE(const struct rt_pending_export, first, it, _first);
@@ -2591,11 +2592,12 @@ rt_feed_net_best(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, bool
   uint ecnt = 0, ocnt = 0;
   for (const struct rt_pending_export *rpe = first; rpe;
       rpe = atomic_load_explicit(&rpe->next, memory_order_acquire))
-  {
-    ecnt++;
-    if (rpe->it.old && (!best || (rpe->it.old != &best->rte)))
-      ocnt++;
-  }
+    if (!seen || !bmap_test(seen, rpe->it.seq))
+    {
+      ecnt++;
+      if (rpe->it.old && (!best || (rpe->it.old != &best->rte)))
+       ocnt++;
+    }
 
   if (ecnt) {
     const net_addr *a = (first->it.new ?: first->it.old)->net;
@@ -2623,7 +2625,7 @@ rt_feed_net_best(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, bool
        rpe = atomic_load_explicit(&rpe->next, memory_order_acquire))
       if (e >= ecnt)
        RT_READ_RETRY(tr);
-      else
+      else if (!seen || !bmap_test(seen, rpe->it.seq))
       {
        feed->exports[e++] = rpe->it.seq;
        if (rpe->it.old && (!best || (rpe->it.old != &best->rte)))
index d4c465ffd61f180a5da5d909a52f33925de59f42..68394247ebe02a5fedacc7047e5ca55849a86fc5 100644 (file)
@@ -2009,7 +2009,7 @@ bgp_out_item_done(struct lfjour *j UNUSED, struct lfjour_item *i UNUSED)
 {}
 
 static struct rt_export_feed *
-bgp_out_feed_net(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, UNUSED const struct rt_export_item *_first)
+bgp_out_feed_net(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, UNUSED struct bmap *seen, bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, UNUSED const struct rt_export_item *_first)
 {
   ASSERT_DIE(u == NULL);
   SKIP_BACK_DECLARE(struct bgp_ptx_private, c, exporter, e);