diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/iface.h | 1 | ||||
-rw-r--r-- | nest/neighbor.c | 41 |
2 files changed, 37 insertions, 5 deletions
diff --git a/nest/iface.h b/nest/iface.h index 5deb5432..6e8c8448 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -153,6 +153,7 @@ typedef struct neighbor { #define NEF_STICKY 1 #define NEF_ONLINK 2 #define NEF_IFACE 4 /* Entry for whole iface */ +#define NEF_NOTIFY_MAIN 0x100 /* Notify from main_birdloop context */ neighbor *neigh_find(struct proto *p, ip_addr a, struct iface *ifa, uint flags); diff --git a/nest/neighbor.c b/nest/neighbor.c index 7466e510..e4d42b4d 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -60,6 +60,7 @@ static slab *neigh_slab; static list neigh_hash_table[NEIGH_HASH_SIZE], sticky_neigh_list; static void neigh_do_notify(void *); +static void neigh_do_notify_main(void *); static inline uint neigh_hash(struct proto *p, ip_addr a, struct iface *i) @@ -270,15 +271,29 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags) n->proto = p; n->flags = flags; n->scope = scope; - n->event = (event) { .hook = neigh_do_notify, .data = n }; + ASSERT_DIE(birdloop_inside(p->loop)); - if (p->loop == &main_birdloop) - n->event.list = &global_event_list; + if (flags & NEF_NOTIFY_MAIN) + n->event = (event) { + .hook = neigh_do_notify_main, + .data = n, + .list = &global_event_list, + }; + else if (p->loop == &main_birdloop) + n->event = (event) { + .hook = neigh_do_notify, + .data = n, + .list = &global_event_list, + }; else { birdloop_link(p->loop); - n->event.list = birdloop_event_list(p->loop); + n->event = (event) { + .hook = neigh_do_notify, + .data = n, + .list = birdloop_event_list(p->loop), + }; } IFACE_UNLOCK; @@ -341,6 +356,14 @@ neigh_notify(neighbor *n) } static void +neigh_do_notify_main(void *data) +{ + neighbor *n = data; + PROTO_LOCKED_FROM_MAIN(n->proto) + neigh_do_notify(data); +} + +static void neigh_do_notify(void *data) { neighbor *n = data; @@ -382,10 +405,18 @@ neigh_down(neighbor *n) static inline void neigh_free(neighbor *n) { + ASSERT_DIE(birdloop_inside(n->proto->loop)); + + if (n->flags & NEF_NOTIFY_MAIN) + ASSERT_DIE(birdloop_inside(&main_birdloop)); + rem_node(&n->n); rem_node(&n->if_n); + + if (n->event.list != &global_event_list) + birdloop_unlink(n->proto->loop); + ev_postpone(&n->event); - birdloop_unlink(n->proto->loop); sl_free(neigh_slab, n); } |