Fix group membership of cloned interfaces when one is moved by
if_vmove(). In if_vmove(), if_detach_internal() and if_attach_internal() were called in series to detach and reattach the interface. When detaching, if_delgroup() was called and the interface leaves all of the group membership. And then upon attachment, if_addgroup(ifp, IFG_ALL) was called and it joined only "all" group again. This had a problem. Normally, a cloned interface automatically joins a group whose name is ifc_name of the cloner in addition to "all" upon creation. However, if_vmove() removed the membership and did not restore upon attachment. Differential Revision: https://reviews.freebsd.org/D1859
This commit is contained in:
parent
2d427c524d
commit
c92a456b55
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=279538
34
sys/net/if.c
34
sys/net/if.c
@ -172,8 +172,8 @@ static void do_link_state_change(void *, int);
|
||||
static int if_getgroup(struct ifgroupreq *, struct ifnet *);
|
||||
static int if_getgroupmembers(struct ifgroupreq *);
|
||||
static void if_delgroups(struct ifnet *);
|
||||
static void if_attach_internal(struct ifnet *, int);
|
||||
static void if_detach_internal(struct ifnet *, int);
|
||||
static void if_attach_internal(struct ifnet *, int, struct if_clone *);
|
||||
static void if_detach_internal(struct ifnet *, int, struct if_clone **);
|
||||
|
||||
#ifdef INET6
|
||||
/*
|
||||
@ -558,6 +558,15 @@ ifq_delete(struct ifaltq *ifq)
|
||||
* tasks, given that we are moving from one vnet to another an ifnet which
|
||||
* has already been fully initialized.
|
||||
*
|
||||
* Note that if_detach_internal() removes group membership unconditionally
|
||||
* even when vmove flag is set, and if_attach_internal() adds only IFG_ALL.
|
||||
* Thus, when if_vmove() is applied to a cloned interface, group membership
|
||||
* is lost while a cloned one always joins a group whose name is
|
||||
* ifc->ifc_name. To recover this after if_detach_internal() and
|
||||
* if_attach_internal(), the cloner should be specified to
|
||||
* if_attach_internal() via ifc. If it is non-NULL, if_attach_internal()
|
||||
* attempts to join a group whose name is ifc->ifc_name.
|
||||
*
|
||||
* XXX:
|
||||
* - The decision to return void and thus require this function to
|
||||
* succeed is questionable.
|
||||
@ -568,7 +577,7 @@ void
|
||||
if_attach(struct ifnet *ifp)
|
||||
{
|
||||
|
||||
if_attach_internal(ifp, 0);
|
||||
if_attach_internal(ifp, 0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -623,7 +632,7 @@ if_hw_tsomax_update(if_t ifp, struct ifnet_hw_tsomax *pmax)
|
||||
}
|
||||
|
||||
static void
|
||||
if_attach_internal(struct ifnet *ifp, int vmove)
|
||||
if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
|
||||
{
|
||||
unsigned socksize, ifasize;
|
||||
int namelen, masklen;
|
||||
@ -642,6 +651,10 @@ if_attach_internal(struct ifnet *ifp, int vmove)
|
||||
|
||||
if_addgroup(ifp, IFG_ALL);
|
||||
|
||||
/* Restore group membership for cloned interfaces. */
|
||||
if (vmove && ifc != NULL)
|
||||
if_clone_addgroup(ifp, ifc);
|
||||
|
||||
getmicrotime(&ifp->if_lastchange);
|
||||
ifp->if_epoch = time_uptime;
|
||||
|
||||
@ -860,12 +873,12 @@ if_detach(struct ifnet *ifp)
|
||||
{
|
||||
|
||||
CURVNET_SET_QUIET(ifp->if_vnet);
|
||||
if_detach_internal(ifp, 0);
|
||||
if_detach_internal(ifp, 0, NULL);
|
||||
CURVNET_RESTORE();
|
||||
}
|
||||
|
||||
static void
|
||||
if_detach_internal(struct ifnet *ifp, int vmove)
|
||||
if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
|
||||
{
|
||||
struct ifaddr *ifa;
|
||||
struct radix_node_head *rnh;
|
||||
@ -894,6 +907,10 @@ if_detach_internal(struct ifnet *ifp, int vmove)
|
||||
return; /* XXX this should panic as well? */
|
||||
}
|
||||
|
||||
/* Check if this is a cloned interface or not. */
|
||||
if (vmove && ifcp != NULL)
|
||||
*ifcp = if_clone_findifc(ifp);
|
||||
|
||||
/*
|
||||
* Remove/wait for pending events.
|
||||
*/
|
||||
@ -999,12 +1016,13 @@ if_detach_internal(struct ifnet *ifp, int vmove)
|
||||
void
|
||||
if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
|
||||
{
|
||||
struct if_clone *ifc;
|
||||
|
||||
/*
|
||||
* Detach from current vnet, but preserve LLADDR info, do not
|
||||
* mark as dead etc. so that the ifnet can be reattached later.
|
||||
*/
|
||||
if_detach_internal(ifp, 1);
|
||||
if_detach_internal(ifp, 1, &ifc);
|
||||
|
||||
/*
|
||||
* Unlink the ifnet from ifindex_table[] in current vnet, and shrink
|
||||
@ -1034,7 +1052,7 @@ if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
|
||||
ifnet_setbyindex_locked(ifp->if_index, ifp);
|
||||
IFNET_WUNLOCK();
|
||||
|
||||
if_attach_internal(ifp, 1);
|
||||
if_attach_internal(ifp, 1, ifc);
|
||||
|
||||
CURVNET_RESTORE();
|
||||
}
|
||||
|
@ -517,6 +517,49 @@ if_clone_list(struct if_clonereq *ifcr)
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* if_clone_findifc() looks up ifnet from the current
|
||||
* cloner list, and returns ifc if found. Note that ifc_refcnt
|
||||
* is incremented.
|
||||
*/
|
||||
struct if_clone *
|
||||
if_clone_findifc(struct ifnet *ifp)
|
||||
{
|
||||
struct if_clone *ifc, *ifc0;
|
||||
struct ifnet *ifcifp;
|
||||
|
||||
ifc0 = NULL;
|
||||
IF_CLONERS_LOCK();
|
||||
LIST_FOREACH(ifc, &V_if_cloners, ifc_list) {
|
||||
IF_CLONE_LOCK(ifc);
|
||||
LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) {
|
||||
if (ifp == ifcifp) {
|
||||
ifc0 = ifc;
|
||||
IF_CLONE_ADDREF_LOCKED(ifc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
IF_CLONE_UNLOCK(ifc);
|
||||
if (ifc0 != NULL)
|
||||
break;
|
||||
}
|
||||
IF_CLONERS_UNLOCK();
|
||||
|
||||
return (ifc0);
|
||||
}
|
||||
|
||||
/*
|
||||
* if_clone_addgroup() decrements ifc_refcnt because it is called after
|
||||
* if_clone_findifc().
|
||||
*/
|
||||
void
|
||||
if_clone_addgroup(struct ifnet *ifp, struct if_clone *ifc)
|
||||
{
|
||||
|
||||
if_addgroup(ifp, ifc->ifc_name);
|
||||
IF_CLONE_REMREF(ifc);
|
||||
}
|
||||
|
||||
/*
|
||||
* A utility function to extract unit numbers from interface names of
|
||||
* the form name###.
|
||||
|
@ -69,6 +69,8 @@ void vnet_if_clone_init(void);
|
||||
int if_clone_create(char *, size_t, caddr_t);
|
||||
int if_clone_destroy(const char *);
|
||||
int if_clone_list(struct if_clonereq *);
|
||||
struct if_clone *if_clone_findifc(struct ifnet *);
|
||||
void if_clone_addgroup(struct ifnet *, struct if_clone *);
|
||||
|
||||
/* The below interface used only by epair(4). */
|
||||
int if_clone_destroyif(struct if_clone *, struct ifnet *);
|
||||
|
Loading…
Reference in New Issue
Block a user