summaryrefslogtreecommitdiff
path: root/sys/net/if.c
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2020-11-25 15:07:22 +0000
committerKristof Provost <kp@FreeBSD.org>2020-11-25 15:07:22 +0000
commita779388f8bb3608b06700268e8cfe872bb97dea8 (patch)
tree2235ade75168cd342a0fc1d613c91853107641a0 /sys/net/if.c
parent3063e1e56b509373d143a3a4c67d388bd390f268 (diff)
downloadsrc-test2-a779388f8bb3608b06700268e8cfe872bb97dea8.tar.gz
src-test2-a779388f8bb3608b06700268e8cfe872bb97dea8.zip
Notes
Diffstat (limited to 'sys/net/if.c')
-rw-r--r--sys/net/if.c122
1 files changed, 82 insertions, 40 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 5c7b60da1778..07078448e3f6 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -275,6 +275,8 @@ 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_siocaddmulti(void *, int);
+static void if_link_ifnet(struct ifnet *);
+static bool if_unlink_ifnet(struct ifnet *, bool);
#ifdef VIMAGE
static int if_vmove(struct ifnet *, struct vnet *);
#endif
@@ -468,15 +470,81 @@ VNET_SYSUNINIT(vnet_if_uninit, SI_SUB_INIT_IF, SI_ORDER_FIRST,
vnet_if_uninit, NULL);
static void
+if_link_ifnet(struct ifnet *ifp)
+{
+
+ IFNET_WLOCK();
+ CK_STAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link);
+#ifdef VIMAGE
+ curvnet->vnet_ifcnt++;
+#endif
+ IFNET_WUNLOCK();
+}
+
+static bool
+if_unlink_ifnet(struct ifnet *ifp, bool vmove)
+{
+ struct ifnet *iter;
+ int found = 0;
+
+ IFNET_WLOCK();
+ CK_STAILQ_FOREACH(iter, &V_ifnet, if_link)
+ if (iter == ifp) {
+ CK_STAILQ_REMOVE(&V_ifnet, ifp, ifnet, if_link);
+ if (!vmove)
+ ifp->if_flags |= IFF_DYING;
+ found = 1;
+ break;
+ }
+#ifdef VIMAGE
+ curvnet->vnet_ifcnt--;
+#endif
+ IFNET_WUNLOCK();
+
+ return (found);
+}
+
+static void
vnet_if_return(const void *unused __unused)
{
struct ifnet *ifp, *nifp;
+ struct ifnet **pending;
+ int found, i;
+
+ i = 0;
+
+ /*
+ * We need to protect our access to the V_ifnet tailq. Ordinarily we'd
+ * enter NET_EPOCH, but that's not possible, because if_vmove() calls
+ * if_detach_internal(), which waits for NET_EPOCH callbacks to
+ * complete. We can't do that from within NET_EPOCH.
+ *
+ * However, we can also use the IFNET_xLOCK, which is the V_ifnet
+ * read/write lock. We cannot hold the lock as we call if_vmove()
+ * though, as that presents LOR w.r.t ifnet_sx, in_multi_sx and iflib
+ * ctx lock.
+ */
+ IFNET_WLOCK();
+
+ pending = malloc(sizeof(struct ifnet *) * curvnet->vnet_ifcnt,
+ M_IFNET, M_WAITOK | M_ZERO);
/* Return all inherited interfaces to their parent vnets. */
CK_STAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) {
- if (ifp->if_home_vnet != ifp->if_vnet)
- if_vmove(ifp, ifp->if_home_vnet);
+ if (ifp->if_home_vnet != ifp->if_vnet) {
+ found = if_unlink_ifnet(ifp, true);
+ MPASS(found);
+
+ pending[i++] = ifp;
+ }
}
+ IFNET_WUNLOCK();
+
+ for (int j = 0; j < i; j++) {
+ if_vmove(pending[j], pending[j]->if_home_vnet);
+ }
+
+ free(pending, M_IFNET);
}
VNET_SYSUNINIT(vnet_if_return, SI_SUB_VNET_DONE, SI_ORDER_ANY,
vnet_if_return, NULL);
@@ -906,12 +974,7 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
}
#endif
- IFNET_WLOCK();
- CK_STAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link);
-#ifdef VIMAGE
- curvnet->vnet_ifcnt++;
-#endif
- IFNET_WUNLOCK();
+ if_link_ifnet(ifp);
if (domain_init_status >= 2)
if_attachdomain1(ifp);
@@ -1049,9 +1112,12 @@ if_purgemaddrs(struct ifnet *ifp)
void
if_detach(struct ifnet *ifp)
{
+ bool found;
CURVNET_SET_QUIET(ifp->if_vnet);
- if_detach_internal(ifp, 0, NULL);
+ found = if_unlink_ifnet(ifp, false);
+ if (found)
+ if_detach_internal(ifp, 0, NULL);
CURVNET_RESTORE();
}
@@ -1071,46 +1137,16 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
struct ifaddr *ifa;
int i;
struct domain *dp;
- struct ifnet *iter;
- int found = 0;
#ifdef VIMAGE
bool shutdown;
shutdown = VNET_IS_SHUTTING_DOWN(ifp->if_vnet);
#endif
- IFNET_WLOCK();
- CK_STAILQ_FOREACH(iter, &V_ifnet, if_link)
- if (iter == ifp) {
- CK_STAILQ_REMOVE(&V_ifnet, ifp, ifnet, if_link);
- if (!vmove)
- ifp->if_flags |= IFF_DYING;
- found = 1;
- break;
- }
- IFNET_WUNLOCK();
- if (!found) {
- /*
- * While we would want to panic here, we cannot
- * guarantee that the interface is indeed still on
- * the list given we don't hold locks all the way.
- */
- return (ENOENT);
-#if 0
- if (vmove)
- panic("%s: ifp=%p not on the ifnet tailq %p",
- __func__, ifp, &V_ifnet);
- else
- return; /* XXX this should panic as well? */
-#endif
- }
/*
* At this point we know the interface still was on the ifnet list
* and we removed it so we are in a stable state.
*/
-#ifdef VIMAGE
- curvnet->vnet_ifcnt--;
-#endif
epoch_wait_preempt(net_epoch_preempt);
/*
@@ -1340,6 +1376,7 @@ if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
struct prison *pr;
struct ifnet *difp;
int error;
+ bool found;
bool shutdown;
/* Try to find the prison within our visibility. */
@@ -1376,6 +1413,9 @@ if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
}
CURVNET_RESTORE();
+ found = if_unlink_ifnet(ifp, true);
+ MPASS(found);
+
/* Move the interface into the child jail/vnet. */
error = if_vmove(ifp, pr->pr_vnet);
@@ -1393,7 +1433,7 @@ if_vmove_reclaim(struct thread *td, char *ifname, int jid)
struct prison *pr;
struct vnet *vnet_dst;
struct ifnet *ifp;
- int error;
+ int error, found;
bool shutdown;
/* Try to find the prison within our visibility. */
@@ -1431,6 +1471,8 @@ if_vmove_reclaim(struct thread *td, char *ifname, int jid)
}
/* Get interface back from child jail/vnet. */
+ found = if_unlink_ifnet(ifp, true);
+ MPASS(found);
error = if_vmove(ifp, vnet_dst);
CURVNET_RESTORE();