diff options
Diffstat (limited to 'proto/bfd')
-rw-r--r-- | proto/bfd/Makefile | 4 | ||||
-rw-r--r-- | proto/bfd/bfd.c | 469 | ||||
-rw-r--r-- | proto/bfd/bfd.h | 27 | ||||
-rw-r--r-- | proto/bfd/config.Y | 1 | ||||
-rw-r--r-- | proto/bfd/io.c | 535 | ||||
-rw-r--r-- | proto/bfd/io.h | 34 | ||||
-rw-r--r-- | proto/bfd/packets.c | 21 |
7 files changed, 225 insertions, 866 deletions
diff --git a/proto/bfd/Makefile b/proto/bfd/Makefile index 402122fc..267dff98 100644 --- a/proto/bfd/Makefile +++ b/proto/bfd/Makefile @@ -1,6 +1,6 @@ -src := bfd.c io.c packets.c +src := bfd.c packets.c obj := $(src-o-files) $(all-daemon) $(cf-local) -tests_objs := $(tests_objs) $(src-o-files)
\ No newline at end of file +tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index dac184c5..63e0deff 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -113,15 +113,26 @@ #define HASH_IP_EQ(a1,n1,a2,n2) ipa_equal(a1, a2) && n1 == n2 #define HASH_IP_FN(a,n) ipa_hash(a) ^ u32_hash(n) -static list bfd_proto_list; -static list bfd_wait_list; +DEFINE_DOMAIN(rtable); +#define BFD_LOCK LOCK_DOMAIN(rtable, bfd_global.lock) +#define BFD_UNLOCK UNLOCK_DOMAIN(rtable, bfd_global.lock) +#define BFD_ASSERT_LOCKED ASSERT_DIE(DOMAIN_IS_LOCKED(rtable, bfd_global.lock)) + +static struct { + DOMAIN(rtable) lock; + list wait_list; + list proto_list; +} bfd_global; + +static struct bfd_session bfd_admin_down = { .loc = { .state = BFD_STATE_ADMIN_DOWN }, }; const char *bfd_state_names[] = { "AdminDown", "Down", "Init", "Up" }; 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_remove_session(struct bfd_proto *p, struct bfd_session *s); +static void bfd_reconfigure_session_hook(void *vsession); /* @@ -140,37 +151,57 @@ bfd_merge_options(const struct bfd_iface_config *cf, const struct bfd_options *o }; } -static void +static int bfd_session_update_state(struct bfd_session *s, uint state, uint diag) { struct bfd_proto *p = s->ifa->bfd; - uint old_state = s->loc_state; - int notify; + uint old_state = BFD_LOC_STATE(s).state; if (state == old_state) - return; + { + if (current_time() > s->last_reqlist_check + 5 S) + { + BFD_LOCK; + if (EMPTY_LIST(s->request_list)) + { + bfd_remove_session(p, s); + BFD_UNLOCK; + return 1; + } + + s->last_reqlist_check = current_time(); + BFD_UNLOCK; + } + return 0; + } TRACE(D_EVENTS, "Session to %I changed state from %s to %s", s->addr, bfd_state_names[old_state], bfd_state_names[state]); - bfd_lock_sessions(p); - s->loc_state = state; - s->loc_diag = diag; + atomic_store_explicit(&s->loc, ((struct bfd_session_state) { .state = state, .diag = diag }), memory_order_release); s->last_state_change = current_time(); - notify = !NODE_VALID(&s->n); - if (notify) - add_tail(&p->notify_list, &s->n); - bfd_unlock_sessions(p); - if (state == BFD_STATE_UP) bfd_session_set_min_tx(s, s->cf.min_tx_int); if (old_state == BFD_STATE_UP) bfd_session_set_min_tx(s, s->cf.idle_tx_int); - if (notify) - bfd_notify_kick(p); + BFD_LOCK; + if (EMPTY_LIST(s->request_list)) + { + bfd_remove_session(p, s); + BFD_UNLOCK; + return 1; + } + + struct bfd_request *req; + node *nn; + WALK_LIST2(req, nn, s->request_list, n) + ev_send_self(&req->event); + + BFD_UNLOCK; + return 0; } static void @@ -188,7 +219,7 @@ bfd_session_update_tx_interval(struct bfd_session *s) return; /* Set timer relative to last tx_timer event */ - tm_set(s->tx_timer, s->last_tx + tx_int_l); + tm_set_in(s->tx_timer, s->last_tx + tx_int_l, s->ifa->bfd->p.loop); } static void @@ -202,7 +233,7 @@ bfd_session_update_detection_time(struct bfd_session *s, int kick) if (!s->last_rx) return; - tm_set(s->hold_timer, s->last_rx + timeout); + tm_set_in(s->hold_timer, s->last_rx + timeout, s->ifa->bfd->p.loop); } static void @@ -215,8 +246,8 @@ bfd_session_control_tx_timer(struct bfd_session *s, int reset) if (s->rem_demand_mode && !s->poll_active && - (s->loc_state == BFD_STATE_UP) && - (s->rem_state == BFD_STATE_UP)) + (BFD_LOC_STATE(s).state == BFD_STATE_UP) && + (s->rem.state == BFD_STATE_UP)) goto stop; if (s->rem_min_rx_int == 0) @@ -226,7 +257,7 @@ bfd_session_control_tx_timer(struct bfd_session *s, int reset) if (reset || !tm_active(s->tx_timer)) { s->last_tx = 0; - tm_start(s->tx_timer, 0); + tm_start_in(s->tx_timer, 0, s->ifa->bfd->p.loop); } return; @@ -286,28 +317,29 @@ bfd_session_process_ctl(struct bfd_session *s, u8 flags, u32 old_tx_int, u32 old int next_state = 0; int diag = BFD_DIAG_NOTHING; - switch (s->loc_state) + switch (BFD_LOC_STATE(s).state) { case BFD_STATE_ADMIN_DOWN: return; case BFD_STATE_DOWN: - if (s->rem_state == BFD_STATE_DOWN) next_state = BFD_STATE_INIT; - else if (s->rem_state == BFD_STATE_INIT) next_state = BFD_STATE_UP; + if (s->rem.state == BFD_STATE_DOWN) next_state = BFD_STATE_INIT; + else if (s->rem.state == BFD_STATE_INIT) next_state = BFD_STATE_UP; break; case BFD_STATE_INIT: - if (s->rem_state == BFD_STATE_ADMIN_DOWN) next_state = BFD_STATE_DOWN, diag = BFD_DIAG_NEIGHBOR_DOWN; - else if (s->rem_state >= BFD_STATE_INIT) next_state = BFD_STATE_UP; + if (s->rem.state == BFD_STATE_ADMIN_DOWN) next_state = BFD_STATE_DOWN, diag = BFD_DIAG_NEIGHBOR_DOWN; + else if (s->rem.state >= BFD_STATE_INIT) next_state = BFD_STATE_UP; break; case BFD_STATE_UP: - if (s->rem_state <= BFD_STATE_DOWN) next_state = BFD_STATE_DOWN, diag = BFD_DIAG_NEIGHBOR_DOWN; + if (s->rem.state <= BFD_STATE_DOWN) next_state = BFD_STATE_DOWN, diag = BFD_DIAG_NEIGHBOR_DOWN; break; } if (next_state) - bfd_session_update_state(s, next_state, diag); + if (bfd_session_update_state(s, next_state, diag)) + return; bfd_session_control_tx_timer(s, 0); @@ -322,7 +354,7 @@ bfd_session_timeout(struct bfd_session *s) TRACE(D_EVENTS, "Session to %I expired", s->addr); - s->rem_state = BFD_STATE_DOWN; + s->rem.state = BFD_STATE_DOWN; s->rem_id = 0; s->rem_min_tx_int = 0; s->rem_min_rx_int = 1; @@ -333,7 +365,8 @@ bfd_session_timeout(struct bfd_session *s) s->poll_active = 0; s->poll_scheduled = 0; - bfd_session_update_state(s, BFD_STATE_DOWN, BFD_DIAG_TIMEOUT); + if (bfd_session_update_state(s, BFD_STATE_DOWN, BFD_DIAG_TIMEOUT)) + return; bfd_session_control_tx_timer(s, 1); } @@ -349,7 +382,7 @@ bfd_session_set_min_tx(struct bfd_session *s, u32 val) s->des_min_tx_new = val; /* Postpone timer update if des_min_tx_int increases and the session is up */ - if ((s->loc_state != BFD_STATE_UP) || (val < s->des_min_tx_int)) + if ((BFD_LOC_STATE(s).state != BFD_STATE_UP) || (val < s->des_min_tx_int)) { s->des_min_tx_int = val; bfd_session_update_tx_interval(s); @@ -369,7 +402,7 @@ bfd_session_set_min_rx(struct bfd_session *s, u32 val) s->req_min_rx_new = val; /* Postpone timer update if req_min_rx_int decreases and the session is up */ - if ((s->loc_state != BFD_STATE_UP) || (val > s->req_min_rx_int)) + if ((BFD_LOC_STATE(s).state != BFD_STATE_UP) || (val > s->req_min_rx_int)) { s->req_min_rx_int = val; bfd_session_update_detection_time(s, 0); @@ -381,12 +414,14 @@ bfd_session_set_min_rx(struct bfd_session *s, u32 val) struct bfd_session * bfd_find_session_by_id(struct bfd_proto *p, u32 id) { + ASSERT_DIE(birdloop_inside(p->p.loop)); return HASH_FIND(p->session_hash_id, HASH_ID, id); } struct bfd_session * bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr, uint ifindex) { + ASSERT_DIE(birdloop_inside(p->p.loop)); return HASH_FIND(p->session_hash_ip, HASH_IP, addr, ifindex); } @@ -419,7 +454,8 @@ bfd_get_free_id(struct bfd_proto *p) static struct bfd_session * bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *iface, struct bfd_options *opts) { - birdloop_enter(p->loop); + ASSERT_DIE(birdloop_inside(p->p.loop)); + BFD_ASSERT_LOCKED; struct bfd_iface *ifa = bfd_get_iface(p, local, iface); @@ -433,10 +469,15 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface * HASH_INSERT(p->session_hash_ip, HASH_IP, s); s->cf = bfd_merge_options(ifa->cf, opts); + s->update_event = (event) { + .hook = bfd_reconfigure_session_hook, + .data = s, + .list = birdloop_event_list(p->p.loop), + }; /* Initialization of state variables - see RFC 5880 6.8.1 */ - s->loc_state = BFD_STATE_DOWN; - s->rem_state = BFD_STATE_DOWN; + atomic_store_explicit(&s->loc, ((struct bfd_session_state) { .state = BFD_STATE_DOWN }), memory_order_relaxed); + s->rem.state = BFD_STATE_DOWN; s->des_min_tx_int = s->des_min_tx_new = s->cf.idle_tx_int; s->req_min_rx_int = s->req_min_rx_new = s->cf.min_rx_int; s->rem_min_rx_int = 1; @@ -444,8 +485,8 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface * s->passive = s->cf.passive; s->tx_csn = random_u32(); - s->tx_timer = tm_new_init(p->tpool, bfd_tx_timer_hook, s, 0, 0); - s->hold_timer = tm_new_init(p->tpool, bfd_hold_timer_hook, s, 0, 0); + s->tx_timer = tm_new_init(p->p.pool, bfd_tx_timer_hook, s, 0, 0); + s->hold_timer = tm_new_init(p->p.pool, bfd_hold_timer_hook, s, 0, 0); bfd_session_update_tx_interval(s); bfd_session_control_tx_timer(s, 1); @@ -454,51 +495,15 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface * TRACE(D_EVENTS, "Session to %I added", s->addr); - birdloop_leave(p->loop); - return s; } -/* -static void -bfd_open_session(struct bfd_proto *p, struct bfd_session *s, ip_addr local, struct iface *ifa) -{ - birdloop_enter(p->loop); - - s->opened = 1; - - bfd_session_control_tx_timer(s); - - birdloop_leave(p->loop); -} - -static void -bfd_close_session(struct bfd_proto *p, struct bfd_session *s) -{ - birdloop_enter(p->loop); - - s->opened = 0; - - bfd_session_update_state(s, BFD_STATE_DOWN, BFD_DIAG_PATH_DOWN); - bfd_session_control_tx_timer(s); - - birdloop_leave(p->loop); -} -*/ - static void bfd_remove_session(struct bfd_proto *p, struct bfd_session *s) { - ip_addr ip = s->addr; - - /* Caller should ensure that request list is empty */ - - birdloop_enter(p->loop); - - /* Remove session from notify list if scheduled for notification */ - /* No need for bfd_lock_sessions(), we are already protected by birdloop_enter() */ - if (NODE_VALID(&s->n)) - rem_node(&s->n); + ASSERT_DIE(birdloop_inside(p->p.loop)); + BFD_ASSERT_LOCKED; + ASSERT_DIE(EMPTY_LIST(s->request_list)); bfd_free_iface(s->ifa); @@ -508,25 +513,27 @@ bfd_remove_session(struct bfd_proto *p, struct bfd_session *s) HASH_REMOVE(p->session_hash_id, HASH_ID, s); HASH_REMOVE(p->session_hash_ip, HASH_IP, s); - sl_free(p->session_slab, s); - - TRACE(D_EVENTS, "Session to %I removed", ip); + TRACE(D_EVENTS, "Session to %I removed", s->addr); - birdloop_leave(p->loop); + sl_free(p->session_slab, s); } static void bfd_reconfigure_session(struct bfd_proto *p, struct bfd_session *s) { + ASSERT_DIE(birdloop_inside(p->p.loop)); + BFD_LOCK; if (EMPTY_LIST(s->request_list)) + { + bfd_remove_session(p, s); + BFD_UNLOCK; return; - - birdloop_enter(p->loop); + } struct bfd_request *req = SKIP_BACK(struct bfd_request, n, HEAD(s->request_list)); s->cf = bfd_merge_options(s->ifa->cf, &req->opts); - u32 tx = (s->loc_state == BFD_STATE_UP) ? s->cf.min_tx_int : s->cf.idle_tx_int; + u32 tx = (BFD_LOC_STATE(s).state == BFD_STATE_UP) ? s->cf.min_tx_int : s->cf.idle_tx_int; bfd_session_set_min_tx(s, tx); bfd_session_set_min_rx(s, s->cf.min_rx_int); s->detect_mult = s->cf.multiplier; @@ -534,9 +541,15 @@ bfd_reconfigure_session(struct bfd_proto *p, struct bfd_session *s) bfd_session_control_tx_timer(s, 0); - birdloop_leave(p->loop); - TRACE(D_EVENTS, "Session to %I reconfigured", s->addr); + BFD_UNLOCK; +} + +static void +bfd_reconfigure_session_hook(void *data) +{ + struct bfd_session *s = data; + return bfd_reconfigure_session(s->ifa->bfd, s); } @@ -573,7 +586,7 @@ bfd_get_iface(struct bfd_proto *p, ip_addr local, struct iface *iface) struct bfd_config *cf = (struct bfd_config *) (p->p.cf); struct bfd_iface_config *ic = bfd_find_iface_config(cf, iface); - ifa = mb_allocz(p->tpool, sizeof(struct bfd_iface)); + ifa = mb_allocz(p->p.pool, sizeof(struct bfd_iface)); ifa->local = local; ifa->iface = iface; ifa->cf = ic; @@ -604,7 +617,7 @@ bfd_free_iface(struct bfd_iface *ifa) } static void -bfd_reconfigure_iface(struct bfd_proto *p, struct bfd_iface *ifa, struct bfd_config *nc) +bfd_reconfigure_iface(struct bfd_proto *p UNUSED, struct bfd_iface *ifa, struct bfd_config *nc) { struct bfd_iface_config *new = bfd_find_iface_config(nc, ifa->iface); struct bfd_iface_config *old = ifa->cf; @@ -618,9 +631,7 @@ bfd_reconfigure_iface(struct bfd_proto *p, struct bfd_iface *ifa, struct bfd_con (new->passive != old->passive); /* This should be probably changed to not access ifa->cf from the BFD thread */ - birdloop_enter(p->loop); ifa->cf = new; - birdloop_leave(p->loop); } @@ -629,17 +640,22 @@ 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(void *data) { - u8 old_state = req->state; + struct bfd_request *req = data; + struct bfd_session_state old = req->old_state; - if (state == old_state) + BFD_LOCK; /* Needed to safely access req->session */ + struct bfd_session_state new = atomic_load_explicit(&req->session->loc, memory_order_acquire); + BFD_UNLOCK; + + if (new.state == old.state) return; - req->state = state; - req->diag = diag; - req->old_state = old_state; - req->down = (old_state == BFD_STATE_UP) && (state == BFD_STATE_DOWN); + req->state = new.state; + req->diag = new.diag; + req->old_state = new; + req->down = (old.state == BFD_STATE_UP) && (new.state == BFD_STATE_DOWN); if (req->hook) req->hook(req); @@ -648,9 +664,12 @@ bfd_request_notify(struct bfd_request *req, u8 state, u8 diag) static int bfd_add_request(struct bfd_proto *p, struct bfd_request *req) { + BFD_ASSERT_LOCKED; + ASSERT_DIE(req->session == &bfd_admin_down); + struct bfd_config *cf = (struct bfd_config *) (p->p.cf); - if (p->p.vrf_set && (p->p.vrf != req->vrf)) + if (p->p.vrf && (p->p.vrf != req->vrf)) return 0; if (ipa_is_ip4(req->addr) ? !cf->accept_ipv4 : !cf->accept_ipv6) @@ -661,7 +680,6 @@ 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; if (!s) s = bfd_add_session(p, req->addr, req->local, req->iface, &req->opts); @@ -670,52 +688,67 @@ bfd_add_request(struct bfd_proto *p, struct bfd_request *req) add_tail(&s->request_list, &req->n); req->session = s; - bfd_lock_sessions(p); - state = s->loc_state; - diag = s->loc_diag; - bfd_unlock_sessions(p); - - bfd_request_notify(req, state, diag); + ev_send_self(&req->event); return 1; } static void -bfd_submit_request(struct bfd_request *req) +bfd_pickup_requests(void *_data UNUSED) { - node *n; + struct bfd_proto *p; + node *nn; + WALK_LIST2(p, nn, bfd_global.proto_list, bfd_node) + { + birdloop_enter(p->p.loop); + BFD_LOCK; - WALK_LIST(n, bfd_proto_list) - if (bfd_add_request(SKIP_BACK(struct bfd_proto, bfd_node, n), req)) - return; + struct bfd_request *req; + node *rn, *rnxt; + WALK_LIST2_DELSAFE(req, rn, rnxt, bfd_global.wait_list, n) + bfd_add_request(p, 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_UNLOCK; + birdloop_ping(p->p.loop); + birdloop_leave(p->p.loop); + } } +static event bfd_pickup_event = { .hook = bfd_pickup_requests }; +#define bfd_schedule_pickup() ev_send(&global_event_list, &bfd_pickup_event) + static void bfd_take_requests(struct bfd_proto *p) { + struct bfd_request *req; node *n, *nn; - - WALK_LIST_DELSAFE(n, nn, bfd_wait_list) - bfd_add_request(p, SKIP_BACK(struct bfd_request, n, n)); + BFD_LOCK; + WALK_LIST2_DELSAFE(req, n, nn, bfd_global.wait_list, n) + bfd_add_request(p, req); + BFD_UNLOCK; } static void bfd_drop_requests(struct bfd_proto *p) { node *n; - - HASH_WALK(p->session_hash_id, next_id, s) + BFD_LOCK; + HASH_WALK_DELSAFE(p->session_hash_id, next_id, s) { - /* We assume that p is not in bfd_proto_list */ WALK_LIST_FIRST(n, s->request_list) - bfd_submit_request(SKIP_BACK(struct bfd_request, n, n)); + { + struct bfd_request *req = SKIP_BACK(struct bfd_request, n, n); + rem_node(&req->n); + add_tail(&bfd_global.wait_list, &req->n); + req->session = &bfd_admin_down; + ev_send_self(&req->event); + } + + bfd_schedule_pickup(); + bfd_remove_session(p, s); } HASH_WALK_END; + BFD_UNLOCK; } static struct resclass bfd_request_class; @@ -724,13 +757,11 @@ struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, struct iface *vrf, void (*hook)(struct bfd_request *), void *data, + struct event_list *list, const struct bfd_options *opts) { struct bfd_request *req = ralloc(p, &bfd_request_class); - /* Hack: self-link req->n, we will call rem_node() on it */ - req->n.prev = req->n.next = &req->n; - req->addr = addr; req->local = local; req->iface = iface; @@ -739,10 +770,19 @@ bfd_request_session(pool *p, ip_addr addr, ip_addr local, if (opts) req->opts = *opts; - bfd_submit_request(req); - req->hook = hook; req->data = data; + req->event = (event) { + .hook = bfd_request_notify, + .data = req, + .list = list, + }; + + BFD_LOCK; + req->session = &bfd_admin_down; + add_tail(&bfd_global.wait_list, &req->n); + bfd_schedule_pickup(); + BFD_UNLOCK; return req; } @@ -750,30 +790,29 @@ bfd_request_session(pool *p, ip_addr addr, ip_addr local, void bfd_update_request(struct bfd_request *req, const struct bfd_options *opts) { - struct bfd_session *s = req->session; - if (!memcmp(opts, &req->opts, sizeof(const struct bfd_options))) return; + BFD_LOCK; req->opts = *opts; - if (s) - bfd_reconfigure_session(s->ifa->bfd, s); + struct bfd_session *s = req->session; + if (s != &bfd_admin_down) + ev_send_self(&s->update_event); + + BFD_UNLOCK; } static void bfd_request_free(resource *r) { struct bfd_request *req = (struct bfd_request *) r; - struct bfd_session *s = req->session; + BFD_LOCK; rem_node(&req->n); + BFD_UNLOCK; - /* 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) - bfd_remove_session(s->ifa->bfd, s); + ev_postpone(&req->event); } static void @@ -810,7 +849,7 @@ bfd_neigh_notify(struct neighbor *nb) if ((nb->scope > 0) && !n->req) { ip_addr local = ipa_nonzero(n->local) ? n->local : nb->ifa->ip; - n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, p->p.vrf, NULL, NULL, NULL); + n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, p->p.vrf, NULL, NULL, birdloop_event_list(p->p.loop), NULL); } if ((nb->scope <= 0) && n->req) @@ -827,7 +866,7 @@ bfd_start_neighbor(struct bfd_proto *p, struct bfd_neighbor *n) if (n->multihop) { - n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, p->p.vrf, NULL, NULL, NULL); + n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, p->p.vrf, NULL, NULL, birdloop_event_list(p->p.loop), NULL); return; } @@ -902,107 +941,15 @@ bfd_reconfigure_neighbors(struct bfd_proto *p, struct bfd_config *new) /* - * BFD notify socket - */ - -/* 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) -{ - struct bfd_proto *p = sk->data; - struct bfd_session *s; - list tmp_list; - u8 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); - init_list(&p->notify_list); - bfd_unlock_sessions(p); - - WALK_LIST_FIRST(s, tmp_list) - { - bfd_lock_sessions(p); - rem_node(&s->n); - state = s->loc_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); - 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; -} - -static inline void -bfd_notify_kick(struct bfd_proto *p) -{ - pipe_kick(p->notify_ws->fd); -} - -static void -bfd_noterr_hook(sock *sk, int err) -{ - struct bfd_proto *p = sk->data; - log(L_ERR "%s: Notify socket error: %m", p->p.name, err); -} - -static void -bfd_notify_init(struct bfd_proto *p) -{ - int pfds[2]; - sock *sk; - - int rv = pipe(pfds); - if (rv < 0) - die("pipe: %m"); - - sk = sk_new(p->p.pool); - sk->type = SK_MAGIC; - sk->rx_hook = bfd_notify_hook; - sk->err_hook = bfd_noterr_hook; - sk->fd = pfds[0]; - sk->data = p; - if (sk_open(sk) < 0) - die("bfd: sk_open failed"); - p->notify_rs = sk; - - /* The write sock is not added to any event loop */ - sk = sk_new(p->p.pool); - sk->type = SK_MAGIC; - sk->fd = pfds[1]; - sk->data = p; - sk->flags = SKF_THREAD; - if (sk_open(sk) < 0) - die("bfd: sk_open failed"); - p->notify_ws = sk; -} - - -/* * BFD protocol glue */ void bfd_init_all(void) { - init_list(&bfd_proto_list); - init_list(&bfd_wait_list); + bfd_global.lock = DOMAIN_NEW(rtable, "BFD Global"); + init_list(&bfd_global.wait_list); + init_list(&bfd_global.proto_list); } static struct proto * @@ -1021,22 +968,13 @@ bfd_start(struct proto *P) struct bfd_proto *p = (struct bfd_proto *) P; struct bfd_config *cf = (struct bfd_config *) (P->cf); - p->loop = birdloop_new(); - p->tpool = rp_new(NULL, "BFD thread root"); - pthread_spin_init(&p->lock, PTHREAD_PROCESS_PRIVATE); - p->session_slab = sl_new(P->pool, sizeof(struct bfd_session)); HASH_INIT(p->session_hash_id, P->pool, 8); HASH_INIT(p->session_hash_ip, P->pool, 8); init_list(&p->iface_list); - init_list(&p->notify_list); - bfd_notify_init(p); - - add_tail(&bfd_proto_list, &p->bfd_node); - - birdloop_enter(p->loop); + add_tail(&bfd_global.proto_list, &p->bfd_node); if (cf->accept_ipv4 && cf->accept_direct) p->rx4_1 = bfd_open_rx_sk(p, 0, SK_IPV4); @@ -1050,42 +988,33 @@ bfd_start(struct proto *P) if (cf->accept_ipv6 && cf->accept_multihop) p->rx6_m = bfd_open_rx_sk(p, 1, SK_IPV6); - birdloop_leave(p->loop); - bfd_take_requests(p); struct bfd_neighbor *n; WALK_LIST(n, cf->neigh_list) bfd_start_neighbor(p, n); - birdloop_start(p->loop); - return PS_UP; } - static int bfd_shutdown(struct proto *P) { struct bfd_proto *p = (struct bfd_proto *) P; - struct bfd_config *cf = (struct bfd_config *) (P->cf); + struct bfd_config *cf = (struct bfd_config *) (p->p.cf); rem_node(&p->bfd_node); - birdloop_stop(p->loop); - - struct bfd_neighbor *n; - WALK_LIST(n, cf->neigh_list) - bfd_stop_neighbor(p, n); + struct bfd_neighbor *bn; + WALK_LIST(bn, cf->neigh_list) + bfd_stop_neighbor(p, bn); bfd_drop_requests(p); - /* FIXME: This is hack */ - birdloop_enter(p->loop); - rfree(p->tpool); - birdloop_leave(p->loop); - - birdloop_free(p->loop); + if (p->rx4_1) sk_stop(p->rx4_1); + if (p->rx4_m) sk_stop(p->rx4_m); + if (p->rx6_1) sk_stop(p->rx6_1); + if (p->rx6_m) sk_stop(p->rx6_m); return PS_DOWN; } @@ -1098,6 +1027,8 @@ bfd_reconfigure(struct proto *P, struct proto_config *c) struct bfd_config *new = (struct bfd_config *) c; struct bfd_iface *ifa; + ASSERT_DIE(birdloop_inside(P->loop)); + /* TODO: Improve accept reconfiguration */ if ((new->accept_ipv4 != old->accept_ipv4) || (new->accept_ipv6 != old->accept_ipv6) || @@ -1105,21 +1036,21 @@ bfd_reconfigure(struct proto *P, struct proto_config *c) (new->accept_multihop != old->accept_multihop)) return 0; - birdloop_mask_wakeups(p->loop); + birdloop_mask_wakeups(p->p.loop); WALK_LIST(ifa, p->iface_list) bfd_reconfigure_iface(p, ifa, new); - HASH_WALK(p->session_hash_id, next_id, s) + HASH_WALK_DELSAFE(p->session_hash_id, next_id, s) { if (s->ifa->changed) bfd_reconfigure_session(p, s); } - HASH_WALK_END; + HASH_WALK_DELSAFE_END; bfd_reconfigure_neighbors(p, new); - birdloop_unmask_wakeups(p->loop); + birdloop_unmask_wakeups(p->p.loop); return 1; } @@ -1140,13 +1071,14 @@ bfd_show_sessions(struct proto *P) { byte tbuf[TM_DATETIME_BUFFER_SIZE]; struct bfd_proto *p = (struct bfd_proto *) P; - uint state, diag UNUSED; btime tx_int, timeout; const char *ifname; + birdloop_enter(P->loop); if (p->p.proto_state != PS_UP) { cli_msg(-1020, "%s: is not up", p->p.name); + birdloop_leave(P->loop); return; } @@ -1154,12 +1086,9 @@ bfd_show_sessions(struct proto *P) cli_msg(-1020, "%-25s %-10s %-10s %-12s %8s %8s", "IP address", "Interface", "State", "Since", "Interval", "Timeout"); - HASH_WALK(p->session_hash_id, next_id, s) { - /* FIXME: this is thread-unsafe, but perhaps harmless */ - state = s->loc_state; - diag = s->loc_diag; + uint state = BFD_LOC_STATE(s).state; ifname = (s->ifa && s->ifa->iface) ? s->ifa->iface->name : "---"; tx_int = s->last_tx ? MAX(s->des_min_tx_int, s->rem_min_rx_int) : 0; timeout = (btime) MAX(s->req_min_rx_int, s->rem_min_tx_int) * s->rem_detect_mult; @@ -1171,6 +1100,8 @@ bfd_show_sessions(struct proto *P) s->addr, ifname, bfd_state_names[state], tbuf, tx_int, timeout); } HASH_WALK_END; + + birdloop_leave(P->loop); } diff --git a/proto/bfd/bfd.h b/proto/bfd/bfd.h index 91fdaa60..b3266857 100644 --- a/proto/bfd/bfd.h +++ b/proto/bfd/bfd.h @@ -17,12 +17,12 @@ #include "nest/password.h" #include "conf/conf.h" #include "lib/hash.h" +#include "lib/io-loop.h" #include "lib/resource.h" #include "lib/socket.h" #include "lib/string.h" #include "nest/bfd.h" -#include "io.h" #define BFD_CONTROL_PORT 3784 @@ -87,19 +87,13 @@ struct bfd_neighbor struct bfd_proto { struct proto p; - struct birdloop *loop; - pool *tpool; - pthread_spinlock_t lock; + node bfd_node; slab *session_slab; HASH(struct bfd_session) session_hash_id; HASH(struct bfd_session) session_hash_ip; - sock *notify_rs; - sock *notify_ws; - list notify_list; - sock *rx4_1; sock *rx6_1; sock *rx4_m; @@ -122,7 +116,6 @@ struct bfd_iface struct bfd_session { - node n; ip_addr addr; /* Address of session */ struct bfd_iface *ifa; /* Iface associated with session */ struct bfd_session *next_id; /* Next in bfd.session_hash_id */ @@ -133,14 +126,15 @@ struct bfd_session u8 poll_active; u8 poll_scheduled; - u8 loc_state; - u8 rem_state; - u8 loc_diag; - u8 rem_diag; + _Atomic struct bfd_session_state loc; + struct bfd_session_state rem; +#define BFD_LOC_STATE(s) atomic_load_explicit(&(s)->loc, memory_order_relaxed) + u32 loc_id; /* Local session ID (local discriminator) */ u32 rem_id; /* Remote session ID (remote discriminator) */ - struct bfd_session_config cf; /* Static configuration parameters */ + struct bfd_session_config cf; /* Static configuration parameers */ + event update_event; /* Reconfiguration requested */ u32 des_min_tx_int; /* Desired min rx interval, local option */ u32 des_min_tx_new; /* Used for des_min_tx_int change */ @@ -162,6 +156,7 @@ struct bfd_session list request_list; /* List of client requests (struct bfd_request) */ btime last_state_change; /* Time of last state change */ + btime last_reqlist_check; /* Time of last check whether the request list is not empty */ u8 notify_running; /* 1 if notify hooks are running */ u8 rx_csn_known; /* Received crypto sequence number is known */ @@ -208,10 +203,6 @@ extern const char *bfd_state_names[]; extern const u8 bfd_auth_type_to_hash_alg[]; - -static inline void bfd_lock_sessions(struct bfd_proto *p) { pthread_spin_lock(&p->lock); } -static inline void bfd_unlock_sessions(struct bfd_proto *p) { pthread_spin_unlock(&p->lock); } - /* bfd.c */ struct bfd_session * bfd_find_session_by_id(struct bfd_proto *p, u32 id); struct bfd_session * bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr, uint ifindex); diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y index df1cba42..ed5479fb 100644 --- a/proto/bfd/config.Y +++ b/proto/bfd/config.Y @@ -36,6 +36,7 @@ proto: bfd_proto ; bfd_proto_start: proto_start BFD { this_proto = proto_config_new(&proto_bfd, $1); + this_proto->loop_order = DOMAIN_ORDER(proto); init_list(&BFD_CFG->patt_list); init_list(&BFD_CFG->neigh_list); BFD_CFG->accept_ipv4 = BFD_CFG->accept_ipv6 = 1; diff --git a/proto/bfd/io.c b/proto/bfd/io.c deleted file mode 100644 index 1cd9365a..00000000 --- a/proto/bfd/io.c +++ /dev/null @@ -1,535 +0,0 @@ -/* - * BIRD -- I/O and event loop - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <pthread.h> -#include <time.h> -#include <sys/time.h> - -#include "nest/bird.h" -#include "proto/bfd/io.h" - -#include "lib/buffer.h" -#include "lib/lists.h" -#include "lib/resource.h" -#include "lib/event.h" -#include "lib/timer.h" -#include "lib/socket.h" - - -struct birdloop -{ - pool *pool; - pthread_t thread; - pthread_mutex_t mutex; - - u8 stop_called; - u8 poll_active; - u8 wakeup_masked; - int wakeup_fds[2]; - - struct timeloop time; - list event_list; - list sock_list; - uint sock_num; - - BUFFER(sock *) poll_sk; - BUFFER(struct pollfd) poll_fd; - u8 poll_changed; - u8 close_scheduled; -}; - - -/* - * Current thread context - */ - -static pthread_key_t current_loop_key; -extern pthread_key_t current_time_key; - -static inline struct birdloop * -birdloop_current(void) -{ - return pthread_getspecific(current_loop_key); -} - -static inline void -birdloop_set_current(struct birdloop *loop) -{ - pthread_setspecific(current_loop_key, loop); - pthread_setspecific(current_time_key, loop ? &loop->time : &main_timeloop); -} - -static inline void -birdloop_init_current(void) -{ - pthread_key_create(¤t_loop_key, NULL); -} - - -/* - * Wakeup code for birdloop - */ - -static void -pipe_new(int *pfds) -{ - int rv = pipe(pfds); - if (rv < 0) - die("pipe: %m"); - - if (fcntl(pfds[0], F_SETFL, O_NONBLOCK) < 0) - die("fcntl(O_NONBLOCK): %m"); - - if (fcntl(pfds[1], F_SETFL, O_NONBLOCK) < 0) - die("fcntl(O_NONBLOCK): %m"); -} - -void -pipe_drain(int fd) -{ - char buf[64]; - int rv; - - try: - rv = read(fd, buf, 64); - if (rv < 0) - { - if (errno == EINTR) - goto try; - if (errno == EAGAIN) - return; - die("wakeup read: %m"); - } - if (rv == 64) - goto try; -} - -void -pipe_kick(int fd) -{ - u64 v = 1; - int rv; - - try: - rv = write(fd, &v, sizeof(u64)); - if (rv < 0) - { - if (errno == EINTR) - goto try; - if (errno == EAGAIN) - return; - die("wakeup write: %m"); - } -} - -static inline void -wakeup_init(struct birdloop *loop) -{ - pipe_new(loop->wakeup_fds); -} - -static inline void -wakeup_drain(struct birdloop *loop) -{ - pipe_drain(loop->wakeup_fds[0]); -} - -static inline void -wakeup_do_kick(struct birdloop *loop) -{ - pipe_kick(loop->wakeup_fds[1]); -} - -static inline void -wakeup_kick(struct birdloop *loop) -{ - if (!loop->wakeup_masked) - wakeup_do_kick(loop); - else - loop->wakeup_masked = 2; -} - -/* For notifications from outside */ -void -wakeup_kick_current(void) -{ - struct birdloop *loop = birdloop_current(); - - if (loop && loop->poll_active) - wakeup_kick(loop); -} - - -/* - * Events - */ - -static inline uint -events_waiting(struct birdloop *loop) -{ - return !EMPTY_LIST(loop->event_list); -} - -static inline void -events_init(struct birdloop *loop) -{ - init_list(&loop->event_list); -} - -static void -events_fire(struct birdloop *loop) -{ - times_update(&loop->time); - ev_run_list(&loop->event_list); -} - -void -ev2_schedule(event *e) -{ - struct birdloop *loop = birdloop_current(); - - if (loop->poll_active && EMPTY_LIST(loop->event_list)) - wakeup_kick(loop); - - if (e->n.next) - rem_node(&e->n); - - add_tail(&loop->event_list, &e->n); -} - - -/* - * Sockets - */ - -static void -sockets_init(struct birdloop *loop) -{ - init_list(&loop->sock_list); - loop->sock_num = 0; - - BUFFER_INIT(loop->poll_sk, loop->pool, 4); - BUFFER_INIT(loop->poll_fd, loop->pool, 4); - loop->poll_changed = 1; /* add wakeup fd */ -} - -static void -sockets_add(struct birdloop *loop, sock *s) -{ - add_tail(&loop->sock_list, &s->n); - loop->sock_num++; - - s->index = -1; - loop->poll_changed = 1; - - if (loop->poll_active) - wakeup_kick(loop); -} - -void -sk_start(sock *s) -{ - struct birdloop *loop = birdloop_current(); - - sockets_add(loop, s); -} - -static void -sockets_remove(struct birdloop *loop, sock *s) -{ - rem_node(&s->n); - loop->sock_num--; - - if (s->index >= 0) - loop->poll_sk.data[s->index] = NULL; - - s->index = -1; - loop->poll_changed = 1; - - /* Wakeup moved to sk_stop() */ -} - -void -sk_stop(sock *s) -{ - struct birdloop *loop = birdloop_current(); - - sockets_remove(loop, s); - - if (loop->poll_active) - { - loop->close_scheduled = 1; - wakeup_kick(loop); - } - else - close(s->fd); - - s->fd = -1; -} - -static inline uint sk_want_events(sock *s) -{ return (s->rx_hook ? POLLIN : 0) | ((s->ttx != s->tpos) ? POLLOUT : 0); } - -/* -FIXME: this should be called from sock code - -static void -sockets_update(struct birdloop *loop, sock *s) -{ - if (s->index >= 0) - loop->poll_fd.data[s->index].events = sk_want_events(s); -} -*/ - -static void -sockets_prepare(struct birdloop *loop) -{ - BUFFER_SET(loop->poll_sk, loop->sock_num + 1); - BUFFER_SET(loop->poll_fd, loop->sock_num + 1); - - struct pollfd *pfd = loop->poll_fd.data; - sock **psk = loop->poll_sk.data; - uint i = 0; - node *n; - - WALK_LIST(n, loop->sock_list) - { - sock *s = SKIP_BACK(sock, n, n); - - ASSERT(i < loop->sock_num); - - s->index = i; - *psk = s; - pfd->fd = s->fd; - pfd->events = sk_want_events(s); - pfd->revents = 0; - - pfd++; - psk++; - i++; - } - - ASSERT(i == loop->sock_num); - - /* Add internal wakeup fd */ - *psk = NULL; - pfd->fd = loop->wakeup_fds[0]; - pfd->events = POLLIN; - pfd->revents = 0; - - loop->poll_changed = 0; -} - -static void -sockets_close_fds(struct birdloop *loop) -{ - struct pollfd *pfd = loop->poll_fd.data; - sock **psk = loop->poll_sk.data; - int poll_num = loop->poll_fd.used - 1; - - int i; - for (i = 0; i < poll_num; i++) - if (psk[i] == NULL) - close(pfd[i].fd); - - loop->close_scheduled = 0; -} - -int sk_read(sock *s, int revents); -int sk_write(sock *s); - -static void -sockets_fire(struct birdloop *loop) -{ - struct pollfd *pfd = loop->poll_fd.data; - sock **psk = loop->poll_sk.data; - int poll_num = loop->poll_fd.used - 1; - - times_update(&loop->time); - - /* Last fd is internal wakeup fd */ - if (pfd[poll_num].revents & POLLIN) - wakeup_drain(loop); - - int i; - for (i = 0; i < poll_num; pfd++, psk++, i++) - { - int e = 1; - - if (! pfd->revents) - continue; - - if (pfd->revents & POLLNVAL) - die("poll: invalid fd %d", pfd->fd); - - if (pfd->revents & POLLIN) - while (e && *psk && (*psk)->rx_hook) - e = sk_read(*psk, 0); - - e = 1; - if (pfd->revents & POLLOUT) - while (e && *psk) - e = sk_write(*psk); - } -} - - -/* - * Birdloop - */ - -static void * birdloop_main(void *arg); - -struct birdloop * -birdloop_new(void) -{ - /* FIXME: this init should be elsewhere and thread-safe */ - static int init = 0; - if (!init) - { birdloop_init_current(); init = 1; } - - pool *p = rp_new(NULL, "Birdloop root"); - struct birdloop *loop = mb_allocz(p, sizeof(struct birdloop)); - loop->pool = p; - pthread_mutex_init(&loop->mutex, NULL); - - wakeup_init(loop); - - events_init(loop); - timers_init(&loop->time, p); - sockets_init(loop); - - return loop; -} - -void -birdloop_start(struct birdloop *loop) -{ - int rv = pthread_create(&loop->thread, NULL, birdloop_main, loop); - if (rv) - die("pthread_create(): %M", rv); -} - -void -birdloop_stop(struct birdloop *loop) -{ - pthread_mutex_lock(&loop->mutex); - loop->stop_called = 1; - wakeup_do_kick(loop); - pthread_mutex_unlock(&loop->mutex); - - int rv = pthread_join(loop->thread, NULL); - if (rv) - die("pthread_join(): %M", rv); -} - -void -birdloop_free(struct birdloop *loop) -{ - rfree(loop->pool); -} - - -void -birdloop_enter(struct birdloop *loop) -{ - /* TODO: these functions could save and restore old context */ - pthread_mutex_lock(&loop->mutex); - birdloop_set_current(loop); -} - -void -birdloop_leave(struct birdloop *loop) -{ - /* TODO: these functions could save and restore old context */ - birdloop_set_current(NULL); - pthread_mutex_unlock(&loop->mutex); -} - -void -birdloop_mask_wakeups(struct birdloop *loop) -{ - pthread_mutex_lock(&loop->mutex); - loop->wakeup_masked = 1; - pthread_mutex_unlock(&loop->mutex); -} - -void -birdloop_unmask_wakeups(struct birdloop *loop) -{ - pthread_mutex_lock(&loop->mutex); - if (loop->wakeup_masked == 2) - wakeup_do_kick(loop); - loop->wakeup_masked = 0; - pthread_mutex_unlock(&loop->mutex); -} - -static void * -birdloop_main(void *arg) -{ - struct birdloop *loop = arg; - timer *t; - int rv, timeout; - - birdloop_set_current(loop); - - pthread_mutex_lock(&loop->mutex); - while (1) - { - events_fire(loop); - timers_fire(&loop->time); - - times_update(&loop->time); - if (events_waiting(loop)) - timeout = 0; - else if (t = timers_first(&loop->time)) - timeout = (tm_remains(t) TO_MS) + 1; - else - timeout = -1; - - if (loop->poll_changed) - sockets_prepare(loop); - - loop->poll_active = 1; - pthread_mutex_unlock(&loop->mutex); - - try: - rv = poll(loop->poll_fd.data, loop->poll_fd.used, timeout); - if (rv < 0) - { - if (errno == EINTR || errno == EAGAIN) - goto try; - die("poll: %m"); - } - - pthread_mutex_lock(&loop->mutex); - loop->poll_active = 0; - - if (loop->close_scheduled) - sockets_close_fds(loop); - - if (loop->stop_called) - break; - - if (rv) - sockets_fire(loop); - - timers_fire(&loop->time); - } - - loop->stop_called = 0; - pthread_mutex_unlock(&loop->mutex); - - return NULL; -} - - diff --git a/proto/bfd/io.h b/proto/bfd/io.h deleted file mode 100644 index ec706e9a..00000000 --- a/proto/bfd/io.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * BIRD -- I/O and event loop - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#ifndef _BIRD_BFD_IO_H_ -#define _BIRD_BFD_IO_H_ - -#include "nest/bird.h" -#include "lib/lists.h" -#include "lib/resource.h" -#include "lib/event.h" -#include "lib/timer.h" -#include "lib/socket.h" - - -void ev2_schedule(event *e); - -void sk_start(sock *s); -void sk_stop(sock *s); - -struct birdloop *birdloop_new(void); -void birdloop_start(struct birdloop *loop); -void birdloop_stop(struct birdloop *loop); -void birdloop_free(struct birdloop *loop); - -void birdloop_enter(struct birdloop *loop); -void birdloop_leave(struct birdloop *loop); -void birdloop_mask_wakeups(struct birdloop *loop); -void birdloop_unmask_wakeups(struct birdloop *loop); - - -#endif /* _BIRD_BFD_IO_H_ */ diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c index 7618e20f..893d582d 100644 --- a/proto/bfd/packets.c +++ b/proto/bfd/packets.c @@ -290,9 +290,11 @@ bfd_send_ctl(struct bfd_proto *p, struct bfd_session *s, int final) if (!sk) return; + struct bfd_session_state loc = BFD_LOC_STATE(s); + pkt = (struct bfd_ctl_packet *) sk->tbuf; - pkt->vdiag = bfd_pack_vdiag(1, s->loc_diag); - pkt->flags = bfd_pack_flags(s->loc_state, 0); + pkt->vdiag = bfd_pack_vdiag(1, loc.diag); + pkt->flags = bfd_pack_flags(loc.state, 0); pkt->detect_mult = s->detect_mult; pkt->length = BFD_BASE_LEN; pkt->snd_id = htonl(s->loc_id); @@ -313,7 +315,7 @@ bfd_send_ctl(struct bfd_proto *p, struct bfd_session *s, int final) log(L_WARN "%s: Old packet overwritten in TX buffer", p->p.name); TRACE(D_PACKETS, "Sending CTL to %I [%s%s]", s->addr, - bfd_state_names[s->loc_state], bfd_format_flags(pkt->flags, fb)); + bfd_state_names[loc.state], bfd_format_flags(pkt->flags, fb)); sk_send_to(sk, pkt->length, s->addr, sk->dport); } @@ -382,16 +384,17 @@ bfd_rx_hook(sock *sk, uint len) u32 old_rx_int = s->rem_min_rx_int; s->rem_id= ntohl(pkt->snd_id); - s->rem_state = bfd_pkt_get_state(pkt); - s->rem_diag = bfd_pkt_get_diag(pkt); + s->rem.state = bfd_pkt_get_state(pkt); + s->rem.diag = bfd_pkt_get_diag(pkt); s->rem_demand_mode = pkt->flags & BFD_FLAG_DEMAND; s->rem_min_tx_int = ntohl(pkt->des_min_tx_int); s->rem_min_rx_int = ntohl(pkt->req_min_rx_int); s->rem_detect_mult = pkt->detect_mult; TRACE(D_PACKETS, "CTL received from %I [%s%s]", sk->faddr, - bfd_state_names[s->rem_state], bfd_format_flags(pkt->flags, fb)); + bfd_state_names[s->rem.state], bfd_format_flags(pkt->flags, fb)); + /* This call may drop the session, must be called in tail position */ bfd_session_process_ctl(s, pkt->flags, old_tx_int, old_rx_int); return 1; @@ -410,7 +413,7 @@ bfd_err_hook(sock *sk, int err) sock * bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af) { - sock *sk = sk_new(p->tpool); + sock *sk = sk_new(p->p.pool); sk->type = SK_UDP; sk->subtype = af; sk->sport = !multihop ? BFD_CONTROL_PORT : BFD_MULTI_CTL_PORT; @@ -425,6 +428,7 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af) sk->tos = IP_PREC_INTERNET_CONTROL; sk->priority = sk_priority_control; sk->flags = SKF_THREAD | SKF_LADDR_RX | (!multihop ? SKF_TTL_RX : 0); + sk->loop = p->p.loop; if (sk_open(sk) < 0) goto err; @@ -441,7 +445,7 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af) sock * bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa) { - sock *sk = sk_new(p->tpool); + sock *sk = sk_new(p->p.pool); sk->type = SK_UDP; sk->saddr = local; sk->dport = ifa ? BFD_CONTROL_PORT : BFD_MULTI_CTL_PORT; @@ -457,6 +461,7 @@ bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa) sk->priority = sk_priority_control; sk->ttl = ifa ? 255 : -1; sk->flags = SKF_THREAD | SKF_BIND | SKF_HIGH_PORT; + sk->loop = p->p.loop; if (sk_open(sk) < 0) goto err; |