]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
BGP: Fix repeated route refresh request
authorMaria Matejka <mq@ucw.cz>
Thu, 8 May 2025 21:03:57 +0000 (23:03 +0200)
committerMaria Matejka <mq@ucw.cz>
Sat, 10 May 2025 14:56:27 +0000 (16:56 +0200)
The previous approach was crashing on rapid successions of route refreshs
without even completing the previous ones. Now the newly requested refreshs
just queue and don't start multiple refreshs over and over again.

proto/bgp/bgp.c
proto/bgp/bgp.h
proto/bgp/packets.c

index 706e9b0bd1f3af0bf1062c20f4a768f417f317e7..33459add0ad76c96390469f314ae45c90c2c9ed5 100644 (file)
@@ -152,6 +152,7 @@ static void bgp_listen_sock_err(sock *sk UNUSED, int err);
 static void bgp_initiate_disable(struct bgp_proto *p, int err_val);
 
 static void bgp_graceful_restart_feed(struct bgp_channel *c);
+static void bgp_restart_route_refresh(void *_bc);
 
 
 static inline int
@@ -762,6 +763,11 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
     c->feed_state = BFS_NONE;
     c->load_state = BFS_NONE;
 
+    c->enhanced_rr_restart = (event) {
+      .hook = bgp_restart_route_refresh,
+      .data = c,
+    };
+
     /* Channels where peer may do GR */
     uint gr_ready = active && local->gr_aware && rem->gr_able;
     uint llgr_ready = active && local->llgr_aware && rem->llgr_able;
@@ -1689,16 +1695,10 @@ bgp_reload_in(struct proto *P, uintptr_t _ UNUSED, int __ UNUSED)
     cli_msg(-8006, "%s: not reloading, not up", P->name);
 }
 
-struct bgp_enhanced_refresh_request {
-  struct rt_feeding_request rfr;
-  struct bgp_channel *c;
-};
-
 static void
 bgp_done_route_refresh(struct rt_feeding_request *rfr)
 {
-  SKIP_BACK_DECLARE(struct bgp_enhanced_refresh_request, berr, rfr, rfr);
-  struct bgp_channel *c = berr->c;
+  SKIP_BACK_DECLARE(struct bgp_channel, c, enhanced_rr_request, rfr);
   SKIP_BACK_DECLARE(struct bgp_proto, p, p, c->c.proto);
 
   /* Schedule EoRR packet */
@@ -1706,8 +1706,6 @@ bgp_done_route_refresh(struct rt_feeding_request *rfr)
 
   c->feed_state = BFS_REFRESHED;
   bgp_schedule_packet(p->conn, c, PKT_UPDATE);
-
-  mb_free(berr);
 }
 
 const char *
@@ -1721,19 +1719,42 @@ bgp_begin_route_refresh(struct bgp_proto *p, struct bgp_channel *c)
     return "from table by simple refeed";
   }
 
-  struct bgp_enhanced_refresh_request *berr = mb_alloc(p->p.pool, sizeof *berr);
-  *berr = (struct bgp_enhanced_refresh_request) {
-    .c = c,
-    .rfr.done = bgp_done_route_refresh,
-  };
+  switch (c->feed_state)
+  {
+    case BFS_NONE:
+      break;
+
+    case BFS_REFRESHING:
+    case BFS_REFRESHED:
+      return c->enhanced_rr_again ? "already queued" : "again";
 
+    default:
+      return "requested before End-Of-RIB sent";
+  }
+
+  c->enhanced_rr_request.done = bgp_done_route_refresh;
   c->feed_state = BFS_REFRESHING;
   bgp_schedule_packet(p->conn, c, PKT_BEGIN_REFRESH);
 
-  rt_export_refeed(&c->c.out_req, &berr->rfr);
+  rt_export_refeed(&c->c.out_req, &c->enhanced_rr_request);
   return "from table by enhanced route refresh";
 }
 
+static void
+bgp_restart_route_refresh(void *_bc)
+{
+  struct bgp_channel *c = _bc;
+  SKIP_BACK_DECLARE(struct bgp_proto, p, p, c->c.proto);
+
+  if ((c->feed_state != BFS_NONE) || (!c->enhanced_rr_again))
+    return;
+
+  c->enhanced_rr_again = 0;
+
+  const char *info = bgp_begin_route_refresh(p, c);
+  BGP_TRACE(D_EVENTS, "Restarting route refresh on %s %s", c->c.name, info);
+}
+
 void
 bgp_reload_out(struct proto *P, uintptr_t _ UNUSED, int __ UNUSED)
 {
index c3a49f5c625d11984e74e15f30070f086c692a2c..73f2b888281e6edbba981eda2508d703246511fb 100644 (file)
@@ -436,6 +436,10 @@ struct bgp_channel {
   struct rt_export_feeder stale_feed;  /* Feeder request for stale route modification */
   event stale_event;                   /* Feeder event for stale route modification */
 
+  struct rt_feeding_request enhanced_rr_request; /* Refeed request for enhanced route refresh */
+  event enhanced_rr_restart;           /* Event to restart enhanced route request */
+  u8 enhanced_rr_again;                        /* Another refeed requested while refeeding */
+
   u8 add_path_rx;                      /* Session expects receive of ADD-PATH extended NLRI */
   u8 add_path_tx;                      /* Session expects transmit of ADD-PATH extended NLRI */
 
index 9ee6d0adb197585762ba4ac992e2a7b4df0ad1e4..d41921a5b6f3ed6dce060962f9a2515e8d8f1a4e 100644 (file)
@@ -3170,6 +3170,9 @@ bgp_fire_tx(struct bgp_conn *conn)
 
       if (c->feed_state == BFS_LOADED)
       {
+       if (c->enhanced_rr_again)
+         ev_send_loop(p->p.loop, &c->enhanced_rr_restart);
+
        c->feed_state = BFS_NONE;
        end = bgp_create_end_mark(c, pkt);
        return bgp_send(conn, PKT_UPDATE, end - buf);
@@ -3177,6 +3180,9 @@ bgp_fire_tx(struct bgp_conn *conn)
 
       else if (c->feed_state == BFS_REFRESHED)
       {
+       if (c->enhanced_rr_again)
+         ev_send_loop(p->p.loop, &c->enhanced_rr_restart);
+
        c->feed_state = BFS_NONE;
        end = bgp_create_end_refresh(c, pkt);
        return bgp_send(conn, PKT_ROUTE_REFRESH, end - buf);