kern/100796: if_tun requires kqueue hooks (patch included)

David Gilbert dgilbert at daveg.ca
Tue Jul 25 02:30:21 UTC 2006


>Number:         100796
>Category:       kern
>Synopsis:       if_tun requires kqueue hooks (patch included)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jul 25 02:30:14 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     David Gilbert
>Release:        FreeBSD 6.1-STABLE i386
>Organization:
DaveG.ca
>Environment:
System: FreeBSD canoe.dclg.ca 6.1-STABLE FreeBSD 6.1-STABLE #8: Mon Jul 24 17:57:45 EDT 2006 dgilbert at canoe.dclg.ca:/usr/src/sys/i386/compile/CANOE i386


These patches are against the 6.1-STABLE branch, but I believe that
the patch should apply against the 7.0 branch (there don't appear to
be a lot of changes).
>Description:
It appears that nobody put kqueue code into if_tun.  Strangely, someone
implemented kqueue for if_tap... and the implementation doesn't appear
difficult.

This patch is made with heavy reference to the code added to if_tap.c
between 1.58 and 1.59.  I'm not at all positive that I understood 
all the nuances, but the patch works (or appears to work).  Someone
might, however, want to give it a once over.

>How-To-Repeat:
Write some code that tries to use kqueue() with if_tun.
>Fix:

--- if_tun.c.orig	Mon Jul 24 18:07:33 2006
+++ if_tun.c	Mon Jul 24 20:34:37 2006
@@ -123,6 +123,26 @@
 static d_write_t	tunwrite;
 static d_ioctl_t	tunioctl;
 static d_poll_t		tunpoll;
+static d_kqfilter_t	tunkqfilter;
+
+/* kqueue(2) */
+static int		tunkqread(struct knote *, long);
+static int		tunkqwrite(struct knote *, long);
+static void		tunkqdetach(struct knote *);
+
+static struct filterops tun_read_filterops = {
+    .f_isfd =		1,
+    .f_attach =		NULL,
+    .f_detach =		tunkqdetach,
+    .f_event =		tunkqread,
+};
+
+static struct filterops tun_write_filterops = {
+    .f_isfd =		1,
+    .f_attach =		NULL,
+    .f_detach =		tunkqdetach,
+    .f_event =		tunkqwrite,
+};
 
 static struct cdevsw tun_cdevsw = {
 	.d_version =	D_VERSION,
@@ -134,6 +154,7 @@
 	.d_ioctl =	tunioctl,
 	.d_poll =	tunpoll,
 	.d_name =	TUNNAME,
+        .d_kqfilter =	tunkqfilter,
 };
 
 static void
@@ -188,7 +209,7 @@
 {
 	static eventhandler_tag tag;
 	struct tun_softc *tp;
-
+        
 	switch (type) {
 	case MOD_LOAD:
 		mtx_init(&tunmtx, "tunmtx", NULL, MTX_DEF);
@@ -202,7 +223,10 @@
 
 		mtx_lock(&tunmtx);
 		while ((tp = TAILQ_FIRST(&tunhead)) != NULL) {
+                        struct ifnet *ifp = TUN2IFP(tp);
 			TAILQ_REMOVE(&tunhead, tp, tun_list);
+                        TUNDEBUG(ifp,"Detaching %s\n", ifp->if_xname);
+                        knlist_destroy(&tp->tun_rsel.si_note);
 			mtx_unlock(&tunmtx);
 			tun_destroy(tp);
 			mtx_lock(&tunmtx);
@@ -231,6 +255,8 @@
 	struct tun_softc *tp = ifp->if_softc;
 	struct mbuf *m;
 
+        TUNDEBUG(ifp,"%s starting\n", ifp->if_xname);
+        
 	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
 		IFQ_LOCK(&ifp->if_snd);
 		IFQ_POLL_NOLOCK(&ifp->if_snd, m);
@@ -252,6 +278,7 @@
 	} else
 		mtx_unlock(&tp->tun_mtx);
 	selwakeuppri(&tp->tun_rsel, PZERO + 1);
+        KNOTE_UNLOCKED(&tp->tun_rsel.si_note, 0);
 }
 
 /* XXX: should return an error code so it can fail. */
@@ -289,6 +316,10 @@
 	if_attach(ifp);
 	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
 	dev->si_drv1 = sc;
+
+        knlist_init(&sc->tun_rsel.si_note, NULL, NULL, NULL, NULL);
+        
+        TUNDEBUG(ifp, "interface %s is created, minor = %#x\n", ifp->if_xname, minor(dev));        
 }
 
 static int
@@ -376,6 +407,7 @@
 
 	funsetown(&tp->tun_sigio);
 	selwakeuppri(&tp->tun_rsel, PZERO + 1);
+        KNOTE_UNLOCKED(&tp->tun_rsel.si_note, 0);
 	TUNDEBUG (ifp, "closed\n");
 	return (0);
 }
@@ -862,4 +894,97 @@
 
 	splx(s);
 	return (revents);
+}
+
+/* tunkqfilter
+ *
+ * support for the kevent() system call
+ */
+
+static int
+tunkqfilter(struct cdev *dev, struct knote *kn)
+{
+    int			s;
+    struct tun_softc	*tp = dev->si_drv1;
+    struct ifnet	*ifp = TUN2IFP(tp);
+
+    s = splimp();
+    switch(kn->kn_filter)
+    {
+    case EVFILT_READ:
+        TUNDEBUG(ifp, "%s kqfilter: EVFILT_READ, minor = %#x\n",
+                 ifp->if_xname, minor(dev));
+        kn->kn_fop = &tun_read_filterops;
+        break;
+
+    case EVFILT_WRITE:
+        TUNDEBUG(ifp, "%s kqfilter: EVFILT_WRITE, minor = %#x\n",
+                 ifp->if_xname, minor(dev));
+        kn->kn_fop = &tun_write_filterops;
+        break;
+
+    default:
+        TUNDEBUG(ifp, "%s kqfilter: invalid filter, minor = %#x\n",
+                 ifp->if_xname, minor(dev));
+        splx(s);
+        return(EINVAL);
+        break;
+    }
+    splx(s);
+
+    kn->kn_hook = (caddr_t) dev;
+    knlist_add(&tp->tun_rsel.si_note, kn, 0);
+
+    return(0);
+}
+
+/* return true of there is data in the interface queue */
+
+static int
+tunkqread(struct knote *kn, long hint)
+{
+    int			ret, s;
+    struct cdev		*dev = (struct cdev *)(kn->kn_hook);
+    struct tun_softc	*tp = dev->si_drv1;
+    struct ifnet	*ifp = TUN2IFP(tp);
+
+    s = splimp();
+    if((kn->kn_data = ifp->if_snd.ifq_len) > 0)
+    {
+        TUNDEBUG(ifp, "%s have data in the queue.  Len = %d, minor = %#x\n",
+                 ifp->if_xname, ifp->if_snd.ifq_len, minor(dev));
+        ret = 1;
+    }
+    else
+    {
+        TUNDEBUG(ifp, "%s waiting for data, minor = %#x\n",ifp->if_xname, minor(dev));
+        ret = 0;
+    }
+    splx(s);
+
+    return(ret);
+}
+
+/* Always can write, always return MTU in kn->data */
+
+static int
+tunkqwrite(struct knote *kn, long hint)
+{
+    int			s;
+    struct tun_softc	*tp = ((struct cdev *) kn->kn_hook)->si_drv1;
+    struct ifnet	*ifp = TUN2IFP(tp);
+
+    s = splimp();
+    kn->kn_data = ifp->if_mtu;
+    splx(s);
+
+    return(1);
+}
+
+static void
+tunkqdetach(struct knote *kn)
+{
+    struct tun_softc		*tp = ((struct cdev *) kn->kn_hook)->si_drv1;
+
+    knlist_remove(&tp->tun_rsel.si_note, kn, 0);
 }

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list