summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2023-08-29 18:23:29 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2023-08-29 18:23:29 +0200
commitaa70e14c9e4cfeb70d2dc9cee497c40057dc105e (patch)
tree6866edc910b7f449ca01cbbebfb6783e628d18d6 /proto
parentf5140d1027f514bc59d46ab8aa09181f5870afbd (diff)
BFD: Improve handling of AdminDown
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.
Diffstat (limited to 'proto')
-rw-r--r--proto/bfd/bfd.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c
index 873e2ed5..97eb2d9b 100644
--- a/proto/bfd/bfd.c
+++ b/proto/bfd/bfd.c
@@ -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 */