]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Allowing to restart a route refresh.
authorMaria Matejka <mq@ucw.cz>
Sun, 19 Mar 2023 12:21:35 +0000 (13:21 +0100)
committerMaria Matejka <mq@ucw.cz>
Tue, 4 Apr 2023 15:00:58 +0000 (17:00 +0200)
Repeated pipe refeed should not end route refresh as the prune routine
may start pruning otherwise valid routes.

The same applies for BGP repeated route refresh.

nest/rt-table.c
proto/bgp/bgp.c

index 4c71663b99f19e10a803dd4f76d5268f8bee2956..8b9b2017e561f3f952ddf19c662dc0faff40f5de 100644 (file)
@@ -2327,16 +2327,16 @@ rt_refresh_begin(struct rt_import_request *req)
 {
   struct rt_import_hook *hook = req->hook;
   ASSERT_DIE(hook);
-  ASSERT_DIE(hook->stale_set == hook->stale_valid);
 
   RT_LOCKED(hook->table, tab)
   {
 
   /* If the pruning routine is too slow */
-  if ((hook->stale_pruned < hook->stale_valid) && (hook->stale_pruned + 128 < hook->stale_valid)
-      || (hook->stale_pruned > hook->stale_valid) && (hook->stale_pruned > hook->stale_valid + 128))
+  if (((hook->stale_set - hook->stale_pruned) & 0xff) >= 240)
   {
-    log(L_WARN "Route refresh flood in table %s", hook->table->name);
+    log(L_WARN "Route refresh flood in table %s (stale_set=%u, stale_pruned=%u)", hook->table->name, hook->stale_set, hook->stale_pruned);
+
+    /* Forcibly set all old routes' stale cycle to zero. */
     FIB_WALK(&tab->fib, net, n)
       {
        for (struct rte_storage *e = n->routes; e; e = e->next)
@@ -2344,19 +2344,15 @@ rt_refresh_begin(struct rt_import_request *req)
            e->rte.stale_cycle = 0;
       }
     FIB_WALK_END;
+
+    /* Smash the route refresh counter and zero everything. */
     tab->rr_counter -= hook->stale_set - hook->stale_pruned;
-    hook->stale_set = 1;
-    hook->stale_valid = 0;
-    hook->stale_pruned = 0;
-  }
-  /* Setting a new value of the stale modifier */
-  else if (!++hook->stale_set)
-  {
-    /* Let's reserve the stale_cycle zero value for always-invalid routes */
-    hook->stale_set = 1;
-    hook->stale_valid = 0;
+    hook->stale_set = hook->stale_valid = hook->stale_pruning = hook->stale_pruned = 0;
   }
 
+  /* Now we can safely increase the stale_set modifier */
+  hook->stale_set++;
+
   /* The table must know that we're route-refreshing */
   tab->rr_counter++;
 
@@ -2382,14 +2378,18 @@ rt_refresh_end(struct rt_import_request *req)
 
   RT_LOCKED(hook->table, tab)
   {
-    hook->stale_valid++;
-    ASSERT_DIE(hook->stale_set == hook->stale_valid);
+    /* Now valid routes are only those one with the latest stale_set value */
+    uint cnt = hook->stale_set - hook->stale_valid;
+    hook->stale_valid = hook->stale_set;
 
     /* Here we can't kick the timer as we aren't in the table service loop */
     rt_schedule_prune(tab);
 
     if (req->trace_routes & D_STATES)
-      log(L_TRACE "%s: route refresh end [%u]", req->name, hook->stale_valid);
+      if (cnt > 1)
+       log(L_TRACE "%s: route refresh end (x%u) [%u]", req->name, cnt, hook->stale_valid);
+      else
+       log(L_TRACE "%s: route refresh end [%u]", req->name, hook->stale_valid);
   }
 }
 
index 851167b66fd9720f124bb9b095e54c2a91d66537..cca1283c43709f536284a385697135a758f4a713 100644 (file)
@@ -805,11 +805,9 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
       {
       case BGP_GRS_NONE:
        c->gr_active = BGP_GRS_ACTIVE;
-       rt_refresh_begin(&c->c.in_req);
-       break;
+       /* fall through */
 
       case BGP_GRS_ACTIVE:
-       rt_refresh_end(&c->c.in_req);
        rt_refresh_begin(&c->c.in_req);
        break;
 
@@ -988,9 +986,6 @@ bgp_refresh_begin(struct bgp_channel *c)
   if (c->load_state == BFS_LOADING)
   { log(L_WARN "%s: BEGIN-OF-RR received before END-OF-RIB, ignoring", p->p.name); return; }
 
-  if (c->load_state == BFS_REFRESHING)
-    rt_refresh_end(&c->c.in_req);
-
   c->load_state = BFS_REFRESHING;
   rt_refresh_begin(&c->c.in_req);
 }