summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nest/iface.c20
-rw-r--r--nest/iface.h13
-rw-r--r--proto/babel/babel.c13
-rw-r--r--proto/babel/packets.c1
-rw-r--r--proto/radv/radv.c23
-rw-r--r--proto/rip/packets.c9
-rw-r--r--proto/rip/rip.c4
7 files changed, 46 insertions, 37 deletions
diff --git a/nest/iface.c b/nest/iface.c
index 56de1f5c..7acadc7d 100644
--- a/nest/iface.c
+++ b/nest/iface.c
@@ -470,10 +470,24 @@ struct ifa *kif_choose_primary(struct iface *i);
static int
ifa_recalc_primary(struct iface *i)
{
- struct ifa *a = kif_choose_primary(i);
+ struct ifa *a;
+ int c = 0;
+
+#ifdef IPV6
+ struct ifa *ll = NULL;
+
+ WALK_LIST(a, i->addrs)
+ if (ipa_is_link_local(a->ip) && (!ll || (a == i->llv6)))
+ ll = a;
+
+ c = (ll != i->llv6);
+ i->llv6 = ll;
+#endif
+
+ a = kif_choose_primary(i);
if (a == i->addr)
- return 0;
+ return c;
if (i->addr)
i->addr->flags &= ~IA_PRIMARY;
@@ -577,7 +591,7 @@ ifa_delete(struct ifa *a)
b->flags &= ~IF_UP;
ifa_notify_change(IF_CHANGE_DOWN, b);
}
- if (b->flags & IA_PRIMARY)
+ if ((b->flags & IA_PRIMARY) || (b == ifa_llv6(i)))
{
if_change_flags(i, i->flags | IF_TMP_DOWN);
ifa_recalc_primary(i);
diff --git a/nest/iface.h b/nest/iface.h
index b8e69838..cf81660b 100644
--- a/nest/iface.h
+++ b/nest/iface.h
@@ -37,6 +37,9 @@ struct iface {
unsigned master_index; /* Interface index of master iface */
list addrs; /* Addresses assigned to this interface */
struct ifa *addr; /* Primary address */
+#ifdef IPV6
+ struct ifa *llv6; /* Selected IPv6 link-local address */
+#endif
struct iface *master; /* Master iface (e.g. for VRF) */
list neighbors; /* All neighbors on this interface */
};
@@ -103,6 +106,16 @@ struct iface *if_find_by_name(char *);
struct iface *if_get_by_name(char *);
void ifa_recalc_all_primary_addresses(void);
+static inline struct ifa *
+ifa_llv6(struct iface *i UNUSED4)
+{
+#ifdef IPV6
+ return i->llv6;
+#else
+ return NULL;
+#endif
+}
+
/* The Neighbor Cache */
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 38be6909..0cfc2cac 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -1488,17 +1488,10 @@ babel_add_iface(struct babel_proto *p, struct iface *new, struct babel_iface_con
ifa->cf = ic;
ifa->pool = pool;
ifa->ifname = new->name;
+ ifa->addr = new->llv6->ip;
add_tail(&p->interfaces, NODE ifa);
- struct ifa *addr;
- WALK_LIST(addr, new->addrs)
- if (ipa_is_link_local(addr->ip))
- ifa->addr = addr->ip;
-
- if (ipa_zero(ifa->addr))
- log(L_WARN "%s: Cannot find link-local addr on %s", p->p.name, new->name);
-
init_list(&ifa->neigh_list);
ifa->hello_seqno = 1;
@@ -1551,6 +1544,10 @@ babel_if_notify(struct proto *P, unsigned flags, struct iface *iface)
if (!(iface->flags & IF_MULTICAST))
return;
+ /* Ignore ifaces without link-local address */
+ if (!iface->llv6)
+ return;
+
if (ic)
babel_add_iface(p, iface, ic);
diff --git a/proto/babel/packets.c b/proto/babel/packets.c
index 768858d0..4b40ff97 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -1087,6 +1087,7 @@ babel_open_socket(struct babel_iface *ifa)
sk->sport = ifa->cf->port;
sk->dport = ifa->cf->port;
sk->iface = ifa->iface;
+ sk->saddr = ifa->addr;
sk->vrf = p->p.vrf;
sk->rx_hook = babel_rx_hook;
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index 7e8950c5..22e4b2f4 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -281,17 +281,6 @@ radv_iface_add(struct object_lock *lock)
radv_iface_notify(ifa, RA_EV_INIT);
}
-static inline struct ifa *
-find_lladdr(struct iface *iface)
-{
- struct ifa *a;
- WALK_LIST(a, iface->addrs)
- if (a->scope == SCOPE_LINK)
- return a;
-
- return NULL;
-}
-
static void
radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_config *cf)
{
@@ -305,18 +294,12 @@ radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_conf
ifa->ra = p;
ifa->cf = cf;
ifa->iface = iface;
+ ifa->addr = iface->llv6;
init_list(&ifa->prefixes);
ifa->prune_time = TIME_INFINITY;
add_tail(&p->iface_list, NODE ifa);
- ifa->addr = find_lladdr(iface);
- if (!ifa->addr)
- {
- log(L_ERR "%s: Missing link-local address on interface %s", p->p.name, iface->name);
- return;
- }
-
timer *tm = tm_new(pool);
tm->hook = radv_timer;
tm->data = ifa;
@@ -360,6 +343,10 @@ radv_if_notify(struct proto *P, unsigned flags, struct iface *iface)
struct radv_iface_config *ic = (struct radv_iface_config *)
iface_patt_find(&cf->patt_list, iface, NULL);
+ /* Ignore ifaces without link-local address */
+ if (!iface->llv6)
+ return;
+
if (ic)
radv_iface_new(p, iface, ic);
diff --git a/proto/rip/packets.c b/proto/rip/packets.c
index 722a9012..d2f968d3 100644
--- a/proto/rip/packets.c
+++ b/proto/rip/packets.c
@@ -739,16 +739,9 @@ rip_open_socket(struct rip_iface *ifa)
sk->sport = ifa->cf->port;
sk->dport = ifa->cf->port;
sk->iface = ifa->iface;
+ sk->saddr = rip_is_v2(p) ? ifa->iface->addr->ip : ifa_llv6(ifa->iface)->ip;
sk->vrf = p->p.vrf;
- /*
- * For RIPv2, we explicitly choose a primary address, mainly to ensure that
- * RIP and BFD uses the same one. For RIPng, we left it to kernel, which
- * should choose some link-local address based on the same scope rule.
- */
- if (rip_is_v2(p))
- sk->saddr = ifa->iface->addr->ip;
-
sk->rx_hook = rip_rx_hook;
sk->tx_hook = rip_tx_hook;
sk->err_hook = rip_err_hook;
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 7b380097..88d7b7c8 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -764,6 +764,10 @@ rip_if_notify(struct proto *P, unsigned flags, struct iface *iface)
{
struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
+ /* For RIPng, ignore ifaces without link-local address */
+ if (rip_is_ng(p) && !ifa_llv6(iface))
+ return;
+
if (ic)
rip_add_iface(p, iface, ic);