Implement vnet_null device

Such device don't need new threads and files but are valid ethernet
devices for the kernel. Convenient for testing.
This commit is contained in:
Ivan Baravy 2023-02-06 16:01:37 +00:00
parent 6a479621e9
commit e71791c0ab
22 changed files with 194 additions and 71 deletions

View File

@ -22,31 +22,20 @@
#include "vnet.h"
#define TAP_DEV "/dev/net/tun"
#define UMKA_TAP_NAME "umka%d"
static STDCALL void
vnet_unload_tap(void) {
printf("vnet_unload_tap\n");
COVERAGE_ON();
COVERAGE_OFF();
}
static STDCALL void
vnet_reset_tap(void) {
printf("vnet_reset_tap\n");
COVERAGE_ON();
COVERAGE_OFF();
}
/*
static void
dump_net_buff(net_buff_t *buf) {
for (size_t i = 0; i < buf->length; i++) {
printf("%2.2x ", buf->data[i]);
}
putchar('\n');
}
*/
static STDCALL int
vnet_transmit_tap(net_buff_t *buf) {
struct vnet *net;
@ -56,20 +45,17 @@ vnet_transmit_tap(net_buff_t *buf) {
:
: "memory");
// printf("vnet_transmit: %d bytes\n", buf->length);
// dump_net_buff(buf);
ssize_t written = write(net->fdout, buf->data, buf->length);
(void)written;
buf->length = 0;
COVERAGE_OFF();
COVERAGE_ON();
// printf("vnet_transmit: %d bytes written\n", written);
return 0;
}
struct vnet *
vnet_init_tap(void) {
struct ifreq ifr = {.ifr_name = UMKA_VNET_NAME,
struct ifreq ifr = {.ifr_name = UMKA_TAP_NAME,
.ifr_flags = IFF_TAP | IFF_NO_PI};
int fd, err;

View File

@ -32,6 +32,10 @@ LDFLAGS=-no-pie
LDFLAGS_32=$(LDFLAGS) -m32
LIBS=-lpthread
ifeq ($(HOST),windows)
LIBS=$(LIBS) -lws2_32
endif
ifeq ($(HOST),linux)
FASM_INCLUDE=$(KOLIBRIOS)/kernel/trunk;$(KOLIBRIOS)/programs/develop/libraries/libcrash/hash
FASM=INCLUDE="$(FASM_INCLUDE)" $(FASM_EXE) $(FASM_FLAGS)
@ -59,10 +63,10 @@ test: umka_shell
umka_shell: umka_shell.o umka.o shell.o trace.o trace_lbr.o vdisk.o \
vdisk/raw.o vdisk/qcow2.o deps/em_inflate/em_inflate.o vnet.o \
$(HOST)/vnet/tap.o vnet/file.o lodepng.o $(HOST)/pci.o \
$(HOST)/vnet/tap.o vnet/file.o vnet/null.o lodepng.o $(HOST)/pci.o \
$(HOST)/thread.o umkaio.o umkart.o deps/optparse/optparse.o \
deps/isocline/src/isocline.o
$(CC) $(LDFLAGS_32) $^ -o $@ -T umka.ld $(LIBS) -lws2_32
$(CC) $(LDFLAGS_32) $^ -o $@ -T umka.ld $(LIBS)
umka_fuse: umka_fuse.o umka.o trace.o trace_lbr.o vdisk.o vdisk/raw.o \
vdisk/qcow2.o deps/em_inflate/em_inflate.o $(HOST)/pci.o \
@ -71,8 +75,8 @@ umka_fuse: umka_fuse.o umka.o trace.o trace_lbr.o vdisk.o vdisk/raw.o \
umka_os: umka_os.o umka.o shell.o lodepng.o vdisk.o vdisk/raw.o vdisk/qcow2.o \
deps/em_inflate/em_inflate.o vnet.o $(HOST)/vnet/tap.o vnet/file.o \
trace.o trace_lbr.o $(HOST)/pci.o $(HOST)/thread.o umkaio.o umkart.o \
deps/isocline/src/isocline.o deps/optparse/optparse.o
vnet/null.o trace.o trace_lbr.o $(HOST)/pci.o $(HOST)/thread.o \
umkaio.o umkart.o deps/isocline/src/isocline.o deps/optparse/optparse.o
$(CC) $(LDFLAGS_32) `sdl2-config --libs` $^ -o $@ -T umka.ld
umka_gen_devices_dat: umka_gen_devices_dat.o umka.o $(HOST)/pci.o \
@ -157,6 +161,9 @@ $(HOST)/vnet/tap.o: $(HOST)/vnet/tap.c vnet/tap.h
vnet/file.o: vnet/file.c vnet/file.h
$(CC) $(CFLAGS_32) -c $< -o $@
vnet/null.o: vnet/null.c vnet/null.h
$(CC) $(CFLAGS_32) -c $< -o $@
umka_shell.o: umka_shell.c umka.h trace.h
$(CC) $(CFLAGS_32) -c $<

31
shell.c
View File

@ -340,7 +340,7 @@ print_hash(struct shell_ctx *ctx, uint8_t *x, size_t len) {
}
void *host_load_file(const char *fname) {
FILE *f = fopen(fname, "r");
FILE *f = fopen(fname, "rb");
if (!f) {
return NULL;
}
@ -1456,7 +1456,7 @@ cmd_get_keyboard_layout(struct shell_ctx *ctx, int argc, char **argv) {
#undef COLS
} else if (argc == 5 && !strcmp(argv[3], "-f")) {
const char *fname = argv[4];
FILE *f = fopen(fname, "w");
FILE *f = fopen(fname, "wb");
if (!f) {
fprintf(ctx->fout, "can't open file for writing: %s\n", fname);
fputs(usage, ctx->fout);
@ -2898,12 +2898,27 @@ cmd_net_add_device(struct shell_ctx *ctx, int argc, char **argv) {
(void)ctx;
(void)argv;
const char *usage = \
"usage: net_add_device\n";
if (argc != 1) {
"usage: net_add_device <devtype>\n"
" devtype null, file or tap\n";
if (argc > 2) {
fputs(usage, ctx->fout);
return;
}
struct vnet *vnet = vnet_init(VNET_TAP); // TODO: list like block devices
int devtype = VNET_DEVTYPE_NULL;
const char *devtypestr = argv[1];
if (devtypestr) {
if (!strcmp(devtypestr, "null")) {
devtype = VNET_DEVTYPE_NULL;
} else if (!strcmp(devtypestr, "file")) {
devtype = VNET_DEVTYPE_FILE;
} else if (!strcmp(devtypestr, "tap")) {
devtype = VNET_DEVTYPE_TAP;
} else {
fprintf(ctx->fout, "bad device type: %s\n", devtypestr);
return;
}
}
struct vnet *vnet = vnet_init(devtype, ctx->running); // TODO: list like block devices
COVERAGE_ON();
int32_t dev_num = kos_net_add_device(&vnet->eth.net);
COVERAGE_OFF();
@ -4069,8 +4084,8 @@ run_test(struct shell_ctx *ctx) {
}
struct shell_ctx *
shell_init(int reproducible, const char *hist_file, struct umka_ctx *umka,
struct umka_io *io, FILE *fin, const atomic_int *running) {
shell_init(const int reproducible, const char *hist_file,
const struct umka_ctx *umka, const struct umka_io *io, FILE *fin) {
struct shell_ctx *ctx = malloc(sizeof(struct shell_ctx));
ctx->umka = umka;
ctx->io = io;
@ -4079,7 +4094,7 @@ shell_init(int reproducible, const char *hist_file, struct umka_ctx *umka,
ctx->var = NULL;
ctx->fin = fin;
ctx->fout = stdout;
ctx->running = running;
ctx->running = &umka->running;
pthread_cond_init(&ctx->cmd_done, NULL);
pthread_mutex_init(&ctx->cmd_mutex, NULL);
return ctx;

View File

@ -37,7 +37,7 @@ struct shell_var {
struct shell_ctx {
const struct umka_ctx *umka;
struct umka_io *io;
const struct umka_io *io;
int reproducible;
const char *hist_file;
struct shell_var *var;
@ -50,8 +50,8 @@ struct shell_ctx {
};
struct shell_ctx *
shell_init(int reproducible, const char *hist_file, struct umka_ctx *umka,
struct umka_io *io, FILE *fin, const atomic_int *running);
shell_init(const int reproducible, const char *hist_file,
const struct umka_ctx *umka, const struct umka_io *io, FILE *fin);
void
shell_close(struct shell_ctx *shell);

View File

@ -114,7 +114,7 @@ pubsym coverage_end
pubsym sha3_256_oneshot, 'hash_oneshot'
pubsym kos_time_to_epoch
pubsym umka_init
pubsym umka_init, 4
pubsym umka_close, 4
pubsym umka_boot
@ -578,11 +578,12 @@ struct umka_ctx
running dd ?
ends
proc umka_init c uses ebx esi edi ebp
proc umka_init c uses ebx esi edi ebp, _running
call umka._.check_alignment
mov eax, umka
mov [eax+umka_ctx.booted], 0
mov [eax+umka_ctx.running], 0
mov ecx, [_running]
mov [eax+umka_ctx.running], ecx
ret
endp

8
umka.h
View File

@ -29,6 +29,12 @@ typedef void siginfo_t;
#define STDCALL __attribute__((__stdcall__))
enum {
UMKA_RUNNING_NEVER,
UMKA_RUNNING_NOT_YET,
UMKA_RUNNING_YES,
};
struct umka_ctx {
int booted;
atomic_int running;
@ -542,7 +548,7 @@ void
irq0(int signo, siginfo_t *info, void *context);
struct umka_ctx *
umka_init(void);
umka_init(int running);
void
umka_close(struct umka_ctx *ctx);

View File

@ -35,7 +35,7 @@ struct umka_fuse_ctx {
static struct umka_fuse_ctx *
umka_fuse_init(void) {
struct umka_fuse_ctx *ctx = malloc(sizeof(struct umka_fuse_ctx));
ctx->umka = umka_init();
ctx->umka = umka_init(UMKA_RUNNING_NEVER);
ctx->io = io_init(&ctx->umka->running);
return ctx;
}

View File

@ -152,7 +152,7 @@ main (int argc, char *argv[]) {
strcpy(pci_path, PCI_BASE_DIR);
umka_init();
umka_init(UMKA_RUNNING_NEVER);
kos_acpi_aml_init();
ctx = kos_acpi_aml_new_thread();
kos_acpi_dev_size = MAX_PCI_DEVICES*16;

View File

@ -72,14 +72,15 @@ struct umka_os_ctx *
umka_os_init(FILE *fstartup, FILE *fboardlog) {
struct umka_os_ctx *ctx = malloc(sizeof(struct umka_os_ctx));
ctx->fboardlog = fboardlog;
ctx->umka = umka_init();
ctx->umka = umka_init(UMKA_RUNNING_NOT_YET);
ctx->io = io_init(&ctx->umka->running);
ctx->shell = shell_init(SHELL_LOG_NONREPRODUCIBLE, history_filename,
ctx->umka, ctx->io, fstartup, &ctx->umka->running);
ctx->umka, ctx->io, fstartup);
return ctx;
}
void build_history_filename(void) {
static void
build_history_filename(void) {
const char *dir_name;
if (!(dir_name = getenv("HOME"))) {
dir_name = ".";
@ -87,7 +88,8 @@ void build_history_filename(void) {
sprintf(history_filename, "%s/%s", dir_name, HIST_FILE_BASENAME);
}
void umka_thread_net_drv(void);
void
umka_thread_net_drv(void);
struct itimerval timeout = {.it_value = {.tv_sec = 0, .tv_usec = 10000},
.it_interval = {.tv_sec = 0, .tv_usec = 10000}};
@ -401,7 +403,7 @@ main(int argc, char *argv[]) {
// load_app("/rd/1/loader");
struct vnet *vnet = vnet_init(VNET_TAP);
struct vnet *vnet = vnet_init(VNET_DEVTYPE_TAP, &os->umka->running);
if (vnet) {
kos_net_add_device(&vnet->eth.net);
} else {
@ -462,7 +464,7 @@ main(int argc, char *argv[]) {
setitimer(ITIMER_REAL, &timeout, NULL);
atomic_store_explicit(&os->umka->running, 1, memory_order_release);
atomic_store_explicit(&os->umka->running, UMKA_RUNNING_YES, memory_order_release);
umka_osloop(); // doesn't return
if (coverage)

View File

@ -34,10 +34,10 @@ char history_filename[PATH_MAX];
struct umka_shell_ctx *
umka_shell_init(int reproducible, FILE *fin) {
struct umka_shell_ctx *ctx = malloc(sizeof(struct umka_shell_ctx));
ctx->umka = umka_init();
ctx->umka = umka_init(UMKA_RUNNING_NEVER);
ctx->io = io_init(NULL);
ctx->shell = shell_init(reproducible, history_filename, ctx->umka, ctx->io,
fin, &ctx->umka->running);
fin);
return ctx;
}

View File

@ -122,7 +122,7 @@ io_close(struct umka_io *io) {
}
ssize_t
io_read(int fd, void *buf, size_t count, struct umka_io *io) {
io_read(int fd, void *buf, size_t count, const struct umka_io *io) {
ssize_t res;
if (!io->running || !*io->running) {
res = read(fd, buf, count);
@ -133,7 +133,7 @@ io_read(int fd, void *buf, size_t count, struct umka_io *io) {
}
ssize_t
io_write(int fd, const void *buf, size_t count, struct umka_io *io) {
io_write(int fd, const void *buf, size_t count, const struct umka_io *io) {
ssize_t res;
if (!io->running || !*io->running) {
res = write(fd, buf, count);

View File

@ -14,6 +14,10 @@
#include <stddef.h>
#include <pthread.h>
#if !defined (O_BINARY)
#define O_BINARY 0 // for Windows
#endif
struct umka_io {
const atomic_int *running;
pthread_t iot;
@ -73,9 +77,9 @@ void
io_close(struct umka_io *io);
ssize_t
io_read(int fd, void *buf, size_t count, struct umka_io *io);
io_read(int fd, void *buf, size_t count, const struct umka_io *io);
ssize_t
io_write(int fd, const void *buf, size_t count, struct umka_io *io);
io_write(int fd, const void *buf, size_t count, const struct umka_io *io);
#endif // UMKAIO_H_INCLUDED

View File

@ -41,8 +41,8 @@ vdisk_adjust_cache_size(void *userdata, size_t suggested_size) {
}
struct vdisk*
vdisk_init(const char *fname, int adjust_cache_size, size_t cache_size,
void *io) {
vdisk_init(const char *fname, const int adjust_cache_size,
const size_t cache_size, const void *io) {
size_t fname_len = strlen(fname);
size_t dot_raw_len = strlen(RAW_SUFFIX);
size_t dot_qcow2_len = strlen(QCOW2_SUFFIX);

View File

@ -19,11 +19,11 @@ struct vdisk {
uint64_t sect_cnt;
unsigned cache_size;
int adjust_cache_size;
void *io;
const void *io;
};
struct vdisk*
vdisk_init(const char *fname, int adjust_cache_size, size_t cache_size,
void *io);
vdisk_init(const char *fname, const int adjust_cache_size,
const size_t cache_size, const void *io);
#endif // VDISK_H_INCLUDED

View File

@ -197,7 +197,7 @@ vdisk_qcow2_write(void *userdata, void *buffer, off_t startsector,
}
struct vdisk*
vdisk_init_qcow2(const char *fname, struct umka_io *io) {
vdisk_init_qcow2(const char *fname, const struct umka_io *io) {
struct vdisk_qcow2 *d =
(struct vdisk_qcow2*)calloc(1, sizeof(struct vdisk_qcow2));
if (!d) {

View File

@ -17,6 +17,6 @@
#define QCOW2_SUFFIX ".qcow2"
struct vdisk*
vdisk_init_qcow2(const char *fname, struct umka_io *io);
vdisk_init_qcow2(const char *fname, const struct umka_io *io);
#endif // VDISK_QCOW2_H_INCLUDED

View File

@ -54,7 +54,7 @@ vdisk_raw_write(void *userdata, void *buffer, off_t startsector,
}
struct vdisk*
vdisk_init_raw(const char *fname, struct umka_io *io) {
vdisk_init_raw(const char *fname, const struct umka_io *io) {
int fd = open(fname, O_RDONLY | O_BINARY);
if (!fd) {
printf("[vdisk.raw]: can't open file '%s': %s\n", fname, strerror(errno));

View File

@ -17,6 +17,6 @@
#define RAW_SUFFIX ".raw"
struct vdisk*
vdisk_init_raw(const char *fname, struct umka_io *io);
vdisk_init_raw(const char *fname, const struct umka_io *io);
#endif // VDISK_RAW_H_INCLUDED

22
vnet.c
View File

@ -22,8 +22,9 @@
#include "umkart.h"
#include "trace.h"
#include "vnet.h"
#include "vnet/tap.h"
#include "vnet/null.h"
#include "vnet/file.h"
#include "vnet/tap.h"
#ifndef _WIN32
#include <unistd.h>
@ -89,13 +90,16 @@ vnet_input_monitor(void *arg) {
}
struct vnet *
vnet_init(enum vnet_type type) {
vnet_init(enum vnet_type type, const atomic_int *running) {
struct vnet *vnet;
switch (type) {
case VNET_FILE:
case VNET_DEVTYPE_NULL:
vnet = vnet_init_null();
break;
case VNET_DEVTYPE_FILE:
vnet = vnet_init_file();
break;
case VNET_TAP:
case VNET_DEVTYPE_TAP:
vnet = vnet_init_tap();
break;
default:
@ -107,6 +111,8 @@ vnet_init(enum vnet_type type) {
return NULL;
}
vnet->running = running;
vnet->eth.net.link_state = ETH_LINK_FD + ETH_LINK_10M;
vnet->eth.net.hwacc = 0;
@ -128,9 +134,11 @@ vnet_init(enum vnet_type type) {
// pthread_mutex_lock(&vnet->mutex);
kos_attach_int_handler(UMKA_IRQ_NETWORK, vnet_input, vnet);
fprintf(stderr, "[vnet] start input_monitor thread\n");
pthread_t thread_input_monitor;
pthread_create(&thread_input_monitor, NULL, vnet_input_monitor, vnet);
if (*running != UMKA_RUNNING_NEVER) {
fprintf(stderr, "[vnet] start input_monitor thread\n");
pthread_t thread_input_monitor;
pthread_create(&thread_input_monitor, NULL, vnet_input_monitor, vnet);
}
return vnet;
}

12
vnet.h
View File

@ -10,28 +10,28 @@
#ifndef VNET_H_INCLUDED
#define VNET_H_INCLUDED
#include <stdatomic.h>
#include "umka.h"
#define UMKA_VNET_NAME "umka%d"
#define VNET_BUFIN_CAP (NET_BUFFER_SIZE - offsetof(net_buff_t, data))
enum vnet_type {
VNET_FILE,
VNET_TAP,
VNET_DEVTYPE_NULL,
VNET_DEVTYPE_FILE,
VNET_DEVTYPE_TAP,
};
struct vnet {
struct eth_device eth;
uint8_t bufin[VNET_BUFIN_CAP];
size_t bufin_len;
// pthread_cond_t cond;
// pthread_mutex_t mutex;
int fdin;
int fdout;
int input_processed;
const atomic_int *running;
};
struct vnet *
vnet_init(enum vnet_type type);
vnet_init(enum vnet_type type, const atomic_int *running);
#endif // VNET_H_INCLUDED

78
vnet/null.c Normal file
View File

@ -0,0 +1,78 @@
/*
SPDX-License-Identifier: GPL-2.0-or-later
UMKa - User-Mode KolibriOS developer tools
vnet - virtual network card, null interface
Copyright (C) 2023 Ivan Baravy <dunkaist@gmail.com>
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "trace.h"
#include "umka.h"
#include "vnet.h"
static STDCALL void
vnet_unload_null(void) {
COVERAGE_ON();
COVERAGE_OFF();
}
static STDCALL void
vnet_reset_null(void) {
COVERAGE_ON();
COVERAGE_OFF();
}
/*
static void
dump_net_buff(net_buff_t *buf) {
for (size_t i = 0; i < buf->length; i++) {
printf("%2.2x ", buf->data[i]);
}
putchar('\n');
}
*/
static STDCALL int
vnet_transmit_null(net_buff_t *buf) {
struct vnet *net;
__asm__ __inline__ __volatile__ (
""
: "=b"(net)
:
: "memory");
// dump_net_buff(buf);
buf->length = 0;
COVERAGE_OFF();
COVERAGE_ON();
return 0;
}
struct vnet *
vnet_init_null(void) {
struct vnet *vnet = malloc(sizeof(struct vnet));
vnet->eth.net.device_type = NET_TYPE_ETH;
vnet->eth.net.mtu = 1514;
char *devname = malloc(8);
sprintf(devname, "UMKNUL%d", 0); // FIXME: support more devices
vnet->eth.net.name = devname;
vnet->eth.net.unload = vnet_unload_null;
vnet->eth.net.reset = vnet_reset_null;
vnet->eth.net.transmit = vnet_transmit_null;
vnet->fdin = 0;
vnet->fdout = 0;
vnet->input_processed = 1;
memcpy(vnet->eth.mac, (uint8_t[]){0x80, 0x2b, 0xf9, 0x3b, 0x6c, 0xca},
sizeof(vnet->eth.mac));
return vnet;
}

16
vnet/null.h Normal file
View File

@ -0,0 +1,16 @@
/*
SPDX-License-Identifier: GPL-2.0-or-later
UMKa - User-Mode KolibriOS developer tools
vnet - virtual network card, null interface
Copyright (C) 2023 Ivan Baravy <dunkaist@gmail.com>
*/
#ifndef VNET_NULL_H_INCLUDED
#define VNET_NULL_H_INCLUDED
struct vnet *
vnet_init_null(void);
#endif // VNET_NULL_H_INCLUDED