Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 27 Feb 2006 11:31:05 GMT
From:      Vilmos Nebehaj <vili@huwico.hu>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/93897: if_tap doesn't handle kqueue(2)
Message-ID:  <200602271131.k1RBV53Q003556@www.freebsd.org>
Resent-Message-ID: <200602271140.k1RBe45d053345@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         93897
>Category:       kern
>Synopsis:       if_tap doesn't handle kqueue(2)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb 27 11:40:04 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Vilmos Nebehaj
>Release:        FreeBSD 6.0
>Organization:
>Environment:
oszoo# uname -a                                                                              
            FreeBSD oszoo.oszoo 6.0-RELEASE FreeBSD 6.0-RELEASE #0: Thu Nov  3 09:36:13 UTC              
            2005     root@x64.samsco.home:/usr/obj/usr/src/sys/GENERIC  i386        
>Description:
Kqueue(2) doesn't work on if_tap devices, so applications have to use select or poll. NetBSD and OpenBSD have had the necessary kqueue bits for quite a while, so it would be desirable for FreeBSD to do the same.
>How-To-Repeat:
Use kqueue/kevent on a file descriptor obtained from opening /dev/tapX.
>Fix:
I've prepared a patch. It cleanly applies against -CURRENT and RELENG_6_0 too. It can be fetched from http://innoidea.com/~vili/if_tap.diff

Index: if_tap.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_tap.c,v
retrieving revision 1.58
diff -u -r1.58 if_tap.c
--- if_tap.c    11 Nov 2005 16:04:48 -0000      1.58
+++ if_tap.c    27 Feb 2006 10:39:38 -0000
@@ -99,6 +99,17 @@
 static d_ioctl_t       tapioctl;
 static d_poll_t                tappoll;
 
+/* kqueue(2) */
+static int             tap_kqfilter(struct cdev *, struct knote *);
+static int             tap_kqread(struct knote *, long);
+static int             tap_kqwrite(struct knote *, long);
+static void            tap_kqdetach(struct knote *);
+
+static struct filterops        tap_read_filterops = { 1, NULL, tap_kqdetach,
+       tap_kqread };
+static struct filterops        tap_write_filterops = { 1, NULL, tap_kqdetach,
+       tap_kqwrite };
+
 static struct cdevsw   tap_cdevsw = {
        .d_version =    D_VERSION,
        .d_flags =      D_PSEUDO | D_NEEDGIANT,
@@ -109,6 +120,7 @@
        .d_ioctl =      tapioctl,
        .d_poll =       tappoll,
        .d_name =       CDEV_NAME,
+       .d_kqfilter =   tap_kqfilter,
 };
 
 /*
@@ -397,6 +409,8 @@
        ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
        splx(s);
 
+       knlist_init(&tp->tap_rsel.si_note, NULL, NULL, NULL, NULL);
+
        TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev));
 
        return (0);
@@ -446,12 +460,15 @@
 
        funsetown(&tp->tap_sigio);
        selwakeuppri(&tp->tap_rsel, PZERO+1);
+       KNOTE(&tp->tap_rsel.si_note, 0, 0);
 
        mtx_lock(&tp->tap_mtx);
        tp->tap_flags &= ~TAP_OPEN;
        tp->tap_pid = 0;
        mtx_unlock(&tp->tap_mtx);
 
+       knlist_destroy(&tp->tap_rsel.si_note);
+
        TAPDEBUG("%s is closed. minor = %#x\n", 
                ifp->if_xname, minor(dev));
 
@@ -586,6 +603,7 @@
                        mtx_unlock(&tp->tap_mtx);
 
                selwakeuppri(&tp->tap_rsel, PZERO+1);
+               KNOTE(&tp->tap_rsel.si_note, 0, 0);
                ifp->if_opackets ++; /* obytes are counted in ether_output */
        }
 
@@ -878,3 +896,78 @@
        splx(s);
        return (revents);
 } /* tappoll */
+
+static int
+tap_kqfilter(struct cdev *dev, struct knote *kn)
+{
+       struct tap_softc        *tp = dev->si_drv1;
+       struct ifnet            *ifp = tp->tap_ifp;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n",
+                       ifp->if_xname, minor(dev));
+               kn->kn_fop = &tap_read_filterops;
+               break;
+       case EVFILT_WRITE:
+               TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n",
+                       ifp->if_xname, minor(dev));
+               kn->kn_fop = &tap_write_filterops;
+               break;
+       default:
+               TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n",
+                       ifp->if_xname, minor(dev));
+               return EINVAL;
+               break;
+       }
+
+       kn->kn_hook = (caddr_t)dev;
+       knlist_add(&tp->tap_rsel.si_note, kn, 0);
+
+       return 0;
+}
+
+/* Return true if there is data in the interface queue. */
+static int
+tap_kqread(struct knote *kn, long hint)
+{
+       int                     ret, s;
+       struct cdev             *dev = (struct cdev *)kn->kn_hook;
+       struct tap_softc        *tp = dev->si_drv1;
+       struct ifnet            *ifp = tp->tap_ifp;
+
+       s = splimp();
+       if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) {
+               TAPDEBUG("%s have data in queue. len = %d, " \
+                       "minor = %#x\n", ifp->if_xname,
+                       ifp->if_snd.ifq_len, minor(dev));
+               ret = 1;
+       } else {
+               TAPDEBUG("%s waiting for data, minor = %#x\n",
+                       ifp->if_xname, minor(dev));
+               ret = 0;
+       }
+       splx(s);
+
+       return ret;
+}
+
+/* Always can write. Return the MTU in kn->data. */
+static int
+tap_kqwrite(struct knote *kn, long hint)
+{
+       struct tap_softc        *tp = ((struct cdev *)kn->kn_hook)->si_drv1;
+       struct ifnet            *ifp = tp->tap_ifp;
+
+       kn->kn_data = ifp->if_mtu;
+
+       return 1;
+}
+
+static void
+tap_kqdetach(struct knote *kn)
+{
+       struct tap_softc        *tp = ((struct cdev *)kn->kn_hook)->si_drv1;
+
+       knlist_remove(&tp->tap_rsel.si_note, kn, 0);
+}
>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200602271131.k1RBV53Q003556>