]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
bfd: when all (not dummy) requests from a bfd session removed, timeout starts. If... tiny_fixes
authorKaterina Kubecova <katerina.kubecova@nic.cz>
Tue, 23 Apr 2024 14:30:08 +0000 (16:30 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 23 Apr 2024 14:36:49 +0000 (16:36 +0200)
nest/bfd.h
proto/bfd/bfd.c
proto/bfd/bfd.h
proto/bfd/config.Y

index d6819fd8a2868271e81d38e3b865645afcc26774..37fc6e6fdb7fbfe4cd2b975d4782136c92c6040d 100644 (file)
@@ -17,6 +17,7 @@ struct bfd_options {
   u32 min_rx_int;
   u32 min_tx_int;
   u32 idle_tx_int;
+  u32 session_delete_timeout;
   u8 multiplier;
   u8 passive;
   u8 passive_set;
index 272d27c0d4d039d2ab3cf1098b2a05995aa2d174..f154757426e5969fdd4ad1711ed354a974c6f7b4 100644 (file)
@@ -159,6 +159,7 @@ static void bfd_session_set_min_tx(struct bfd_session *s, u32 val);
 static struct bfd_iface *bfd_get_iface(struct bfd_proto *p, ip_addr local, struct iface *iface);
 static void bfd_free_iface(struct bfd_iface *ifa);
 static inline void bfd_notify_kick(struct bfd_proto *p);
+static void bfd_request_free(resource *r);
 
 
 /*
@@ -693,6 +694,22 @@ bfd_request_notify(struct bfd_request *req, u8 state, u8 remote, u8 diag)
     req->hook(req);
 }
 
+void
+bfd_delete_dummy_request(timer *t)
+{
+  struct bfd_session *s = t->data;
+  struct bfd_request *req = s->dummy_request.req;
+  s->dummy_request.req = NULL;
+  if (list_length(&s->request_list) != 1)
+  {
+    log(L_WARN "BFD: Attempt to delete dummy request from session with % requests in total.", list_length(&s->request_list));
+    return;
+  }
+  rfree(&req->r);
+}
+
+static struct resclass bfd_request_class;
+
 static int
 bfd_add_request(struct bfd_proto *p, struct bfd_request *req)
 {
@@ -712,7 +729,18 @@ bfd_add_request(struct bfd_proto *p, struct bfd_request *req)
   u8 loc_state, rem_state, diag;
 
   if (!s)
+  {
     s = bfd_add_session(p, req->addr, req->local, req->iface, &req->opts);
+    // Create one dummy request in order to be able keep session some time after last real request will be removed
+    struct bfd_request *dummy_request = ralloc(p->p.pool, &bfd_request_class);
+    add_tail(&s->request_list, &dummy_request->n);
+    dummy_request->session = s;
+
+    s->dummy_request.t = tm_new_init(p->p.pool, bfd_delete_dummy_request, s, 0, 0);
+    s->dummy_request.req = dummy_request;
+    s->dummy_request.p = p;
+  } else
+    tm_stop(s->dummy_request.t);
 
   rem_node(&req->n);
   add_tail(&s->request_list, &req->n);
@@ -767,8 +795,6 @@ bfd_drop_requests(struct bfd_proto *p)
   HASH_WALK_END(p->session_hash_id);
 }
 
-static struct resclass bfd_request_class;
-
 struct bfd_request *
 bfd_request_session(pool *p, ip_addr addr, ip_addr local,
                    struct iface *iface, struct iface *vrf,
@@ -821,8 +847,20 @@ bfd_request_free(resource *r)
   /* Remove the session if there is no request for it. Skip that if
      inside notify hooks, will be handled by bfd_notify_hook() itself */
 
-  if (s && EMPTY_LIST(s->request_list) && !s->notify_running)
+  if (s && EMPTY_LIST(s->request_list))
     bfd_remove_session(s->ifa->bfd, s);
+  else if (s && list_length(&s->request_list) == 1)
+  {
+    struct bfd_request *f_req = SKIP_BACK(struct bfd_request, n, HEAD(s->request_list));
+    if (f_req != s->dummy_request.req)
+      bug("Last bfd request is not the dummy one");
+    if (!tm_active(s->dummy_request.t))
+    {
+      struct bfd_config *conf = (struct bfd_config *) (s->dummy_request.p->p.cf);
+      btime time = (btime) conf->session_delete_timeout S;
+      tm_start(s->dummy_request.t, time);
+    }
+  }
 }
 
 static void
@@ -986,14 +1024,9 @@ bfd_notify_hook(sock *sk, uint len UNUSED)
     diag = s->loc_diag;
     bfd_unlock_sessions(p);
 
-    s->notify_running = 1;
     WALK_LIST_DELSAFE(n, nn, s->request_list)
       bfd_request_notify(SKIP_BACK(struct bfd_request, n, n), loc_state, rem_state, diag);
-    s->notify_running = 0;
 
-    /* Remove the session if all requests were removed in notify hooks */
-    if (EMPTY_LIST(s->request_list))
-      bfd_remove_session(p, s);
   }
 
   return 0;
index 847c6b14bef4911b0c76159995c4e63dad6bbd2d..07be733f23f67ab6553985548d7530eb1eac22da 100644 (file)
@@ -43,6 +43,7 @@ struct bfd_config
   list patt_list;              /* List of iface configs (struct bfd_iface_config) */
   list neigh_list;             /* List of configured neighbors (struct bfd_neighbor) */
   struct bfd_iface_config *multihop; /* Multihop pseudoiface config */
+  u32 session_delete_timeout;
   u8 accept_ipv4;
   u8 accept_ipv6;
   u8 accept_direct;
@@ -124,6 +125,13 @@ struct bfd_iface
   u8 changed;
 };
 
+struct dummy_request
+{
+  struct bfd_request *req;
+  struct bfd_proto *p; // to get actual timeout
+  timer *t;
+};
+
 struct bfd_session
 {
   node n;
@@ -165,8 +173,8 @@ struct bfd_session
   timer *hold_timer;                   /* Timer for session down detection time */
 
   list request_list;                   /* List of client requests (struct bfd_request) */
+  struct dummy_request dummy_request;  /* Request and timer for delating removing session */
   btime last_state_change;             /* Time of last state change */
-  u8 notify_running;                   /* 1 if notify hooks are running */
 
   u8 rx_csn_known;                     /* Received crypto sequence number is known */
   u32 rx_csn;                          /* Last received crypto sequence number */
index 1a7474b0b18ddf328e8ce1a14fe77ad09a4f7cfc..fec9116ed8359a0fb6be264847d1a02a66e6ee0d 100644 (file)
@@ -24,7 +24,7 @@ CF_DECLS
 CF_KEYWORDS(BFD, MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE,
        INTERFACE, MULTIHOP, NEIGHBOR, DEV, LOCAL, AUTHENTICATION,
        NONE, SIMPLE, METICULOUS, KEYED, MD5, SHA1, IPV4, IPV6, DIRECT,
-       STRICT, BIND)
+       STRICT, BIND, SESSION, DELETE, TIMEOUT)
 
 %type <iface> bfd_neigh_iface
 %type <a> bfd_neigh_local
@@ -42,6 +42,7 @@ bfd_proto_start: proto_start BFD
   init_list(&BFD_CFG->neigh_list);
   BFD_CFG->accept_ipv4 = BFD_CFG->accept_ipv6 = 1;
   BFD_CFG->accept_direct = BFD_CFG->accept_multihop = 1;
+  BFD_CFG->session_delete_timeout = 30;
 };
 
 bfd_proto_item:
@@ -51,6 +52,7 @@ bfd_proto_item:
  | MULTIHOP bfd_multihop
  | NEIGHBOR bfd_neighbor
  | STRICT BIND bool { BFD_CFG->strict_bind = $3; }
+ | SESSION DELETE TIMEOUT expr { BFD_CFG->session_delete_timeout = $4; }
  ;
 
 bfd_proto_opts: