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>