in testing tap(4) performance on the same box with the following config using claudios userlandbridge (tbridge) in between two tap interfaces each tap was also added their own standard bridge(4) along with 1 physical interface.
iperf3client--ix0--bridge0--tap0--tbridge--tap1--bridge1--ix1---iperf3svr with a 1socket 2 core system that gives 3Gb/s we got the following performance tbridge -t gave 557Mb/s TCP throughput btw (tbridge -t did not stop after using ^C or kill but did respond to kill -s SIGKILL ) tbridge -s gave 455Mb/s TCP throughput tbridge -p gave 448Mb/s TCP throughput tbridge -k gave 458mb/s TCP througput im going to try this again with more CPUs as the workload of forwarding in this box involves 3 bridges in series. I will also try with the tpmr(4) driver so something about OpenVPN has a bottleneck that reduces performance by a factor of 3 -4x ---------- Forwarded message --------- From: Tom Smyth <tom.sm...@wirelessconnect.eu> Date: Tue, 21 Jan 2020 at 11:15 Subject: Re: tap(4) performance tuning on (amd64) To: Tom Smyth <tom.sm...@wirelessconnect.eu>, Misc <misc@openbsd.org> Thanks Claudio, the program now seems to run without exiting ... Ill do some tests and get back to you later Tom Smyth On Tue, 21 Jan 2020 at 03:09, Claudio Jeker <cje...@diehard.n-r-g.com> wrote: > > On Tue, Jan 21, 2020 at 02:44:35AM +0000, Tom Smyth wrote: > > Claudio, > > Thanks for this, > > I compiled it on Openbsd 6.6 (stable) amd64 > > > > it compiled without error > > > > the binary seems to run fine but, > > ./tbridge -k /dev/tap0 /dev/tap1 > > > > runs and displays the usage message and gives an errorlevel of 1 > > every time use the -k or -t or -s or -p arguments see terminal > > conversation below > > > > Shit, I added a last minute check and as usual introduced a bug. > Line 189 change if (ch != 0) to if (mode != 0) > > -- > :wq Claudio > > /* > * Copyright (c) 2020 Claudio Jeker <clau...@openbsd.org> > * > * Permission to use, copy, modify, and distribute this software for any > * purpose with or without fee is hereby granted, provided that the above > * copyright notice and this permission notice appear in all copies. > * > * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > */ > #include <sys/types.h> > #include <sys/event.h> > #include <sys/time.h> > > #include <err.h> > #include <errno.h> > #include <fcntl.h> > #include <poll.h> > #include <pthread.h> > #include <signal.h> > #include <stdio.h> > #include <stdlib.h> > #include <string.h> > #include <unistd.h> > > volatile sig_atomic_t quit; > > static void > do_read(int in, int out) > { > char buf[2048]; > ssize_t n, o; > > n = read(in, buf, sizeof(buf)); > if (n == -1) > err(1, "read"); > o = write(out, buf, n); > if (o == -1) > err(1, "read"); > if (o != n) > errx(1, "short write"); > } > > static void > do_poll(int fd[2]) > { > struct pollfd pfd[2]; > int n, i; > > while (quit == 0) { > memset(pfd, 0, sizeof(pfd)); > pfd[0].fd = fd[0]; > pfd[0].events = POLLIN; > > pfd[1].fd = fd[1]; > pfd[1].events = POLLIN; > > n = poll(pfd, 2, INFTIM); > if (n == -1) > err(1, "poll"); > if (n == 0) > errx(1, "poll: timeout"); > for (i = 0; i < 2; i++) { > if (pfd[i].revents & POLLIN) > do_read(fd[i], fd[(i + 1) & 0x1]); > else if (pfd[i].revents & (POLLHUP | POLLERR)) > errx(1, "fd %d revents %x", i, pfd[i].revents); > } > } > > } > > static void > do_select(int fd[2]) > { > fd_set readfds; > int n, i, maxfd = -1; > > while (quit == 0) { > FD_ZERO(&readfds); > for (i = 0; i < 2; i++) { > if (fd[i] > maxfd) > maxfd = fd[i]; > FD_SET(fd[i], &readfds); > } > n = select(maxfd + 1, &readfds, NULL, NULL, NULL); > if (n == -1) > err(1, "select"); > if (n == 0) > errx(1, "select: timeout"); > for (i = 0; i < 2; i++) { > if (FD_ISSET(fd[i], &readfds)) > do_read(fd[i], fd[(i + 1) & 0x1]); > } > } > } > > static void > do_kqueue(int fd[2]) > { > struct kevent kev[2]; > int kq, i, n; > > if ((kq = kqueue()) == -1) > err(1, "kqueue"); > > memset(kev, 0, sizeof(kev)); > for (i = 0; i < 2; i++) { > EV_SET(&kev[i], fd[i], EVFILT_READ, EV_ADD | EV_ENABLE, > 0, 0, (void *)(intptr_t)i); > } > if (kevent(kq, kev, 2, NULL, 0, NULL) == -1) > err(1, "kevent register"); > > while (quit == 0) { > n = kevent(kq, NULL, 0, kev, 2, NULL); > if (n == -1) > err(1, "kevent"); > if (n == 0) > errx(1, "kevent: timeout"); > for (i = 0; i < n; i++) { > if (kev[i].flags & EV_ERROR) > errc(1, kev[i].data, "kevent EV_ERROR"); > if (kev[i].filter == EVFILT_READ) { > int r = (int)kev[i].udata; > do_read(fd[r], fd[(r + 1) & 0x1]); > } > } > } > } > > static void * > run_thread(void *arg) > { > int *fd = arg; > > while (quit == 0) > do_read(fd[0], fd[1]); > > return NULL; > } > > static void > do_thread(int fd[2]) > { > pthread_t tid; > int ret; > > ret = pthread_create(&tid, NULL, run_thread, fd); > if (ret) { > errc(1, ret, "pthread_create"); > } > > while (quit == 0) > do_read(fd[1], fd[0]); > } > > static void > sighdlr(int sig) > { > quit = 1; > } > > static __dead void > usage(void) > { > fprintf(stderr, "tbridge -k | -p | -s | -t tapA tapB\n"); > exit(1); > } > > int > main(int argc, char **argv) > { > int fd[2]; > int ch = 0; > int mode = 0; > > while ((ch = getopt(argc, argv, "kpst")) != -1) { > switch (ch) { > case 'k': > case 'p': > case 's': > case 't': > if (mode != 0) > usage(); > mode = ch; > break; > default: > usage(); > } > } > argc -= optind; > argv += optind; > if (argc != 2) > usage(); > > signal(SIGTERM, sighdlr); > signal(SIGINT, sighdlr); > signal(SIGHUP, sighdlr); > > fd[0] = open(argv[0], O_RDWR); > if (fd[0] == -1) > err(1, "open %s", argv[1]); > > fd[1] = open(argv[1], O_RDWR); > if (fd[1] == -1) > err(1, "open %s", argv[2]); > > switch (mode) { > case 'k': > do_kqueue(fd); > break; > case 'p': > do_poll(fd); > break; > case 's': > do_select(fd); > break; > case 't': > do_thread(fd); > break; > } > exit(0); > } -- Kindest regards, Tom Smyth. -- Kindest regards, Tom Smyth.