summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorreyk <reyk@openbsd.org>2016-10-05 17:30:13 +0000
committerreyk <reyk@openbsd.org>2016-10-05 17:30:13 +0000
commit789e0822cdf00d35167b6ecc6a5f8a060f53d340 (patch)
treeddacdf795361f55a16d92df4974a5da107391d92
parentCheck if oldd == newd before dup2(), if that is the case we need to remove (diff)
downloadwireguard-openbsd-789e0822cdf00d35167b6ecc6a5f8a060f53d340.tar.xz
wireguard-openbsd-789e0822cdf00d35167b6ecc6a5f8a060f53d340.zip
Add support for enhanced networking configuration and virtual switches.
See vm.conf(5) for more details. OK mlarkin@
-rw-r--r--etc/examples/vm.conf27
-rw-r--r--usr.sbin/vmd/config.c85
-rw-r--r--usr.sbin/vmd/parse.y276
-rw-r--r--usr.sbin/vmd/priv.c139
-rw-r--r--usr.sbin/vmd/proc.h9
-rw-r--r--usr.sbin/vmd/virtio.c12
-rw-r--r--usr.sbin/vmd/vm.conf.5129
-rw-r--r--usr.sbin/vmd/vmd.c55
-rw-r--r--usr.sbin/vmd/vmd.h51
-rw-r--r--usr.sbin/vmd/vmm.c22
10 files changed, 708 insertions, 97 deletions
diff --git a/etc/examples/vm.conf b/etc/examples/vm.conf
index 1d514c8a494..d1afb794e35 100644
--- a/etc/examples/vm.conf
+++ b/etc/examples/vm.conf
@@ -1,4 +1,4 @@
-# $OpenBSD: vm.conf,v 1.4 2016/01/06 09:59:30 reyk Exp $
+# $OpenBSD: vm.conf,v 1.5 2016/10/05 17:30:13 reyk Exp $
#
# Macros
@@ -9,6 +9,19 @@ sets="/var/www/htdocs/pub/OpenBSD/snapshots/amd64/"
# Virtual machines
#
+switch "wired" {
+ # This interface will default to bridge0, but switch(4) is supported
+ #interface switch0
+
+ # Add additional members
+ add em0
+ down
+}
+
+switch "wireless" {
+ add iwm0
+}
+
# OpenBSD snapshot install test
vm "openbsd.vm" {
memory 512M
@@ -18,17 +31,23 @@ vm "openbsd.vm" {
disk "/home/vm/OpenBSD.img"
# Second disk from OpenBSD contains the install sets
- disk $sets "install59.fs"
+ disk $sets "install60.fs"
# Interface will show up as tap(4) on the host and as vio(4) in the VM
- interfaces 1
+ interface { switch "wireless" }
+ interface { switch "wired" }
}
# Another VM that is disabled on startup
vm "vm1.example.com" {
disable
memory 1G
- interfaces 2
kernel "/bsd"
disk "/home/vm/vm1-disk.img"
+
+ # Use a specific tap(4) interface with a hardcoded MAC address
+ interface tap3 {
+ lladdr 00:11:22:aa:bb:cc
+ down
+ }
}
diff --git a/usr.sbin/vmd/config.c b/usr.sbin/vmd/config.c
index e3de3abbd35..a8198f5583b 100644
--- a/usr.sbin/vmd/config.c
+++ b/usr.sbin/vmd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.13 2016/10/04 17:17:30 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.14 2016/10/05 17:30:13 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -38,6 +38,9 @@
#include "proc.h"
#include "vmd.h"
+/* Supported bridge types */
+const char *vmd_descsw[] = { "switch", "bridge", NULL };
+
int
config_init(struct vmd *env)
{
@@ -56,6 +59,12 @@ config_init(struct vmd *env)
return (-1);
TAILQ_INIT(env->vmd_vms);
}
+ if (what & CONFIG_SWITCHES) {
+ if ((env->vmd_switches = calloc(1,
+ sizeof(*env->vmd_switches))) == NULL)
+ return (-1);
+ TAILQ_INIT(env->vmd_switches);
+ }
return (0);
}
@@ -65,13 +74,19 @@ config_purge(struct vmd *env, unsigned int reset)
{
struct privsep *ps = &env->vmd_ps;
struct vmd_vm *vm;
+ struct vmd_switch *vsw;
unsigned int what;
what = ps->ps_what[privsep_process] & reset;
if (what & CONFIG_VMS && env->vmd_vms != NULL) {
while ((vm = TAILQ_FIRST(env->vmd_vms)) != NULL)
vm_remove(vm);
- env->vmd_vmcount = 0;
+ env->vmd_nvm = 0;
+ }
+ if (what & CONFIG_SWITCHES && env->vmd_switches != NULL) {
+ while ((vsw = TAILQ_FIRST(env->vmd_switches)) != NULL)
+ switch_remove(vsw);
+ env->vmd_nswitches = 0;
}
}
@@ -105,17 +120,21 @@ config_getreset(struct vmd *env, struct imsg *imsg)
}
int
-config_getvm(struct privsep *ps, struct vm_create_params *vcp,
+config_getvm(struct privsep *ps, struct vmop_create_params *vmc,
int kernel_fd, uint32_t peerid)
{
struct vmd *env = ps->ps_env;
struct vmd_vm *vm = NULL;
+ struct vmd_if *vif;
+ struct vm_create_params *vcp = &vmc->vmc_params;
unsigned int i;
int fd, ttys_fd;
int kernfd = -1, *diskfds = NULL, *tapfds = NULL;
int saved_errno = 0;
char ptyname[VM_TTYNAME_MAX];
- char ifname[IF_NAMESIZE];
+ char ifname[IF_NAMESIZE], *s;
+ char path[PATH_MAX];
+ unsigned int unit;
errno = 0;
@@ -146,7 +165,7 @@ config_getvm(struct privsep *ps, struct vm_create_params *vcp,
for (i = 0; i < vcp->vcp_ndisks; i++)
vm->vm_disks[i] = -1;
for (i = 0; i < vcp->vcp_nnics; i++)
- vm->vm_ifs[i] = -1;
+ vm->vm_ifs[i].vif_fd = -1;
vm->vm_kernel = -1;
vm->vm_vmid = env->vmd_nvm + 1;
@@ -203,19 +222,58 @@ config_getvm(struct privsep *ps, struct vm_create_params *vcp,
}
}
- /* Open disk network interfaces */
+ /* Open network interfaces */
for (i = 0 ; i < vcp->vcp_nnics; i++) {
- if ((tapfds[i] = opentap(ifname)) == -1) {
+ vif = &vm->vm_ifs[i];
+
+ /* Check if the user has requested a specific tap(4) */
+ s = vmc->vmc_ifnames[i];
+ if (*s != '\0' && strcmp("tap", s) != 0) {
+ if (priv_getiftype(s, ifname, &unit) == -1 ||
+ strcmp(ifname, "tap") != 0) {
+ saved_errno = errno;
+ log_warn("%s: invalid tap name",
+ __func__);
+ goto fail;
+ }
+ } else
+ s = NULL;
+
+ /*
+ * Either open the requested tap(4) device or get
+ * the next available one.
+ */
+ if (s != NULL) {
+ snprintf(path, PATH_MAX, "/dev/%s", s);
+ tapfds[i] = open(path, O_RDWR | O_NONBLOCK);
+ } else {
+ tapfds[i] = opentap(ifname);
+ s = ifname;
+ }
+ if (tapfds[i] == -1) {
saved_errno = errno;
- log_warn("%s: can't open tap", __func__);
+ log_warn("%s: can't open %s", __func__, s);
goto fail;
}
-
- if ((vm->vm_ifnames[i] = strdup(ifname)) == NULL) {
+ if ((vif->vif_name = strdup(s)) == NULL) {
saved_errno = errno;
log_warn("%s: can't save ifname", __func__);
goto fail;
}
+
+ /* Check if the the interface is attached to a switch */
+ s = vmc->vmc_ifswitch[i];
+ if (*s != '\0') {
+ if ((vif->vif_switch = strdup(s)) == NULL) {
+ saved_errno = errno;
+ log_warn("%s: can't save switch",
+ __func__);
+ goto fail;
+ }
+ }
+
+ /* Set the interface status */
+ vif->vif_flags = vmc->vmc_ifflags[i] & IFF_UP;
}
/* Open TTY */
@@ -230,7 +288,7 @@ config_getvm(struct privsep *ps, struct vm_create_params *vcp,
/* Send VM information */
proc_compose_imsg(ps, PROC_VMM, -1,
IMSG_VMDOP_START_VM_REQUEST, vm->vm_vmid, kernfd,
- vcp, sizeof(*vcp));
+ vmc, sizeof(*vmc));
for (i = 0; i < vcp->vcp_ndisks; i++) {
proc_compose_imsg(ps, PROC_VMM, -1,
IMSG_VMDOP_START_VM_DISK, vm->vm_vmid, diskfds[i],
@@ -317,11 +375,11 @@ config_getif(struct privsep *ps, struct imsg *imsg)
IMSG_SIZE_CHECK(imsg, &n);
memcpy(&n, imsg->data, sizeof(n));
if (n >= vm->vm_params.vcp_nnics ||
- vm->vm_ifs[n] != -1 || imsg->fd == -1) {
+ vm->vm_ifs[n].vif_fd != -1 || imsg->fd == -1) {
log_debug("invalid interface id");
goto fail;
}
- vm->vm_ifs[n] = imsg->fd;
+ vm->vm_ifs[n].vif_fd = imsg->fd;
return (0);
fail:
@@ -329,5 +387,4 @@ config_getif(struct privsep *ps, struct imsg *imsg)
close(imsg->fd);
errno = EINVAL;
return (-1);
-
}
diff --git a/usr.sbin/vmd/parse.y b/usr.sbin/vmd/parse.y
index f7fece01b15..023150567d7 100644
--- a/usr.sbin/vmd/parse.y
+++ b/usr.sbin/vmd/parse.y
@@ -1,7 +1,7 @@
-/* $OpenBSD: parse.y,v 1.7 2016/06/21 21:35:25 benno Exp $ */
+/* $OpenBSD: parse.y,v 1.8 2016/10/05 17:30:13 reyk Exp $ */
/*
- * Copyright (c) 2007-2015 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2007-2016 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
* Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -25,10 +25,15 @@
%{
#include <sys/types.h>
#include <sys/queue.h>
+#include <sys/socket.h>
#include <sys/uio.h>
#include <machine/vmmvar.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
@@ -78,14 +83,21 @@ char *symget(const char *);
ssize_t parse_size(char *, int64_t);
int parse_disk(char *);
-static struct vm_create_params vcp;
-static int vcp_disable = 0;
-static int errors = 0;
-
+static struct vmop_create_params vmc;
+static struct vm_create_params *vcp;
+static struct vmd_switch *vsw;
+static struct vmd_if *vif;
+static unsigned int vsw_unit;
+static char vsw_type[IF_NAMESIZE];
+static int vcp_disable;
+static size_t vcp_nnics;
+static int errors;
extern struct vmd *env;
+extern const char *vmd_descsw[];
typedef struct {
union {
+ u_int8_t lladdr[ETHER_ADDR_LEN];
int64_t number;
char *string;
} v;
@@ -96,12 +108,15 @@ typedef struct {
%token INCLUDE ERROR
-%token DISK NIFS PATH SIZE VMID
-%token ENABLE DISABLE VM KERNEL MEMORY
+%token ADD DISK DOWN INTERFACE NIFS PATH SIZE SWITCH UP VMID
+%token ENABLE DISABLE VM KERNEL LLADDR MEMORY
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.number> disable
+%type <v.number> updown
+%type <v.lladdr> lladdr
%type <v.string> string
+%type <v.string> optstring
%%
@@ -109,7 +124,8 @@ grammar : /* empty */
| grammar include '\n'
| grammar '\n'
| grammar varset '\n'
- | grammar main '\n'
+ | grammar switch '\n'
+ | grammar vm '\n'
| grammar error '\n' { file->errors++; }
;
@@ -144,41 +160,143 @@ varset : STRING '=' STRING {
}
;
-main : VM string {
- memset(&vcp, 0, sizeof(vcp));
+switch : SWITCH string {
+ if ((vsw = calloc(1, sizeof(*vsw))) == NULL)
+ fatal("could not allocate switch");
+
+ vsw->sw_id = env->vmd_nswitches + 1;
+ vsw->sw_name = $2;
+ vsw->sw_flags = IFF_UP;
+ snprintf(vsw->sw_ifname, sizeof(vsw->sw_ifname),
+ "%s%u", vsw_type, vsw_unit++);
+ TAILQ_INIT(&vsw->sw_ifs);
+
+ vcp_disable = 0;
+ } '{' optnl switch_opts_l '}' {
+ TAILQ_INSERT_TAIL(env->vmd_switches, vsw, sw_entry);
+ env->vmd_nswitches++;
+
+ if (vcp_disable) {
+ log_debug("%s:%d: switch \"%s\""
+ " skipped (disabled)",
+ file->name, yylval.lineno, vsw->sw_name);
+ } else if (!env->vmd_noaction) {
+ /*
+ * XXX Configure the switch right away -
+ * XXX this should be done after parsing
+ * XXX the configuration.
+ */
+ if (vm_priv_brconfig(&env->vmd_ps, vsw) == -1) {
+ log_warn("%s:%d: switch \"%s\" failed",
+ file->name, yylval.lineno,
+ vsw->sw_name);
+ YYERROR;
+ } else {
+ log_debug("%s:%d: switch \"%s\""
+ " configured",
+ file->name, yylval.lineno,
+ vsw->sw_name);
+ }
+ }
+ }
+ ;
+
+switch_opts_l : switch_opts_l switch_opts nl
+ | switch_opts optnl
+ ;
+
+switch_opts : disable {
+ vcp_disable = $1;
+ }
+ | ADD string {
+ char type[IF_NAMESIZE];
+
+ if ((vif = calloc(1, sizeof(*vif))) == NULL)
+ fatal("could not allocate interface");
+
+ if (priv_getiftype($2, type, NULL) == -1) {
+ yyerror("invalid interface: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ vif->vif_name = $2;
+
+ TAILQ_INSERT_TAIL(&vsw->sw_ifs, vif, vif_entry);
+ }
+ | INTERFACE string {
+ if (priv_getiftype($2, vsw_type, &vsw_unit) == -1 ||
+ priv_findname(vsw_type, vmd_descsw) == -1) {
+ yyerror("invalid switch interface: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ vsw_unit++;
+
+ if (strlcpy(vsw->sw_ifname, $2,
+ sizeof(vsw->sw_ifname)) >= sizeof(vsw->sw_ifname)) {
+ yyerror("switch interface too long: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ | updown {
+ if ($1)
+ vsw->sw_flags |= IFF_UP;
+ else
+ vsw->sw_flags &= ~IFF_UP;
+ }
+ ;
+
+vm : VM string {
+ unsigned int i;
+
+ memset(&vmc, 0, sizeof(vmc));
+ vcp = &vmc.vmc_params;
vcp_disable = 0;
- if (strlcpy(vcp.vcp_name, $2, sizeof(vcp.vcp_name)) >=
- sizeof(vcp.vcp_name)) {
+ vcp_nnics = 0;
+
+ for (i = 0; i < VMM_MAX_NICS_PER_VM; i++) {
+ /* Set the interface to UP by default */
+ vmc.vmc_ifflags[i] |= IFF_UP;
+ }
+
+ if (strlcpy(vcp->vcp_name, $2, sizeof(vcp->vcp_name)) >=
+ sizeof(vcp->vcp_name)) {
yyerror("vm name too long");
YYERROR;
}
} '{' optnl vm_opts_l '}' {
int ret;
+ /* configured interfaces vs. number of interfaces */
+ if (vcp_nnics > vcp->vcp_nnics)
+ vcp->vcp_nnics = vcp_nnics;
+
if (vcp_disable) {
log_debug("%s:%d: vm \"%s\" skipped (disabled)",
- file->name, yylval.lineno, vcp.vcp_name);
+ file->name, yylval.lineno, vcp->vcp_name);
} else if (!env->vmd_noaction) {
/*
* XXX Start the vm right away -
* XXX this should be done after parsing
* XXX the configuration.
*/
- ret = config_getvm(&env->vmd_ps, &vcp, -1, -1);
+ ret = config_getvm(&env->vmd_ps, &vmc, -1, -1);
if (ret == -1 && errno == EALREADY) {
log_debug("%s:%d: vm \"%s\""
" skipped (running)",
file->name, yylval.lineno,
- vcp.vcp_name);
+ vcp->vcp_name);
} else if (ret == -1) {
log_warn("%s:%d: vm \"%s\" failed",
file->name, yylval.lineno,
- vcp.vcp_name);
+ vcp->vcp_name);
YYERROR;
} else {
log_debug("%s:%d: vm \"%s\" enabled",
file->name, yylval.lineno,
- vcp.vcp_name);
+ vcp->vcp_name);
}
}
}
@@ -199,14 +317,47 @@ vm_opts : disable {
}
free($2);
}
+ | INTERFACE optstring iface_opts_o {
+ unsigned int i;
+ char type[IF_NAMESIZE];
+
+ i = vcp_nnics;
+ if (++vcp_nnics > VMM_MAX_NICS_PER_VM) {
+ yyerror("too many interfaces: %zu", vcp_nnics);
+ free($2);
+ YYERROR;
+ }
+
+ if ($2 != NULL) {
+ if (strcmp($2, "tap") != 0 &&
+ (priv_getiftype($2, type, NULL) == -1 ||
+ strcmp(type, "tap") != 0)) {
+ yyerror("invalid interface: %s", $2);
+ free($2);
+ YYERROR;
+ }
+
+ if (strlcpy(vmc.vmc_ifnames[i], $2,
+ sizeof(vmc.vmc_ifnames[i])) >=
+ sizeof(vmc.vmc_ifnames[i])) {
+ yyerror("interface name too long: %s",
+ $2);
+ free($2);
+ YYERROR;
+ }
+ }
+ free($2);
+ }
| KERNEL string {
- if (vcp.vcp_kernel[0] != '\0') {
+ if (vcp->vcp_kernel[0] != '\0') {
yyerror("kernel specified more than once");
free($2);
YYERROR;
+
}
- if (strlcpy(vcp.vcp_kernel, $2,
- sizeof(vcp.vcp_kernel)) >= sizeof(vcp.vcp_kernel)) {
+ if (strlcpy(vcp->vcp_kernel, $2,
+ sizeof(vcp->vcp_kernel)) >=
+ sizeof(vcp->vcp_kernel)) {
yyerror("kernel name too long");
free($2);
YYERROR;
@@ -214,7 +365,7 @@ vm_opts : disable {
free($2);
}
| NIFS NUMBER {
- if (vcp.vcp_nnics != 0) {
+ if (vcp->vcp_nnics != 0) {
yyerror("interfaces specified more than once");
YYERROR;
}
@@ -222,11 +373,11 @@ vm_opts : disable {
yyerror("too many interfaces: %lld", $2);
YYERROR;
}
- vcp.vcp_nnics = (size_t)$2;
+ vcp->vcp_nnics = (size_t)$2;
}
| MEMORY NUMBER {
ssize_t res;
- if (vcp.vcp_memranges[0].vmr_size != 0) {
+ if (vcp->vcp_memranges[0].vmr_size != 0) {
yyerror("memory specified more than once");
YYERROR;
}
@@ -234,11 +385,11 @@ vm_opts : disable {
yyerror("failed to parse size: %lld", $2);
YYERROR;
}
- vcp.vcp_memranges[0].vmr_size = (size_t)res;
+ vcp->vcp_memranges[0].vmr_size = (size_t)res;
}
| MEMORY STRING {
ssize_t res;
- if (vcp.vcp_memranges[0].vmr_size != 0) {
+ if (vcp->vcp_memranges[0].vmr_size != 0) {
yyerror("argument specified more than once");
free($2);
YYERROR;
@@ -248,11 +399,47 @@ vm_opts : disable {
free($2);
YYERROR;
}
- vcp.vcp_memranges[0].vmr_size = (size_t)res;
+ vcp->vcp_memranges[0].vmr_size = (size_t)res;
}
;
-string : STRING string {
+iface_opts_o : '{' optnl iface_opts_l '}'
+ | /* empty */
+ ;
+
+iface_opts_l : iface_opts_l iface_opts optnl
+ | iface_opts optnl
+ ;
+
+iface_opts : SWITCH string {
+ unsigned int i = vcp_nnics;
+
+ /* No need to check if the switch exists */
+ if (strlcpy(vmc.vmc_ifswitch[i], $2,
+ sizeof(vmc.vmc_ifswitch[i])) >=
+ sizeof(vmc.vmc_ifswitch[i])) {
+ yyerror("switch name too long: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ | LLADDR lladdr {
+ memcpy(vcp->vcp_macs[vcp_nnics], $2, ETHER_ADDR_LEN);
+ }
+ | updown {
+ if ($1)
+ vmc.vmc_ifflags[vcp_nnics] |= IFF_UP;
+ else
+ vmc.vmc_ifflags[vcp_nnics] &= ~IFF_UP;
+ }
+ ;
+
+optstring : STRING { $$ = $1; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+string : STRING string {
if (asprintf(&$$, "%s%s", $1, $2) == -1)
fatal("asprintf string");
free($1);
@@ -261,6 +448,24 @@ string : STRING string {
| STRING
;
+lladdr : STRING {
+ struct ether_addr *ea;
+
+ if ((ea = ether_aton($1)) == NULL) {
+ yyerror("invalid address: %s\n", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+
+ memcpy($$, ea, ETHER_ADDR_LEN);
+ }
+ ;
+
+updown : UP { $$ = 1; }
+ | DOWN { $$ = 0; }
+ ;
+
disable : ENABLE { $$ = 0; }
| DISABLE { $$ = 1; }
;
@@ -306,15 +511,21 @@ lookup(char *s)
{
/* this has to be sorted always */
static const struct keywords keywords[] = {
+ { "add", ADD },
{ "disable", DISABLE },
{ "disk", DISK },
+ { "down", DOWN },
{ "enable", ENABLE },
{ "id", VMID },
{ "include", INCLUDE },
+ { "interface", INTERFACE },
{ "interfaces", NIFS },
{ "kernel", KERNEL },
+ { "lladdr", LLADDR },
{ "memory", MEMORY },
{ "size", SIZE },
+ { "switch", SWITCH },
+ { "up", UP },
{ "vm", VM }
};
const struct keywords *p;
@@ -631,6 +842,9 @@ parse_config(const char *filename)
topfile = file;
setservent(1);
+ /* Set the default switch type */
+ (void)strlcpy(vsw_type, VMD_SWITCH_TYPE, sizeof(vsw_type));
+
yyparse();
errors = file->errors;
popfile();
@@ -760,18 +974,18 @@ parse_size(char *word, int64_t val)
int
parse_disk(char *word)
{
- if (vcp.vcp_ndisks >= VMM_MAX_DISKS_PER_VM) {
+ if (vcp->vcp_ndisks >= VMM_MAX_DISKS_PER_VM) {
log_warnx("too many disks");
return (-1);
}
- if (strlcpy(vcp.vcp_disks[vcp.vcp_ndisks], word,
+ if (strlcpy(vcp->vcp_disks[vcp->vcp_ndisks], word,
VMM_MAX_PATH_DISK) >= VMM_MAX_PATH_DISK) {
log_warnx("disk path too long");
return (-1);
}
- vcp.vcp_ndisks++;
+ vcp->vcp_ndisks++;
return (0);
}
diff --git a/usr.sbin/vmd/priv.c b/usr.sbin/vmd/priv.c
index 987b38c71e7..65799d0251f 100644
--- a/usr.sbin/vmd/priv.c
+++ b/usr.sbin/vmd/priv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: priv.c,v 1.1 2016/10/04 17:17:30 reyk Exp $ */
+/* $OpenBSD: priv.c,v 1.2 2016/10/05 17:30:13 reyk Exp $ */
/*
* Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org>
@@ -25,6 +25,9 @@
#include <sys/tree.h>
#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/if_bridge.h>
#include <errno.h>
#include <event.h>
@@ -41,9 +44,6 @@
int priv_dispatch_parent(int, struct privsep_proc *, struct imsg *);
void priv_run(struct privsep *, struct privsep_proc *, void *);
-int priv_getiftype(char *, char *, unsigned int *);
-int priv_findname(const char *, const char **);
-
static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT, priv_dispatch_parent }
};
@@ -77,25 +77,72 @@ priv_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
struct vmop_ifreq vfr;
struct vmd *env = ps->ps_env;
struct ifreq ifr;
+ struct ifbreq ifbr;
char type[IF_NAMESIZE];
- unsigned int unit;
switch (imsg->hdr.type) {
case IMSG_VMDOP_PRIV_IFDESCR:
+ case IMSG_VMDOP_PRIV_IFCREATE:
+ case IMSG_VMDOP_PRIV_IFADD:
+ case IMSG_VMDOP_PRIV_IFUP:
+ case IMSG_VMDOP_PRIV_IFDOWN:
IMSG_SIZE_CHECK(imsg, &vfr);
memcpy(&vfr, imsg->data, sizeof(vfr));
/* We should not get malicious requests from the parent */
- if (priv_getiftype(vfr.vfr_name, type, &unit) == -1 ||
+ if (priv_getiftype(vfr.vfr_name, type, NULL) == -1 ||
priv_findname(type, desct) == -1)
fatalx("%s: rejected priv operation on interface: %s",
__func__, vfr.vfr_name);
+ break;
+ default:
+ return (-1);
+ }
+ switch (imsg->hdr.type) {
+ case IMSG_VMDOP_PRIV_IFDESCR:
+ /* Set the interface description */
strlcpy(ifr.ifr_name, vfr.vfr_name, sizeof(ifr.ifr_name));
ifr.ifr_data = (caddr_t)vfr.vfr_value;
if (ioctl(env->vmd_fd, SIOCSIFDESCR, &ifr) < 0)
log_warn("SIOCSIFDESCR");
break;
+ case IMSG_VMDOP_PRIV_IFCREATE:
+ /* Create the bridge if it doesn't exist */
+ strlcpy(ifr.ifr_name, vfr.vfr_name, sizeof(ifr.ifr_name));
+ if (ioctl(env->vmd_fd, SIOCIFCREATE, &ifr) < 0 &&
+ errno != EEXIST)
+ log_warn("SIOCIFCREATE");
+ break;
+ case IMSG_VMDOP_PRIV_IFADD:
+ if (priv_getiftype(vfr.vfr_value, type, NULL) == -1)
+ fatalx("%s: rejected to add interface: %s",
+ __func__, vfr.vfr_value);
+
+ /* Attach the device to the bridge */
+ strlcpy(ifbr.ifbr_name, vfr.vfr_name,
+ sizeof(ifbr.ifbr_name));
+ strlcpy(ifbr.ifbr_ifsname, vfr.vfr_value,
+ sizeof(ifbr.ifbr_ifsname));
+ if (ioctl(env->vmd_fd, SIOCBRDGADD, &ifbr) < 0 &&
+ errno != EEXIST)
+ log_warn("SIOCBRDGADD");
+ break;
+ case IMSG_VMDOP_PRIV_IFUP:
+ case IMSG_VMDOP_PRIV_IFDOWN:
+ /* Set the interface status */
+ strlcpy(ifr.ifr_name, vfr.vfr_name, sizeof(ifr.ifr_name));
+ if (ioctl(env->vmd_fd, SIOCGIFFLAGS, &ifr) < 0) {
+ log_warn("SIOCGIFFLAGS");
+ break;
+ }
+ if (imsg->hdr.type == IMSG_VMDOP_PRIV_IFUP)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(env->vmd_fd, SIOCSIFFLAGS, &ifr) < 0)
+ log_warn("SIOCSIFFLAGS");
+ break;
default:
return (-1);
}
@@ -148,14 +195,18 @@ int
vm_priv_ifconfig(struct privsep *ps, struct vmd_vm *vm)
{
struct vm_create_params *vcp = &vm->vm_params;
+ struct vmd_if *vif;
+ struct vmd_switch *vsw;
unsigned int i;
- struct vmop_ifreq vfr;
+ struct vmop_ifreq vfr, vfbr;
for (i = 0; i < VMM_MAX_NICS_PER_VM; i++) {
- if (vm->vm_ifnames[i] == NULL)
+ vif = &vm->vm_ifs[i];
+
+ if (vif->vif_name == NULL)
break;
- if (strlcpy(vfr.vfr_name, vm->vm_ifnames[i],
+ if (strlcpy(vfr.vfr_name, vif->vif_name,
sizeof(vfr.vfr_name)) >= sizeof(vfr.vfr_name))
return (-1);
@@ -163,11 +214,79 @@ vm_priv_ifconfig(struct privsep *ps, struct vmd_vm *vm)
(void)snprintf(vfr.vfr_value, sizeof(vfr.vfr_value),
"vm%u-if%u-%s", vm->vm_vmid, i, vcp->vcp_name);
+ log_debug("%s: interface %s description %s", __func__,
+ vfr.vfr_name, vfr.vfr_value);
+
proc_compose(ps, PROC_PRIV, IMSG_VMDOP_PRIV_IFDESCR,
&vfr, sizeof(vfr));
- /* XXX Add interface to bridge/switch */
+ /* Add interface to bridge/switch */
+ if ((vsw = switch_getbyname(vif->vif_switch)) != NULL) {
+ if (strlcpy(vfbr.vfr_name, vsw->sw_ifname,
+ sizeof(vfbr.vfr_name)) >= sizeof(vfbr.vfr_name))
+ return (-1);
+ if (strlcpy(vfbr.vfr_value, vif->vif_name,
+ sizeof(vfbr.vfr_value)) >= sizeof(vfbr.vfr_value))
+ return (-1);
+
+ log_debug("%s: interface %s add %s", __func__,
+ vfbr.vfr_name, vfbr.vfr_value);
+
+ proc_compose(ps, PROC_PRIV, IMSG_VMDOP_PRIV_IFCREATE,
+ &vfbr, sizeof(vfbr));
+ proc_compose(ps, PROC_PRIV, IMSG_VMDOP_PRIV_IFADD,
+ &vfbr, sizeof(vfbr));
+ } else if (vif->vif_switch != NULL)
+ log_warnx("switch %s not found", vif->vif_switch);
+
+ /* Set the new interface status to up or down */
+ proc_compose(ps, PROC_PRIV, (vif->vif_flags & IFF_UP) ?
+ IMSG_VMDOP_PRIV_IFUP : IMSG_VMDOP_PRIV_IFDOWN,
+ &vfr, sizeof(vfr));
}
return (0);
}
+
+int
+vm_priv_brconfig(struct privsep *ps, struct vmd_switch *vsw)
+{
+ struct vmd_if *vif;
+ struct vmop_ifreq vfr;
+
+ if (strlcpy(vfr.vfr_name, vsw->sw_ifname,
+ sizeof(vfr.vfr_name)) >= sizeof(vfr.vfr_name))
+ return (-1);
+
+ proc_compose(ps, PROC_PRIV, IMSG_VMDOP_PRIV_IFCREATE,
+ &vfr, sizeof(vfr));
+
+ /* Description can be truncated */
+ (void)snprintf(vfr.vfr_value, sizeof(vfr.vfr_value),
+ "switch%u-%s", vsw->sw_id, vsw->sw_name);
+
+ log_debug("%s: interface %s description %s", __func__,
+ vfr.vfr_name, vfr.vfr_value);
+
+ proc_compose(ps, PROC_PRIV, IMSG_VMDOP_PRIV_IFDESCR,
+ &vfr, sizeof(vfr));
+
+ TAILQ_FOREACH(vif, &vsw->sw_ifs, vif_entry) {
+ if (strlcpy(vfr.vfr_value, vif->vif_name,
+ sizeof(vfr.vfr_value)) >= sizeof(vfr.vfr_value))
+ return (-1);
+
+ log_debug("%s: interface %s add %s", __func__,
+ vfr.vfr_name, vfr.vfr_value);
+
+ proc_compose(ps, PROC_PRIV, IMSG_VMDOP_PRIV_IFADD,
+ &vfr, sizeof(vfr));
+ }
+
+ /* Set the new interface status to up or down */
+ proc_compose(ps, PROC_PRIV, (vsw->sw_flags & IFF_UP) ?
+ IMSG_VMDOP_PRIV_IFUP : IMSG_VMDOP_PRIV_IFDOWN,
+ &vfr, sizeof(vfr));
+
+ return (0);
+}
diff --git a/usr.sbin/vmd/proc.h b/usr.sbin/vmd/proc.h
index 053d9a527f5..0d402d5dd21 100644
--- a/usr.sbin/vmd/proc.h
+++ b/usr.sbin/vmd/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.8 2016/10/04 17:17:30 reyk Exp $ */
+/* $OpenBSD: proc.h,v 1.9 2016/10/05 17:30:13 reyk Exp $ */
/*
* Copyright (c) 2010-2015 Reyk Floeter <reyk@openbsd.org>
@@ -48,9 +48,9 @@ struct imsgev {
short events;
};
-#define IMSG_SIZE_CHECK(imsg, p) do { \
- if (IMSG_DATA_SIZE(imsg) < sizeof(*p)) \
- fatalx("bad length imsg received"); \
+#define IMSG_SIZE_CHECK(imsg, p) do { \
+ if (IMSG_DATA_SIZE(imsg) < sizeof(*p)) \
+ fatalx("bad length imsg received (%s)", #p); \
} while (0)
#define IMSG_DATA_SIZE(imsg) ((imsg)->hdr.len - IMSG_HEADER_SIZE)
@@ -95,6 +95,7 @@ enum privsep_procid {
#define CONFIG_RELOAD 0x00
#define CONFIG_VMS 0x01
+#define CONFIG_SWITCHES 0x02
#define CONFIG_ALL 0xff
struct privsep_pipes {
diff --git a/usr.sbin/vmd/virtio.c b/usr.sbin/vmd/virtio.c
index e652d2f839f..4af04d5cb66 100644
--- a/usr.sbin/vmd/virtio.c
+++ b/usr.sbin/vmd/virtio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: virtio.c,v 1.20 2016/10/03 05:59:24 mlarkin Exp $ */
+/* $OpenBSD: virtio.c,v 1.21 2016/10/05 17:30:13 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -1169,6 +1169,7 @@ out:
void
virtio_init(struct vm_create_params *vcp, int *child_disks, int *child_taps)
{
+ static const uint8_t zero_mac[6];
uint8_t id;
uint8_t i;
int ret;
@@ -1304,11 +1305,12 @@ virtio_init(struct vm_create_params *vcp, int *child_disks, int *child_taps)
return;
}
-#if 0
/* User defined MAC */
- vionet[i].cfg.device_feature = VIRTIO_NET_F_MAC;
- bcopy(&vcp->vcp_macs[i], &vionet[i].mac, 6);
-#endif
+ if (memcmp(zero_mac, &vcp->vcp_macs[i], 6) != 0) {
+ vionet[i].cfg.device_feature =
+ VIRTIO_NET_F_MAC;
+ bcopy(&vcp->vcp_macs[i], &vionet[i].mac, 6);
+ }
}
}
}
diff --git a/usr.sbin/vmd/vm.conf.5 b/usr.sbin/vmd/vm.conf.5
index 77f474686be..8d0ca2e47ac 100644
--- a/usr.sbin/vmd/vm.conf.5
+++ b/usr.sbin/vmd/vm.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: vm.conf.5,v 1.5 2016/05/05 09:00:44 schwarze Exp $
+.\" $OpenBSD: vm.conf.5,v 1.6 2016/10/05 17:30:13 reyk Exp $
.\"
.\" Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
.\" Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: May 5 2016 $
+.Dd $Mdocdate: October 5 2016 $
.Dt VM.CONF 5
.Os
.Sh NAME
@@ -38,6 +38,8 @@ User-defined variables may be defined and used later, simplifying the
configuration file.
.It Sy VM Configuration
Configuration for each individual virtual machine.
+.It Sy Switch Configuration
+Configuration for virtual switches.
.El
.Pp
Within the sections,
@@ -110,18 +112,133 @@ Disk image file (may be specified multiple times to add multiple disk images).
Kernel to load when booting the VM.
.It Cm memory Ar bytes
Memory size of the VM, in bytes, rounded to megabytes.
+.It Cm interface Oo name Oc Op Brq ...
+Network interface to add to the VM.
+The optional
+.Ar name
+can be either
+.Sq tap
+to select the next available
+.Xr tap 4
+interface on the VM host side, this is the default, or
+.Ar tapN
+to select a specific one.
+Valid options are:
+.Bl -tag -width Ds
+.It Cm lladdr Ar etheraddr
+Change the link layer address (MAC address) of the interface on the
+VM guest side.
+The
+.Ar etheraddr
+is specified as six colon-separated hex values.
+If not specified, the address will be set to all zeros and eventually
+randomized by the guest OS inside the VM.
+.It Cm switch Ar name
+Set the virtual switch
+by
+.Ar name .
+See the
+.Sx SWITCH CONFIGURATION
+section about virtual switches.
+This option is ignored if a switch with a matching name cannot be found.
+.Sx
+.It Cm up
+Start the interface forwarding packets.
+This is the default.
+.It Cm down
+Stop the interface from forwarding packets.
+.El
.It Cm interfaces Ar count
-Number of network interfaces to add to the VM.
+Optional minimum number of network interfaces to add to the VM.
+If the
+.Ar count
+is greater than the number of
+.Ic interface
+statements, additional default interfaces will be added.
+.El
+.Sh SWITCH CONFIGURATION
+Virtual switches can be configured at any point in the configuration file;
+they allow
+.Nm switchd
+to add network interfaces of VMs to the underlying switch interfaces
+automatically.
+It is possible to pre-configure switch interfaces using
+.Xr hostname.if 5
+or
+.Xr ifconfig 8 ,
+see the sections
+.Sx BRIDGE
+or
+.Sx SWITCH
+in
+.Xr ifconfig 8
+accordingly.
+.Pp
+Each
+.Ic switch
+section starts with a declaration of the virtual switch:
+.Bl -tag -width Ds
+.It Ic switch Ar name Brq ...
+This name can be any string, and is typically a network name.
+.El
+.Pp
+Followed by a block of parameters that is enclosed in curly brackets:
+.Bl -tag -width Ds
+.It Cm add Ar interface
+Add
+.Ar interface
+as a member of the switch.
+Any network interface can be added, typically as an uplink interface,
+but it can be a member of at most one switch.
+.It Cm enable
+Automatically configure the switch.
+This is the default if neither
+.Cm enable
+nor
+.Cm disable
+is specified.
+.It Cm disable
+Do not configure this switch.
+.It Cm interface Ar name
+Set the
+.Xr switch 4
+or
+.Xr bridge 4
+network interface of this switch.
+If not specified,
+.Ar bridge0
+will be used where the interface unit will be incremented for each switch,
+eg.
+.Ar bridge0 , bridge1 , ...
+If the type is changed to
+.Ar switch0 ,
+it will be used for each following switch.
+.It Cm up
+Start the switch forwarding packets.
+This is the default.
+.It Cm down
+Stop the switch from forwarding packets.
.El
.Sh EXAMPLES
-Create a new VM with 512MB memory, 1 network interface, one disk image
-('disk.img') and boot from kernel '/bsd':
+Create a new VM with 512MB memory, 1 network interface connected to
+.Dq uplink ,
+one disk image
+.Sq disk.img
+and boot from kernel
+.Sq /bsd :
.Bd -literal -offset indent
vm "vm2.example.com" {
memory 512M
- interfaces 1
disk "/var/vmm/vm2-disk.img"
kernel "/bsd"
+ interface { switch "uplink" }
+}
+.Ed
+.Pp
+Create the switch "uplink" with an additional physical network interface:
+.Bd -literal -offset indent
+switch "uplink" {
+ add em0
}
.Ed
.Sh SEE ALSO
diff --git a/usr.sbin/vmd/vmd.c b/usr.sbin/vmd/vmd.c
index c4aadb8419d..c8815be76e0 100644
--- a/usr.sbin/vmd/vmd.c
+++ b/usr.sbin/vmd/vmd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmd.c,v 1.31 2016/10/04 17:17:30 reyk Exp $ */
+/* $OpenBSD: vmd.c,v 1.32 2016/10/05 17:30:13 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -65,7 +65,7 @@ vmd_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg)
{
struct privsep *ps = p->p_ps;
int res = 0, cmd = 0, v = 0;
- struct vm_create_params vcp;
+ struct vmop_create_params vmc;
struct vmop_id vid;
struct vm_terminate_params vtp;
struct vmop_result vmr;
@@ -75,9 +75,9 @@ vmd_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg)
switch (imsg->hdr.type) {
case IMSG_VMDOP_START_VM_REQUEST:
- IMSG_SIZE_CHECK(imsg, &vcp);
- memcpy(&vcp, imsg->data, sizeof(vcp));
- res = config_getvm(ps, &vcp, -1, imsg->hdr.peerid);
+ IMSG_SIZE_CHECK(imsg, &vmc);
+ memcpy(&vmc, imsg->data, sizeof(vmc));
+ res = config_getvm(ps, &vmc, -1, imsg->hdr.peerid);
if (res == -1) {
res = errno;
cmd = IMSG_VMDOP_START_VM_RESPONSE;
@@ -500,6 +500,8 @@ vm_getbyname(const char *name)
{
struct vmd_vm *vm;
+ if (name == NULL)
+ return (NULL);
TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
if (strcmp(vm->vm_params.vcp_name, name) == 0)
return (vm);
@@ -536,9 +538,10 @@ vm_remove(struct vmd_vm *vm)
close(vm->vm_disks[i]);
}
for (i = 0; i < VMM_MAX_NICS_PER_VM; i++) {
- if (vm->vm_ifs[i] != -1)
- close(vm->vm_ifs[i]);
- free(vm->vm_ifnames[i]);
+ if (vm->vm_ifs[i].vif_fd != -1)
+ close(vm->vm_ifs[i].vif_fd);
+ free(vm->vm_ifs[i].vif_name);
+ free(vm->vm_ifs[i].vif_switch);
}
if (vm->vm_kernel != -1)
close(vm->vm_kernel);
@@ -549,6 +552,42 @@ vm_remove(struct vmd_vm *vm)
free(vm);
}
+void
+switch_remove(struct vmd_switch *vsw)
+{
+ struct vmd_if *vif;
+
+ if (vsw == NULL)
+ return;
+
+ TAILQ_REMOVE(env->vmd_switches, vsw, sw_entry);
+
+ while ((vif = TAILQ_FIRST(&vsw->sw_ifs)) != NULL) {
+ free(vif->vif_name);
+ free(vif->vif_switch);
+ TAILQ_REMOVE(&vsw->sw_ifs, vif, vif_entry);
+ free(vif);
+ }
+
+ free(vsw->sw_name);
+ free(vsw);
+}
+
+struct vmd_switch *
+switch_getbyname(const char *name)
+{
+ struct vmd_switch *vsw;
+
+ if (name == NULL)
+ return (NULL);
+ TAILQ_FOREACH(vsw, env->vmd_switches, sw_entry) {
+ if (strcmp(vsw->sw_name, name) == 0)
+ return (vsw);
+ }
+
+ return (NULL);
+}
+
char *
get_string(uint8_t *ptr, size_t len)
{
diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h
index 472b2d970d3..c072e1219b6 100644
--- a/usr.sbin/vmd/vmd.h
+++ b/usr.sbin/vmd/vmd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmd.h,v 1.26 2016/10/04 17:17:30 reyk Exp $ */
+/* $OpenBSD: vmd.h,v 1.27 2016/10/05 17:30:13 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -40,6 +40,7 @@
#define VM_TTYNAME_MAX 16
#define MAX_TAP 256
#define NR_BACKLOG 5
+#define VMD_SWITCH_TYPE "bridge"
#ifdef VMD_DEBUG
#define dprintf(x...) do { log_debug(x); } while(0)
@@ -61,7 +62,11 @@ enum imsg_type {
IMSG_VMDOP_GET_INFO_VM_END_DATA,
IMSG_VMDOP_LOAD,
IMSG_VMDOP_RELOAD,
- IMSG_VMDOP_PRIV_IFDESCR
+ IMSG_VMDOP_PRIV_IFDESCR,
+ IMSG_VMDOP_PRIV_IFADD,
+ IMSG_VMDOP_PRIV_IFCREATE,
+ IMSG_VMDOP_PRIV_IFUP,
+ IMSG_VMDOP_PRIV_IFDOWN
};
struct vmop_result {
@@ -87,14 +92,41 @@ struct vmop_ifreq {
char vfr_value[VM_NAME_MAX];
};
+struct vmop_create_params {
+ struct vm_create_params vmc_params;
+
+ /* userland-only part of the create params */
+ unsigned int vmc_ifflags[VMM_MAX_NICS_PER_VM];
+ char vmc_ifnames[VMM_MAX_NICS_PER_VM][IF_NAMESIZE];
+ char vmc_ifswitch[VMM_MAX_NICS_PER_VM][VM_NAME_MAX];
+};
+
+struct vmd_if {
+ char *vif_name;
+ char *vif_switch;
+ int vif_fd;
+ unsigned int vif_flags;
+ TAILQ_ENTRY(vmd_if) vif_entry;
+};
+TAILQ_HEAD(viflist, vmd_if);
+
+struct vmd_switch {
+ uint32_t sw_id;
+ char *sw_name;
+ char sw_ifname[IF_NAMESIZE];
+ unsigned int sw_flags;
+ struct viflist sw_ifs;
+ TAILQ_ENTRY(vmd_switch) sw_entry;
+};
+TAILQ_HEAD(switchlist, vmd_switch);
+
struct vmd_vm {
struct vm_create_params vm_params;
pid_t vm_pid;
uint32_t vm_vmid;
int vm_kernel;
int vm_disks[VMM_MAX_DISKS_PER_VM];
- int vm_ifs[VMM_MAX_NICS_PER_VM];
- char *vm_ifnames[VMM_MAX_NICS_PER_VM];
+ struct vmd_if vm_ifs[VMM_MAX_NICS_PER_VM];
char *vm_ttyname;
int vm_tty;
uint32_t vm_peerid;
@@ -109,11 +141,13 @@ struct vmd {
int vmd_debug;
int vmd_verbose;
int vmd_noaction;
- int vmd_vmcount;
uint32_t vmd_nvm;
struct vmlist *vmd_vms;
+ uint32_t vmd_nswitches;
+ struct switchlist *vmd_switches;
+
int vmd_fd;
};
@@ -124,11 +158,16 @@ struct vmd_vm *vm_getbyid(uint32_t);
struct vmd_vm *vm_getbyname(const char *);
struct vmd_vm *vm_getbypid(pid_t);
void vm_remove(struct vmd_vm *);
+void switch_remove(struct vmd_switch *);
+struct vmd_switch *switch_getbyname(const char *);
char *get_string(uint8_t *, size_t);
/* priv.c */
void priv(struct privsep *, struct privsep_proc *);
+int priv_getiftype(char *, char *, unsigned int *);
+int priv_findname(const char *, const char **);
int vm_priv_ifconfig(struct privsep *, struct vmd_vm *);
+int vm_priv_brconfig(struct privsep *, struct vmd_switch *);
/* vmm.c */
void vmm(struct privsep *, struct privsep_proc *);
@@ -144,7 +183,7 @@ int config_init(struct vmd *);
void config_purge(struct vmd *, unsigned int);
int config_setreset(struct vmd *, unsigned int);
int config_getreset(struct vmd *, struct imsg *);
-int config_getvm(struct privsep *, struct vm_create_params *,
+int config_getvm(struct privsep *, struct vmop_create_params *,
int, uint32_t);
int config_getdisk(struct privsep *, struct imsg *);
int config_getif(struct privsep *, struct imsg *);
diff --git a/usr.sbin/vmd/vmm.c b/usr.sbin/vmd/vmm.c
index 972cbdea3b0..83215c24023 100644
--- a/usr.sbin/vmd/vmm.c
+++ b/usr.sbin/vmd/vmm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmm.c,v 1.46 2016/10/04 17:17:30 reyk Exp $ */
+/* $OpenBSD: vmm.c,v 1.47 2016/10/05 17:30:13 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -177,7 +177,7 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
{
struct privsep *ps = p->p_ps;
int res = 0, cmd = 0;
- struct vm_create_params vcp;
+ struct vmop_create_params vmc;
struct vm_terminate_params vtp;
struct vmop_result vmr;
uint32_t id = 0;
@@ -185,9 +185,9 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
switch (imsg->hdr.type) {
case IMSG_VMDOP_START_VM_REQUEST:
- IMSG_SIZE_CHECK(imsg, &vcp);
- memcpy(&vcp, imsg->data, sizeof(vcp));
- res = config_getvm(ps, &vcp, imsg->fd, imsg->hdr.peerid);
+ IMSG_SIZE_CHECK(imsg, &vmc);
+ memcpy(&vmc, imsg->data, sizeof(vmc));
+ res = config_getvm(ps, &vmc, imsg->fd, imsg->hdr.peerid);
if (res == -1) {
res = errno;
cmd = IMSG_VMDOP_START_VM_RESPONSE;
@@ -388,6 +388,7 @@ opentap(char *ifname)
int i, fd;
char path[PATH_MAX];
+ strlcpy(ifname, "tap", IF_NAMESIZE);
for (i = 0; i < MAX_TAP; i++) {
snprintf(path, PATH_MAX, "/dev/tap%d", i);
fd = open(path, O_RDWR | O_NONBLOCK);
@@ -432,7 +433,7 @@ start_vm(struct imsg *imsg, uint32_t *id)
struct vmd_vm *vm;
size_t i;
int ret = EINVAL;
- int fds[2];
+ int fds[2], nicfds[VMM_MAX_NICS_PER_VM];
struct vcpu_reg_state vrs;
if ((vm = vm_getbyvmid(imsg->hdr.peerid)) == NULL) {
@@ -470,8 +471,8 @@ start_vm(struct imsg *imsg, uint32_t *id)
}
for (i = 0 ; i < vcp->vcp_nnics; i++) {
- close(vm->vm_ifs[i]);
- vm->vm_ifs[i] = -1;
+ close(vm->vm_ifs[i].vif_fd);
+ vm->vm_ifs[i].vif_fd = -1;
}
close(vm->vm_kernel);
@@ -549,8 +550,11 @@ start_vm(struct imsg *imsg, uint32_t *id)
if (fcntl(con_fd, F_SETFL, O_NONBLOCK) == -1)
fatal("failed to set nonblocking mode on console");
+ for (i = 0; i < VMM_MAX_NICS_PER_VM; i++)
+ nicfds[i] = vm->vm_ifs[i].vif_fd;
+
/* Execute the vcpu run loop(s) for this VM */
- ret = run_vm(vm->vm_disks, vm->vm_ifs, vcp, &vrs);
+ ret = run_vm(vm->vm_disks, nicfds, vcp, &vrs);
_exit(ret != 0);
}