summaryrefslogtreecommitdiffstats
path: root/nest
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2011-12-08 01:09:26 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2011-12-09 05:58:32 +0100
commitb95254f5391542985202b64353c0d0dd6a28ecf7 (patch)
treef5ff53574e859f24db2ef04f96b5f27f6dea73fb /nest
parent2779d50a24dc1b7c6b4cf83a17af817c02462855 (diff)
downloadbird-b95254f5391542985202b64353c0d0dd6a28ecf7.tar
bird-b95254f5391542985202b64353c0d0dd6a28ecf7.zip
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.
Diffstat (limited to 'nest')
-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
*