qrap: Strip network devices from command line, set them up according to machine

The previous approach wasn't really robust: adding a -netdev option
without libvirt knowing could result in clashes with other devices.

Drop network devices from command line, check the available busses
and addresses from all -device options according to the -machine
parameter, and add a virtio-net device using an available address
or bus. Then, add a corresponding -netdev socket option.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Stefano Brivio 2021-05-12 08:35:36 +02:00
parent 7503332a1e
commit 5307faa059

115
qrap.c
View file

@ -27,6 +27,9 @@
#include "passt.h" #include "passt.h"
#define STRINGIFY(x) #x
#define STR(x) STRINGIFY(x)
static char *qemu_names[] = { static char *qemu_names[] = {
"kvm", "kvm",
"qemu-kvm", "qemu-kvm",
@ -37,6 +40,36 @@ static char *qemu_names[] = {
NULL, NULL,
}; };
static const struct drop_arg {
char *name;
char *val;
} drop_args[] = {
{ "-netdev", NULL },
{ "-net", NULL },
{ "-device", "virtio-net-pci," },
{ "-device", "virtio-net-ccw," },
{ "-device", "e1000," },
{ "-device", "rtl8139," },
{ 0 },
};
static const struct pci_dev {
char *mach;
char *name;
char *template;
char *template_post;
int first;
int last;
} pci_devs[] = {
{ "pc-q35", "virtio-net-pci",
"bus=pci.", ",addr=0x0", 3, 16 },
{ "pc-", "virtio-net-pci",
"bus=pci.0,addr=0x", "", 2, /* 1: ISA bridge */ 16 },
{ "s390-ccw", "virtio-net-ccw",
"devno=fe.0.", "", 1, 16 },
{ 0 },
};
#define DEFAULT_FD 5 #define DEFAULT_FD 5
/** /**
@ -63,13 +96,13 @@ void usage(const char *name)
*/ */
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char *qemu_argv[ARG_MAX], net_id[ARG_MAX] = { 0 }, *net_id_end; char *qemu_argv[ARG_MAX], dev_str[ARG_MAX];
int i, s, qemu_argc = 0, in_netdev = 0, has_socket = 0; int i, s, qemu_argc = 0, addr_map = 0, has_dev = 0;
struct sockaddr_un addr = { struct sockaddr_un addr = {
.sun_family = AF_UNIX, .sun_family = AF_UNIX,
.sun_path = UNIX_SOCK_PATH, .sun_path = UNIX_SOCK_PATH,
}; };
char fd_str[ARG_MAX]; const struct pci_dev *dev = NULL;
long fd; long fd;
if (argc >= 3) { if (argc >= 3) {
@ -90,39 +123,73 @@ int main(int argc, char **argv)
} }
fd = DEFAULT_FD; fd = DEFAULT_FD;
for (qemu_argc = 1, i = 1; i < argc; i++) {
char *p;
if (in_netdev) { for (i = 1; i < argc - 1; i++) {
in_netdev = 0; if (strcmp(argv[i], "-machine"))
if (strstr(argv[i], ",socket") || continue;
strstr(argv[i], "socket,"))
has_socket = 1; for (dev = pci_devs; dev->mach; dev++) {
} else if (!strcmp(argv[i], "-net") || if (strstr(argv[i + 1], dev->mach) == argv[i + 1])
!strcmp(argv[i], "-netdev")) { break;
in_netdev = 1; }
} }
if (!*net_id && (p = strstr(argv[i], ",netdev="))) if (!dev || !dev->mach)
strncpy(net_id, p + strlen(",netdev="), ARG_MAX); dev = pci_devs;
for (qemu_argc = 1, i = 1; i < argc; i++) {
const struct drop_arg *a;
for (a = drop_args; a->name; a++) {
if (!strcmp(argv[i], a->name)) {
if (!a->val)
break;
if (i + 1 < argc &&
strstr(argv[i + 1], a->val) == argv[i + 1])
break;
}
}
if (a->name) {
i++;
continue;
}
if (!strcmp(argv[i], "-device") && i + 1 < argc) {
char *p;
long n;
has_dev = 1;
if ((p = strstr(argv[i + 1], dev->template))) {
n = strtol(p + strlen(dev->template), NULL, 16);
if (!errno)
addr_map |= (1 << n);
}
}
qemu_argv[qemu_argc++] = argv[i]; qemu_argv[qemu_argc++] = argv[i];
} }
for (i = dev->first; i < dev->last; i++) {
if (!(addr_map & (1 << i)))
break;
}
if (i == dev->last) {
fprintf(stderr, "Couldn't find free address for device\n");
usage(argv[0]);
}
if (!has_socket) { if (has_dev) {
if (*net_id) { qemu_argv[qemu_argc++] = "-device";
net_id_end = strpbrk(net_id, ", "); snprintf(dev_str, ARG_MAX, "%s,%s%x%s,netdev=hostnet0",
if (net_id_end) dev->name, dev->template, i, dev->template_post);
*net_id_end = 0; qemu_argv[qemu_argc++] = dev_str;
} }
qemu_argv[qemu_argc++] = "-netdev"; qemu_argv[qemu_argc++] = "-netdev";
snprintf(fd_str, ARG_MAX, "socket,fd=%u,id=%s", DEFAULT_FD, qemu_argv[qemu_argc++] = "socket,fd=" STR(DEFAULT_FD) ",id=hostnet0";
*net_id ? net_id : "hostnet0");
qemu_argv[qemu_argc++] = fd_str;
qemu_argv[qemu_argc] = NULL; qemu_argv[qemu_argc] = NULL;
}
valid_args: valid_args:
s = socket(AF_UNIX, SOCK_STREAM, 0); s = socket(AF_UNIX, SOCK_STREAM, 0);