From: Maria Matejka Date: Tue, 24 Oct 2023 07:34:06 +0000 (+0200) Subject: Merge commit 'aa70e14c' into thread-next X-Git-Tag: v3.0.0~383 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6c85016dd42045e3d57d7ba58fb57cecd939ae8b;p=thirdparty%2Fbird.git Merge commit 'aa70e14c' into thread-next --- 6c85016dd42045e3d57d7ba58fb57cecd939ae8b diff --cc proto/bfd/bfd.c index 5980148b4,97eb2d9b4..cb0f5ae89 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@@ -645,20 -648,10 +645,20 @@@ bfd_request_notify(struct bfd_request * 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) + { + struct birdloop *target = !birdloop_inside(req->target) ? req->target : NULL; + + if (target) + birdloop_enter(target); + req->hook(req); + + if (target) + birdloop_leave(target); + } } static int @@@ -711,84 -691,20 +711,84 @@@ bfd_add_request(struct bfd_proto *p, st } static void -bfd_submit_request(struct bfd_request *req) +bfd_pickup_requests(void *_data UNUSED) { - node *n; + /* NOTE TO MY FUTURE SELF + * + * Functions bfd_take_requests() and bfd_drop_requests() need to have + * consistent &bfd_global.wait_list and this is ensured only by having these + * functions called from bfd_start() and bfd_shutdown() which are both called + * in PROTO_LOCKED_FROM_MAIN context, i.e. always from &main_birdloop. + * + * This pickup event is also called in &main_birdloop, therefore we can + * freely do BFD_LOCK/BFD_UNLOCK while processing all the requests. All BFD + * protocols capable of bfd_add_request() are either started before this code + * happens or after that. + * + * If BFD protocols could start in parallel with this routine, they might + * miss some of the waiting requests, thus if anybody tries to start + * protocols or run this pickup event outside &main_birdloop in future, they + * shall ensure that this race condition is mitigated somehow. + * + * Thank you, my future self, for understanding. Have a nice day! + */ + + DBG("BFD pickup loop starting"); + + BFD_LOCK; + do { + bfd_global.pickup_reload = 0; + BFD_UNLOCK; + + node *n; + WALK_LIST(n, bfd_global.proto_list) + { + struct bfd_proto *p = SKIP_BACK(struct bfd_proto, bfd_node, n); + birdloop_enter(p->p.loop); + BFD_LOCK; + + TRACE(D_EVENTS, "Picking up new requests (%d available)", list_length(&bfd_global.pickup_list)); + + node *rn, *rnxt; + WALK_LIST_DELSAFE(rn, rnxt, bfd_global.pickup_list) + bfd_add_request(p, SKIP_BACK(struct bfd_request, n, rn)); + + BFD_UNLOCK; + + /* Remove sessions with no requests */ + HASH_WALK_DELSAFE(p->session_hash_id, next_id, s) + { + if (EMPTY_LIST(s->request_list)) + bfd_remove_session_locked(p, s); + } + HASH_WALK_END; - WALK_LIST(n, bfd_proto_list) - if (bfd_add_request(SKIP_BACK(struct bfd_proto, bfd_node, n), req)) - return; + birdloop_leave(p->p.loop); + } - rem_node(&req->n); - add_tail(&bfd_wait_list, &req->n); - req->session = NULL; - bfd_request_notify(req, BFD_STATE_ADMIN_DOWN, BFD_STATE_ADMIN_DOWN, 0); + BFD_LOCK; + } while (bfd_global.pickup_reload); + + list tmp_list; + init_list(&tmp_list); + add_tail_list(&tmp_list, &bfd_global.pickup_list); + + init_list(&bfd_global.pickup_list); + BFD_UNLOCK; + + log(L_TRACE "No protocol for %d BFD requests", list_length(&tmp_list)); + + node *n; + WALK_LIST(n, tmp_list) - bfd_request_notify(SKIP_BACK(struct bfd_request, n, n), BFD_STATE_ADMIN_DOWN, 0); ++ bfd_request_notify(SKIP_BACK(struct bfd_request, n, n), BFD_STATE_ADMIN_DOWN, BFD_STATE_ADMIN_DOWN, 0); + + BFD_LOCK; + add_tail_list(&bfd_global.wait_list, &tmp_list); + BFD_UNLOCK; } +static event bfd_pickup_event = { .hook = bfd_pickup_requests }; + static void bfd_take_requests(struct bfd_proto *p) { @@@ -1020,15 -917,21 +1020,15 @@@ bfd_reconfigure_neighbors(struct bfd_pr /* This core notify code should be replaced after main loop transition to birdloop */ -int pipe(int pipefd[2]); -void pipe_drain(int fd); -void pipe_kick(int fd); - -static int -bfd_notify_hook(sock *sk, uint len UNUSED) +static void +bfd_notify_hook(void *data) { - struct bfd_proto *p = sk->data; + struct bfd_proto *p = data; struct bfd_session *s; list tmp_list; - u8 state, diag; + u8 loc_state, rem_state, diag; node *n, *nn; - pipe_drain(sk->fd); - bfd_lock_sessions(p); init_list(&tmp_list); add_tail_list(&tmp_list, &p->notify_list); @@@ -1043,8 -947,10 +1044,8 @@@ 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 */ if (EMPTY_LIST(s->request_list))