From b95254f5391542985202b64353c0d0dd6a28ecf7 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 8 Dec 2011 01:09:26 +0100 Subject: Update the neighbor cache on every address addition or removal Only updating the cache when an interface goes up or down leaves it unaware of addresses that are added or removed without taking the interface down. --- nest/iface.c | 11 +++++----- nest/iface.h | 3 +-- nest/neighbor.c | 67 +++++++++++++++++++++++++++------------------------------ 3 files changed, 39 insertions(+), 42 deletions(-) diff --git a/nest/iface.c b/nest/iface.c index 2ff2611..2c61680 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -157,8 +157,14 @@ ifa_notify_change(unsigned c, struct ifa *a) struct proto *p; DBG("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip); + if (c & IF_CHANGE_UP) + neigh_ifa_update(a); + WALK_LIST(p, active_proto_list) ifa_send_notify(p, c, a); + + if (c & IF_CHANGE_DOWN) + neigh_ifa_update(a); } static inline void @@ -195,8 +201,6 @@ if_notify_change(unsigned c, struct iface *i) if_dump(i); #endif - if (c & IF_CHANGE_UP) - neigh_if_up(i); if (c & IF_CHANGE_DOWN) WALK_LIST(a, i->addrs) { @@ -216,9 +220,6 @@ if_notify_change(unsigned c, struct iface *i) if ((c & (IF_CHANGE_UP | IF_CHANGE_DOWN | IF_CHANGE_LINK)) == IF_CHANGE_LINK) neigh_if_link(i); - - if (c & IF_CHANGE_DOWN) - neigh_if_down(i); } static unsigned diff --git a/nest/iface.h b/nest/iface.h index a9cf6cd..6d333a1 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -128,8 +128,7 @@ static inline int neigh_connected_to(struct proto *p, ip_addr *a, struct iface * void neigh_dump(neighbor *); void neigh_dump_all(void); void neigh_prune(void); -void neigh_if_up(struct iface *); -void neigh_if_down(struct iface *); +void neigh_ifa_update(struct ifa *); void neigh_if_link(struct iface *); void neigh_init(struct pool *); diff --git a/nest/neighbor.c b/nest/neighbor.c index 1a5ac21..cf1b2e9 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -220,20 +220,47 @@ neigh_dump_all(void) } /** - * neigh_if_up: notify neighbor cache about interface up event - * @i: interface in question + * neigh_ifa_update: notify neighbor cache about interface address + * add or remove event + * @ifa: interface address in question * - * Tell the neighbor cache that a new interface became up. + * Tell the neighbor cache that a address was added or removed. * * The neighbor cache wakes up all inactive sticky neighbors with - * addresses belonging to prefixes of the interface @i. + * addresses belonging to prefixes of the interface belonging to @ifa + * and causes all unreachable neighbors to be flushed + * + * A change of the scope of a neighbor is handle as a remove with + * a consequent add */ void -neigh_if_up(struct iface *i) +neigh_ifa_update(struct ifa *a) { + node *x, *y; neighbor *n, *next; + struct iface *i = a->iface; int scope; + /* Remove all neighbors whose scope has changed */ + WALK_LIST_DELSAFE(x, y, i->neighbors) + { + n = SKIP_BACK(neighbor, if_n, x); + if (if_connected(&n->addr, i) != n->scope) + { + DBG("Flushing neighbor %I on %s\n", n->addr, i->name); + rem_node(&n->if_n); + n->iface = NULL; + if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING) + n->proto->neigh_notify(n); + rem_node(&n->n); + if (n->flags & NEF_STICKY) + add_tail(&sticky_neigh_list, &n->n); + else + sl_free(neigh_slab, n); + } + } + + /* Traverse the sticky neighbor list to find neighbors that are reachable now */ WALK_LIST_DELSAFE(n, next, sticky_neigh_list) if ((scope = if_connected(&n->addr, i)) >= 0) { @@ -248,36 +275,6 @@ neigh_if_up(struct iface *i) } } -/** - * neigh_if_down - notify neighbor cache about interface down event - * @i: the interface in question - * - * Notify the neighbor cache that an interface has ceased to exist. - * - * It causes all entries belonging to neighbors connected to this interface - * to be flushed. - */ -void -neigh_if_down(struct iface *i) -{ - node *x, *y; - - WALK_LIST_DELSAFE(x, y, i->neighbors) - { - neighbor *n = SKIP_BACK(neighbor, if_n, x); - DBG("Flushing neighbor %I on %s\n", n->addr, i->name); - rem_node(&n->if_n); - n->iface = NULL; - if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING) - n->proto->neigh_notify(n); - rem_node(&n->n); - if (n->flags & NEF_STICKY) - add_tail(&sticky_neigh_list, &n->n); - else - sl_free(neigh_slab, n); - } -} - /** * neigh_if_link - notify neighbor cache about interface link change * @i: the interface in question -- cgit v1.2.3