Date: Wed, 1 Mar 2006 11:14:22 GMT From: Vilmos Nebehaj <vili@huwico.hu> To: freebsd-gnats-submit@FreeBSD.org Subject: kern/93976: if_tun doesn't handle kqueue(2) Message-ID: <200603011114.k21BEMSR038405@www.freebsd.org> Resent-Message-ID: <200603011120.k21BK40x047425@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 93976 >Category: kern >Synopsis: if_tun 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: Wed Mar 01 11:20:03 GMT 2006 >Closed-Date: >Last-Modified: >Originator: Vilmos Nebehaj >Release: FreeBSD 6.0 >Organization: >Environment: FreeBSD oszoo.oszoo 6.0-RELEASE-p4 FreeBSD 6.0-RELEASE-p4 #0: Mon Feb 27 16:55:18 CET 2006 root@oszoo.oszoo:/usr/obj/usr/src/sys/GENERIC i386 >Description: The same as with if_tap in http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/93897 . Kevent returns an error if someone tries to use it on a tun device (/dev/tunX), because kqueue bits are missing from if_tun.c.I've prepared a patch to address this issue: http://innoidea.com/~vili/if_tun.diff , it cleanly applies against -CURRENT and RELENG_6_0 too. Index: if_tun.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_tun.c,v retrieving revision 1.152.2.2 diff -u -r1.152.2.2 if_tun.c --- if_tun.c 25 Aug 2005 05:01:20 -0000 1.152.2.2 +++ if_tun.c 1 Mar 2006 10:47:48 -0000 @@ -117,6 +117,17 @@ struct rtentry *rt); static void tunstart(struct ifnet *); +/* kqueue(2) */ +static int tun_kqfilter(struct cdev *, struct knote *); +static int tun_kqread(struct knote *, long); +static int tun_kqwrite(struct knote *, long); +static void tun_kqdetach(struct knote *); + +static struct filterops tun_read_filterops = { 1, NULL, tun_kqdetach, + tun_kqread }; +static struct filterops tun_write_filterops = { 1, NULL, tun_kqdetach, + tun_kqwrite }; + static d_open_t tunopen; static d_close_t tunclose; static d_read_t tunread; @@ -134,6 +145,7 @@ .d_ioctl = tunioctl, .d_poll = tunpoll, .d_name = TUNNAME, + .d_kqfilter = tun_kqfilter, }; static void @@ -252,6 +264,7 @@ } else mtx_unlock(&tp->tun_mtx); selwakeuppri(&tp->tun_rsel, PZERO + 1); + KNOTE(&tp->tun_rsel.si_note, 0, 0); } /* XXX: should return an error code so it can fail. */ @@ -323,6 +336,9 @@ tp->tun_flags |= TUN_OPEN; mtx_unlock(&tp->tun_mtx); ifp = TUN2IFP(tp); + + knlist_init(&tp->tun_rsel.si_note, NULL, NULL, NULL, NULL); + TUNDEBUG(ifp, "open\n"); return (0); @@ -376,6 +392,10 @@ funsetown(&tp->tun_sigio); selwakeuppri(&tp->tun_rsel, PZERO + 1); + KNOTE(&tp->tun_rsel.si_note, 0, 0); + + knlist_destroy(&tp->tun_rsel.si_note); + TUNDEBUG (ifp, "closed\n"); return (0); } @@ -862,4 +882,84 @@ splx(s); return (revents); +} + +static int +tun_kqfilter(struct cdev *dev, struct knote *kn) +{ + int s; + struct tun_softc *tp = dev->si_drv1; + struct ifnet *ifp = tp->tun_ifp; + + s = splimp(); + switch (kn->kn_filter) { + case EVFILT_READ: + TUNDEBUG(ifp, "kqfilter: EVFILT_READ, minor = %#x\n", + minor(dev)); + kn->kn_fop = &tun_read_filterops; + break; + case EVFILT_WRITE: + TUNDEBUG(ifp, "kqfilter: EVFILT_WRITE, minor = %#x\n", + minor(dev)); + kn->kn_fop = &tun_write_filterops; + break; + default: + TUNDEBUG(ifp, "kqfilter: invalid filter, minor = %#x\n", + 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 if there is data in the interface queue. */ +static int +tun_kqread(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 = tp->tun_ifp; + + s = splimp(); + if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { + TUNDEBUG(ifp, "have data in queue. len = %d, " \ + "minor = %#x\n", ifp->if_snd.ifq_len, minor(dev)); + ret = 1; + } else { + TUNDEBUG(ifp, "waiting for data, minor = %#x\n", minor(dev)); + ret = 0; + } + splx(s); + + return ret; +} + +/* Always can write. Return the MTU in kn->data. */ +static int +tun_kqwrite(struct knote *kn, long hint) +{ + int s; + struct tun_softc *tp = ((struct cdev *)kn->kn_hook)->si_drv1; + struct ifnet *ifp = tp->tun_ifp; + + s = splimp(); + kn->kn_data = ifp->if_mtu; + splx(s); + + return 1; +} + +static void +tun_kqdetach(struct knote *kn) +{ + struct tun_softc *tp = ((struct cdev *)kn->kn_hook)->si_drv1; + + knlist_remove(&tp->tun_rsel.si_note, kn, 0); } >How-To-Repeat: Use kqueue/kevent on a file descriptor obtained from opening /dev/tunX. >Fix: I've prepared a patch to address this issue: http://innoidea.com/~vili/if_tun.diff , it cleanly applies against -CURRENT and RELENG_6_0 too. Index: if_tun.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_tun.c,v retrieving revision 1.152.2.2 diff -u -r1.152.2.2 if_tun.c --- if_tun.c 25 Aug 2005 05:01:20 -0000 1.152.2.2 +++ if_tun.c 1 Mar 2006 10:47:48 -0000 @@ -117,6 +117,17 @@ struct rtentry *rt); static void tunstart(struct ifnet *); +/* kqueue(2) */ +static int tun_kqfilter(struct cdev *, struct knote *); +static int tun_kqread(struct knote *, long); +static int tun_kqwrite(struct knote *, long); +static void tun_kqdetach(struct knote *); + +static struct filterops tun_read_filterops = { 1, NULL, tun_kqdetach, + tun_kqread }; +static struct filterops tun_write_filterops = { 1, NULL, tun_kqdetach, + tun_kqwrite }; + static d_open_t tunopen; static d_close_t tunclose; static d_read_t tunread; @@ -134,6 +145,7 @@ .d_ioctl = tunioctl, .d_poll = tunpoll, .d_name = TUNNAME, + .d_kqfilter = tun_kqfilter, }; static void @@ -252,6 +264,7 @@ } else mtx_unlock(&tp->tun_mtx); selwakeuppri(&tp->tun_rsel, PZERO + 1); + KNOTE(&tp->tun_rsel.si_note, 0, 0); } /* XXX: should return an error code so it can fail. */ @@ -323,6 +336,9 @@ tp->tun_flags |= TUN_OPEN; mtx_unlock(&tp->tun_mtx); ifp = TUN2IFP(tp); + + knlist_init(&tp->tun_rsel.si_note, NULL, NULL, NULL, NULL); + TUNDEBUG(ifp, "open\n"); return (0); @@ -376,6 +392,10 @@ funsetown(&tp->tun_sigio); selwakeuppri(&tp->tun_rsel, PZERO + 1); + KNOTE(&tp->tun_rsel.si_note, 0, 0); + + knlist_destroy(&tp->tun_rsel.si_note); + TUNDEBUG (ifp, "closed\n"); return (0); } @@ -862,4 +882,84 @@ splx(s); return (revents); +} + +static int +tun_kqfilter(struct cdev *dev, struct knote *kn) +{ + int s; + struct tun_softc *tp = dev->si_drv1; + struct ifnet *ifp = tp->tun_ifp; + + s = splimp(); + switch (kn->kn_filter) { + case EVFILT_READ: + TUNDEBUG(ifp, "kqfilter: EVFILT_READ, minor = %#x\n", + minor(dev)); + kn->kn_fop = &tun_read_filterops; + break; + case EVFILT_WRITE: + TUNDEBUG(ifp, "kqfilter: EVFILT_WRITE, minor = %#x\n", + minor(dev)); + kn->kn_fop = &tun_write_filterops; + break; + default: + TUNDEBUG(ifp, "kqfilter: invalid filter, minor = %#x\n", + 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 if there is data in the interface queue. */ +static int +tun_kqread(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 = tp->tun_ifp; + + s = splimp(); + if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { + TUNDEBUG(ifp, "have data in queue. len = %d, " \ + "minor = %#x\n", ifp->if_snd.ifq_len, minor(dev)); + ret = 1; + } else { + TUNDEBUG(ifp, "waiting for data, minor = %#x\n", minor(dev)); + ret = 0; + } + splx(s); + + return ret; +} + +/* Always can write. Return the MTU in kn->data. */ +static int +tun_kqwrite(struct knote *kn, long hint) +{ + int s; + struct tun_softc *tp = ((struct cdev *)kn->kn_hook)->si_drv1; + struct ifnet *ifp = tp->tun_ifp; + + s = splimp(); + kn->kn_data = ifp->if_mtu; + splx(s); + + return 1; +} + +static void +tun_kqdetach(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:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200603011114.k21BEMSR038405>