Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 19 Mar 2019 00:27:48 +0000 (UTC)
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r345286 - stable/11/sys/net
Message-ID:  <201903190027.x2J0RmWJ015347@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kp
Date: Tue Mar 19 00:27:48 2019
New Revision: 345286
URL: https://svnweb.freebsd.org/changeset/base/345286

Log:
  MFC r344794:
  
  tun: VIMAGE fix for if_tun cloner
  
  The if_tun cloner is not virtualised, but if_clone_attach() does use a
  virtualised list of cloners.
  The result is that we can't find the if_tun cloner when we try to remove
  a renamed tun interface. Virtualise the cloner, and move the final
  cleanup into a sysuninit so that we're sure this happens after all of
  the vnet_sysuninits
  
  Note that we need unit numbers to be system-unique (rather than unique
  per vnet, as is done by if_clone_simple()). The unit number is used to
  create the corresponding /dev/tunX device node, and this node must match
  with the interface.
  Switch to if_clone_advanced() so that we have control over the unit
  numbers.
  
  Reproduction scenario:
  	jail -c -n foo persist vnet
  	jexec test ifconfig tun create
  	jexec test ifconfig tun0 name wg0
  	jexec test ifconfig wg0 destroy
  
  PR:		235704
  Reviewed by:	bz, hrs, hselasky
  Differential Revision:	https://reviews.freebsd.org/D19248

Modified:
  stable/11/sys/net/if_tun.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/net/if_tun.c
==============================================================================
--- stable/11/sys/net/if_tun.c	Tue Mar 19 00:27:45 2019	(r345285)
+++ stable/11/sys/net/if_tun.c	Tue Mar 19 00:27:48 2019	(r345286)
@@ -41,6 +41,7 @@
 #include <sys/uio.h>
 #include <sys/malloc.h>
 #include <sys/random.h>
+#include <sys/ctype.h>
 
 #include <net/if.h>
 #include <net/if_var.h>
@@ -105,6 +106,7 @@ struct tun_softc {
  * which is static after setup.
  */
 static struct mtx tunmtx;
+static eventhandler_tag tag;
 static const char tunname[] = "tun";
 static MALLOC_DEFINE(M_TUN, tunname, "Tunnel Interface");
 static int tundebug = 0;
@@ -129,9 +131,12 @@ static int	tunoutput(struct ifnet *, struct mbuf *,
 		    const struct sockaddr *, struct route *ro);
 static void	tunstart(struct ifnet *);
 
-static int	tun_clone_create(struct if_clone *, int, caddr_t);
-static void	tun_clone_destroy(struct ifnet *);
-static struct if_clone *tun_cloner;
+static int	tun_clone_match(struct if_clone *ifc, const char *name);
+static int	tun_clone_create(struct if_clone *, char *, size_t, caddr_t);
+static int	tun_clone_destroy(struct if_clone *, struct ifnet *);
+static struct unrhdr	*tun_unrhdr;
+VNET_DEFINE_STATIC(struct if_clone *, tun_cloner);
+#define V_tun_cloner VNET(tun_cloner)
 
 static d_open_t		tunopen;
 static d_close_t	tunclose;
@@ -173,11 +178,35 @@ static struct cdevsw tun_cdevsw = {
 };
 
 static int
-tun_clone_create(struct if_clone *ifc, int unit, caddr_t params)
+tun_clone_match(struct if_clone *ifc, const char *name)
 {
+	if (strncmp(tunname, name, 3) == 0 &&
+	    (name[3] == '\0' || isdigit(name[3])))
+		return (1);
+
+	return (0);
+}
+
+static int
+tun_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
+{
 	struct cdev *dev;
-	int i;
+	int err, unit, i;
 
+	err = ifc_name2unit(name, &unit);
+	if (err != 0)
+		return (err);
+
+	if (unit != -1) {
+		/* If this unit number is still available that/s okay. */
+		if (alloc_unr_specific(tun_unrhdr, unit) == -1)
+			return (EEXIST);
+	} else {
+		unit = alloc_unr(tun_unrhdr);
+	}
+
+	snprintf(name, IFNAMSIZ, "%s%d", tunname, unit);
+
 	/* find any existing device, or allocate new unit number */
 	i = clone_create(&tunclones, &tun_cdevsw, &unit, &dev, 0);
 	if (i) {
@@ -252,6 +281,7 @@ tun_destroy(struct tun_softc *tp)
 	dev = tp->tun_dev;
 	bpfdetach(TUN2IFP(tp));
 	if_detach(TUN2IFP(tp));
+	free_unr(tun_unrhdr, TUN2IFP(tp)->if_dunit);
 	if_free(TUN2IFP(tp));
 	destroy_dev(dev);
 	seldrain(&tp->tun_rsel);
@@ -263,8 +293,8 @@ tun_destroy(struct tun_softc *tp)
 	CURVNET_RESTORE();
 }
 
-static void
-tun_clone_destroy(struct ifnet *ifp)
+static int
+tun_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
 {
 	struct tun_softc *tp = ifp->if_softc;
 
@@ -272,39 +302,64 @@ tun_clone_destroy(struct ifnet *ifp)
 	TAILQ_REMOVE(&tunhead, tp, tun_list);
 	mtx_unlock(&tunmtx);
 	tun_destroy(tp);
+
+	return (0);
 }
 
+static void
+vnet_tun_init(const void *unused __unused)
+{
+	V_tun_cloner = if_clone_advanced(tunname, 0, tun_clone_match,
+			tun_clone_create, tun_clone_destroy);
+}
+VNET_SYSINIT(vnet_tun_init, SI_SUB_PROTO_IF, SI_ORDER_ANY,
+		vnet_tun_init, NULL);
+
+static void
+vnet_tun_uninit(const void *unused __unused)
+{
+	if_clone_detach(V_tun_cloner);
+}
+VNET_SYSUNINIT(vnet_tun_uninit, SI_SUB_PROTO_IF, SI_ORDER_ANY,
+    vnet_tun_uninit, NULL);
+
+static void
+tun_uninit(const void *unused __unused)
+{
+	struct tun_softc *tp;
+
+	EVENTHANDLER_DEREGISTER(dev_clone, tag);
+	drain_dev_clone_events();
+
+	mtx_lock(&tunmtx);
+	while ((tp = TAILQ_FIRST(&tunhead)) != NULL) {
+		TAILQ_REMOVE(&tunhead, tp, tun_list);
+		mtx_unlock(&tunmtx);
+		tun_destroy(tp);
+		mtx_lock(&tunmtx);
+	}
+	mtx_unlock(&tunmtx);
+	delete_unrhdr(tun_unrhdr);
+	clone_cleanup(&tunclones);
+	mtx_destroy(&tunmtx);
+}
+SYSUNINIT(tun_uninit, SI_SUB_PROTO_IF, SI_ORDER_ANY, tun_uninit, NULL);
+
 static int
 tunmodevent(module_t mod, int type, void *data)
 {
-	static eventhandler_tag tag;
-	struct tun_softc *tp;
 
 	switch (type) {
 	case MOD_LOAD:
 		mtx_init(&tunmtx, "tunmtx", NULL, MTX_DEF);
 		clone_setup(&tunclones);
+		tun_unrhdr = new_unrhdr(0, IF_MAXUNIT, &tunmtx);
 		tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000);
 		if (tag == NULL)
 			return (ENOMEM);
-		tun_cloner = if_clone_simple(tunname, tun_clone_create,
-		    tun_clone_destroy, 0);
 		break;
 	case MOD_UNLOAD:
-		if_clone_detach(tun_cloner);
-		EVENTHANDLER_DEREGISTER(dev_clone, tag);
-		drain_dev_clone_events();
-
-		mtx_lock(&tunmtx);
-		while ((tp = TAILQ_FIRST(&tunhead)) != NULL) {
-			TAILQ_REMOVE(&tunhead, tp, tun_list);
-			mtx_unlock(&tunmtx);
-			tun_destroy(tp);
-			mtx_lock(&tunmtx);
-		}
-		mtx_unlock(&tunmtx);
-		clone_cleanup(&tunclones);
-		mtx_destroy(&tunmtx);
+		/* See tun_uninit, so it's done after the vnet_sysuninit() */
 		break;
 	default:
 		return EOPNOTSUPP;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903190027.x2J0RmWJ015347>