From owner-freebsd-bugs@FreeBSD.ORG Tue Jul 25 02:30:20 2006 Return-Path: X-Original-To: freebsd-bugs@hub.freebsd.org Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id E768F16A521 for ; Tue, 25 Jul 2006 02:30:20 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 531F043D5C for ; Tue, 25 Jul 2006 02:30:15 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id k6P2UFnJ001623 for ; Tue, 25 Jul 2006 02:30:15 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id k6P2UF4R001622; Tue, 25 Jul 2006 02:30:15 GMT (envelope-from gnats) Resent-Date: Tue, 25 Jul 2006 02:30:15 GMT Resent-Message-Id: <200607250230.k6P2UF4R001622@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, David Gilbert Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id ADC2016A4DD for ; Tue, 25 Jul 2006 02:21:27 +0000 (UTC) (envelope-from dgilbert@daveg.ca) Received: from ox.eicat.ca (ox.eicat.ca [66.96.30.35]) by mx1.FreeBSD.org (Postfix) with ESMTP id 2589F43D55 for ; Tue, 25 Jul 2006 02:21:27 +0000 (GMT) (envelope-from dgilbert@daveg.ca) Received: by ox.eicat.ca (Postfix, from userid 66) id 5D9511E0E0; Mon, 24 Jul 2006 22:21:26 -0400 (EDT) Received: by canoe.dclg.ca (Postfix, from userid 101) id A54FB4AC45; Mon, 24 Jul 2006 22:20:23 -0400 (EDT) Message-Id: <20060725022023.A54FB4AC45@canoe.dclg.ca> Date: Mon, 24 Jul 2006 22:20:23 -0400 (EDT) From: David Gilbert To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: Subject: kern/100796: if_tun requires kqueue hooks (patch included) X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: David Gilbert List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 25 Jul 2006 02:30:21 -0000 >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@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: