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;
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);
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 */
};
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 */
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;
if (!(iface->flags & IF_MULTICAST))
return;
+ /* Ignore ifaces without link-local address */
+ if (!iface->llv6)
+ return;
+
if (ic)
babel_add_iface(p, iface, ic);
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;
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)
{
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;
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);
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;
{
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);