Skip to content

Enable user-mode networking through SLIRP #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .ci/test-netdev.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,13 @@ ASSERT expect <<DONE
expect "riscv32 GNU/Linux" { send "ip l set eth0 up\n" } timeout { exit 3 }
expect "# " { send "ip a add 192.168.10.2/24 dev eth0\n" }
expect "# " { send "ping -c 3 192.168.10.1\n" }
expect "3 packets transmitted, 3 packets received, 0% packet loss" { } timeout { exit 4 }
expect "3 packets transmitted, 3 packets received, 0% packet loss" { } timeout { exit 4 }
} elseif { "$NETDEV" == "user" } {
# Test slirp configuration
expect "riscv32 GNU/Linux" { send "\x01"; send "x" } timeout { exit 3 }
expect "riscv32 GNU/Linux" { send "ip addr add 10.0.2.15/24 dev eth0\n" } timeout { exit 3 }
expect "# " { send "ip link set eth0 up\n"}
expect "# " { send "ip route add default via 10.0.2.2\n"}
expect "# " { send "ping -c 3 10.0.2.2\n" }
expect "3 packets transmitted, 3 packets received, 0% packet loss" { } timeout { exit 4 }
}
DONE
}
Expand Down
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@
path = mini-gdbstub
url = https://github.com/RinHizakura/mini-gdbstub
shallow = true
[submodule "minislirp"]
path = minislirp
url = https://github.com/edubart/minislirp
shallow = true
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ $(call set-feature, VIRTIONET)
ifeq ($(call has, VIRTIONET), 1)
OBJS_EXTRA += virtio-net.o
OBJS_EXTRA += netdev.o
OBJS_EXTRA += slirp.o
endif

# virtio-snd
Expand Down Expand Up @@ -113,6 +114,17 @@ $(GDBSTUB_LIB): mini-gdbstub/Makefile
$(MAKE) -C $(dir $<)
$(OBJS): $(GDBSTUB_LIB)

ifeq ($(call has, VIRTIONET), 1)
MINISLIRP_DIR := minislirp
MINISLIRP_LIB := minislirp/src/libslirp.a
LDFLAGS += $(MINISLIRP_LIB)
$(MINISLIRP_DIR)/src/Makefile:
git submodule update --init $(MINISLIRP_DIR)
$(MINISLIRP_LIB): $(MINISLIRP_DIR)/src/Makefile
$(MAKE) -C $(dir $<)
$(OBJS): $(MINISLIRP_LIB)
endif

$(BIN): $(OBJS)
$(VECHO) " LD\t$@\n"
$(Q)$(CC) -o $@ $^ $(LDFLAGS)
Expand Down Expand Up @@ -171,6 +183,7 @@ build-image:
clean:
$(Q)$(RM) $(BIN) $(OBJS) $(deps)
$(Q)$(MAKE) -C mini-gdbstub clean
$(Q)$(MAKE) -C minislirp/src clean

distclean: clean
$(Q)$(RM) riscv-harts.dtsi
Expand Down
4 changes: 4 additions & 0 deletions device.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#if SEMU_HAS(VIRTIONET)
#include "netdev.h"
#endif
#include "riscv.h"
#include "virtio.h"

Expand Down Expand Up @@ -120,6 +122,8 @@ void virtio_net_write(hart_t *core,
uint32_t value);
void virtio_net_refresh_queue(virtio_net_state_t *vnet);

void virtio_net_recv_from_peer(void *peer);

bool virtio_net_init(virtio_net_state_t *vnet, const char *name);
#endif /* SEMU_HAS(VIRTIONET) */

Expand Down
35 changes: 32 additions & 3 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -761,9 +761,38 @@ static int semu_run(emu_state_t *emu)

/* Emulate */
while (!emu->stopped) {
ret = semu_step(emu);
if (ret)
return ret;
#if SEMU_HAS(VIRTIONET)
int i = 0;
if (emu->vnet.peer.type == NETDEV_IMPL_user && boot_complete) {
net_user_options_t *usr = (net_user_options_t *) emu->vnet.peer.op;

uint32_t timeout = -1;
usr->pfd_len = 1;
slirp_pollfds_fill_socket(usr->slirp, &timeout,
semu_slirp_add_poll_socket, usr);

/* Poll the internal pipe for incoming data. If data is
* available (POLL_IN), process it and forward it to the
* virtio-net device.
*/
int pollout = poll(usr->pfd, usr->pfd_len, 1);
if (usr->pfd[0].revents & POLLIN) {
virtio_net_recv_from_peer(usr->peer);
}
slirp_pollfds_poll(usr->slirp, (pollout <= 0),
semu_slirp_get_revents, usr);
for (i = 0; i < SLIRP_POLL_INTERVAL; i++) {
ret = semu_step(emu);
if (ret)
return ret;
}
} else
#endif
{
ret = semu_step(emu);
if (ret)
return ret;
}
}

/* unreachable */
Expand Down
1 change: 1 addition & 0 deletions minislirp
Submodule minislirp added at 0bf4a4
15 changes: 13 additions & 2 deletions netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <string.h>
#include <sys/ioctl.h>

#include "device.h"
#include "netdev.h"

static int net_init_tap();
Expand Down Expand Up @@ -55,9 +56,19 @@ static int net_init_tap(netdev_t *netdev)
return 0;
}

static int net_init_user(netdev_t *netdev UNUSED)
static int net_init_user(netdev_t *netdev)
{
/* TODO: create slirp dev */
net_user_options_t *usr = (net_user_options_t *) netdev->op;
memset(usr, 0, sizeof(*usr));
usr->peer = container_of(netdev, virtio_net_state_t, peer);
if (pipe(usr->channel) < 0)
return false;
assert(fcntl(usr->channel[SLIRP_READ_SIDE], F_SETFL,
fcntl(usr->channel[SLIRP_READ_SIDE], F_GETFL, 0) |
O_NONBLOCK) >= 0);

net_slirp_init(usr);

return 0;
}

Expand Down
33 changes: 31 additions & 2 deletions netdev.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#pragma once

#include <stdbool.h>
#include <poll.h>
#include <unistd.h>

#include "minislirp/src/libslirp.h"
#include "utils.h"


/* clang-format off */
#define SUPPORTED_DEVICES \
Expand All @@ -18,10 +23,34 @@ typedef struct {
int tap_fd;
} net_tap_options_t;

/* SLIRP */
#define SLIRP_POLL_INTERVAL 100000
#define SLIRP_READ_SIDE 0
#define SLIRP_WRITE_SIDE 1
typedef struct {
/* TODO: Implement user option */
semu_timer_t timer;
Slirp *slirp;
SlirpTimerId id;
void *cb_opaque;
void (*cb)(void *opaque);
int64_t expire_timer_msec;
} slirp_timer;

typedef struct {
Slirp *slirp;
int channel[2];
int pfd_len;
int pfd_size;
struct pollfd *pfd;
slirp_timer *timer;
void *peer;
} net_user_options_t;

Slirp *slirp_create(net_user_options_t *usr, SlirpConfig *cfg);
int net_slirp_init(net_user_options_t *usr);
int semu_slirp_add_poll_socket(slirp_os_socket fd, int events, void *opaque);
int semu_slirp_get_revents(int idx, void *opaque);

typedef struct {
char *name;
netdev_impl_t type;
Expand Down
Loading