FreeBSD/sys/netinet6/in6_ifattach.c
/*
 * NOTE: in6_ifdetach() does not support loopback if at this moment.
 *
 * When shutting down a VNET we clean up layers top-down.  In that case
 * upper layer protocols (ulp) are cleaned up already and locks are destroyed
 * and we must not call into these cleanup functions anymore, thus purgeulp
 * is set to 0 in that case by in6_ifdetach_destroy().
 * The normal case of destroying a (cloned) interface still needs to cleanup
 * everything related to the interface and will have purgeulp set to 1.
 */
in6_ifdetach() does not support loopback if at this moment.
When shutting down a VNET we clean up layers top-down.  In that case
upper layer protocols (ulp) are cleaned up already and locks are destroyed
and we must not call into these cleanup functions anymore, thus purgeulp
is set to 0 in that case by in6_ifdetach_destroy().
The normal case of destroying a (cloned) interface still needs to cleanup
everything related to the interface and will have purgeulp set to 1.
in6_ifdetach () does not support loopback if at this moment . When shutting down a VNET we clean up layers top - down . In that case upper layer protocols ( ulp ) are cleaned up already and locks are destroyed and we must not call into these cleanup functions anymore thus purgeulp is set to 0 in that case by in6_ifdetach_destroy () . The normal case of destroying a ( cloned ) interface still needs to cleanup everything related to the interface and will have purgeulp set to 1 .
static void
_in6_ifdetach(struct ifnet *ifp, int purgeulp)
{
	struct ifaddr *ifa, *next;
	if (ifp->if_afdata[AF_INET6] == NULL)
		return;
	if (purgeulp)
		nd6_purge(ifp);
	TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
		if (ifa->ifa_addr->sa_family != AF_INET6)
			continue;
		in6_purgeaddr(ifa);
	}
	if (purgeulp) {
		in6_pcbpurgeif0(&V_udbinfo, ifp);
		in6_pcbpurgeif0(&V_ulitecbinfo, ifp);
		in6_pcbpurgeif0(&V_ripcbinfo, ifp);
	}
	in6_purgemaddrs(ifp);
	if (purgeulp)
		nd6_purge(ifp);
}
static void _in6_ifdetach ( struct ifnet * ifp , int purgeulp ) { struct ifaddr * ifa , * next ; if ( ifp -> if_afdata [ AF_INET6 ] == NULL ) return ; if ( purgeulp ) nd6_purge ( ifp ) ; TAILQ_FOREACH_SAFE ( ifa , & ifp -> if_addrhead , ifa_link , next ) { if ( ifa -> ifa_addr -> sa_family != AF_INET6 ) continue ; in6_purgeaddr ( ifa ) ; } if ( purgeulp ) { in6_pcbpurgeif0 ( & V_udbinfo , ifp ) ; in6_pcbpurgeif0 ( & V_ulitecbinfo , ifp ) ; in6_pcbpurgeif0 ( & V_ripcbinfo , ifp ) ; } in6_purgemaddrs ( ifp ) ; if ( purgeulp ) nd6_purge ( ifp ) ; }
NOTE: in6_ifdetach() does not support loopback if at this moment.
NOTE : in6_ifdetach () does not support loopback if at this moment .
/*
	 * Remove neighbor management table.
	 * Enabling the nd6_purge will panic on vmove for interfaces on VNET
	 * teardown as the IPv6 layer is cleaned up already and the locks
	 * are destroyed.
	 */ /*
	 * nuke any of IPv6 addresses we have
	 * XXX: all addresses should be already removed
	 */ /* leave from all multicast groups joined */ /*
	 * remove neighbor management table.  we call it twice just to make
	 * sure we nuke everything.  maybe we need just one call.
	 * XXX: since the first call did not release addresses, some prefixes
	 * might remain.  We should call nd6_purge() again to release the
	 * prefixes after removing all addresses above.
	 * (Or can we just delay calling nd6_purge until at this point?)
	 */