From 45d0cd8adf7cffc9be558ffb017834cac6bef098 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 11 Oct 2017 17:36:39 +0900 Subject: [PATCH 1/3] lkl: Support two different file descriptors for rx and tx This change allows lkl to use two different file descriptor for network rx and tx. This helps introducing new uni-directinal network channel(such as PIPE). Reviewed-by: Hajime Tazaki Signed-off-by: Motomu Utsumi --- tools/lkl/lib/virtio_net_fd.c | 32 +++++++++++++++++++------------- tools/lkl/lib/virtio_net_fd.h | 5 +++-- tools/lkl/lib/virtio_net_raw.c | 2 +- tools/lkl/lib/virtio_net_tap.c | 2 +- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/tools/lkl/lib/virtio_net_fd.c b/tools/lkl/lib/virtio_net_fd.c index 6fa09cabde4670..62735c6c8aa904 100644 --- a/tools/lkl/lib/virtio_net_fd.c +++ b/tools/lkl/lib/virtio_net_fd.c @@ -23,7 +23,8 @@ struct lkl_netdev_fd { struct lkl_netdev dev; /* file-descriptor based device */ - int fd; + int fd_rx; + int fd_tx; /* * Controlls the poll mask for fd. Can be acccessed concurrently from * poll, tx, or rx routines but there is no need for syncronization @@ -48,7 +49,7 @@ static int fd_net_tx(struct lkl_netdev *nd, struct iovec *iov, int cnt) container_of(nd, struct lkl_netdev_fd, dev); do { - ret = writev(nd_fd->fd, iov, cnt); + ret = writev(nd_fd->fd_tx, iov, cnt); } while (ret == -1 && errno == EINTR); if (ret < 0) { @@ -72,7 +73,7 @@ static int fd_net_rx(struct lkl_netdev *nd, struct iovec *iov, int cnt) container_of(nd, struct lkl_netdev_fd, dev); do { - ret = readv(nd_fd->fd, (struct iovec *)iov, cnt); + ret = readv(nd_fd->fd_rx, (struct iovec *)iov, cnt); } while (ret == -1 && errno == EINTR); if (ret < 0) { @@ -93,9 +94,12 @@ static int fd_net_poll(struct lkl_netdev *nd) { struct lkl_netdev_fd *nd_fd = container_of(nd, struct lkl_netdev_fd, dev); - struct pollfd pfds[2] = { + struct pollfd pfds[3] = { { - .fd = nd_fd->fd, + .fd = nd_fd->fd_rx, + }, + { + .fd = nd_fd->fd_tx, }, { .fd = nd_fd->pipe[0], @@ -107,10 +111,10 @@ static int fd_net_poll(struct lkl_netdev *nd) if (nd_fd->poll_rx) pfds[0].events |= POLLIN|POLLPRI; if (nd_fd->poll_tx) - pfds[0].events |= POLLOUT; + pfds[1].events |= POLLOUT; do { - ret = poll(pfds, 2, -1); + ret = poll(pfds, 3, -1); } while (ret == -1 && errno == EINTR); if (ret < 0) { @@ -118,10 +122,10 @@ static int fd_net_poll(struct lkl_netdev *nd) return 0; } - if (pfds[1].revents & (POLLHUP|POLLNVAL)) + if (pfds[2].revents & (POLLHUP|POLLNVAL)) return LKL_DEV_NET_POLL_HUP; - if (pfds[1].revents & POLLIN) { + if (pfds[2].revents & POLLIN) { char tmp[PIPE_BUF]; ret = read(nd_fd->pipe[0], tmp, PIPE_BUF); @@ -138,7 +142,7 @@ static int fd_net_poll(struct lkl_netdev *nd) ret |= LKL_DEV_NET_POLL_RX; } - if (pfds[0].revents & POLLOUT) { + if (pfds[1].revents & POLLOUT) { nd_fd->poll_tx = 0; ret |= LKL_DEV_NET_POLL_TX; } @@ -161,7 +165,8 @@ static void fd_net_free(struct lkl_netdev *nd) struct lkl_netdev_fd *nd_fd = container_of(nd, struct lkl_netdev_fd, dev); - close(nd_fd->fd); + close(nd_fd->fd_rx); + close(nd_fd->fd_tx); free(nd_fd); } @@ -173,7 +178,7 @@ struct lkl_dev_net_ops fd_net_ops = { .free = fd_net_free, }; -struct lkl_netdev *lkl_register_netdev_fd(int fd) +struct lkl_netdev *lkl_register_netdev_fd(int fd_rx, int fd_tx) { struct lkl_netdev_fd *nd; @@ -186,7 +191,8 @@ struct lkl_netdev *lkl_register_netdev_fd(int fd) memset(nd, 0, sizeof(*nd)); - nd->fd = fd; + nd->fd_rx = fd_rx; + nd->fd_tx = fd_tx; if (pipe(nd->pipe) < 0) { perror("pipe"); free(nd); diff --git a/tools/lkl/lib/virtio_net_fd.h b/tools/lkl/lib/virtio_net_fd.h index 5c1921b99a7921..a15a4de65580d4 100644 --- a/tools/lkl/lib/virtio_net_fd.h +++ b/tools/lkl/lib/virtio_net_fd.h @@ -7,10 +7,11 @@ struct ifreq; * lkl_register_netdev_linux_fdnet - register a file descriptor-based network * device as a NIC * - * @fd - a POSIX file descriptor number for input/output + * @fd_rx - a POSIX file descriptor number for input + * @fd_tx - a POSIX file descriptor number for output * @returns a struct lkl_netdev_linux_fdnet entry for virtio-net */ -struct lkl_netdev *lkl_register_netdev_fd(int fd); +struct lkl_netdev *lkl_register_netdev_fd(int fd_rx, int fd_tx); /** diff --git a/tools/lkl/lib/virtio_net_raw.c b/tools/lkl/lib/virtio_net_raw.c index 1161e945f06720..b019865f49e2ee 100644 --- a/tools/lkl/lib/virtio_net_raw.c +++ b/tools/lkl/lib/virtio_net_raw.c @@ -58,5 +58,5 @@ struct lkl_netdev *lkl_netdev_raw_create(const char *ifname) fd_flags = fcntl(fd, F_GETFD, NULL); fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK); - return lkl_register_netdev_fd(fd); + return lkl_register_netdev_fd(fd, fd); } diff --git a/tools/lkl/lib/virtio_net_tap.c b/tools/lkl/lib/virtio_net_tap.c index c8979ce8d679ec..09ef520721733d 100644 --- a/tools/lkl/lib/virtio_net_tap.c +++ b/tools/lkl/lib/virtio_net_tap.c @@ -69,7 +69,7 @@ struct lkl_netdev *lkl_netdev_tap_init(const char *path, int offload, close(fd); return NULL; } - nd = lkl_register_netdev_fd(fd); + nd = lkl_register_netdev_fd(fd, fd); if (!nd) { perror("failed to register to."); close(fd); From b31aa0d12d8597d2029861fbafd3d0ba0959ed9c Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 11 Oct 2017 18:35:45 +0900 Subject: [PATCH 2/3] lkl: Introduce pipe network backend for virtio device This commit allows lkl to use anonymous pipe and named pipe as network channel. For example: $ LKL_HIJACK_NET_IFTYPE=pipe \ LKL_HIJACK_NET_IFPARAMS="named pipe|/dev/stdout" \ LKL_HIJACK_NET_IP=192.168.0.1 \ LKL_HIJACK_NET_NETMASK_LEN=24 \ lkl-hijack.sh sleep 30 | \ LKL_HIJACK_NET_IFTYPE=pipe \ LKL_HIJACK_NET_IFPARAMS="/dev/stdin|named pipe" \ LKL_HIJACK_NET_IP=192.168.0.2 \ LKL_HIJACK_NET_NETMASK_LEN=24 \ lkl-hijack.sh ping 192.168.0.1 Reviewed-by: Hajime Tazaki Signed-off-by: Motomu Utsumi --- tools/lkl/include/lkl.h | 10 +++++ tools/lkl/lib/Build | 1 + tools/lkl/lib/hijack/init.c | 2 + tools/lkl/lib/virtio_net_pipe.c | 68 +++++++++++++++++++++++++++++++++ tools/lkl/tests/hijack-test.sh | 65 +++++++++++++++++++++++++++++++ tools/lkl/tests/net-test.c | 2 + tools/lkl/tests/net.sh | 25 ++++++++++++ 7 files changed, 173 insertions(+) create mode 100644 tools/lkl/lib/virtio_net_pipe.c diff --git a/tools/lkl/include/lkl.h b/tools/lkl/include/lkl.h index 4c70c96d9e8506..80ba0f3c5eac5b 100644 --- a/tools/lkl/include/lkl.h +++ b/tools/lkl/include/lkl.h @@ -426,6 +426,16 @@ struct lkl_netdev *lkl_netdev_raw_create(const char *ifname); */ struct lkl_netdev *lkl_netdev_macvtap_create(const char *path, int offload); +/** + * lkl_netdev_pipe_create - create pipe net_device for the virtio + * net backend + * + * @ifname - a file name for the rx and tx pipe device. need to be configured + * on host in advance. delimiter is "|". e.g. "rx_name|tx_name". + * @offload - offload bits for the device + */ +struct lkl_netdev *lkl_netdev_pipe_create(char *ifname, int offload); + /* * lkl_register_dbg_handler- register a signal handler that loads a debug lib. * diff --git a/tools/lkl/lib/Build b/tools/lkl/lib/Build index 99e88616224d79..c146596a7a6c6f 100644 --- a/tools/lkl/lib/Build +++ b/tools/lkl/lib/Build @@ -20,3 +20,4 @@ lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_raw.o lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_macvtap.o lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_dpdk.o lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_vde.o +lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_pipe.o diff --git a/tools/lkl/lib/hijack/init.c b/tools/lkl/lib/hijack/init.c index 1717f0301de92b..1e52246886b2d0 100644 --- a/tools/lkl/lib/hijack/init.c +++ b/tools/lkl/lib/hijack/init.c @@ -282,6 +282,8 @@ hijack_init(void) nd = lkl_netdev_macvtap_create(ifparams, offload); } else if ((strcmp(iftype, "dpdk") == 0)) { nd = lkl_netdev_dpdk_create(ifparams, offload, mac); + } else if ((strcmp(iftype, "pipe") == 0)) { + nd = lkl_netdev_pipe_create(ifparams, offload); } else { if (offload) { fprintf(stderr, diff --git a/tools/lkl/lib/virtio_net_pipe.c b/tools/lkl/lib/virtio_net_pipe.c new file mode 100644 index 00000000000000..6d5a8569da28cc --- /dev/null +++ b/tools/lkl/lib/virtio_net_pipe.c @@ -0,0 +1,68 @@ +/* + * pipe based virtual network interface feature for LKL + * Copyright (c) 2017,2016 Motomu Utsumi + * + * Author: Motomu Utsumi + * + * Current implementation is linux-specific. + */ +#include +#include +#include +#include +#include + +#include "virtio.h" +#include "virtio_net_fd.h" + +struct lkl_netdev *lkl_netdev_pipe_create(char *ifname, int offload) +{ + struct lkl_netdev *nd; + int fd_rx, fd_tx; + char *ifname_rx = NULL, *ifname_tx = NULL; + + ifname_rx = strtok(ifname, "|"); + if (ifname_rx == NULL) { + fprintf(stderr, "invalid ifname format: %s\n", ifname); + return NULL; + } + + ifname_tx = strtok(NULL, "|"); + if (ifname_tx == NULL) { + fprintf(stderr, "invalid ifname format: %s\n", ifname); + return NULL; + } + + if (strtok(NULL, "|") != NULL) { + fprintf(stderr, "invalid ifname format: %s\n", ifname); + return NULL; + } + + fd_rx = open(ifname_rx, O_RDWR|O_NONBLOCK); + if (fd_rx < 0) { + perror("can not open ifname_rx pipe"); + return NULL; + } + + fd_tx = open(ifname_tx, O_RDWR|O_NONBLOCK); + if (fd_tx < 0) { + perror("can not open ifname_tx pipe"); + close(fd_rx); + return NULL; + } + + nd = lkl_register_netdev_fd(fd_rx, fd_tx); + if (!nd) { + perror("failed to register to."); + close(fd_rx); + close(fd_tx); + return NULL; + } + + /* + * To avoid mismatch with LKL otherside, + * we always enabled vnet hdr + */ + nd->has_vnet_hdr = 1; + return nd; +} diff --git a/tools/lkl/tests/hijack-test.sh b/tools/lkl/tests/hijack-test.sh index 0e0bb389bf6fdd..80e3811bb8de55 100755 --- a/tools/lkl/tests/hijack-test.sh +++ b/tools/lkl/tests/hijack-test.sh @@ -72,6 +72,71 @@ elif [ "${CROSS_COMPILE}" = "aarch64-linux-android-" ] ; then (echo "$ans" | grep "100756k") || true fi +echo "== PIPE tests ==" +if [ -z `which mkfifo` ]; then + echo "WARNIG: no mkfifo command, skipping PIPE tests." +else + +fifo1=${work_dir}/fifo1 +fifo2=${work_dir}/fifo2 +mkfifo ${fifo1} +mkfifo ${fifo2} + +# Make sure our device has the addresses we expect +addr=$(LKL_HIJACK_NET_IFTYPE=pipe \ + LKL_HIJACK_NET_IFPARAMS="${fifo1}|${fifo2}" \ + LKL_HIJACK_NET_IP=192.168.13.2 \ + LKL_HIJACK_NET_NETMASK_LEN=24 \ + LKL_HIJACK_NET_MAC="aa:bb:cc:dd:ee:ff" \ + ${hijack_script} ip addr) +echo "$addr" | grep eth0 +echo "$addr" | grep 192.168.13.2 +echo "$addr" | grep "aa:bb:cc:dd:ee:ff" + +# Copy ping so we're allowed to run it under LKL +cp $(which ping) . +cp $(which ping6) . + +# Ping receiver +LKL_HIJACK_NET_IFTYPE=pipe \ + LKL_HIJACK_NET_IFPARAMS="${fifo1}|${fifo2}" \ + LKL_HIJACK_NET_IP=192.168.13.1 \ + LKL_HIJACK_NET_NETMASK_LEN=24 \ + LKL_HIJACK_NET_GATEWAY=192.168.13.2 \ + LKL_HIJACK_NET_IPV6=fc03::1 \ + LKL_HIJACK_NET_NETMASK6_LEN=64\ + LKL_HIJACK_NET_GATEWAY6=fc03::2 \ + ${hijack_script} sleep 10 & + +sleep 5 + +# Ping under LKL +sudo LKL_HIJACK_NET_IFTYPE=pipe \ + LKL_HIJACK_NET_IFPARAMS="${fifo2}|${fifo1}" \ + LKL_HIJACK_NET_IP=192.168.13.2 \ + LKL_HIJACK_NET_NETMASK_LEN=24 \ + LKL_HIJACK_NET_GATEWAY=192.168.13.1 \ + LKL_HIJACK_NET_IPV6=fc03::2 \ + LKL_HIJACK_NET_NETMASK6_LEN=64\ + LKL_HIJACK_NET_GATEWAY6=fc03::1 \ + ${hijack_script} ./ping 192.168.13.1 -c 1 + +# Ping 6 under LKL +sudo LKL_HIJACK_NET_IFTYPE=pipe \ + LKL_HIJACK_NET_IFPARAMS="${fifo2}|${fifo1}" \ + LKL_HIJACK_NET_IP=192.168.13.2 \ + LKL_HIJACK_NET_NETMASK_LEN=24 \ + LKL_HIJACK_NET_GATEWAY=192.168.13.1 \ + LKL_HIJACK_NET_IPV6=fc03::2 \ + LKL_HIJACK_NET_NETMASK6_LEN=64\ + LKL_HIJACK_NET_GATEWAY6=fc03::1 \ + ${hijack_script} ./ping6 fc03::1 -c 1 + +wait +rm ./ping +rm ./ping6 +fi + echo "== TAP tests ==" if [ ! -c /dev/net/tun ]; then echo "WARNING: missing /dev/net/tun, skipping TAP and VDE tests." diff --git a/tools/lkl/tests/net-test.c b/tools/lkl/tests/net-test.c index b766962d991faa..5927b328184df8 100644 --- a/tools/lkl/tests/net-test.c +++ b/tools/lkl/tests/net-test.c @@ -144,6 +144,8 @@ static int test_net_init(int argc, char **argv) nd = lkl_netdev_raw_create(ifname); else if (iftype && ifname && (strncmp(iftype, "macvtap", 7) == 0)) nd = lkl_netdev_macvtap_create(ifname, 0); + else if (iftype && ifname && (strncmp(iftype, "pipe", 4) == 0)) + nd = lkl_netdev_pipe_create(ifname, 0); if (!nd) { fprintf(stderr, "init netdev failed\n"); diff --git a/tools/lkl/tests/net.sh b/tools/lkl/tests/net.sh index 52048c0e0ddd91..1133fc50358121 100755 --- a/tools/lkl/tests/net.sh +++ b/tools/lkl/tests/net.sh @@ -17,8 +17,13 @@ GW=`ip route get ${TEST_HOST} |head -n1 | cut -d ' ' -f3` script_dir=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) cd ${script_dir} +# Make a temporary directory to run tests in, since we'll be copying +# things there. +work_dir=$(mktemp -d) + # And make sure we clean up when we're done function clear_work_dir { + rm -rf ${work_dir} ${SUDO} ip link set dev lkl_ptt1 down &> /dev/null || true ${SUDO} ip tuntap del dev lkl_ptt1 mode tap &> /dev/null || true ${SUDO} ip link del dev lkl_vtap0 type macvtap &> /dev/null || true @@ -26,6 +31,26 @@ function clear_work_dir { trap clear_work_dir EXIT +echo "== PIPE (LKL net) tests ==" +if [ -z `which mkfifo` ]; then + echo "WARNIG: no mkfifo command, skipping PIPE tests." +else + +fifo1=${work_dir}/fifo1 +fifo2=${work_dir}/fifo2 +mkfifo ${fifo1} +mkfifo ${fifo2} +hijack_script=${script_dir}/../bin/lkl-hijack.sh +LKL_HIJACK_NET_IFTYPE=pipe \ + LKL_HIJACK_NET_IFPARAMS="${fifo1}|${fifo2}" \ + LKL_HIJACK_NET_IP=192.168.16.1 \ + LKL_HIJACK_NET_NETMASK_LEN=24 \ + ${hijack_script} sleep 10 & +sleep 5 +./net-test pipe "${fifo2}|${fifo1}" 192.168.16.1 192.168.16.2 24 +wait +fi + echo "== TAP (LKL net) tests ==" if [ -c /dev/net/tun ]; then ${SUDO} ip link set dev lkl_ptt1 down || true From db2c3db0b046e0f408ffa98c94bc0622593fd3a6 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Fri, 13 Oct 2017 11:00:17 +0900 Subject: [PATCH 3/3] lkl: fix test for android environment "bash -e" does not work in android so use "set -e". Also ignore an error of "ip link add" for macvtap test in android. Signed-off-by: Motomu Utsumi --- tools/lkl/tests/net.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/lkl/tests/net.sh b/tools/lkl/tests/net.sh index 1133fc50358121..cae07ea67bb7de 100755 --- a/tools/lkl/tests/net.sh +++ b/tools/lkl/tests/net.sh @@ -1,4 +1,6 @@ -#!/bin/bash -e +#!/bin/bash + +set -e # currently not supported mingw if [ "`printenv CONFIG_AUTO_LKL_POSIX_HOST`" != "y" ] ; then @@ -81,7 +83,8 @@ if ! [ -z $DST ]; then ${SUDO} ip link set dev ${IFNAME} promisc off echo "== macvtap (LKL net) tests ==" - ${SUDO} ip link add link ${IFNAME} name lkl_vtap0 type macvtap mode passthru + ${SUDO} ip link add link ${IFNAME} name lkl_vtap0 \ + type macvtap mode passthru || true if ls /dev/tap* > /dev/null 2>&1 ; then ${SUDO} ip link set dev lkl_vtap0 up ${SUDO} chown ${USER} `ls /dev/tap*`