diff options
-rw-r--r-- | nest/iface.c | 20 | ||||
-rw-r--r-- | nest/iface.h | 13 | ||||
-rw-r--r-- | proto/babel/babel.c | 13 | ||||
-rw-r--r-- | proto/babel/packets.c | 1 | ||||
-rw-r--r-- | proto/radv/radv.c | 23 | ||||
-rw-r--r-- | proto/rip/packets.c | 9 | ||||
-rw-r--r-- | proto/rip/rip.c | 4 |
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); |