Hi!

I see my openvpn handling a lot of small packets (around 100 bytes) at a
high rate. I have seen packing smaller packets into one bigger packet
suggested but the idea always rejected for various reasons.

Anyways, I made a little patch to do that (works agains 2.1rc4), and did
a couple of quick tests. I run 50 ping -i 0 -s 153 for 30 seconds,
observing CPU usage and made note of bytes transfered over the link. In
both cases, 18.7MB was pushed back and forth (pings, you know).

I looked at CPU usage with top, so it is a tad subjective measure, but
with multipacketing the cpu usage was mostly something like 10%-15%, but
without it more like 20% (I used UDP transport with TLS layer).

So it can probably give an advantage in some cases.

I submit the patch to your scrutiny

Siim Põder

diff -aur openvpn-2.1~rc2/forward.c openvpn-2.1~rc2-multipacket/forward.c
--- openvpn-2.1~rc2/forward.c	2006-10-16 01:30:21.000000000 +0300
+++ openvpn-2.1~rc2-multipacket/forward.c	2007-06-18 17:12:36.000000000 +0300
@@ -867,6 +867,69 @@
 }

 /*
+ * Pack multiple packets into the buffer
+ * Output: c->c2.buf
+ */
+
+void
+read_incoming_tun_mp(struct context *c)
+{
+  int readlen = 0, packets = 0;
+  BLEN (&c->c2.buf) = 0;
+
+  ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame)));
+  ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame)));
+
+  /* First check if there was a packet left out from last batch and use that one */
+  if (BLEN (&c->c2.from_tun_of) != 0)
+  {
+    memcpy(BPTR (&c->c2.buf), BPTR (&c->c2.from_tun_of), BLEN (&c->c2.from_tun_of));
+    BLEN (&c->c2.buf) = BLEN (&c->c2.from_tun_of);
+    BLEN (&c->c2.from_tun_of) = 0;
+  }
+
+  /* Read more packets to fill the buffer */
+  while (MAX_RW_SIZE_TUN (&c->c2.frame) - BLEN (&c->c2.buf) - 2 > 0)
+  {
+    readlen = read_tun (c->c1.tuntap, BPTR (&c->c2.buf) + BLEN (&c->c2.buf) + 2, MAX_RW_SIZE_TUN (&c->c2.frame));
+    if (readlen > 0)
+    {
+      packets++;
+      *(uint16_t*) (BPTR (&c->c2.buf) + BLEN (&c->c2.buf)) = readlen;
+      BLEN (&c->c2.buf) += readlen + 2;
+    }
+    else
+      break;
+  }
+
+  /* Last packet does not fit MTU, keep it post-buffer for retrieval next time around */
+  if (BLEN (&c->c2.buf) > MAX_RW_SIZE_TUN (&c->c2.frame))
+  {
+    BLEN (&c->c2.buf) -= readlen + 2;
+    memcpy(&c->c2.from_tun_of, &c->c2.buf, sizeof(struct buffer));
+    c->c2.from_tun_of.offset += BLEN (&c->c2.buf);
+    BLEN (&c->c2.from_tun_of) = readlen + 2;
+#ifdef PACKET_TRUNCATION_CHECK
+    ipv4_packet_size_verify (BPTR (&c->c2.from_tun_of) + c->c2.from_tun_of.offset + 2,
+			     BLEN (&c->c2.from_tun_of) - 2,
+			     TUNNEL_TYPE (c->c1.tuntap),
+			     "READ_TUN",
+			     &c->c2.n_trunc_tun_read);
+#endif
+  }
+#ifdef PACKET_TRUNCATION_CHECK
+  else if (packets == 1)
+  {
+    ipv4_packet_size_verify (BPTR (&c->c2.buf) + 2,
+			     BLEN (&c->c2.buf) - 2,
+			     TUNNEL_TYPE (c->c1.tuntap),
+			     "READ_TUN",
+			     &c->c2.n_trunc_tun_read);
+  }
+#endif
+}
+
+/*
  * Output: c->c2.buf
  */

@@ -881,21 +944,26 @@
   perf_push (PERF_READ_IN_TUN);

   c->c2.buf = c->c2.buffers->read_tun_buf;
+  if (c->options.multipacket)
+    read_incoming_tun_mp (c);
+  else
+  {
 #ifdef TUN_PASS_BUFFER
-  read_tun_buffered (c->c1.tuntap, &c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame));
+    read_tun_buffered (c->c1.tuntap, &c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame));
 #else
-  ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame)));
-  ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame)));
-  c->c2.buf.len = read_tun (c->c1.tuntap, BPTR (&c->c2.buf), MAX_RW_SIZE_TUN (&c->c2.frame));
+    ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame)));
+    ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame)));
+    c->c2.buf.len = read_tun (c->c1.tuntap, BPTR (&c->c2.buf), MAX_RW_SIZE_TUN (&c->c2.frame));
 #endif

 #ifdef PACKET_TRUNCATION_CHECK
-  ipv4_packet_size_verify (BPTR (&c->c2.buf),
-			   BLEN (&c->c2.buf),
-			   TUNNEL_TYPE (c->c1.tuntap),
-			   "READ_TUN",
-			   &c->c2.n_trunc_tun_read);
+    ipv4_packet_size_verify (BPTR (&c->c2.buf),
+			     BLEN (&c->c2.buf),
+			     TUNNEL_TYPE (c->c1.tuntap),
+			     "READ_TUN",
+			     &c->c2.n_trunc_tun_read);
 #endif
+  }

   /* Was TUN/TAP interface stopped? */
   if (tuntap_stop (c->c2.buf.len))
@@ -1160,6 +1228,25 @@
 #endif
       dmsg (D_TUN_RW, "TUN WRITE [%d]", BLEN (&c->c2.to_tun));

+      /* if multiple packets are packed into one frame */
+      if (c->options.multipacket)
+      {
+        size = 0;
+	//fprintf(stderr, "Multipacketing\n");
+        while (size < BLEN (&c->c2.to_tun))
+	{
+#ifdef PACKET_TRUNCATION_CHECK
+          ipv4_packet_size_verify (BPTR (&c->c2.to_tun) + size + 2,
+			           *(uint16_t*) (BPTR (&c->c2.to_tun) + size),
+			           TUNNEL_TYPE (c->c1.tuntap),
+			           "WRITE_TUN",
+			           &c->c2.n_trunc_tun_write);
+#endif
+          size += write_tun (c->c1.tuntap, BPTR (&c->c2.to_tun) + size + 2, *(uint16_t*) (BPTR (&c->c2.to_tun) + size) ) + 2;
+	}
+      }
+      else /* not multipacket */
+      {
 #ifdef PACKET_TRUNCATION_CHECK
       ipv4_packet_size_verify (BPTR (&c->c2.to_tun),
 			       BLEN (&c->c2.to_tun),
@@ -1173,7 +1260,6 @@
 #else
       size = write_tun (c->c1.tuntap, BPTR (&c->c2.to_tun), BLEN (&c->c2.to_tun));
 #endif
-
       if (size > 0)
 	c->c2.tun_write_bytes += size;
       check_status (size, "write to TUN/TAP", NULL, c->c1.tuntap);
@@ -1192,6 +1278,7 @@
 	  /* indicate activity regarding --inactive parameter */
 	  register_activity (c, size);
 	}
+      }
     }
   else
     {
diff -aur openvpn-2.1~rc2/init.c openvpn-2.1~rc2-multipacket/init.c
--- openvpn-2.1~rc2/init.c	2006-11-23 23:35:20.000000000 +0200
+++ openvpn-2.1~rc2-multipacket/init.c	2007-06-18 16:11:50.000000000 +0300
@@ -1816,7 +1816,7 @@
   ALLOC_OBJ_CLEAR (b, struct context_buffers);

   b->read_link_buf = alloc_buf (BUF_SIZE (frame));
-  b->read_tun_buf = alloc_buf (BUF_SIZE (frame));
+  b->read_tun_buf = alloc_buf (BUF_SIZE (frame) * 2);

   b->aux_buf = alloc_buf (BUF_SIZE (frame));

@@ -1865,6 +1865,7 @@
 {
   c->c2.buffers = init_context_buffers (&c->c2.frame);
   c->c2.buffers_owned = true;
+  c->c2.from_tun_of.len = 0;
 }

 #ifdef ENABLE_FRAGMENT
Only in openvpn-2.1~rc2/install-win32: openvpn.nsi
diff -aur openvpn-2.1~rc2/openvpn.h openvpn-2.1~rc2-multipacket/openvpn.h
--- openvpn-2.1~rc2/openvpn.h	2006-11-23 23:34:40.000000000 +0200
+++ openvpn-2.1~rc2-multipacket/openvpn.h	2007-06-18 16:14:09.000000000 +0300
@@ -357,6 +357,7 @@
    * struct context_buffers.
    */
   struct buffer buf;
+  struct buffer from_tun_of;
   struct buffer to_tun;
   struct buffer to_link;

Only in openvpn-2.1~rc2: openvpn.spec
diff -aur openvpn-2.1~rc2/options.c openvpn-2.1~rc2-multipacket/options.c
--- openvpn-2.1~rc2/options.c	2007-02-28 05:50:35.000000000 +0200
+++ openvpn-2.1~rc2-multipacket/options.c	2007-06-18 16:11:50.000000000 +0300
@@ -298,6 +298,7 @@
   "--comp-noadapt  : Don't use adaptive compression when --comp-lzo\n"
   "                  is specified.\n"
 #endif
+  "--multipacket   : Pack consequtive small packets into one bigger packet.\n"
 #ifdef ENABLE_MANAGEMENT
   "--management ip port [pass] : Enable a TCP server on ip:port to handle\n"
   "                  management functions.  pass is a password file\n"
@@ -1177,6 +1178,8 @@
   SHOW_INT (lzo);
 #endif

+  SHOW_BOOL (multipacket);
+
   SHOW_STR (route_script);
   SHOW_STR (route_default_gateway);
   SHOW_INT (route_default_metric);
@@ -2004,6 +2007,8 @@
  * --comp-lzo
  * --fragment
  *
+ * --multipacket
+ *
  * Crypto Options:
  *
  * --cipher
@@ -2081,6 +2086,9 @@
     buf_printf (&out, ",comp-lzo");
 #endif

+  if (o->multipacket)
+    buf_printf (&out, ",multipacket");
+
 #ifdef ENABLE_FRAGMENT
   if (o->fragment)
     buf_printf (&out, ",mtu-dynamic");
@@ -4651,6 +4659,11 @@
       options->lzo &= ~LZO_ADAPTIVE;
     }
 #endif /* USE_LZO */
+  else if (streq (p[0], "multipacket"))
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->multipacket = true;
+    }
 #ifdef USE_CRYPTO
   else if (streq (p[0], "show-ciphers"))
     {
diff -aur openvpn-2.1~rc2/options.h openvpn-2.1~rc2-multipacket/options.h
--- openvpn-2.1~rc2/options.h	2006-10-16 01:30:21.000000000 +0300
+++ openvpn-2.1~rc2-multipacket/options.h	2007-06-18 16:14:09.000000000 +0300
@@ -236,6 +236,9 @@
   unsigned int lzo;
 #endif

+  /* pack consequtive small packets into one MTU-sized packet */
+  bool multipacket;
+
   /* buffer sizes */
   int rcvbuf;
   int sndbuf;

Reply via email to