A cloned tap device patch (for a person to test KQEMU 1.4.0pre1 for QEMU 0.10.1)

Naoya Sugioka naoya.sugioka at gmail.com
Tue May 5 17:35:55 PDT 2009


Hello,

As some of you already know, I wrote a kqemu patch for DragonFly, but
I found very simple problem to use it.
I cannot create tap0 cloned interface by ifconfig comamnd now, so I
made a patch.

Attachment is a suggested patch to create tap cloned tap device (only
tap device) only applicapable with HEAD.
I 'd like to post this patch to share with community and get a feedback from.

I'm start using this to use QEMU/KQEMU as a virtual server of
DragonFly/FreeBSD. Unfortuantelly, I saw
DMA address error when using wirh Linux guest though...

thank you,
-Naoya
diff --git a/sys/net/tap/if_tap.c b/sys/net/tap/if_tap.c
index f4bd6ca..e50ae4b 100644
--- a/sys/net/tap/if_tap.c
+++ b/sys/net/tap/if_tap.c
@@ -65,6 +65,7 @@
 #include <net/if.h>
 #include <net/ifq_var.h>
 #include <net/if_arp.h>
+#include <net/if_clone.h>
 #include <net/route.h>
 
 #include <netinet/in.h>
@@ -87,6 +88,11 @@ static int 		tapmodevent	(module_t, int, void *);
 /* device */
 static void		tapcreate	(cdev_t);
 
+/* clone */
+static int		tap_clone_create(struct if_clone *, int);
+static void		tap_clone_destroy(struct ifnet *);
+
+
 /* network interface */
 static void		tapifstart	(struct ifnet *);
 static int		tapifioctl	(struct ifnet *, u_long, caddr_t,
@@ -117,10 +123,24 @@ static struct dev_ops	tap_ops = {
 static int		taprefcnt = 0;		/* module ref. counter   */
 static int		taplastunit = -1;	/* max. open unit number */
 static int		tapdebug = 0;		/* debug flag            */
+static int		tapuopen = 0;		/* all user open()       */
+static int		tapuponopen = 0;	/* IFF_UP       */
 
 MALLOC_DECLARE(M_TAP);
 MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
+struct if_clone tap_cloner = IF_CLONE_INITIALIZER("tap",
+			tap_clone_create,
+			tap_clone_destroy, 0, IF_MAXUNIT);
 SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
+SYSCTL_DECL(_net_link);
+SYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
+    "Ethernet tunnel software network interface");
+SYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
+	"Allow user to open /dev/tap (based on node permissions)");
+SYSCTL_INT(_net_link_tap, OID_AUTO, up_on_open, CTLFLAG_RW, &tapuponopen, 0,
+	"Bring interface up when /dev/tap is opened");
+SYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
+
 DEV_MODULE(if_tap, tapmodevent, NULL);
 
 /*
@@ -131,55 +151,28 @@ DEV_MODULE(if_tap, tapmodevent, NULL);
 static int
 tapmodevent(module_t mod, int type, void *data)
 {
-	static int		 attached = 0;
-	struct ifnet		*ifp = NULL;
-	int			 unit;
-
+	struct tap_softc*	tp;
 	switch (type) {
 	case MOD_LOAD:
-		if (attached)
+		if (!SLIST_EMPTY(&tap_listhead))
 			return (EEXIST);
 
 		dev_ops_add(&tap_ops, 0, 0);
-		attached = 1;
+		SLIST_INIT(&tap_listhead);
+		if_clone_attach(&tap_cloner);
+
 		break;
 
 	case MOD_UNLOAD:
 		if (taprefcnt > 0)
 			return (EBUSY);
 
+		if_clone_detach(&tap_cloner);
 		dev_ops_remove(&tap_ops, 0, 0);
 
-		/* XXX: maintain tap ifs in a local list */
-		unit = 0;
-		while (unit <= taplastunit) {
-			TAILQ_FOREACH(ifp, &ifnet, if_link) {
-				if ((strcmp(ifp->if_dname, TAP) == 0) ||
-				    (strcmp(ifp->if_dname, VMNET) == 0)) {
-					if (ifp->if_dunit == unit)
-						break;
-				}
-			}
-
-			if (ifp != NULL) {
-				struct tap_softc	*tp = ifp->if_softc;
-
-				TAPDEBUG(ifp, "detached. minor = %#x, " \
-					"taplastunit = %d\n",
-					minor(tp->tap_dev), taplastunit);
-
-				ifnet_serialize_all(ifp);
-				tapifstop(tp, 1);
-				ifnet_deserialize_all(ifp);
-
-				ether_ifdetach(ifp);
-				destroy_dev(tp->tap_dev);
-				kfree(tp, M_TAP);
-			} else {
-				unit++;
-			}
-		}
-		attached = 0;
+		/*  maintain tap ifs in a local list */
+		SLIST_FOREACH(tp, &tap_listhead, tap_entries)
+			tap_clone_destroy(&tp->tap_if);
 		break;
 
 	default:
@@ -250,9 +243,64 @@ tapcreate(cdev_t dev)
 	tp->tap_flags |= TAP_INITED;
 	tp->tap_devq.ifq_maxlen = ifqmaxlen;
 
+        SLIST_INSERT_HEAD(&tap_listhead, tp, tap_entries);
+
 	TAPDEBUG(ifp, "created. minor = %#x\n", minor(tp->tap_dev));
 } /* tapcreate */
 
+/*
+ * tap_clone_create:
+ *
+ *	Create a new tap instance.
+ */
+static int
+tap_clone_create(struct if_clone *ifc, int unit)
+{
+	struct ifnet		*ifp = NULL;
+	struct tap_softc 	*tp = NULL;
+	uint8_t			ether_addr[ETHER_ADDR_LEN];
+
+	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
+
+	tp->tap_dev = make_dev(&tap_ops, unit, UID_ROOT, GID_WHEEL, 
+						0600, "%s%d", ifc->ifc_name, unit);
+	tp->tap_dev->si_drv1 = tp;
+	reference_dev(tp->tap_dev);	/* so we can destroy it later */
+
+	/* generate fake MAC address: 00 bd xx xx xx unit_no */
+	ether_addr[0] = 0x00;
+	ether_addr[1] = 0xbd;
+	bcopy(&ticks, &ether_addr[2], 3);
+	ether_addr[5] = (u_char)unit;
+
+	ifp = &tp->tap_if;
+	ifp->if_softc = tp;
+
+	if_initname(ifp, ifc->ifc_name, unit);
+	if (unit > taplastunit)
+		taplastunit = unit;
+
+	ifp->if_init = tapifinit;
+	ifp->if_start = tapifstart;
+	ifp->if_ioctl = tapifioctl;
+	ifp->if_mtu = ETHERMTU;
+	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
+	ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
+	ifq_set_ready(&ifp->if_snd);
+
+	ether_ifattach(ifp, ether_addr, NULL);
+
+	tp->tap_flags |= TAP_INITED;
+	tp->tap_devq.ifq_maxlen = ifqmaxlen;
+
+        SLIST_INSERT_HEAD(&tap_listhead, tp, tap_entries);
+
+	TAPDEBUG(ifp, "clone created. minor = %#x tap_flags = 0x%x\n",
+			minor(tp->tap_dev), tp->tap_flags);
+
+        return (0);
+}
+
 
 /*
  * tapopen 
@@ -262,15 +310,17 @@ tapcreate(cdev_t dev)
 static int
 tapopen(struct dev_open_args *ap)
 {
-	cdev_t dev = ap->a_head.a_dev;
+	cdev_t dev = NULL;
 	struct tap_softc *tp = NULL;
 	struct ifnet *ifp = NULL;
 	int error;
 
-	if ((error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) != 0)
+	if (tapuopen == 0 && 
+	    (error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) != 0)
 		return (error);
 
 	get_mplock();
+	dev = ap->a_head.a_dev;
 	tp = dev->si_drv1;
 	if (tp == NULL) {
 		tapcreate(dev);
@@ -296,6 +346,10 @@ tapopen(struct dev_open_args *ap)
 		fsetown(curthread->td_proc->p_pid, &tp->tap_sigtd);
 	tp->tap_flags |= TAP_OPEN;
 	taprefcnt ++;
+	ifp = &tp->tap_if;
+
+	if (tapuponopen)
+		ifp->if_flags |= IFF_UP;
 
 	TAPDEBUG(ifp, "opened. minor = %#x, refcnt = %d, taplastunit = %d\n",
 		 minor(tp->tap_dev), taprefcnt, taplastunit);
@@ -366,6 +420,35 @@ tapclose(struct dev_close_args *ap)
 	return (0);
 }
 
+/*
+ * tap_clone_destroy:
+ *
+ *	Destroy a tap instance.
+ */
+static void
+tap_clone_destroy(struct ifnet *ifp)
+{
+	struct tap_softc *tp = ifp->if_softc;
+
+	TAPDEBUG(ifp, "clone destroyed. minor = %#x, refcnt = %d, taplastunit = %d\n",
+		 minor(tp->tap_dev), taprefcnt, taplastunit);
+	/*
+	 * Do we really need this?
+	 */
+	IF_DRAIN(&ifp->if_snd);
+
+	ifnet_serialize_all(ifp);
+	tapifstop(tp, 1);
+	ifnet_deserialize_all(ifp);
+
+	ether_ifdetach(ifp);
+	SLIST_REMOVE(&tap_listhead, tp, tap_softc, tap_entries);
+
+	destroy_dev(tp->tap_dev);
+	kfree(tp, M_TAP);
+
+	taplastunit--;
+}
 
 /*
  * tapifinit
@@ -380,7 +463,8 @@ tapifinit(void *xtp)
 	struct tap_softc *tp = xtp;
 	struct ifnet *ifp = &tp->tap_if;
 
-	TAPDEBUG(ifp, "initializing, minor = %#x\n", minor(tp->tap_dev));
+	TAPDEBUG(ifp, "initializing, minor = %#x tap_flags = 0x%x\n",
+			minor(tp->tap_dev), tp->tap_flags);
 
 	ASSERT_IFNET_SERIALIZED_ALL(ifp);
 
@@ -745,7 +829,7 @@ tapwrite(struct dev_write_args *ap)
 	struct mbuf		*top = NULL, **mp = NULL, *m = NULL;
 	int		 	 error = 0, tlen, mlen;
 
-	TAPDEBUG(ifp, "writing, minor = %#x\n", minor(tp->tap_dev));
+//	TAPDEBUG(ifp, "writing, minor = %#x\n", minor(tp->tap_dev));
 
 	if (uio->uio_resid == 0)
 		return (0);
@@ -844,7 +928,8 @@ tappoll(struct dev_poll_args *ap)
 	if (ap->a_events & (POLLOUT | POLLWRNORM))
 		revents |= (ap->a_events & (POLLOUT | POLLWRNORM));
 	ap->a_events = revents;
-	return(0);
+
+	return revents;
 }
 
 /*
diff --git a/sys/net/tap/if_tapvar.h b/sys/net/tap/if_tapvar.h
index 2cd173e..cc712d5 100644
--- a/sys/net/tap/if_tapvar.h
+++ b/sys/net/tap/if_tapvar.h
@@ -61,6 +61,10 @@ struct tap_softc {
 	struct sigio	*tap_sigio;		/* information for async I/O */
 	struct selinfo	 tap_rsel;		/* read select               */
 	struct ifqueue	 tap_devq;
+
+	SLIST_ENTRY(tap_softc)	tap_entries;
 };
 
+SLIST_HEAD(,tap_softc) tap_listhead;
+
 #endif /* !_NET_IF_TAPVAR_H_ */




More information about the Submit mailing list