On Thu, Jan 23, 2014 at 11:05:26PM +0400, Roman Bogorodskiy wrote: > At this point it has a limited functionality and is highly > experimental. Supported domain operations are: > > * define > * start > * destroy > * dumpxml > * dominfo > > It's only possible to have only one disk device and only one > network, which should be of type bridge. > diff --git a/configure.ac b/configure.ac > index 3a70375..bfbd3a8 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -524,6 +524,10 @@ AC_ARG_WITH([parallels], > [AS_HELP_STRING([--with-parallels], > [add Parallels Cloud Server support @<:@default=check@:>@])]) > m4_divert_text([DEFAULTS], [with_parallels=check]) > +AC_ARG_WITH([bhyve], > + [AS_HELP_STRING([--with-bhyve], > + [add BHyVe support @<:@default=check@:>@])]) > +m4_divert_text([DEFAULTS], [with_bhyve=check]) I think it is probably possible to move this into the LIBVIRT_DRIVER_CHECK_BHYVE macro too. If that doesn't work then just create a LIBVIRT_DRIVER_ARG_BHYVE macro for it. Then we have everything in the isolated .m4 file > AC_ARG_WITH([test], > [AS_HELP_STRING([--with-test], > [add test driver support @<:@default=yes@:>@])]) > @@ -1031,6 +1035,12 @@ fi > AM_CONDITIONAL([WITH_PARALLELS], [test "$with_parallels" = "yes"]) > > dnl > +dnl Checks for bhyve driver > +dnl > + > +LIBVIRT_DRIVER_CHECK_BHYVE > + > +dnl > dnl check for shell that understands <> redirection without truncation, > dnl needed by src/qemu/qemu_monitor_{text,json}.c. > dnl > @@ -2677,6 +2687,7 @@ AC_MSG_NOTICE([ PHYP: $with_phyp]) > AC_MSG_NOTICE([ ESX: $with_esx]) > AC_MSG_NOTICE([ Hyper-V: $with_hyperv]) > AC_MSG_NOTICE([Parallels: $with_parallels]) > +LIBIVRT_DRIVER_RESULT_BHYVE > AC_MSG_NOTICE([ Test: $with_test]) > AC_MSG_NOTICE([ Remote: $with_remote]) > AC_MSG_NOTICE([ Network: $with_network]) > diff --git a/src/Makefile.am b/src/Makefile.am > index 8f77658..6b95f64 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -515,6 +515,7 @@ DRIVER_SOURCE_FILES = \ > $(NULL) > > STATEFUL_DRIVER_SOURCE_FILES = \ > + $(BHYVE_DRIVER_SOURCES) \ > $(INTERFACE_DRIVER_SOURCES) \ > $(LIBXL_DRIVER_SOURCES) \ > $(LXC_DRIVER_SOURCES) \ Nit-pick - inconsistent indentation - the other lines use tabs, but you've used spaces. Although we dislike tabs, just follow existing practice in this file > @@ -772,6 +773,15 @@ PARALLELS_DRIVER_SOURCES = \ > parallels/parallels_storage.c \ > parallels/parallels_network.c > > +BHYVE_DRIVER_SOURCES = \ > + bhyve/bhyve_command.c \ > + bhyve/bhyve_command.h \ > + bhyve/bhyve_driver.h \ > + bhyve/bhyve_driver.c \ > + bhyve/bhyve_process.c \ > + bhyve/bhyve_process.h \ > + bhyve/bhyve_utils.h Same indentation note here. > diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c > new file mode 100644 > index 0000000..f2988cf > --- /dev/null > +++ b/src/bhyve/bhyve_command.c > @@ -0,0 +1,269 @@ > +static char* > +virTapGetRealDeviceName(char *name) Can you aim to use 'virBhyve' as the pefix for absolutely every function and struct you define in src/bhyve/ files. We've not been all that good at this in other virt drivers but its the rough goal we're aiming for is to have all function prefixes match filename prefix. > +{ > + /* This is an ugly hack, because if we rename > + * tap device to vnet%d, its device name will be > + * still /dev/tap%d, and bhyve tries too open /dev/tap%d, > + * so we have to find the real name > + */ > + char *ret = NULL; > + struct dirent *dp; > + char *devpath = NULL; > + int fd; > + > + DIR* dirp = opendir("/dev"); '*' should associate with the variable rather than the type. > + if (dirp == NULL) { > + return NULL; > + } virReportSystemError() when this fails. > + > + while ((dp = readdir(dirp)) != NULL) { > + if (STRPREFIX(dp->d_name, "tap")) { > + struct ifreq ifr; > + if (virAsprintf(&devpath, "/dev/%s", dp->d_name) < 0) { > + goto cleanup; > + } > + if ((fd = open(devpath, O_RDWR)) < 0) > + goto cleanup; virReportSystemError() > + > + if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) > + goto cleanup; virReportSystemError() > + > + if (STREQ(name, ifr.ifr_name)) { > + /* we can ignore the return value > + * because we still have nothing > + * to do but return; > + */ > + ignore_value(VIR_STRDUP(ret, dp->d_name)); > + goto cleanup; > + } > + > + VIR_FREE(devpath); > + VIR_FORCE_CLOSE(fd); > + } > + } > + > +cleanup: > + VIR_FREE(devpath); > + VIR_FORCE_CLOSE(fd); > + closedir(dirp); > + return ret; > +} > + > +static int > +bhyveBuildNetArgStr(const virDomainDef *def, virCommandPtr cmd) > +{ > + virDomainNetDefPtr net = NULL; > + char *brname = NULL; > + char *realifname = NULL; > + int *tapfd = NULL; > + > + if (def->nnets != 1) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > + _("domain should have one and only one net defined")); > + return -1; > + } > + > + net = def->nets[0]; > + > + if (net != NULL) { > + int actualType = virDomainNetGetActualType(net); > + > + if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { > + if (VIR_STRDUP(brname, virDomainNetGetActualBridgeName(net)) < 0) > + return -1L; > + } else { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + _("Network type %d is not supported"), > + virDomainNetGetActualType(net)); > + return -1; > + } > + > + if (!net->ifname || > + STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) || > + strchr(net->ifname, '%')) { > + VIR_FREE(net->ifname); > + if (VIR_STRDUP(net->ifname, VIR_NET_GENERATED_PREFIX "%d") < 0) { > + VIR_FREE(brname); > + return -1; > + } > + } > + > + if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, > + def->uuid, tapfd, 1, > + virDomainNetGetActualVirtPortProfile(net), > + virDomainNetGetActualVlan(net), > + VIR_NETDEV_TAP_CREATE_IFUP | VIR_NETDEV_TAP_CREATE_PERSIST) < 0) { > + VIR_FREE(net->ifname); > + VIR_FREE(brname); > + return -1; > + } > + } > + > + realifname = virTapGetRealDeviceName(net->ifname); > + > + if (realifname == NULL) { > + VIR_FREE(net->ifname); > + VIR_FREE(brname); > + return -1; > + } > + > + VIR_INFO("%s -> %s", net->ifname, realifname); s/INFO/DEBUG/ > + /* hack on top of other hack: we need to set > + * interface to 'UP' again after re-opening to find its > + * name > + */ > + if (virNetDevSetOnline(net->ifname, true) != 0) { > + VIR_FREE(net->ifname); > + VIR_FREE(brname); > + return -1; > + } > + > + virCommandAddArg(cmd, "-s"); > + virCommandAddArg(cmd, "0:0,hostbridge"); > + virCommandAddArg(cmd, "-s"); > + virCommandAddArgFormat(cmd, "1:0,virtio-net,%s", realifname); > + > + return 0; > +} > +virCommandPtr > +virBhyveProcessBuildBhyveCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED, > + virDomainObjPtr vm) > +{ > + /* > + * /usr/sbin/bhyve -c 2 -m 256 -AI -H -P \ > + * -s 0:0,hostbridge \ > + * -s 1:0,virtio-net,tap0 \ > + * -s 2:0,ahci-hd,${IMG} \ > + * -S 31,uart,stdio \ > + * vm0 > + */ > + virCommandPtr cmd = NULL; > + cmd = virCommandNew(BHYVE); simpler to merge these onto 1 line. > + > + /* CPUs */ > + virCommandAddArg(cmd, "-c"); > + virCommandAddArgFormat(cmd, "%d", vm->def->vcpus); > + > + /* Memory */ > + virCommandAddArg(cmd, "-m"); > + virCommandAddArgFormat(cmd, "%llu", > + VIR_DIV_UP(vm->def->mem.max_balloon, 1024)); > + > + /* Options */ > + virCommandAddArg(cmd, "-A"); /* Create an ACPI table */ You can look at the 'acpi' features flag to turn this on/off > + virCommandAddArg(cmd, "-I"); /* Present ioapic to the guest */ Likewise you can look at the 'apic' features flag to turn this on/off > + virCommandAddArg(cmd, "-H"); /* vmexit from guest on hlt */ > + virCommandAddArg(cmd, "-P"); /* vmexit from guest on pause */ What's the functional effect of having these set, or not ? > + > + /* Devices */ > + if (bhyveBuildNetArgStr(vm->def, cmd) < 0) > + goto error; > + if (bhyveBuildDiskArgStr(vm->def, cmd) < 0) > + goto error; > + virCommandAddArg(cmd, "-S"); > + virCommandAddArg(cmd, "31,uart"); > + virCommandAddArg(cmd, vm->def->name); > + > + return cmd; > + > +error: > + virCommandFree(cmd); > + return NULL; > +} > + > +virCommandPtr > +virBhyveProcessBuildDestroyCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED, > + virDomainObjPtr vm) > +{ > + virCommandPtr cmd = virCommandNew(BHYVECTL); > + > + virCommandAddArg(cmd, "--destroy"); > + virCommandAddArgPair(cmd, "--vm", vm->def->name); > + > + return cmd; > +} > + > +virCommandPtr > +virBhyveProcessBuildLoadCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED, > + virDomainObjPtr vm) > +{ > + virCommandPtr cmd; > + virDomainDiskDefPtr disk = vm->def->disks[0]; > + > + cmd = virCommandNew(BHYVELOAD); > + > + /* Memory */ > + virCommandAddArg(cmd, "-m"); > + virCommandAddArgFormat(cmd, "%llu", > + VIR_DIV_UP(vm->def->mem.max_balloon, 1024)); > + > + /* Image path */ > + virCommandAddArg(cmd, "-d"); > + virCommandAddArgFormat(cmd, disk->src); > + > + /* VM name */ > + virCommandAddArg(cmd, vm->def->name); > + > + return cmd; > +} > diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c > new file mode 100644 > index 0000000..5ddb26a > --- /dev/null > +++ b/src/bhyve/bhyve_driver.c > diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c > new file mode 100644 > index 0000000..95553d7 > --- /dev/null > +++ b/src/bhyve/bhyve_process.c > @@ -0,0 +1,205 @@ > +/* > + * bhyve_process.c: bhyve process management > + * > + * Copyright (C) 2013 Roman Bogorodskiy > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library. If not, see > + * <http://www.gnu.org/licenses/>. > + * > + */ > + > +#include <config.h> > + > +#include <fcntl.h> > +#include <sys/types.h> > +#include <dirent.h> > +#include <sys/ioctl.h> > +#include <net/if.h> > +#include <net/if_tap.h> > + > +#include "bhyve_process.h" > +#include "bhyve_command.h" > +#include "datatypes.h" > +#include "virerror.h" > +#include "virlog.h" > +#include "virfile.h" > +#include "viralloc.h" > +#include "vircommand.h" > +#include "virstring.h" > +#include "virpidfile.h" > +#include "virprocess.h" > +#include "virnetdev.h" > +#include "virnetdevbridge.h" > +#include "virnetdevtap.h" > + > +#define VIR_FROM_THIS VIR_FROM_BHYVE > + > +int > +virBhyveProcessStart(virConnectPtr conn, > + bhyveConnPtr driver, > + virDomainObjPtr vm, > + virDomainRunningReason reason ATTRIBUTE_UNUSED) > +{ > + char *logfile = NULL; > + int logfd = -1; > + off_t pos = -1; > + char ebuf[1024]; > + virCommandPtr cmd = NULL; > + bhyveConnPtr privconn = conn->privateData; > + int ret = -1, status; > + > + if (vm->def->ndisks != 1) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > + _("Domain should have one and only one disk defined")); > + return -1; > + } I'd suggest that can live in just the virBhyveProcessBuildBhyveCmd method > +int > +virBhyveProcessStop(bhyveConnPtr driver, > + virDomainObjPtr vm, > + virDomainShutoffReason reason ATTRIBUTE_UNUSED) > +{ > + int i; > + int ret = -1; > + int status; > + virCommandPtr cmd = NULL; > + Still want to sanity check with virDomainObjIsActive() before proceeeding there > + /* First, try to kill 'bhyve' process */ > + if (virProcessKillPainfully(vm->pid, true) != 0) > + VIR_WARN("Failed to gracefully stop bhyve VM '%s' (pid: %llu)", > + vm->def->name, > + (unsigned long long)vm->pid); > + > + for (i = 0; i < vm->def->nnets; i++) { > + virDomainNetDefPtr net = vm->def->nets[i]; > + int actualType = virDomainNetGetActualType(net); > + > + if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { > + ignore_value(virNetDevBridgeRemovePort( > + virDomainNetGetActualBridgeName(net), > + net->ifname)); > + ignore_value(virNetDevTapDelete(net->ifname)); > + } > + } > + > + /* No matter if shutdown was successful or not, we > + * need to unload the VM */ > + if (!(cmd = virBhyveProcessBuildDestroyCmd(driver, vm))) > + goto cleanup; > + > + if (virCommandRun(cmd, &status) < 0) > + goto cleanup; > + > + if (status != 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Guest failed to stop: %d"), status); > + goto cleanup; > + } > + > + ret = 0; > + > +cleanup: > + virCommandFree(cmd); > + return ret; > +} > + Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list