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_ */

Reply via email to