tun TUNDOIOVEC ioctl

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

tun TUNDOIOVEC ioctl

Ted Unangst-6
I'm not really expecting tun to provide blistering performance, but
one of the things that keeps it slower than need be is the one packet
per read/write implementation. It'd be pretty cool to have
something like readv() or writev() provide the ability to operate on
multiple packets at once. Unfortunately the v interfaces don't provide
quite enough information, but we can create a new one with ioctl.

The TUNDOIOVEC ioctl takes a struct consisting of two iov arrays, one
for read and one for write, and the relevant counts. One syscall will
(without blocking) receive and send up to 8 packets in each direction.
Then it updates the structure so userland knows how many packets went
each way.

Thoughts?

Index: if_tun.c
===================================================================
RCS file: /cvs/src/sys/net/if_tun.c,v
retrieving revision 1.125
diff -u -p -r1.125 if_tun.c
--- if_tun.c 5 May 2014 11:44:33 -0000 1.125
+++ if_tun.c 10 Jul 2014 20:11:27 -0000
@@ -132,6 +132,8 @@ void filt_tunwdetach(struct knote *);
 void tunstart(struct ifnet *);
 void tun_link_state(struct tun_softc *);
 
+int tuncopyout(struct ifnet *ifp, struct mbuf *m0, struct uio *uio);
+
 struct filterops tunread_filtops =
  { 1, NULL, filt_tunrdetach, filt_tunread};
 
@@ -603,10 +605,13 @@ tun_wakeup(struct tun_softc *tp)
 int
 tunioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
 {
- int s;
+ int i, s, ret;
  struct tun_softc *tp;
+ struct ifnet *ifp;
  struct tuninfo *tunp;
+ struct tuniovec *tiov;
  struct mbuf *m;
+ struct uio uio;
 
  if ((tp = tun_lookup(minor(dev))) == NULL)
  return (ENXIO);
@@ -699,10 +704,47 @@ tunioctl(dev_t dev, u_long cmd, caddr_t
  bcopy(data, tp->arpcom.ac_enaddr,
     sizeof(tp->arpcom.ac_enaddr));
  break;
+ case TUNDOIOVEC:
+ splx(s);
+ ifp = &tp->tun_if;
+ tiov = (struct tuniovec *)data;
+ for (i = 0; i < tiov->readcnt; i++) {
+ s = splnet();
+ if ((tp->tun_flags & TUN_READY) != TUN_READY)
+ break;
+ IFQ_DEQUEUE(&ifp->if_snd, m);
+ splx(s);
+ if (m == NULL)
+ break;
+ uio.uio_iov = &tiov->readiov[i];
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = 0;
+ uio.uio_resid = tiov->readiov[i].iov_len;
+ uio.uio_segflg = UIO_USERSPACE;
+ uio.uio_rw = UIO_READ;
+ uio.uio_procp = p;
+ ret = tuncopyout(ifp, m, &uio);
+ if (ret != 0)
+ break;
+ }
+ tiov->readcnt = i;
+ for (i = 0; i < tiov->writecnt; i++) {
+ uio.uio_iov = &tiov->writeiov[i];
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = 0;
+ uio.uio_resid = tiov->writeiov[i].iov_len;
+ uio.uio_segflg = UIO_USERSPACE;
+ uio.uio_rw = UIO_WRITE;
+ uio.uio_procp = p;
+ ret = tunwrite(dev, &uio, 0);
+ if (ret != 0)
+ break;
+ }
+ tiov->writecnt = i;
+ return (0);
  default:
 #ifdef PIPEX
     {
- int ret;
  ret = pipex_ioctl(&tp->pipex_iface, cmd, data);
  splx(s);
  return (ret);
@@ -725,8 +767,8 @@ tunread(dev_t dev, struct uio *uio, int
 {
  struct tun_softc *tp;
  struct ifnet *ifp;
- struct mbuf *m, *m0;
- int error = 0, len, s;
+ struct mbuf *m0;
+ int error = 0, s;
 
  if ((tp = tun_lookup(minor(dev))) == NULL)
  return (ENXIO);
@@ -763,6 +805,15 @@ tunread(dev_t dev, struct uio *uio, int
  }
  } while (m0 == NULL);
  splx(s);
+
+ return tuncopyout(ifp, m0, uio);
+}
+
+int
+tuncopyout(struct ifnet *ifp, struct mbuf *m0, struct uio *uio)
+{
+ struct mbuf *m;
+ int error, len;
 
  while (m0 != NULL && uio->uio_resid > 0 && error == 0) {
  len = min(uio->uio_resid, m0->m_len);
Index: if_tun.h
===================================================================
RCS file: /cvs/src/sys/net/if_tun.h,v
retrieving revision 1.15
diff -u -p -r1.15 if_tun.h
--- if_tun.h 6 Feb 2007 10:49:40 -0000 1.15
+++ if_tun.h 10 Jul 2014 19:47:40 -0000
@@ -68,4 +68,13 @@ struct tuninfo {
 #define TUNSDEBUG _IOW('t', 94, int)
 #define TUNGDEBUG _IOR('t', 95, int)
 
+#define TUNMAXIOS 8
+struct tuniovec {
+ int readcnt;
+ struct iovec readiov[TUNMAXIOS];
+ int writecnt;
+ struct iovec writeiov[TUNMAXIOS];
+};
+#define TUNDOIOVEC _IOWR('t', 96, struct tuniovec)
+
 #endif /* _NET_IF_TUN_H_ */

Reply | Threaded
Open this post in threaded view
|

Re: tun TUNDOIOVEC ioctl

Matthew Dempsky-3
On Thu, Jul 10, 2014 at 1:20 PM, Ted Unangst <[hidden email]> wrote:
> Thoughts?

Seems kind of hacky to me, but if it results in significant
performance improvements in real world uses, then I could be swayed
since it's not very intrusive either.

Reply | Threaded
Open this post in threaded view
|

Re: tun TUNDOIOVEC ioctl

Henning Brauer-7
* Matthew Dempsky <[hidden email]> [2014-07-10 22:56]:
> On Thu, Jul 10, 2014 at 1:20 PM, Ted Unangst <[hidden email]> wrote:
> > Thoughts?
>
> Seems kind of hacky to me, but if it results in significant
> performance improvements in real world uses, then I could be swayed
> since it's not very intrusive either.

indeed.

--
Henning Brauer, [hidden email], [hidden email]
BS Web Services GmbH, http://bsws.de, Full-Service ISP
Secure Hosting, Mail and DNS. Virtual & Dedicated Servers, Root to Fully Managed
Henning Brauer Consulting, http://henningbrauer.com/