Create new in6_purgeifaddr() which purges bound ifa prefix if
it gets unused. Currently if_purgeifaddrs() uses in6_purgeaddr() to remove IPv6 ifaddrs. in6_purgeaddr() does not trrigger prefix removal if number of linked ifas goes to 0, as this is a low-level function. As a result, if_purgeifaddrs() purges all IPv4/IPv6 addresses but keeps corresponding IPv6 prefixes. Fix this by creating higher-level wrapper which handles unused prefix usecase and use it in if_purgeifaddrs(). Differential revision: https://reviews.freebsd.org/D28128
This commit is contained in:
parent
da8cc827ae
commit
f9e0752e35
@ -1077,7 +1077,7 @@ if_purgeaddrs(struct ifnet *ifp)
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
if (ifa->ifa_addr->sa_family == AF_INET6) {
|
||||
in6_purgeaddr(ifa);
|
||||
in6_purgeifaddr((struct in6_ifaddr *)ifa);
|
||||
/* ifp_addrhead is already updated */
|
||||
continue;
|
||||
}
|
||||
|
@ -696,31 +696,10 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
}
|
||||
|
||||
case SIOCDIFADDR_IN6:
|
||||
{
|
||||
struct nd_prefix *pr;
|
||||
|
||||
/*
|
||||
* If the address being deleted is the only one that owns
|
||||
* the corresponding prefix, expire the prefix as well.
|
||||
* XXX: theoretically, we don't have to worry about such
|
||||
* relationship, since we separate the address management
|
||||
* and the prefix management. We do this, however, to provide
|
||||
* as much backward compatibility as possible in terms of
|
||||
* the ioctl operation.
|
||||
* Note that in6_purgeaddr() will decrement ndpr_addrcnt.
|
||||
*/
|
||||
pr = ia->ia6_ndpr;
|
||||
in6_purgeaddr(&ia->ia_ifa);
|
||||
if (pr != NULL && pr->ndpr_addrcnt == 0) {
|
||||
ND6_WLOCK();
|
||||
nd6_prefix_unlink(pr, NULL);
|
||||
ND6_WUNLOCK();
|
||||
nd6_prefix_del(pr);
|
||||
}
|
||||
in6_purgeifaddr(ia);
|
||||
EVENTHANDLER_INVOKE(ifaddr_event_ext, ifp, &ia->ia_ifa,
|
||||
IFADDR_EVENT_DEL);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (ifp->if_ioctl == NULL) {
|
||||
@ -1364,6 +1343,36 @@ in6_purgeaddr(struct ifaddr *ifa)
|
||||
in6_unlink_ifa(ia, ifp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes @ia from the corresponding interfaces and unlinks corresponding
|
||||
* prefix if no addresses are using it anymore.
|
||||
*/
|
||||
void
|
||||
in6_purgeifaddr(struct in6_ifaddr *ia)
|
||||
{
|
||||
struct nd_prefix *pr;
|
||||
|
||||
/*
|
||||
* If the address being deleted is the only one that owns
|
||||
* the corresponding prefix, expire the prefix as well.
|
||||
* XXX: theoretically, we don't have to worry about such
|
||||
* relationship, since we separate the address management
|
||||
* and the prefix management. We do this, however, to provide
|
||||
* as much backward compatibility as possible in terms of
|
||||
* the ioctl operation.
|
||||
* Note that in6_purgeaddr() will decrement ndpr_addrcnt.
|
||||
*/
|
||||
pr = ia->ia6_ndpr;
|
||||
in6_purgeaddr(&ia->ia_ifa);
|
||||
if (pr != NULL && pr->ndpr_addrcnt == 0) {
|
||||
ND6_WLOCK();
|
||||
nd6_prefix_unlink(pr, NULL);
|
||||
ND6_WUNLOCK();
|
||||
nd6_prefix_del(pr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
|
||||
{
|
||||
|
@ -887,6 +887,7 @@ int in6_update_ifa(struct ifnet *, struct in6_aliasreq *,
|
||||
void in6_prepare_ifra(struct in6_aliasreq *, const struct in6_addr *,
|
||||
const struct in6_addr *);
|
||||
void in6_purgeaddr(struct ifaddr *);
|
||||
void in6_purgeifaddr(struct in6_ifaddr *);
|
||||
int in6if_do_dad(struct ifnet *);
|
||||
void in6_savemkludge(struct in6_ifaddr *);
|
||||
void *in6_domifattach(struct ifnet *);
|
||||
|
Loading…
Reference in New Issue
Block a user