Do not perform DAD on stf(4) interfaces.
stf(4) interfaces are not multicast-capable so they can't perform DAD. They also did not set IFF_DRV_RUNNING when an address was assigned, so the logic in nd6_timer() would periodically flag such an address as tentative, resulting in interface flapping. Fix the problem by setting IFF_DRV_RUNNING when an address is assigned, and do some related cleanup: - In in6if_do_dad(), remove a redundant check for !UP || !RUNNING. There is only one caller in the tree, and it only looks at whether the return value is non-zero. - Have in6if_do_dad() return false if the interface is not multicast-capable. - Set ND6_IFF_NO_DAD when an address is assigned to an stf(4) interface and the interface goes UP as a result. Note that this is not sufficient to fix the problem because the new address is marked as tentative and DAD is started before in6_ifattach() is called. However, setting no_dad is formally correct. - Change nd6_timer() to not flag addresses as tentative if no_dad is set. This is based on a patch from Viktor Dukhovni. Reported by: Viktor Dukhovni <ietf-dane@dukhovni.org> Reviewed by: ae MFC after: 3 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D19751
This commit is contained in:
parent
1c50bec8ef
commit
ca1163bd5f
@ -724,6 +724,7 @@ stf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
}
|
||||
|
||||
ifp->if_flags |= IFF_UP;
|
||||
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
||||
break;
|
||||
|
||||
case SIOCADDMULTI:
|
||||
|
@ -1951,26 +1951,14 @@ in6_if_up(struct ifnet *ifp)
|
||||
int
|
||||
in6if_do_dad(struct ifnet *ifp)
|
||||
{
|
||||
|
||||
if ((ifp->if_flags & IFF_LOOPBACK) != 0)
|
||||
return (0);
|
||||
|
||||
if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) ||
|
||||
(ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD))
|
||||
if ((ifp->if_flags & IFF_MULTICAST) == 0)
|
||||
return (0);
|
||||
if ((ND_IFINFO(ifp)->flags &
|
||||
(ND6_IFF_IFDISABLED | ND6_IFF_NO_DAD)) != 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Our DAD routine requires the interface up and running.
|
||||
* However, some interfaces can be up before the RUNNING
|
||||
* status. Additionally, users may try to assign addresses
|
||||
* before the interface becomes up (or running).
|
||||
* This function returns EAGAIN in that case.
|
||||
* The caller should mark "tentative" on the address instead of
|
||||
* performing DAD immediately.
|
||||
*/
|
||||
if (!((ifp->if_flags & IFF_UP) &&
|
||||
(ifp->if_drv_flags & IFF_DRV_RUNNING)))
|
||||
return (EAGAIN);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
@ -692,6 +692,7 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
|
||||
* it is rather harmful to have one.
|
||||
*/
|
||||
ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL;
|
||||
ND_IFINFO(ifp)->flags |= ND6_IFF_NO_DAD;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -900,6 +900,7 @@ nd6_timer(void *arg)
|
||||
struct nd_prhead prl;
|
||||
struct nd_defrouter *dr, *ndr;
|
||||
struct nd_prefix *pr, *npr;
|
||||
struct ifnet *ifp;
|
||||
struct in6_ifaddr *ia6, *nia6;
|
||||
uint64_t genid;
|
||||
|
||||
@ -996,14 +997,15 @@ nd6_timer(void *arg)
|
||||
* Check status of the interface. If it is down,
|
||||
* mark the address as tentative for future DAD.
|
||||
*/
|
||||
if ((ia6->ia_ifp->if_flags & IFF_UP) == 0 ||
|
||||
(ia6->ia_ifp->if_drv_flags & IFF_DRV_RUNNING)
|
||||
== 0 ||
|
||||
(ND_IFINFO(ia6->ia_ifp)->flags &
|
||||
ND6_IFF_IFDISABLED) != 0) {
|
||||
ifp = ia6->ia_ifp;
|
||||
if ((ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD) == 0 &&
|
||||
((ifp->if_flags & IFF_UP) == 0 ||
|
||||
(ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
|
||||
(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) != 0)){
|
||||
ia6->ia6_flags &= ~IN6_IFF_DUPLICATED;
|
||||
ia6->ia6_flags |= IN6_IFF_TENTATIVE;
|
||||
}
|
||||
|
||||
/*
|
||||
* A new RA might have made a deprecated address
|
||||
* preferred.
|
||||
|
Loading…
x
Reference in New Issue
Block a user