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


test3b# ./tbridge -k /dev/tap0 /dev/tap1
tbridge -k | -p | -s | -t tapA tapB
persistentg3b# ./tbridge -p /dev/tap0 /dev/tap1
tbridge -k | -p | -s | -t tapA tapB
test3b# echo $?
1
test3b# ./tbridge -s /dev/tap0 /dev/tap1
tbridge -k | -p | -s | -t tapA tapB
test3b# echo $?
1
test3b# ./tbridge -t /dev/tap0 /dev/tap1
tbridge -k | -p | -s | -t tapA tapB
test3b# echo $?
1
test3b# ./tbridge /dev/tap0 /dev/tap1
test3b# echo $?
0

I tried with and without creating the tunnel interfaces first,  with
ifconfig tap create
i tried with our without running ifconfig tap1 up
i tried with and without adding each tap to a separate  bridge(4)
I ran  the binary as root  for all tests
I tried running tbridge with interface name "tap1" / "tap0"  as opposed
to the device name /dev/tap1 /dev/tap2 (just in case)

 will try with current  after I get some sleep
( was just trying to do a benchmark of release /stable vs  current  also )


Thanks for this it is a help
 as I was trying and (losing with socat)  I think socat port on
OpenBSD6.6 amd64
is compiled without tap / tun support

cheers,
Tom Smyth






On Mon, 20 Jan 2020 at 10:38, Claudio Jeker <cje...@diehard.n-r-g.com> wrote:
>
> On Fri, Jan 10, 2020 at 01:00:49PM +0000, Tom Smyth wrote:
> > Hi lads,
> >
> > I have been doing some testing with tap(4) and openvpn (standard ssl )
> > I have been using openvpn with tap and I have been trying with null
> > encryption. null authentication,
> > the performance of the tap interface  seems to be about 100-150Mb/s  on a 
> > system
> > which can give  3Gb/s-5Gb/s on ix(4) interfaces  in Bridge mode and
> > 4-8Gb/s on tpmr mode
> > I was wondering is there a sysctl setting that if modified would
> > improve the tap interface performance.
> > I have tried with tpmr(4) and  bridge(4)
> >
> > is there a simple way  testing a tap(4) interface throughput /
> > performance without Openvpn process
> >
> > I can try mlvpn and wireguard
> > but I would love if there was a trick where I can just test the tap(4)
> > interface  with something like pair(4)...
> >
> > ix0---bridge0--tap0---someprocess--tap1-bridge1--ix1
> > or
> > ix0--tpmr0--tap0--someprocess--tap1-tpmr1-ix1
> >
> > is there a simple "someprocess" that would provide forwarding packets
> > between tap0 and tap1 in userland
> > so that any performance testing on tap(4) interfaces does not have the
> > distractions of complex userland programs with encryption /
> > encapsulation overheads
> >
>
> I just wrote a simple tun/tap bridge for testing so here you go.
> Compile it with 'cc -Wall -o tbridge tbridge.c -lpthread' and run it
> with 'tbridge -k /dev/tun0 /dev/tun1' to wire tun0 and tun1 together.
> You can select between, select(2), poll(2), kqueue(2) and pthreads as the
> way on how to multiplex the reads.
>
> For me the code triggers scheduler inefficencies and causes packets drops
> on the output queue when there are multiple packet producers.
> --
> :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 (ch != 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.

Reply via email to