Skip to content

Commit 18cee69

Browse files
author
Octavian Purdila
committed
Merge pull request torvalds#122 from eaas-framework/vde-upstream
Add a VDE backend driver for virtio-net
2 parents 41efdf8 + 33f2ba4 commit 18cee69

File tree

6 files changed

+229
-5
lines changed

6 files changed

+229
-5
lines changed

tools/lkl/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ ifneq (,$(filter $(OUTPUT_FORMAT),elf64-x86-64 elf32-i386 elf64-x86-64-freebsd e
5959
LDFLAGS +=-L$(RTE_SDK)/$(RTE_TARGET)/lib
6060
LDFLAGS +=-Wl,--whole-archive -ldpdk -Wl,--no-whole-archive -lm -ldl
6161
endif
62+
# Virtual Distributed Ethernet configuration
63+
ifeq ($(vde),yes)
64+
export CONFIG_AUTO_LKL_VIRTIO_NET_VDE=y
65+
CFLAGS += -DCONFIG_AUTO_LKL_VIRTIO_NET_VDE
66+
LDLIBS += $(shell pkg-config --libs vdeplug)
67+
endif
6268
else ifneq (,$(filter $(OUTPUT_FORMAT),pe-i386))
6369
KOPT = "KALLSYMS_EXTRA_PASS=1"
6470
LDLIBS += -lws2_32

tools/lkl/include/lkl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,14 @@ struct lkl_netdev *lkl_netdev_tap_create(const char *ifname);
271271
*/
272272
struct lkl_netdev *lkl_netdev_dpdk_create(const char *ifname);
273273

274+
/**
275+
* lkl_netdev_vde_create - create VDE net_device for the virtio net backend
276+
*
277+
* @switch_path - path to the VDE switch directory. Needs to be started on host
278+
* in advance.
279+
*/
280+
struct lkl_netdev *lkl_netdev_vde_create(const char *switch_path);
281+
274282
#ifdef __cplusplus
275283
}
276284
#endif

tools/lkl/lib/Build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CFLAGS_posix-host.o += -D_FILE_OFFSET_BITS=64
2+
CFLAGS_virtio_net_vde.o += $(shell pkg-config --cflags vdeplug)
23

34
lkl-y += fs.o
45
lkl-y += iomem.o
@@ -11,3 +12,4 @@ lkl-y += virtio.o
1112
lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net.o
1213
lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_tap.o
1314
lkl-$(CONFIG_AUTO_LKL_VIRTIO_NET_DPDK) += virtio_net_dpdk.o
15+
lkl-$(CONFIG_AUTO_LKL_VIRTIO_NET_VDE) += virtio_net_vde.o

tools/lkl/lib/hijack/init.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,14 @@ hijack_init(void)
165165
nd = lkl_netdev_tap_create(tap);
166166
}
167167

168-
if (!nd && iftype && ifparams && (strncmp(iftype, "tap", 3) == 0))
169-
nd = lkl_netdev_tap_create(ifparams);
170-
else if (!tap && iftype && ifparams && (strncmp(iftype, "dpdk", 4) == 0))
171-
nd = lkl_netdev_dpdk_create(ifparams);
168+
if (!nd && iftype && ifparams) {
169+
if ((strcmp(iftype, "tap") == 0))
170+
nd = lkl_netdev_tap_create(ifparams);
171+
else if (strcmp(iftype, "dpdk") == 0)
172+
nd = lkl_netdev_dpdk_create(ifparams);
173+
else if (strcmp(iftype, "vde") == 0)
174+
nd = lkl_netdev_vde_create(ifparams);
175+
}
172176

173177
if (nd) {
174178
ret = parse_mac_str(mac_str, mac);

tools/lkl/lib/virtio_net_vde.c

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#ifdef CONFIG_AUTO_LKL_VIRTIO_NET_VDE
2+
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <string.h>
6+
#include <errno.h>
7+
#include <poll.h>
8+
#include <lkl.h>
9+
#include <lkl_host.h>
10+
11+
#include <libvdeplug.h>
12+
13+
struct lkl_netdev_vde {
14+
struct lkl_dev_net_ops *ops;
15+
VDECONN *conn;
16+
};
17+
18+
struct lkl_netdev *nuse_vif_vde_create(char *switch_path);
19+
static int net_vde_tx(struct lkl_netdev *nd, void *data, int len);
20+
static int net_vde_rx(struct lkl_netdev *nd, void *data, int *len);
21+
static int net_vde_poll_with_timeout(struct lkl_netdev *nd, int events,
22+
int timeout);
23+
static int net_vde_poll(struct lkl_netdev *nd, int events);
24+
25+
struct lkl_dev_net_ops vde_net_ops = {
26+
.tx = net_vde_tx,
27+
.rx = net_vde_rx,
28+
.poll = net_vde_poll,
29+
};
30+
31+
int net_vde_tx(struct lkl_netdev *nd, void *data, int len)
32+
{
33+
int ret;
34+
struct lkl_netdev_vde *nd_vde;
35+
36+
nd_vde = (struct lkl_netdev_vde *) nd;
37+
38+
ret = vde_send(nd_vde->conn, data, len, 0);
39+
if (ret <= 0 && errno == EAGAIN)
40+
return -1;
41+
return 0;
42+
}
43+
44+
int net_vde_rx(struct lkl_netdev *nd, void *data, int *len)
45+
{
46+
int ret;
47+
struct lkl_netdev_vde *nd_vde;
48+
49+
nd_vde = (struct lkl_netdev_vde *) nd;
50+
51+
/*
52+
* Due to a bug in libvdeplug we have to first poll to make sure
53+
* that there is data available.
54+
* The correct solution would be to just use
55+
* ret = vde_recv(nd_vde->conn, data, *len, MSG_DONTWAIT);
56+
* This should be changed once libvdeplug is fixed.
57+
*/
58+
ret = 0;
59+
if (net_vde_poll_with_timeout(nd, LKL_DEV_NET_POLL_RX, 0) &
60+
LKL_DEV_NET_POLL_RX)
61+
ret = vde_recv(nd_vde->conn, data, *len, 0);
62+
if (ret <= 0)
63+
return -1;
64+
*len = ret;
65+
return 0;
66+
}
67+
68+
int net_vde_poll_with_timeout(struct lkl_netdev *nd, int events, int timeout)
69+
{
70+
int ret;
71+
struct lkl_netdev_vde *nd_vde;
72+
73+
nd_vde = (struct lkl_netdev_vde *) nd;
74+
75+
struct pollfd pollfds[] = {
76+
{
77+
.fd = vde_datafd(nd_vde->conn),
78+
},
79+
{
80+
.fd = vde_ctlfd(nd_vde->conn),
81+
.events = POLLHUP | POLLIN
82+
}
83+
};
84+
85+
if (events & LKL_DEV_NET_POLL_RX)
86+
pollfds[0].events |= POLLIN;
87+
if (events & LKL_DEV_NET_POLL_TX)
88+
pollfds[0].events |= POLLOUT;
89+
90+
while (poll(pollfds, 2, timeout) < 0 && errno == EINTR)
91+
;
92+
93+
ret = 0;
94+
95+
if (pollfds[1].revents & (POLLHUP | POLLNVAL | POLLIN))
96+
return -1;
97+
if (pollfds[0].revents & (POLLHUP | POLLNVAL))
98+
return -1;
99+
100+
if (pollfds[0].revents & POLLIN)
101+
ret |= LKL_DEV_NET_POLL_RX;
102+
if (pollfds[0].revents & POLLOUT)
103+
ret |= LKL_DEV_NET_POLL_TX;
104+
105+
return ret;
106+
}
107+
108+
int net_vde_poll(struct lkl_netdev *nd, int events)
109+
{
110+
return net_vde_poll_with_timeout(nd, events, -1);
111+
}
112+
113+
struct lkl_netdev *lkl_netdev_vde_create(char const *switch_path)
114+
{
115+
struct lkl_netdev_vde *nd;
116+
struct vde_open_args open_args = {.port = 0, .group = 0, .mode = 0700 };
117+
char *switch_path_copy = 0;
118+
119+
nd = (struct lkl_netdev_vde *)malloc(sizeof(*nd));
120+
if (!nd) {
121+
fprintf(stderr, "Failed to allocate memory.\n");
122+
/* TODO: propagate the error state, maybe use errno? */
123+
return 0;
124+
}
125+
nd->ops = &vde_net_ops;
126+
127+
/* vde_open() allows the null pointer as path which means
128+
* "VDE default path"
129+
*/
130+
if (switch_path != 0) {
131+
/* vde_open() takes a non-const char * which is a bug in their
132+
* function declaration. Even though the implementation does not
133+
* modify the string, we shouldn't just cast away the const.
134+
*/
135+
size_t switch_path_length = strlen(switch_path);
136+
137+
switch_path_copy = calloc(switch_path_length + 1, sizeof(char));
138+
if (!switch_path_copy) {
139+
fprintf(stderr, "Failed to allocate memory.\n");
140+
/* TODO: propagate the error state, maybe use errno? */
141+
return 0;
142+
}
143+
strncpy(switch_path_copy, switch_path, switch_path_length);
144+
}
145+
nd->conn = vde_open(switch_path_copy, "lkl-virtio-net", &open_args);
146+
free(switch_path_copy);
147+
if (nd->conn == 0) {
148+
fprintf(stderr, "Failed to connect to vde switch.\n");
149+
/* TODO: propagate the error state, maybe use errno? */
150+
return 0;
151+
}
152+
153+
return (struct lkl_netdev *)nd;
154+
}
155+
156+
#else /* CONFIG_AUTO_LKL_VIRTIO_NET_VDE */
157+
158+
struct lkl_netdev *lkl_netdev_vde_create(char const *switch_path)
159+
{
160+
fprintf(stderr, "lkl: The host library was compiled without support for VDE networking. Please rebuild with VDE enabled.\n");
161+
return 0;
162+
}
163+
164+
#endif /* CONFIG_AUTO_LKL_VIRTIO_NET_VDE */

tools/lkl/tests/hijack-test.sh

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ work_dir=$(mktemp -d)
1616

1717
# And make sure we clean up when we're done
1818
function clear_work_dir {
19+
test -f ${VDESWITCH}.pid && kill $(cat ${VDESWITCH}.pid)
1920
rm -rf ${work_dir}
2021
sudo ip link set dev lkl_ptt0 down &> /dev/null || true
2122
sudo ip tuntap del dev lkl_ptt0 mode tap &> /dev/null || true
@@ -55,7 +56,7 @@ echo "$ans" | grep "0x0" # lo's dev_id
5556

5657
echo "== TAP tests =="
5758
if [ ! -c /dev/net/tun ]; then
58-
echo "WARNING: missing /dev/net/tun, skipping TAP tests ."
59+
echo "WARNING: missing /dev/net/tun, skipping TAP and VDE tests."
5960
exit 0
6061
fi
6162

@@ -87,3 +88,42 @@ rm ./ping
8788
sudo arp -d 192.168.13.2
8889
sudo ping -i 0.01 -c 65 192.168.13.2 &
8990
${hijack_script} sleep 3
91+
92+
echo "== VDE tests =="
93+
if [ ! -x "$(which vde_switch)" ]; then
94+
echo "WARNING: Cannot find a vde_switch executable, skipping VDE tests."
95+
exit 0
96+
fi
97+
VDESWITCH=${work_dir}/vde_switch
98+
99+
export LKL_HIJACK_NET_IFTYPE=vde
100+
export LKL_HIJACK_NET_IFPARAMS=${VDESWITCH}
101+
export LKL_HIJACK_NET_IP=192.168.13.2
102+
export LKL_HIJACK_NET_NETMASK_LEN=24
103+
104+
sudo ip link set dev lkl_ptt0 down &> /dev/null || true
105+
sudo ip link del dev lkl_ptt0 &> /dev/null || true
106+
sudo ip tuntap add dev lkl_ptt0 mode tap user $USER
107+
sudo ip link set dev lkl_ptt0 up
108+
sudo ip addr add dev lkl_ptt0 192.168.13.1/24
109+
110+
sleep 2
111+
vde_switch -d -t lkl_ptt0 -s ${VDESWITCH} -p ${VDESWITCH}.pid
112+
113+
# Make sure our device has the addresses we expect
114+
addr=$(LKL_HIJACK_NET_MAC="aa:bb:cc:dd:ee:ff" ${hijack_script} ip addr)
115+
echo "$addr" | grep eth0
116+
echo "$addr" | grep 192.168.13.2
117+
echo "$addr" | grep "aa:bb:cc:dd:ee:ff"
118+
119+
# Copy ping so we're allowed to run it under LKL
120+
cp $(which ping) .
121+
122+
# Make sure we can ping the host from inside LKL
123+
${hijack_script} ./ping 192.168.13.1 -c 1
124+
rm ./ping
125+
126+
# Now let's check that the host can see LKL.
127+
sudo arp -d 192.168.13.2
128+
sudo ping -i 0.01 -c 65 192.168.13.2 &
129+
${hijack_script} sleep 3

0 commit comments

Comments
 (0)