Skip to content

Commit

Permalink
Refactor network device handling for flexible device support
Browse files Browse the repository at this point in the history
Separate network device handling to support various network backends,
such as Slirp, instead of hard-coding the TAP device. The '-netdev'
flag can now be used to specify the network device type, defaulting
to TAP if unspecified. Additionally, packet transfer functions are
now tailored to each network device, enabling more modular and
extensible network device development.
  • Loading branch information
chiangkd committed Nov 26, 2024
1 parent a0ad61b commit c0263f3
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 46 deletions.
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ ifeq ($(call has, VIRTIOBLK), 1)
endif
endif

NETDEV ?= tap
# virtio-net
ENABLE_VIRTIONET ?= 1
ifneq ($(UNAME_S),Linux)
Expand All @@ -39,6 +40,7 @@ endif
$(call set-feature, VIRTIONET)
ifeq ($(call has, VIRTIONET), 1)
OBJS_EXTRA += virtio-net.o
OBJS_EXTRA += netdev.o
endif

BIN = semu
Expand Down Expand Up @@ -96,7 +98,7 @@ ext4.img:

check: $(BIN) minimal.dtb $(KERNEL_DATA) $(INITRD_DATA) $(DISKIMG_FILE)
@$(call notice, Ready to launch Linux kernel. Please be patient.)
$(Q)./$(BIN) -k $(KERNEL_DATA) -c $(SMP) -b minimal.dtb -i $(INITRD_DATA) $(OPTS)
$(Q)./$(BIN) -k $(KERNEL_DATA) -c $(SMP) -b minimal.dtb -i $(INITRD_DATA) -n $(NETDEV) $(OPTS)

build-image:
scripts/build-image.sh
Expand Down
5 changes: 3 additions & 2 deletions device.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "netdev.h"
#include "riscv.h"
#include "virtio.h"

Expand Down Expand Up @@ -101,7 +102,7 @@ typedef struct {
uint32_t Status;
uint32_t InterruptStatus;
/* supplied by environment */
int tap_fd;
netdev_t peer;
uint32_t *ram;
/* implementation-specific */
void *priv;
Expand All @@ -119,7 +120,7 @@ void virtio_net_write(hart_t *core,
uint32_t value);
void virtio_net_refresh_queue(virtio_net_state_t *vnet);

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

/* VirtIO-Block */
Expand Down
20 changes: 15 additions & 5 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,19 +440,22 @@ static void handle_options(int argc,
char **dtb_file,
char **initrd_file,
char **disk_file,
char **net_dev,
int *hart_count)
{
*kernel_file = *dtb_file = *initrd_file = *disk_file = NULL;
*kernel_file = *dtb_file = *initrd_file = *disk_file = *net_dev = NULL;

int optidx = 0;
struct option opts[] = {
{"kernel", 1, NULL, 'k'}, {"dtb", 1, NULL, 'b'},
{"initrd", 1, NULL, 'i'}, {"disk", 1, NULL, 'd'},
{"smp", 1, NULL, 'c'}, {"help", 0, NULL, 'h'},
{"netdev", 1, NULL, 'n'}, {"smp", 1, NULL, 'c'},
{"help", 0, NULL, 'h'},
};

int c;
while ((c = getopt_long(argc, argv, "k:b:i:d:c:h", opts, &optidx)) != -1) {
while ((c = getopt_long(argc, argv, "k:b:i:d:n:c:h", opts, &optidx)) !=
-1) {
switch (c) {
case 'k':
*kernel_file = optarg;
Expand All @@ -466,6 +469,9 @@ static void handle_options(int argc,
case 'd':
*disk_file = optarg;
break;
case 'n':
*net_dev = optarg;
break;
case 'c':
*hart_count = atoi(optarg);
break;
Expand All @@ -487,6 +493,9 @@ static void handle_options(int argc,

if (!*dtb_file)
*dtb_file = "minimal.dtb";

if (!*net_dev)
*net_dev = "tap";
}


Expand All @@ -509,9 +518,10 @@ static int semu_start(int argc, char **argv)
char *dtb_file;
char *initrd_file;
char *disk_file;
char *netdev;
int hart_count = 1;
handle_options(argc, argv, &kernel_file, &dtb_file, &initrd_file,
&disk_file, &hart_count);
&disk_file, &netdev, &hart_count);

/* Initialize the emulator */
emu_state_t emu;
Expand Down Expand Up @@ -573,7 +583,7 @@ static int semu_start(int argc, char **argv)
emu.uart.in_fd = 0, emu.uart.out_fd = 1;
capture_keyboard_input(); /* set up uart */
#if SEMU_HAS(VIRTIONET)
if (!virtio_net_init(&(emu.vnet)))
if (!virtio_net_init(&(emu.vnet), netdev))
fprintf(stderr, "No virtio-net functioned\n");
emu.vnet.ram = emu.ram;
#endif
Expand Down
87 changes: 87 additions & 0 deletions netdev.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>

#include "netdev.h"

static int net_init_tap();
static int net_init_user();

static const char *netdev_driver_lookup[] = {
#define _(dev) [NET_DEV_DRIVER_##dev] = #dev,
SUPPORTED_DEVICES
#undef _
NULL,
};

static int find_net_dev_idx(const char *net_type, const char **netlookup)
{
if (!net_type)
return -1;
int i = 0;
while (netlookup[i]) {
if (!strcmp(net_type, netlookup[i])) {
return i;
}
i++;
}
return -1;
}

static int net_init_tap(netdev_t *netdev)
{
net_tap_options *tap;
tap = &netdev->op.tap;
tap->tap_fd = open("/dev/net/tun", O_RDWR);
if (tap->tap_fd < 0) {
fprintf(stderr, "failed to open TAP device: %s\n", strerror(errno));
return false;
}

/* Specify persistent tap device */
struct ifreq ifreq = {.ifr_flags = IFF_TAP | IFF_NO_PI};
strncpy(ifreq.ifr_name, "tap%d", sizeof(ifreq.ifr_name));
if (ioctl(tap->tap_fd, TUNSETIFF, &ifreq) < 0) {
fprintf(stderr, "failed to allocate TAP device: %s\n", strerror(errno));
return false;
}

fprintf(stderr, "allocated TAP interface: %s\n", ifreq.ifr_name);
assert(fcntl(tap->tap_fd, F_SETFL,
fcntl(tap->tap_fd, F_GETFL, 0) | O_NONBLOCK) >= 0);
return 0;
}

static int net_init_user(netdev_t *netdev)
{
/* TODO: create slirp dev */
return 0;
}

int netdev_init(netdev_t *netdev, const char *net_type)
{
int dev_idx = find_net_dev_idx(net_type, netdev_driver_lookup);
if (dev_idx == -1)
return false;
netdev->type = dev_idx;

switch (dev_idx) {
#define _(dev) \
case NET_DEV_DRIVER_##dev: \
net_init_##dev(netdev); \
break;
SUPPORTED_DEVICES
#undef _
default:
fprintf(stderr, "unknown network device\n");
break;
}

return true;
}
32 changes: 32 additions & 0 deletions netdev.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

/* clang-format off */
#define SUPPORTED_DEVICES \
_(tap) \
_(user)
/* clang-format on */

typedef enum {
#define _(dev) NET_DEV_DRIVER_##dev,
SUPPORTED_DEVICES
#undef _
} net_dev_driver_t;

typedef struct {
int tap_fd;
} net_tap_options;

typedef struct {
/* TODO: Implement user option */
} net_user_options;

typedef struct {
char *name;
net_dev_driver_t type;
union {
net_tap_options tap;
net_user_options user;
} op;
} netdev_t;

int netdev_init(netdev_t *nedtev, const char *net_type);
Loading

0 comments on commit c0263f3

Please sign in to comment.