diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2012-01-01 12:02:20 +0100 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2012-01-01 12:14:42 +0100 |
commit | 69a8259c5e438f949bd58b1a2f8e1d12a49f9216 (patch) | |
tree | 5d685368ce58732ce4a9133b5f5bc43b20b78476 /nest | |
parent | c32c3f88f0c8788118ed3701c11a5aea2aaf9356 (diff) |
Allows sticky link-local neighbors.
Allows using NEF_STICKY neighbors with link-local addresses. This is
used for static route nexthops, they can be specified like fe80::1%eth0
.
Diffstat (limited to 'nest')
-rw-r--r-- | nest/iface.c | 18 | ||||
-rw-r--r-- | nest/iface.h | 5 | ||||
-rw-r--r-- | nest/neighbor.c | 13 |
3 files changed, 29 insertions, 7 deletions
diff --git a/nest/iface.c b/nest/iface.c index bf57a9b1..b8b214e5 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -424,6 +424,24 @@ if_find_by_name(char *name) return NULL; } +struct iface * +if_get_by_name(char *name) +{ + struct iface *i; + + if (i = if_find_by_name(name)) + return i; + + /* No active iface, create a dummy */ + i = mb_allocz(if_pool, sizeof(struct iface)); + strncpy(i->name, name, sizeof(i->name)-1); + i->flags = IF_SHUTDOWN; + init_list(&i->addrs); + init_list(&i->neighbors); + add_tail(&iface_list, &i->n); + return i; +} + struct ifa *kif_choose_primary(struct iface *i); static int diff --git a/nest/iface.h b/nest/iface.h index 7307844e..d6d58ff9 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -97,6 +97,7 @@ void if_flush_ifaces(struct proto *p); void if_feed_baby(struct proto *); struct iface *if_find_by_index(unsigned); struct iface *if_find_by_name(char *); +struct iface *if_get_by_name(char *); void ifa_recalc_all_primary_addresses(void); /* The Neighbor Cache */ @@ -110,11 +111,13 @@ typedef struct neighbor { void *data; /* Protocol-specific data */ unsigned aux; /* Protocol-specific data */ unsigned flags; - unsigned scope; /* Address scope, SCOPE_HOST when it's our own address */ + int scope; /* Address scope, -1 for unreachable sticky neighbors, + SCOPE_HOST when it's our own address */ } neighbor; #define NEF_STICKY 1 #define NEF_ONLINK 2 +#define NEF_BIND 4 /* Used internally for neighbors bound to an iface */ neighbor *neigh_find(struct proto *, ip_addr *, unsigned flags); neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags); diff --git a/nest/neighbor.c b/nest/neighbor.c index 67bd32b3..506d9bde 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -133,6 +133,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) if (ifa) { scope = if_connected(a, ifa); + flags |= NEF_BIND; if ((scope < 0) && (flags & NEF_ONLINK)) scope = class & IADDR_SCOPE_MASK; @@ -160,10 +161,7 @@ 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; } n->iface = ifa; @@ -235,7 +233,9 @@ neigh_down(neighbor *n) { DBG("Flushing neighbor %I on %s\n", n->addr, i->name); rem_node(&n->if_n); - n->iface = NULL; + if (! (n->flags & NEF_BIND)) + n->iface = NULL; + n->scope = -1; if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING) n->proto->neigh_notify(n); rem_node(&n->n); @@ -262,7 +262,8 @@ neigh_if_up(struct iface *i) int scope; WALK_LIST_DELSAFE(n, next, sticky_neigh_list) - if ((scope = if_connected(&n->addr, i)) >= 0) + if ((!n->iface || n->iface == i) && + ((scope = if_connected(&n->addr, i)) >= 0)) neigh_up(n, i, scope); } @@ -339,7 +340,7 @@ neigh_prune_one(neighbor *n) if (n->proto->proto_state != PS_DOWN) return; rem_node(&n->n); - if (n->iface) + if (n->scope >= 0) rem_node(&n->if_n); sl_free(neigh_slab, n); } |