summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nest/iface.c11
-rw-r--r--nest/iface.h3
-rw-r--r--nest/neighbor.c67
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)
{
@@ -249,36 +276,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
*