Skip to content

Commit 6dbe25e

Browse files
authored
Merge pull request #80 from chiangkd/slirp-dev
Enable user-mode networking through SLIRP
2 parents 161f30c + f3e994b commit 6dbe25e

File tree

10 files changed

+347
-13
lines changed

10 files changed

+347
-13
lines changed

.ci/test-netdev.sh

+6-3
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,13 @@ ASSERT expect <<DONE
4545
expect "riscv32 GNU/Linux" { send "ip l set eth0 up\n" } timeout { exit 3 }
4646
expect "# " { send "ip a add 192.168.10.2/24 dev eth0\n" }
4747
expect "# " { send "ping -c 3 192.168.10.1\n" }
48-
expect "3 packets transmitted, 3 packets received, 0% packet loss" { } timeout { exit 4 }
48+
expect "3 packets transmitted, 3 packets received, 0% packet loss" { } timeout { exit 4 }
4949
} elseif { "$NETDEV" == "user" } {
50-
# Test slirp configuration
51-
expect "riscv32 GNU/Linux" { send "\x01"; send "x" } timeout { exit 3 }
50+
expect "riscv32 GNU/Linux" { send "ip addr add 10.0.2.15/24 dev eth0\n" } timeout { exit 3 }
51+
expect "# " { send "ip link set eth0 up\n"}
52+
expect "# " { send "ip route add default via 10.0.2.2\n"}
53+
expect "# " { send "ping -c 3 10.0.2.2\n" }
54+
expect "3 packets transmitted, 3 packets received, 0% packet loss" { } timeout { exit 4 }
5255
}
5356
DONE
5457
}

.gitmodules

+4
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@
66
path = mini-gdbstub
77
url = https://github.com/RinHizakura/mini-gdbstub
88
shallow = true
9+
[submodule "minislirp"]
10+
path = minislirp
11+
url = https://github.com/edubart/minislirp
12+
shallow = true

Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ $(call set-feature, VIRTIONET)
5151
ifeq ($(call has, VIRTIONET), 1)
5252
OBJS_EXTRA += virtio-net.o
5353
OBJS_EXTRA += netdev.o
54+
OBJS_EXTRA += slirp.o
5455
endif
5556

5657
# virtio-snd
@@ -113,6 +114,17 @@ $(GDBSTUB_LIB): mini-gdbstub/Makefile
113114
$(MAKE) -C $(dir $<)
114115
$(OBJS): $(GDBSTUB_LIB)
115116

117+
ifeq ($(call has, VIRTIONET), 1)
118+
MINISLIRP_DIR := minislirp
119+
MINISLIRP_LIB := minislirp/src/libslirp.a
120+
LDFLAGS += $(MINISLIRP_LIB)
121+
$(MINISLIRP_DIR)/src/Makefile:
122+
git submodule update --init $(MINISLIRP_DIR)
123+
$(MINISLIRP_LIB): $(MINISLIRP_DIR)/src/Makefile
124+
$(MAKE) -C $(dir $<)
125+
$(OBJS): $(MINISLIRP_LIB)
126+
endif
127+
116128
$(BIN): $(OBJS)
117129
$(VECHO) " LD\t$@\n"
118130
$(Q)$(CC) -o $@ $^ $(LDFLAGS)
@@ -171,6 +183,7 @@ build-image:
171183
clean:
172184
$(Q)$(RM) $(BIN) $(OBJS) $(deps)
173185
$(Q)$(MAKE) -C mini-gdbstub clean
186+
$(Q)$(MAKE) -C minislirp/src clean
174187

175188
distclean: clean
176189
$(Q)$(RM) riscv-harts.dtsi

device.h

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#pragma once
22

3+
#if SEMU_HAS(VIRTIONET)
34
#include "netdev.h"
5+
#endif
46
#include "riscv.h"
57
#include "virtio.h"
68

@@ -120,6 +122,8 @@ void virtio_net_write(hart_t *core,
120122
uint32_t value);
121123
void virtio_net_refresh_queue(virtio_net_state_t *vnet);
122124

125+
void virtio_net_recv_from_peer(void *peer);
126+
123127
bool virtio_net_init(virtio_net_state_t *vnet, const char *name);
124128
#endif /* SEMU_HAS(VIRTIONET) */
125129

main.c

+32-3
Original file line numberDiff line numberDiff line change
@@ -761,9 +761,38 @@ static int semu_run(emu_state_t *emu)
761761

762762
/* Emulate */
763763
while (!emu->stopped) {
764-
ret = semu_step(emu);
765-
if (ret)
766-
return ret;
764+
#if SEMU_HAS(VIRTIONET)
765+
int i = 0;
766+
if (emu->vnet.peer.type == NETDEV_IMPL_user && boot_complete) {
767+
net_user_options_t *usr = (net_user_options_t *) emu->vnet.peer.op;
768+
769+
uint32_t timeout = -1;
770+
usr->pfd_len = 1;
771+
slirp_pollfds_fill_socket(usr->slirp, &timeout,
772+
semu_slirp_add_poll_socket, usr);
773+
774+
/* Poll the internal pipe for incoming data. If data is
775+
* available (POLL_IN), process it and forward it to the
776+
* virtio-net device.
777+
*/
778+
int pollout = poll(usr->pfd, usr->pfd_len, 1);
779+
if (usr->pfd[0].revents & POLLIN) {
780+
virtio_net_recv_from_peer(usr->peer);
781+
}
782+
slirp_pollfds_poll(usr->slirp, (pollout <= 0),
783+
semu_slirp_get_revents, usr);
784+
for (i = 0; i < SLIRP_POLL_INTERVAL; i++) {
785+
ret = semu_step(emu);
786+
if (ret)
787+
return ret;
788+
}
789+
} else
790+
#endif
791+
{
792+
ret = semu_step(emu);
793+
if (ret)
794+
return ret;
795+
}
767796
}
768797

769798
/* unreachable */

minislirp

Submodule minislirp added at 0bf4a41

netdev.c

+13-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <string.h>
99
#include <sys/ioctl.h>
1010

11+
#include "device.h"
1112
#include "netdev.h"
1213

1314
static int net_init_tap();
@@ -55,9 +56,19 @@ static int net_init_tap(netdev_t *netdev)
5556
return 0;
5657
}
5758

58-
static int net_init_user(netdev_t *netdev UNUSED)
59+
static int net_init_user(netdev_t *netdev)
5960
{
60-
/* TODO: create slirp dev */
61+
net_user_options_t *usr = (net_user_options_t *) netdev->op;
62+
memset(usr, 0, sizeof(*usr));
63+
usr->peer = container_of(netdev, virtio_net_state_t, peer);
64+
if (pipe(usr->channel) < 0)
65+
return false;
66+
assert(fcntl(usr->channel[SLIRP_READ_SIDE], F_SETFL,
67+
fcntl(usr->channel[SLIRP_READ_SIDE], F_GETFL, 0) |
68+
O_NONBLOCK) >= 0);
69+
70+
net_slirp_init(usr);
71+
6172
return 0;
6273
}
6374

netdev.h

+31-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
#pragma once
22

3-
#include <stdbool.h>
3+
#include <poll.h>
4+
#include <unistd.h>
5+
6+
#include "minislirp/src/libslirp.h"
7+
#include "utils.h"
8+
49

510
/* clang-format off */
611
#define SUPPORTED_DEVICES \
@@ -18,10 +23,34 @@ typedef struct {
1823
int tap_fd;
1924
} net_tap_options_t;
2025

26+
/* SLIRP */
27+
#define SLIRP_POLL_INTERVAL 100000
28+
#define SLIRP_READ_SIDE 0
29+
#define SLIRP_WRITE_SIDE 1
2130
typedef struct {
22-
/* TODO: Implement user option */
31+
semu_timer_t timer;
32+
Slirp *slirp;
33+
SlirpTimerId id;
34+
void *cb_opaque;
35+
void (*cb)(void *opaque);
36+
int64_t expire_timer_msec;
37+
} slirp_timer;
38+
39+
typedef struct {
40+
Slirp *slirp;
41+
int channel[2];
42+
int pfd_len;
43+
int pfd_size;
44+
struct pollfd *pfd;
45+
slirp_timer *timer;
46+
void *peer;
2347
} net_user_options_t;
2448

49+
Slirp *slirp_create(net_user_options_t *usr, SlirpConfig *cfg);
50+
int net_slirp_init(net_user_options_t *usr);
51+
int semu_slirp_add_poll_socket(slirp_os_socket fd, int events, void *opaque);
52+
int semu_slirp_get_revents(int idx, void *opaque);
53+
2554
typedef struct {
2655
char *name;
2756
netdev_impl_t type;

0 commit comments

Comments
 (0)