aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Smirnoff <glebius@FreeBSD.org>2022-01-25 05:06:59 +0000
committerGleb Smirnoff <glebius@FreeBSD.org>2022-01-25 05:06:59 +0000
commit54712fc42350acb4991d8bd8604b08562660e962 (patch)
tree672dd176b253843d6fe0bea66e2d3fddb1c81942
parent4a178afb4aa9876094c19faf6d3bf065a5ebe163 (diff)
downloadsrc-54712fc42350acb4991d8bd8604b08562660e962.tar.gz
src-54712fc42350acb4991d8bd8604b08562660e962.zip
if_vmove: improve restoration in cloner's ifgroup membership
* Do a single call into if_clone.c instead of two. The cloner can't disappear since the interface sits on its list. * Make restoration smarter - check that cloner with same name exists in the new vnet. Differential revision: https://reviews.freebsd.org/D33941
-rw-r--r--sys/net/if.c34
-rw-r--r--sys/net/if_clone.c47
-rw-r--r--sys/net/if_clone.h3
3 files changed, 37 insertions, 47 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 8700485ff6a5..4622f978acd9 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -285,8 +285,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, struct if_clone *);
-static int if_detach_internal(struct ifnet *, int, struct if_clone **);
+static void if_attach_internal(struct ifnet *, bool);
+static int if_detach_internal(struct ifnet *, bool);
static void if_siocaddmulti(void *, int);
static void if_link_ifnet(struct ifnet *);
static bool if_unlink_ifnet(struct ifnet *, bool);
@@ -775,7 +775,7 @@ void
if_attach(struct ifnet *ifp)
{
- if_attach_internal(ifp, 0, NULL);
+ if_attach_internal(ifp, false);
}
/*
@@ -830,7 +830,7 @@ if_hw_tsomax_update(if_t ifp, struct ifnet_hw_tsomax *pmax)
}
static void
-if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
+if_attach_internal(struct ifnet *ifp, bool vmove)
{
unsigned socksize, ifasize;
int namelen, masklen;
@@ -847,9 +847,11 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
if_addgroup(ifp, IFG_ALL);
- /* Restore group membership for cloned interfaces. */
- if (vmove && ifc != NULL)
- if_clone_addgroup(ifp, ifc);
+#ifdef VIMAGE
+ /* Restore group membership for cloned interface. */
+ if (vmove)
+ if_clone_restoregroup(ifp);
+#endif
getmicrotime(&ifp->if_lastchange);
ifp->if_epoch = time_uptime;
@@ -1097,7 +1099,7 @@ if_detach(struct ifnet *ifp)
found = if_unlink_ifnet(ifp, false);
if (found) {
sx_xlock(&ifnet_detach_sxlock);
- if_detach_internal(ifp, 0, NULL);
+ if_detach_internal(ifp, false);
sx_xunlock(&ifnet_detach_sxlock);
}
CURVNET_RESTORE();
@@ -1114,7 +1116,7 @@ if_detach(struct ifnet *ifp)
* the cloned interfaces are destoyed as first thing of teardown.
*/
static int
-if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
+if_detach_internal(struct ifnet *ifp, bool vmove)
{
struct ifaddr *ifa;
int i;
@@ -1149,15 +1151,6 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
taskqueue_drain(taskqueue_swi, &ifp->if_linktask);
taskqueue_drain(taskqueue_swi, &ifp->if_addmultitask);
- /*
- * Check if this is a cloned interface or not. Must do even if
- * shutting down as a if_vmove_reclaim() would move the ifp and
- * the if_clone_addgroup() will have a corrupted string overwise
- * from a gibberish pointer.
- */
- if (vmove && ifcp != NULL)
- *ifcp = if_clone_findifc(ifp);
-
if_down(ifp);
#ifdef VIMAGE
@@ -1271,7 +1264,6 @@ finish_vnet_shutdown:
static int
if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
{
- struct if_clone *ifc;
#ifdef DEV_BPF
u_int bif_dlt, bif_hdrlen;
#endif
@@ -1291,7 +1283,7 @@ if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
* mark as dead etc. so that the ifnet can be reattached later.
* If we cannot find it, we lost the race to someone else.
*/
- rc = if_detach_internal(ifp, 1, &ifc);
+ rc = if_detach_internal(ifp, true);
if (rc != 0)
return (rc);
@@ -1318,7 +1310,7 @@ if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
*/
CURVNET_SET_QUIET(new_vnet);
ifindex_alloc(ifp);
- if_attach_internal(ifp, 1, ifc);
+ if_attach_internal(ifp, true);
#ifdef DEV_BPF
if (ifp->if_bpf == NULL)
diff --git a/sys/net/if_clone.c b/sys/net/if_clone.c
index a98e43328e0c..7660c91bd2e1 100644
--- a/sys/net/if_clone.c
+++ b/sys/net/if_clone.c
@@ -525,49 +525,48 @@ done:
return (err);
}
+#ifdef VIMAGE
/*
- * if_clone_findifc() looks up ifnet from the current
- * cloner list, and returns ifc if found. Note that ifc_refcnt
- * is incremented.
+ * if_clone_restoregroup() is used in context of if_vmove().
+ *
+ * Since if_detach_internal() has removed the interface from ALL groups, we
+ * need to "restore" interface membership in the cloner's group. Note that
+ * interface belongs to cloner in its home vnet, so we first find the original
+ * cloner, and then we confirm that cloner with the same name exists in the
+ * current vnet.
*/
-struct if_clone *
-if_clone_findifc(struct ifnet *ifp)
+void
+if_clone_restoregroup(struct ifnet *ifp)
{
- struct if_clone *ifc, *ifc0;
+ struct if_clone *ifc;
struct ifnet *ifcifp;
+ char ifc_name[IFCLOSIZ] = { [0] = '\0' };
- ifc0 = NULL;
+ CURVNET_SET_QUIET(ifp->if_home_vnet);
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);
+ strncpy(ifc_name, ifc->ifc_name, IFCLOSIZ-1);
break;
}
}
IF_CLONE_UNLOCK(ifc);
- if (ifc0 != NULL)
+ if (ifc_name[0] != '\0')
break;
}
+ CURVNET_RESTORE();
+ LIST_FOREACH(ifc, &V_if_cloners, ifc_list)
+ if (strcmp(ifc->ifc_name, ifc_name) == 0 &&
+ ((ifc->ifc_flags & IFC_NOGROUP) == 0))
+ 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 ((ifc->ifc_flags & IFC_NOGROUP) == 0) {
- if_addgroup(ifp, ifc->ifc_name);
- IF_CLONE_REMREF(ifc);
- }
+ if (ifc != NULL)
+ if_addgroup(ifp, ifc_name);
}
+#endif
/*
* A utility function to extract unit numbers from interface names of
diff --git a/sys/net/if_clone.h b/sys/net/if_clone.h
index ed7d6f4d02d5..e454e5d57845 100644
--- a/sys/net/if_clone.h
+++ b/sys/net/if_clone.h
@@ -76,8 +76,7 @@ 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 *);
+void if_clone_restoregroup(struct ifnet *);
/* The below interfaces are used only by epair(4). */
void if_clone_addif(struct if_clone *, struct ifnet *);