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/neighbor.c | 67 +++++++++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 35 deletions(-) (limited to 'nest/neighbor.c') 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