0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

bfd: when all (not dummy) requests from a bfd session removed, timeout starts. If timeout ends without adding a request to that session, session is deleted. (Keeping empty session is done by having dummy request)

This commit is contained in:
Katerina Kubecova 2024-04-23 16:30:08 +02:00 committed by Ondrej Zajicek
parent 416a51ac92
commit fee58fd886
4 changed files with 54 additions and 10 deletions

View 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;

View 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;

View 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 */

View 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: