diff options
author | Maria Matejka <mq@ucw.cz> | 2023-01-31 13:07:46 +0100 |
---|---|---|
committer | Maria Matejka <mq@ucw.cz> | 2023-02-02 15:57:21 +0100 |
commit | c354e8f4c199ca7dec441394156d18badac71b81 (patch) | |
tree | d5a0c43215603bef858699aa49678e27894893f8 /nest/neighbor.c | |
parent | 64e08775251960a2b009fc35a084610c9c4c4909 (diff) |
Interface updates are asynchronous
Instead of propagating interface updates as they are loaded from kernel,
they are enqueued and all the notifications are called from a
protocol-specific event. This change allows to break the locking loop
between protocols and interfaces.
Anyway, this change is based on v2 branch to keep the changes between v2
and v3 smaller.
Diffstat (limited to 'nest/neighbor.c')
-rw-r--r-- | nest/neighbor.c | 63 |
1 files changed, 46 insertions, 17 deletions
diff --git a/nest/neighbor.c b/nest/neighbor.c index c27db989..88ac2860 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -258,13 +258,15 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags) add_tail((scope >= 0) ? &iface->neighbors : &sticky_neigh_list, &n->if_n); proto_neigh_add_tail(&p->neighbors, n); n->addr = a; - n->ifa = addr; - n->iface = iface; - n->ifreq = ifreq; + ifa_link(n->ifa = addr); + if_link(n->iface = iface); + if_link(n->ifreq = ifreq); n->proto = p; n->flags = flags; n->scope = scope; + neigh_link(n); + return n; } @@ -309,19 +311,20 @@ neigh_dump_all(void) static inline void neigh_notify(neighbor *n) { - if (n->proto && n->proto->neigh_notify && (n->proto->proto_state != PS_STOP)) - n->proto->neigh_notify(n); + if_enqueue_notify_to((struct iface_notification) { .type = IFNOT_NEIGHBOR, .n = n, }, &n->proto->iface_sub); } static void neigh_up(neighbor *n, struct iface *i, struct ifa *a, int scope) { DBG("Waking up sticky neighbor %I\n", n->addr); - n->iface = i; - n->ifa = a; + if_link(n->iface = i); + ifa_link(n->ifa = a); + n->scope = scope; - rem_node(&n->if_n); + rem_node(&n->if_n); /* HACK: Here the neighbor is always in the sticky list, + regardless whether it is sticky or not */ add_tail(&i->neighbors, &n->if_n); neigh_notify(n); @@ -331,25 +334,48 @@ static void neigh_down(neighbor *n) { DBG("Flushing neighbor %I on %s\n", n->addr, n->iface->name); - n->iface = NULL; - n->ifa = NULL; + n->scope = -1; rem_node(&n->if_n); add_tail(&sticky_neigh_list, &n->if_n); + ifa_unlink(n->ifa); + n->ifa = NULL; + + if_unlink(n->iface); + n->iface = NULL; + neigh_notify(n); } -static inline void -neigh_free(neighbor *n) +void +neigh_link(neighbor *n) { - proto_neigh_rem_node(&n->proto->neighbors, n); + n->uc++; +} + +void +neigh_unlink(neighbor *n) +{ + if (--n->uc) + return; + + struct proto *p = n->proto; + proto_neigh_rem_node(&p->neighbors, n); + + if ((p->proto_state == PS_DOWN) && EMPTY_TLIST(proto_neigh, &p->neighbors)) + ev_schedule(p->event); + n->proto = NULL; rem_node(&n->n); rem_node(&n->if_n); + ifa_unlink(n->ifa); + if_unlink(n->iface); + if_unlink(n->ifreq); + sl_free(n); } @@ -399,7 +425,8 @@ neigh_update(neighbor *n, struct iface *iface) { if (ifa != n->ifa) { - n->ifa = ifa; + ifa_unlink(n->ifa); + ifa_link(n->ifa = ifa); neigh_notify(n); } @@ -413,7 +440,7 @@ neigh_update(neighbor *n, struct iface *iface) if ((n->scope < 0) && !(n->flags & NEF_STICKY)) { - neigh_free(n); + neigh_unlink(n); return; } @@ -534,8 +561,10 @@ neigh_ifa_down(struct ifa *a) void neigh_prune(struct proto *p) { - while (!EMPTY_TLIST(proto_neigh, &p->neighbors)) - neigh_free(THEAD(proto_neigh, &p->neighbors)); + WALK_TLIST_DELSAFE(proto_neigh, n, &p->neighbors) + neigh_unlink(n); + + ASSERT_DIE(EMPTY_TLIST(proto_neigh, &p->neighbors)); } /** |