]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixed secondary route export
authorMaria Matejka <mq@ucw.cz>
Fri, 28 Jun 2024 19:38:54 +0000 (21:38 +0200)
committerMaria Matejka <mq@ucw.cz>
Fri, 28 Jun 2024 20:03:45 +0000 (22:03 +0200)
nest/proto.c
nest/route.h
nest/rt-export.c
nest/rt-table.c

index 81d1e9240e1338a3656a1ad8982aa2ee1bed15f4..2bb0766ecbed17fc41c14f767993a355c48bc140 100644 (file)
@@ -108,8 +108,6 @@ void
 channel_request_full_refeed(struct channel *c)
 {
   rt_export_refeed(&c->out_req, NULL);
-  bmap_reset(&c->export_accepted_map, 16);
-  bmap_reset(&c->export_rejected_map, 16);
 }
 
 static void
index 3b56ccb6b4ed8feda4d751d851ccda730c6c609e..72089929686e9c93775498d8c0b9eef5ac659bb6 100644 (file)
@@ -331,9 +331,21 @@ static inline bool
 rt_net_is_feeding_request(struct rt_export_request *req, const net_addr *n)
 {
   struct netindex *ni = NET_TO_INDEX(n);
-  return
-    !bmap_test(&req->feed_map, ni->index)
-    && rt_net_is_feeding_feeder(&req->feeder, n);
+  switch (rt_export_get_state(req))
+  {
+    case TES_PARTIAL:
+    case TES_FEEDING:
+      break;
+
+    default:
+      return 0;
+  }
+
+  /* Already fed */
+  if (bmap_test(&req->feed_map, ni->index))
+    return 0;
+
+  return rt_net_is_feeding_feeder(&req->feeder, n);
 }
 
 #define rt_net_is_feeding(h, n)        _Generic((h), \
index e7cfeab84376945a6f8504dc64874f1ee275a313..a1d17a393bd1e62cfcc63f9b6f2614f2105f5af2 100644 (file)
@@ -103,9 +103,7 @@ rt_export_get(struct rt_export_request *r)
       else if (feed = rt_export_next_feed(&r->feeder))
       {
        /* Feeding more */
-       bmap_set(&r->feed_map, feed->ni->index);
        rtex_trace(r, D_ROUTES, "Feeding %N", feed->ni->addr);
-
        EXPORT_FOUND(RT_EXPORT_FEED);
       }
       else if (rt_export_get_state(r) == TES_DOWN)
@@ -158,7 +156,6 @@ rt_export_get(struct rt_export_request *r)
        feed = e->feed_net(e, u, ni->index, NULL, NULL, update);
       }
 
-      bmap_set(&r->feed_map, ni->index);
       ASSERT_DIE(feed && (feed != &rt_feed_index_out_of_range));
 
       EXPORT_FOUND(RT_EXPORT_FEED);
@@ -193,6 +190,8 @@ rt_export_release(const struct rt_export_union *u)
       for (uint i = 0; i < u->feed->count_exports; i++)
        bmap_set(&r->seq_map, u->feed->exports[i]);
 
+      bmap_set(&r->feed_map, u->feed->ni->index);
+
       if (!u->update)
        break;
 
index eaabb93957f178582e21f5130760d86d5c597290..a76a12ec3a2dc015be16be0d0f037f580af3f00f 100644 (file)
@@ -1081,13 +1081,21 @@ rt_notify_basic(struct channel *c, const rte *new, const rte *old)
   do_rt_notify(c, np ? np->net : old->net, np, old);
 }
 
+#if 0
+#define RT_NOTIFY_DEBUG(fmt...)        log(L_TRACE "rt_notify_accepted: " fmt, ##fmt)
+#else
+#define RT_NOTIFY_DEBUG(...)
+#endif
+
 static void
 rt_notify_accepted(struct channel *c, const struct rt_export_feed *feed)
 {
-  rte *old_best, *new_best;
+  rte *old_best = NULL, *new_best = NULL;
   bool feeding = rt_net_is_feeding(&c->out_req, feed->ni->addr);
   bool idempotent = 0;
 
+  RT_NOTIFY_DEBUG("%s feed for %N with %u routes", feeding ? "refeed" : "regular", feed->ni->addr, feed->count_routes);
+
   for (uint i = 0; i < feed->count_routes; i++)
   {
     rte *r = &feed->block[i];
@@ -1095,45 +1103,62 @@ rt_notify_accepted(struct channel *c, const struct rt_export_feed *feed)
     /* Previously exported */
     if (!old_best && bmap_test(&c->export_accepted_map, r->id))
     {
+      RT_NOTIFY_DEBUG("route %u id %u previously exported, is old best", i, r->id);
       old_best = r;
 
+      /* Is being withdrawn */
+      if (r->flags & REF_OBSOLETE)
+       RT_NOTIFY_DEBUG("route %u id %u is also obsolete", i, r->id);
+
       /* Is still the best and need not be refed anyway */
-      if (!new_best && !feeding)
+      else if (!new_best && !feeding)
       {
-       idempotent = 1;
+       RT_NOTIFY_DEBUG("route %u id %u is also new best (idempotent)", i, r->id);
        new_best = r;
+       idempotent = 1;
       }
     }
 
     /* Unflag obsolete routes */
-    if (r->flags & REF_OBSOLETE)
+    else if (r->flags & REF_OBSOLETE)
+    {
+      RT_NOTIFY_DEBUG("route %u id %u is obsolete", i, r->id);
       bmap_clear(&c->export_rejected_map, r->id);
+    }
 
     /* Mark invalid as rejected */
     else if (!rte_is_valid(r))
+    {
+      RT_NOTIFY_DEBUG("route %u id %u is invalid", i, r->id);
       bmap_set(&c->export_rejected_map, r->id);
+    }
 
     /* Already rejected */
     else if (!feeding && bmap_test(&c->export_rejected_map, r->id))
-      ;
+      RT_NOTIFY_DEBUG("route %u id %u has been rejected before", i, r->id);
 
     /* No new best route yet and this is a valid candidate */
     else if (!new_best)
     {
       /* This branch should not be executed if this route is old best */
-      ASSERT_DIE(r != old_best);
+      ASSERT_DIE(feeding || (r != old_best));
 
       /* Have no new best route yet, try this route not seen before */
       new_best = export_filter(c, r, 0);
-      DBG("rt_notify_accepted: checking route id %u: %s\n", r->id, new_best ? "ok" : "no");
+      RT_NOTIFY_DEBUG("route %u id %u is a new_best candidate %s", i, r->id,
+         new_best ? "and is accepted" : "but got rejected");
     }
+
+    /* Just a debug message for the last case */
+    else
+      RT_NOTIFY_DEBUG("route %u id %u is suboptimal, not checking", i, r->id);
   }
 
   /* Nothing to export */
   if (!idempotent && (new_best || old_best))
     do_rt_notify(c, feed->ni->addr, new_best, old_best);
   else
-    DBG("rt_notify_accepted: nothing to export\n");
+    RT_NOTIFY_DEBUG("nothing to export for %N", feed->ni->addr);
 }
 
 void