]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
BFD: Improve handling of AdminDown
authorOndrej Zajicek <santiago@crfreenet.org>
Tue, 29 Aug 2023 16:23:29 +0000 (18:23 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 29 Aug 2023 16:23:29 +0000 (18:23 +0200)
According to RFC 5882, system should not interpret the local or remote
session state transition to AdminDown as failure. We followed that for
the local session state but not for the remote session state (which
just triggered a transition of the local state to Down). The patch
fixes that.

We do not properly generate AdminDown on our side, so the patch is
relevant just for interoperability with other systems.

Thanks to Sunnat Samadov for the bugreport.

proto/bfd/bfd.c

index 873e2ed5cc80b18fcd975139b11c00b40cc4986e..97eb2d9b44302a34ef1f340b71827cd0c06671d4 100644 (file)
@@ -638,7 +638,7 @@ bfd_reconfigure_iface(struct bfd_proto *p, struct bfd_iface *ifa, struct bfd_con
  */
 
 static void
-bfd_request_notify(struct bfd_request *req, u8 state, u8 diag)
+bfd_request_notify(struct bfd_request *req, u8 state, u8 remote, u8 diag)
 {
   u8 old_state = req->state;
 
@@ -648,7 +648,7 @@ bfd_request_notify(struct bfd_request *req, u8 state, u8 diag)
   req->state = state;
   req->diag = diag;
   req->old_state = old_state;
-  req->down = (old_state == BFD_STATE_UP) && (state == BFD_STATE_DOWN);
+  req->down = (old_state == BFD_STATE_UP) && (state == BFD_STATE_DOWN) && (remote != BFD_STATE_ADMIN_DOWN);
 
   if (req->hook)
     req->hook(req);
@@ -670,7 +670,7 @@ bfd_add_request(struct bfd_proto *p, struct bfd_request *req)
 
   uint ifindex = req->iface ? req->iface->index : 0;
   struct bfd_session *s = bfd_find_session_by_addr(p, req->addr, ifindex);
-  u8 state, diag;
+  u8 loc_state, rem_state, diag;
 
   if (!s)
     s = bfd_add_session(p, req->addr, req->local, req->iface, &req->opts);
@@ -680,11 +680,12 @@ bfd_add_request(struct bfd_proto *p, struct bfd_request *req)
   req->session = s;
 
   bfd_lock_sessions(p);
-  state = s->loc_state;
+  loc_state = s->loc_state;
+  rem_state = s->rem_state;
   diag = s->loc_diag;
   bfd_unlock_sessions(p);
 
-  bfd_request_notify(req, state, diag);
+  bfd_request_notify(req, loc_state, rem_state, diag);
 
   return 1;
 }
@@ -701,7 +702,7 @@ bfd_submit_request(struct bfd_request *req)
   rem_node(&req->n);
   add_tail(&bfd_wait_list, &req->n);
   req->session = NULL;
-  bfd_request_notify(req, BFD_STATE_ADMIN_DOWN, 0);
+  bfd_request_notify(req, BFD_STATE_ADMIN_DOWN, BFD_STATE_ADMIN_DOWN, 0);
 }
 
 static void
@@ -926,7 +927,7 @@ bfd_notify_hook(sock *sk, uint len UNUSED)
   struct bfd_proto *p = sk->data;
   struct bfd_session *s;
   list tmp_list;
-  u8 state, diag;
+  u8 loc_state, rem_state, diag;
   node *n, *nn;
 
   pipe_drain(sk->fd);
@@ -941,13 +942,14 @@ bfd_notify_hook(sock *sk, uint len UNUSED)
   {
     bfd_lock_sessions(p);
     rem_node(&s->n);
-    state = s->loc_state;
+    loc_state = s->loc_state;
+    rem_state = s->rem_state;
     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), state, diag);
+      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 */