summaryrefslogtreecommitdiffstats
path: root/nest
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2011-12-08 05:53:53 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2011-12-09 06:08:47 +0100
commit631487aa2d45aa2078a08f1852e4a7482abbc2b5 (patch)
tree0388c166eeea1290caa8420f41d8aa9531ba4c00 /nest
parenta0d2290cf82fc77b6497e08a1a69246e4084729d (diff)
downloadbird-631487aa2d45aa2078a08f1852e4a7482abbc2b5.tar
bird-631487aa2d45aa2078a08f1852e4a7482abbc2b5.zip
Make NEF_STICKY work with fixed interfaces and allow specifying interface names
Diffstat (limited to 'nest')
-rw-r--r--nest/iface.h2
-rw-r--r--nest/neighbor.c35
2 files changed, 28 insertions, 9 deletions
diff --git a/nest/iface.h b/nest/iface.h
index 6d333a1..315dda5 100644
--- a/nest/iface.h
+++ b/nest/iface.h
@@ -106,6 +106,7 @@ typedef struct neighbor {
node if_n; /* Node in per-interface neighbor list */
ip_addr addr; /* Address of the neighbor */
struct iface *iface; /* Interface it's connected to */
+ char bound_iface[16]; /* Name of the interface it's bound to */
struct proto *proto; /* Protocol this belongs to */
void *data; /* Protocol-specific data */
unsigned aux; /* Protocol-specific data */
@@ -118,6 +119,7 @@ typedef struct neighbor {
neighbor *neigh_find(struct proto *, ip_addr *, unsigned flags);
neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags);
+neighbor *neigh_find_ifname(struct proto *, ip_addr *, char *, unsigned flags);
static inline int neigh_connected_to(struct proto *p, ip_addr *a, struct iface *i)
{
diff --git a/nest/neighbor.c b/nest/neighbor.c
index cf1b2e9..de75b1d 100644
--- a/nest/neighbor.c
+++ b/nest/neighbor.c
@@ -49,6 +49,9 @@
static slab *neigh_slab;
static list sticky_neigh_list, neigh_hash_table[NEIGH_HASH_SIZE];
+static neighbor *
+neigh_find_internal(struct proto *p, ip_addr *a, struct iface *ifa, char *bound_iface, unsigned flags);
+
static inline unsigned int
neigh_hash(struct proto *p, ip_addr *a)
{
@@ -108,15 +111,26 @@ if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */
neighbor *
neigh_find(struct proto *p, ip_addr *a, unsigned flags)
{
- return neigh_find2(p, a, NULL, flags);
+ return neigh_find_internal(p, a, NULL, NULL, flags);
}
-
neighbor *
neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
{
+ return neigh_find_internal(p, a, ifa, ifa ? ifa->name : NULL, flags);
+}
+
+neighbor *
+neigh_find_ifname(struct proto *p, ip_addr *a, char *ifname, unsigned flags)
+{
+ return neigh_find_internal(p, a, ifname ? if_find_by_name(ifname) : NULL, ifname, flags);
+}
+
+static neighbor *
+neigh_find_internal(struct proto *p, ip_addr *a, struct iface *ifa, char *ifname, unsigned flags)
+{
neighbor *n;
- int class, scope = -1; ;
+ int class, scope = -1;
unsigned int h = neigh_hash(p, a);
struct iface *i;
@@ -128,7 +142,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
if (class < 0) /* Invalid address */
return NULL;
if (((class & IADDR_SCOPE_MASK) == SCOPE_HOST) ||
- (((class & IADDR_SCOPE_MASK) == SCOPE_LINK) && (ifa == NULL)) ||
+ (((class & IADDR_SCOPE_MASK) == SCOPE_LINK) && (ifa == NULL) && (ifname == NULL)) ||
!(class & IADDR_HOST))
return NULL; /* Bad scope or a somecast */
@@ -139,7 +153,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
if ((scope < 0) && (flags & NEF_ONLINK))
scope = class & IADDR_SCOPE_MASK;
}
- else
+ else if (ifname == NULL)
WALK_LIST(i, iface_list)
if ((scope = if_connected(a, i)) >= 0)
{
@@ -162,8 +176,6 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
}
else
{
- /* sticky flag does not work for link-local neighbors;
- fortunately, we don't use this combination */
add_tail(&sticky_neigh_list, &n->n);
ifa = NULL;
scope = -1;
@@ -174,6 +186,8 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
n->aux = 0;
n->flags = flags;
n->scope = scope;
+ strncpy(n->bound_iface, ifname ?: "", sizeof(n->bound_iface)-1);
+
return n;
}
@@ -195,6 +209,8 @@ neigh_dump(neighbor *n)
debug("%s %p %08x scope %s", n->proto->name, n->data, n->aux, ip_scope_text(n->scope));
if (n->flags & NEF_STICKY)
debug(" STICKY");
+ if (*n->bound_iface)
+ debug(" bound to %s", n->bound_iface);
debug("\n");
}
@@ -230,7 +246,7 @@ neigh_dump_all(void)
* 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 change of the scope of a neighbor is handled as a remove with
* a consequent add
*/
void
@@ -262,7 +278,8 @@ neigh_ifa_update(struct ifa *a)
/* 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)
+ if ((!(*n->bound_iface) || strcmp(n->bound_iface, i->name) == 0)
+ && (scope = if_connected(&n->addr, i)) >= 0)
{
n->iface = i;
n->scope = scope;