[libvirt] [PATCH v7 1/2] bhyve: add a basic driver
Daniel P. Berrange
berrange at redhat.com
Tue Feb 11 11:20:50 UTC 2014
On Sun, Feb 09, 2014 at 06:46:12PM +0400, Roman Bogorodskiy wrote:
> +static int
> +bhyveBuildDiskArgStr(const virDomainDef *def, virCommandPtr cmd)
> +{
> + virDomainDiskDefPtr disk;
> +
> + if (def->ndisks != 1) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("domain should have one and only one disk defined"));
> + return -1;
> + }
> +
> + disk = def->disks[0];
> +
> + virCommandAddArg(cmd, "-s");
> + virCommandAddArgFormat(cmd, "2:0,ahci-hd,%s", disk->src);
Before accessing disk->src, you need to check what disk->type
is - the 'src' field is only valid for file/block backed disks,
not network backed ones.
Also based on the fact that your arg contains the string 'ahci'
is is correct to say this is exposing a SATA bus disk ?
If so, you also want to validate disk->bus == VIR_DOMAIN_DISK_BUS_SATA
and disk->device == VIR_DOMAIN_DISK_DEVICE_DISK and report
CONFIG_UNSUPPORTED in both cases.
> + /* Clarification about -H and -P flags from Peter Grehan:
> + * -H and -P flags force the guest to exit when it executes IA32 HLT and PAUSE
> + * instructions respectively.
> + *
> + * For the HLT exit, bhyve uses that to infer that the guest is idling and can
> + * be put to sleep until an external event arrives. If this option is not used,
> + * the guest will always use 100% of CPU on the host.
> + *
> + * The PAUSE exit is most useful when there are large numbers of guest VMs running,
> + * since it forces the guest to exit when it spins on a lock acquisition.
> + */
> + virCommandAddArg(cmd, "-H"); /* vmexit from guest on hlt */
> + virCommandAddArg(cmd, "-P"); /* vmexit from guest on pause */
Ok, agree that both of those make sense to enable unconditionally.
> + virCommandAddArg(cmd, "-S");
> + virCommandAddArg(cmd, "31,uart");
Hmm, this is enabling a serial port right ? If so, you only want
todo this if you have def->nserials == 1 I reckon. What is the
string '31' saying ?
> +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);
Curious, so you have to repeat the disk specification in two commands.
Same comment about validating the disk->type before accessing 'src'
> diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c
> new file mode 100644
> index 0000000..e8e082b
> --- /dev/null
> +++ b/src/bhyve/bhyve_driver.c
> +static virDrvOpenStatus
> +bhyveConnectOpen(virConnectPtr conn,
> + virConnectAuthPtr auth ATTRIBUTE_UNUSED,
> + unsigned int flags)
> +{
> + virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
> +
> + if (!conn->uri)
> + return VIR_DRV_OPEN_DECLINED;
This means that you'll never be able to default to "bhyve"
when URI == NULL. Generally we have this auto-detected
eg
if (conn->uri == NULL) {
if (bhyve_driver == NULL) {
return VIR_DRV_OPEN_DECLINED
}
...accept...
} else {
...all the logic below....
See qemuConnectOpen for an example of logic to follow
> +
> + if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "bhyve"))
> + return VIR_DRV_OPEN_DECLINED;
> +
> + if (conn->uri->server)
> + return VIR_DRV_OPEN_DECLINED;
> +
> + if (!STREQ_NULLABLE(conn->uri->path, "/system")) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unexpected bhyve URI path '%s', try bhyve:///system"),
> + conn->uri->path);
> + return VIR_DRV_OPEN_ERROR;
> + }
> +
> + if (bhyve_driver == NULL) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + "%s", _("bhyve state driver is not active"));
> + return VIR_DRV_OPEN_ERROR;
> + }
> +
> + conn->privateData = bhyve_driver;
> +
> + return VIR_DRV_OPEN_SUCCESS;
> +}
> +static virDomainPtr
> +bhyveDomainDefineXML(virConnectPtr conn, const char *xml)
> +{
> + bhyveConnPtr privconn = conn->privateData;
> + virDomainPtr dom = NULL;
> + virDomainDefPtr def = NULL;
> + virDomainDefPtr oldDef = NULL;
> + virDomainObjPtr vm = NULL;
> +
> + if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
> + 1 << VIR_DOMAIN_VIRT_BHYVE,
> + VIR_DOMAIN_XML_INACTIVE)) == NULL) {
> + virReportError(VIR_ERR_INVALID_ARG, "%s",
> + _("Can't parse XML desc"));
> + goto cleanup;
> + }
> +
> + if (!(vm = virDomainObjListAdd(privconn->domains, def,
> + privconn->xmlopt,
> + 0, &oldDef)))
> + goto cleanup;
> +
> + VIR_INFO("Creating domain '%s'", vm->def->name);
> + dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
> + if (dom) dom->id = vm->def->id;
> +
> + if (virDomainSaveConfig(BHYVE_CONFIG_DIR, vm->def) < 0) {
> + goto cleanup;
> + }
Nit-pick: we avoid {} for a single-line body
> +static int
> +bhyveConnectListDefinedDomains(virConnectPtr conn, char **const names,
> + int maxnames)
> +{
> + bhyveConnPtr privconn = conn->privateData;
> + int n;
> +
> + memset(names, 0, sizeof(*names) * maxnames);
> + n = virDomainObjListGetInactiveNames(privconn->domains, names,
> + maxnames, NULL, NULL);
> +
> + return n;
> +}
> +
> +static int
> +bhyveConnectNumOfDefinedDomains(virConnectPtr conn)
> +{
> + bhyveConnPtr privconn = conn->privateData;
> + int count;
> +
> + count = virDomainObjListNumOfDomains(privconn->domains, false,
> + NULL, NULL);
> +
> + return count;
> +}
> +
> +static int
> +bhyveConnectListAllDomains(virConnectPtr conn,
> + virDomainPtr **domains,
> + unsigned int flags)
> +{
> + bhyveConnPtr privconn = conn->privateData;
> + int ret = -1;
> +
> + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
> +
> + ret = virDomainObjListExport(privconn->domains, conn, domains,
> + NULL, flags);
> +
> + return ret;
> +}
> +int
> +virBhyveProcessStart(virConnectPtr conn,
> + bhyveConnPtr driver,
> + virDomainObjPtr vm,
> + virDomainRunningReason reason)
> + VIR_INFO("Loading domain '%s'", vm->def->name);
> + if (virCommandRun(cmd, &status) < 0)
> + goto cleanup;
Now the domain is loaded...
> +
> + if (status != 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Guest failed to load: %d"), status);
> + goto cleanup;
> + }
> +
> + virCommandFree(cmd);
> +
> + VIR_FREE(privconn->pidfile);
> + if (!(privconn->pidfile = virPidFileBuildPath(BHYVE_STATE_DIR,
> + vm->def->name))) {
> + virReportSystemError(errno,
> + "%s", _("Failed to build pidfile path."));
> + goto cleanup;
> + }
> +
> + if (unlink(privconn->pidfile) < 0 &&
> + errno != ENOENT) {
> + virReportSystemError(errno,
> + _("Cannot remove state PID file %s"),
> + privconn->pidfile);
> + goto cleanup;
> + }
> +
> + /* Call bhyve to start the VM */
> + if (!(cmd = virBhyveProcessBuildBhyveCmd(driver,
> + vm)))
> + goto cleanup;
I'd suggest this building is done before loading the domain
so you don't needlessly load the domain before we detect any
possible user configuration errors.
Regards,
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 :|
More information about the libvir-list
mailing list