]> 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 11:55:35 +0000 (13:55 +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 d12444ed1a457d13fc8d2840f48169a7305750ff..8ca1214f0de19d722441ce614c51af15088db684 100644 (file)
@@ -155,6 +155,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);
 
 
 /*
@@ -1213,6 +1214,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;
@@ -2188,16 +2194,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 */
@@ -2205,8 +2205,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 *
@@ -2220,19 +2218,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 cd37227b174f8621b24d20a50c9c202934509e13..138acbf7f1605b48e159bd6f6c5d5e1ad917b8c6 100644 (file)
@@ -469,6 +469,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 12b60729cb7579f6a309b0169ad19a53eb8f1f72..6cba8b66cd31c3de574b5f2c4e03aa108eda52af 100644 (file)
@@ -3213,6 +3213,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);
@@ -3220,6 +3223,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);