[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

added kqueue support to tun(4)



Hello,

I added full kqueue support to the tun(4) driver, could some others please
test/comment/commit?

Specifically, the spl...() priorities were borrowed from the bpf(4)
driver, feedback on them would be appreciated.

cheers!
-=chris

--
Christopher Maxwell
cmaxwell_(_at_)_themanor_(_dot_)_net

--- if_tun.c.stable	Fri Aug 15 16:32:19 2003
+++ if_tun.c	Mon Nov 24 14:28:00 2003
@@ -136,6 +136,10 @@
 #ifdef ALTQ
 static void tunstart(struct ifnet *);
 #endif
+int	filt_tunread(struct knote *, long);
+int	filt_tunwrite(struct knote *, long);
+void	filt_tunrdetach(struct knote *);
+void	filt_tunwdetach(struct knote *);

 void
 tunattach(n)
@@ -258,6 +262,7 @@
 	}
 	tp->tun_pgid = 0;
 	selwakeup(&tp->tun_rsel);
+	KNOTE(&tp->tun_rsel.si_note, 0);

 	TUNDEBUG(("%s: closed\n", ifp->if_xname));
 	return (0);
@@ -433,6 +438,7 @@
 		csignal(tp->tun_pgid, SIGIO,
 		    tp->tun_siguid, tp->tun_sigeuid);
 	selwakeup(&tp->tun_rsel);
+	KNOTE(&tp->tun_rsel.si_note, 0);
 	return 0;
 }

@@ -780,14 +786,124 @@
 	return 0;
 }

-/* Does not currently work */
+/*
+ * kqueue(2) support.
+ *
+ * The tun driver uses an array of tun_softc's based on the minor number
+ * of the device.  kn->kn_hook gets set to the specific tun_softc.
+ *
+ * filt_tunread() sets kn->kn_data to the iface qsize
+ * filt_tunwrite() sets kn->kn_data to the MTU size
+ */

+struct filterops tunread_filtops =
+	{ 1, NULL, filt_tunrdetach, filt_tunread};
+
+struct filterops tunwrite_filtops =
+	{ 1, NULL, filt_tunwdetach, filt_tunwrite};
+
 int
 tunkqfilter(dev_t dev,struct knote *kn)
 {
-	return (1);
+	int unit, s;
+	struct klist *klist;
+	struct tun_softc *tp;
+	struct ifnet *ifp;
+
+	if ((unit = minor(dev)) >= ntun)
+		return ENXIO;
+
+	tp = &tunctl[unit];
+	ifp = &tp->tun_if;
+
+	s = splimp();
+	TUNDEBUG(("%s: tunselect\n", ifp->if_xname));
+	splx(s);
+
+	switch (kn->kn_filter) {
+		case EVFILT_READ:
+			klist = &tp->tun_rsel.si_note;
+			kn->kn_fop = &tunread_filtops;
+			break;
+		case EVFILT_WRITE:
+			klist = &tp->tun_wsel.si_note;
+			kn->kn_fop = &tunwrite_filtops;
+			break;
+		default:
+			return EPERM;	/* 1 */
+	}
+
+	kn->kn_hook = (caddr_t)tp;
+
+	s = splhigh();
+	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+	splx(s);
+
+	return 0;
 }

+void
+filt_tunrdetach(struct knote *kn)
+{
+	int s;
+	struct tun_softc *tp = (struct tun_softc *)kn->kn_hook;
+
+	s = splhigh();
+	SLIST_REMOVE(&tp->tun_rsel.si_note, kn, knote, kn_selnext);
+	splx(s);
+}
+
+int
+filt_tunread(struct knote *kn, long hint)
+{
+	int s;
+	struct tun_softc *tp;
+	struct ifnet *ifp;
+	struct mbuf *m;
+
+	tp = (struct tun_softc *)kn->kn_hook;
+	ifp = &tp->tun_if;
+
+	s = splnet();
+	IFQ_POLL(&ifp->if_snd, m);
+	if (m != NULL) {
+		splx(s);
+		kn->kn_data = ifp->if_snd.ifq_len;
+
+		TUNDEBUG(("%s: tunkqread q=%d\n", ifp->if_xname,
+					ifp->if_snd.ifq_len));
+		return 1;
+	}
+	splx(s);
+	TUNDEBUG(("%s: tunkqread waiting\n", ifp->if_xname));
+	return 0;
+}
+
+void
+filt_tunwdetach(struct knote *kn)
+{
+	int s;
+	struct tun_softc *tp = (struct tun_softc *)kn->kn_hook;
+
+	s = splhigh();
+	SLIST_REMOVE(&tp->tun_wsel.si_note, kn, knote, kn_selnext);
+	splx(s);
+}
+
+int
+filt_tunwrite(struct knote *kn, long hint)
+{
+	struct tun_softc *tp;
+	struct ifnet *ifp;
+
+	tp = (struct tun_softc *)kn->kn_hook;
+	ifp = &tp->tun_if;
+
+	kn->kn_data = ifp->if_mtu;
+
+	return 1;
+}
+
 #ifdef ALTQ
 /*
  * Start packet transmission on the interface.
@@ -815,6 +931,7 @@
 			csignal(tp->tun_pgid, SIGIO,
 			    tp->tun_siguid, tp->tun_sigeuid);
 		selwakeup(&tp->tun_rsel);
+		KNOTE(&tp->tun_rsel.si_note, 0);
 	}
 }
 #endif