svn commit: r345286 - stable/11/sys/net
Kristof Provost
kp at FreeBSD.org
Tue Mar 19 00:27:49 UTC 2019
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;
More information about the svn-src-stable-11
mailing list