summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/iface.h1
-rw-r--r--nest/neighbor.c41
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);
}