[PATCH] Receive multiple packets at a time

Dave Taht dave.taht at gmail.com
Wed Dec 2 13:21:56 CET 2015


Oh, goodie!

I'd made a start on the send direction here:
https://github.com/dtaht/tinc/commits/master

Perhaps that will help.

I would not just pull that as it was just some late night hacking...
and it turns out the posix time calls I upgraded to to get better than
second resolution are not supported on OSX.

My ultimate intent was to move to not bottlenecking or dropping
packets on the recv buffer ever (but I figured recvmmsg AND threads
would be needed), and move tinc queue management to an fq_codel like
system, so as to remove apparent network delays when it was
bottlenecked on crypto or output.

There are also some notes there on how to do tos encapsulation more
right in the upcoming ecn'd world.... and I think I discussed here the
prospect of doing a fully fq'd vpn utilizing an entire ipv6 /64....

Dave Täht
Let's go make home routers and wifi faster! With better software!
https://www.gofundme.com/savewifi


On Wed, Dec 2, 2015 at 12:58 PM, Samuel Thibault
<samuel.thibault at ens-lyon.org> wrote:
> Hello,
>
> Linux has a recvmmsg() system call which allows to achieve several
> recvfrom() at a time.  The patch below makes tinc use it (patch against
> 1.1-pre11). Basically the patch turns the handle_incoming_vpn_data
> variables into arrays (of size 1 when recvmmsg is not available, and
> thus compiled the same as before), and makes the code index into the
> arrays. You may want to use interdiff -w /dev/null patch to better see
> what changes the patch makes.
>
> With this patch, I saw the non-ciphered bandwidth achieved over direct
> ethernet improve from 680Mbps to 800Mbps (or conversely, reduce the CPU
> usage for the same bandwidth).
>
> More is yet to come: I'll have a look at extending the tun/tap interface
> to send/receive several packets at a time, and then also using sendmmsg
> will again improve performance.
>
> Samuel
>
> --- configure.ac.original       2015-10-02 17:06:31.250034677 +0200
> +++ configure.ac        2015-10-02 17:06:54.147546590 +0200
> @@ -187,7 +187,7 @@
>
>  dnl Checks for library functions.
>  AC_TYPE_SIGNAL
> -AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random select strdup strerror strsignal strtol system time usleep unsetenv vsyslog writev],
> +AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random recvmmsg select strdup strerror strsignal strtol system time usleep unsetenv vsyslog writev],
>    [], [], [#include "src/have.h"]
>  )
>
> --- src/net_packet.c.original   2015-10-02 16:26:36.828841493 +0200
> +++ src/net_packet.c    2015-10-02 17:15:05.892051503 +0200
> @@ -1057,92 +1057,137 @@
>         return n;
>  }
>
> +#ifdef HAVE_RECVMMSG
> +#define MAX_MSG  256
> +#else
> +#define MAX_MSG  1
> +#endif
> +
>  void handle_incoming_vpn_data(void *data, int flags) {
>         listen_socket_t *ls = data;
> -       vpn_packet_t pkt;
> +       vpn_packet_t pkt[MAX_MSG];
>         char *hostname;
>         node_id_t nullid = {};
> -       sockaddr_t addr = {};
> -       socklen_t addrlen = sizeof addr;
> +       sockaddr_t addr[MAX_MSG] = {};
> +#ifdef HAVE_RECVMMSG
> +       struct mmsghdr msg[MAX_MSG];
> +       struct iovec iov[MAX_MSG];
> +#else
> +       socklen_t addrlen = sizeof addr[0];
> +#endif
>         node_t *from, *to;
>         bool direct = false;
> +       int num = 1, i;
>
> -       pkt.offset = 0;
> -       int len = recvfrom(ls->udp.fd, DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
> +#ifdef HAVE_RECVMMSG
> +       for (i = 0; i < MAX_MSG; i++)
> +       {
> +               pkt[i].offset = 0;
> +               msg[i].msg_hdr.msg_name = &addr[i].sa;
> +               msg[i].msg_hdr.msg_namelen = sizeof(addr[i]);
> +               iov[i].iov_base = DATA(&pkt[i]);
> +               iov[i].iov_len = MAXSIZE;
> +               msg[i].msg_hdr.msg_iov = &iov[i];
> +               msg[i].msg_hdr.msg_iovlen = 1;
> +               msg[i].msg_hdr.msg_control = NULL;
> +               msg[i].msg_hdr.msg_controllen = 0;
> +       }
>
> -       if(len <= 0 || len > MAXSIZE) {
> +       num = recvmmsg(ls->udp.fd, msg, MAX_MSG, MSG_DONTWAIT, NULL);
> +#else
> +       pkt[0].offset = 0;
> +       int len = recvfrom(ls->udp.fd, DATA(&pkt[0]), MAXSIZE, 0, &addr[0].sa, &addrlen);
> +#endif
> +
> +#ifdef HAVE_RECVMMSG
> +       if(num < 0)
> +#else
> +       if(len <= 0 || len > MAXSIZE)
> +#endif
> +       {
>                 if(!sockwouldblock(sockerrno))
>                         logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
>                 return;
>         }
>
> -       pkt.len = len;
> -
> -       sockaddrunmap(&addr); /* Some braindead IPv6 implementations do stupid things. */
> -
> -       // Try to figure out who sent this packet.
> -
> -       node_t *n = lookup_node_udp(&addr);
> -
> -       if(!n) {
> -               // It might be from a 1.1 node, which might have a source ID in the packet.
> -               pkt.offset = 2 * sizeof(node_id_t);
> -               from = lookup_node_id(SRCID(&pkt));
> -               if(from && !memcmp(DSTID(&pkt), &nullid, sizeof nullid) && from->status.sptps) {
> -                       if(sptps_verify_datagram(&from->sptps, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t)))
> -                               n = from;
> -                       else
> -                               goto skip_harder;
> +#ifndef HAVE_RECVMMSG
> +       pkt[0].len = len;
> +#endif
> +
> +       for (i = 0; i < num; i++)
> +       {
> +#ifdef HAVE_RECVMMSG
> +               pkt[i].len = msg[i].msg_len;
> +               if(pkt[i].len <= 0 || pkt[i].len > MAXSIZE)
> +                       continue;
> +#endif
> +
> +               sockaddrunmap(&addr[i]); /* Some braindead IPv6 implementations do stupid things. */
> +
> +               // Try to figure out who sent this packet.
> +
> +               node_t *n = lookup_node_udp(&addr[i]);
> +
> +               if(!n) {
> +                       // It might be from a 1.1 node, which might have a source ID in the packet.
> +                       pkt[i].offset = 2 * sizeof(node_id_t);
> +                       from = lookup_node_id(SRCID(&pkt[i]));
> +                       if(from && !memcmp(DSTID(&pkt[i]), &nullid, sizeof nullid) && from->status.sptps) {
> +                               if(sptps_verify_datagram(&from->sptps, DATA(&pkt[i]), pkt[i].len - 2 * sizeof(node_id_t)))
> +                                       n = from;
> +                               else
> +                                       goto skip_harder;
> +                       }
>                 }
> -       }
>
> -       if(!n) {
> -               pkt.offset = 0;
> -               n = try_harder(&addr, &pkt);
> -       }
> +               if(!n) {
> +                       pkt[i].offset = 0;
> +                       n = try_harder(&addr[i], &pkt[i]);
> +               }
>
> -skip_harder:
> -       if(!n) {
> -               if(debug_level >= DEBUG_PROTOCOL) {
> -                       hostname = sockaddr2hostname(&addr);
> -                       logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
> -                       free(hostname);
> +       skip_harder:
> +               if(!n) {
> +                       if(debug_level >= DEBUG_PROTOCOL) {
> +                               hostname = sockaddr2hostname(&addr[i]);
> +                               logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
> +                               free(hostname);
> +                       }
> +                       continue;
>                 }
> -               return;
> -       }
>
> -       if(n->status.sptps) {
> -               pkt.offset = 2 * sizeof(node_id_t);
> +               if(n->status.sptps) {
> +                       pkt[i].offset = 2 * sizeof(node_id_t);
>
> -               if(!memcmp(DSTID(&pkt), &nullid, sizeof nullid)) {
> +                       if(!memcmp(DSTID(&pkt[i]), &nullid, sizeof nullid)) {
> +                               direct = true;
> +                               from = n;
> +                               to = myself;
> +                       } else {
> +                               from = lookup_node_id(SRCID(&pkt[i]));
> +                               to = lookup_node_id(DSTID(&pkt[i]));
> +                       }
> +                       if(!from || !to) {
> +                               logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from %s (%s) with unknown source and/or destination ID", n->name, n->hostname);
> +                               continue;
> +                       }
> +
> +                       if(to != myself) {
> +                               send_sptps_data_priv(to, n, 0, DATA(&pkt[i]), pkt[i].len - 2 * sizeof(node_id_t));
> +                               continue;
> +                       }
> +               } else {
>                         direct = true;
>                         from = n;
> -                       to = myself;
> -               } else {
> -                       from = lookup_node_id(SRCID(&pkt));
> -                       to = lookup_node_id(DSTID(&pkt));
> -               }
> -               if(!from || !to) {
> -                       logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from %s (%s) with unknown source and/or destination ID", n->name, n->hostname);
> -                       return;
>                 }
>
> -               if(to != myself) {
> -                       send_sptps_data_priv(to, n, 0, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t));
> -                       return;
> -               }
> -       } else {
> -               direct = true;
> -               from = n;
> +               pkt[i].offset = 0;
> +               if(!receive_udppacket(from, &pkt[i]))
> +                       continue;
> +
> +               n->sock = ls - listen_socket;
> +               if(direct && sockaddrcmp(&addr[i], &n->address))
> +                       update_node_udp(n, &addr[i]);
>         }
> -
> -       pkt.offset = 0;
> -       if(!receive_udppacket(from, &pkt))
> -               return;
> -
> -       n->sock = ls - listen_socket;
> -       if(direct && sockaddrcmp(&addr, &n->address))
> -               update_node_udp(n, &addr);
>  }
>
>  void handle_device_data(void *data, int flags) {
>
> _______________________________________________
> tinc-devel mailing list
> tinc-devel at tinc-vpn.org
> http://www.tinc-vpn.org/cgi-bin/mailman/listinfo/tinc-devel


More information about the tinc-devel mailing list