src/access/viraccessdriverpolkit.c
src/access/viraccessmanager.c
src/bhyve/bhyve_command.c
+src/bhyve/bhyve_device.c
src/bhyve/bhyve_driver.c
src/bhyve/bhyve_process.c
src/conf/capabilities.c
bhyve/bhyve_capabilities.h \
bhyve/bhyve_command.c \
bhyve/bhyve_command.h \
+ bhyve/bhyve_device.c \
+ bhyve/bhyve_device.h \
+ bhyve/bhyve_domain.c \
+ bhyve/bhyve_domain.h \
bhyve/bhyve_driver.h \
bhyve/bhyve_driver.c \
bhyve/bhyve_process.c \
VIR_LOG_INIT("bhyve.bhyve_command");
static int
-bhyveBuildNetArgStr(const virDomainDef *def, virCommandPtr cmd, bool dryRun)
+bhyveBuildNetArgStr(const virDomainDef *def,
+ virDomainNetDefPtr net,
+ virCommandPtr cmd,
+ bool dryRun)
{
- virDomainNetDefPtr net = NULL;
- char *brname = NULL;
+ char macaddr[VIR_MAC_STRING_BUFLEN];
char *realifname = NULL;
int *tapfd = NULL;
- char macaddr[VIR_MAC_STRING_BUFLEN];
+ char *brname = NULL;
+ int actualType = virDomainNetGetActualType(net);
- if (def->nnets != 1) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("domain should have one and only one net defined"));
+ if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+ if (VIR_STRDUP(brname, virDomainNetGetActualBridgeName(net)) < 0)
+ return -1;
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Network type %d is not supported"),
+ virDomainNetGetActualType(net));
return -1;
}
- net = def->nets[0];
-
- if (net) {
- int actualType = virDomainNetGetActualType(net);
-
- if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
- if (VIR_STRDUP(brname, virDomainNetGetActualBridgeName(net)) < 0)
- return -1;
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Network type %d is not supported"),
- virDomainNetGetActualType(net));
+ 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 (!net->ifname ||
- STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
- strchr(net->ifname, '%')) {
+ if (!dryRun) {
+ 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);
- if (VIR_STRDUP(net->ifname, VIR_NET_GENERATED_PREFIX "%d") < 0) {
- VIR_FREE(brname);
- return -1;
- }
+ VIR_FREE(brname);
+ return -1;
}
- if (!dryRun)
- 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;
- }
- }
-
- if (!dryRun) {
realifname = virNetDevTapGetRealDeviceName(net->ifname);
if (realifname == NULL) {
* name
*/
if (virNetDevSetOnline(net->ifname, true) != 0) {
+ VIR_FREE(realifname);
VIR_FREE(net->ifname);
VIR_FREE(brname);
return -1;
virCommandAddArg(cmd, "-s");
- virCommandAddArgFormat(cmd, "1:0,virtio-net,%s,mac=%s",
+ virCommandAddArgFormat(cmd, "%d:0,virtio-net,%s,mac=%s",
+ net->info.addr.pci.slot,
realifname, virMacAddrFormat(&net->mac, macaddr));
+ VIR_FREE(realifname);
return 0;
}
return -1;
}
- virCommandAddArgList(cmd, "-s", "31,lpc", NULL);
+ virCommandAddArgList(cmd, "-s", "1,lpc", NULL);
virCommandAddArg(cmd, "-l");
virCommandAddArgFormat(cmd, "com%d,%s",
chr->target.port + 1, chr->source.data.file.path);
}
static int
-bhyveBuildDiskArgStr(const virDomainDef *def, virCommandPtr cmd)
+bhyveBuildDiskArgStr(const virDomainDef *def ATTRIBUTE_UNUSED,
+ virDomainDiskDefPtr disk,
+ virCommandPtr cmd)
{
- virDomainDiskDefPtr disk;
const char *bus_type;
- 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];
-
switch (disk->bus) {
case VIR_DOMAIN_DISK_BUS_SATA:
bus_type = "ahci-hd";
}
virCommandAddArg(cmd, "-s");
- virCommandAddArgFormat(cmd, "2:0,%s,%s", bus_type,
+ virCommandAddArgFormat(cmd, "%d:0,%s,%s",
+ disk->info.addr.pci.slot, bus_type,
virDomainDiskGetSource(disk));
return 0;
* -S 31,uart,stdio \
* vm0
*/
+ size_t i;
+
virCommandPtr cmd = virCommandNew(BHYVE);
/* CPUs */
virCommandAddArgList(cmd, "-s", "0:0,hostbridge", NULL);
/* Devices */
- if (bhyveBuildNetArgStr(def, cmd, dryRun) < 0)
- goto error;
- if (bhyveBuildDiskArgStr(def, cmd) < 0)
- goto error;
+ for (i = 0; i < def->nnets; i++) {
+ virDomainNetDefPtr net = def->nets[i];
+ if (bhyveBuildNetArgStr(def, net, cmd, dryRun) < 0)
+ goto error;
+ }
+ for (i = 0; i < def->ndisks; i++) {
+ virDomainDiskDefPtr disk = def->disks[i];
+
+ if (bhyveBuildDiskArgStr(def, disk, cmd) < 0)
+ goto error;
+ }
if (bhyveBuildConsoleArgStr(def, cmd) < 0)
goto error;
virCommandAddArg(cmd, def->name);
virCommandPtr cmd;
virDomainDiskDefPtr disk;
- if (def->ndisks != 1) {
+ if (def->ndisks < 1) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("domain should have one and only one disk defined"));
+ _("domain should have at least one disk defined"));
return NULL;
}
--- /dev/null
+/*
+ * bhyve_device.c: bhyve device management
+ *
+ * Copyright (C) 2014 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/>.
+ *
+ * Author: Roman Bogorodskiy
+ */
+
+#include <config.h>
+
+#include "bhyve_device.h"
+#include "domain_addr.h"
+#include "viralloc.h"
+#include "virlog.h"
+#include "virstring.h"
+
+#define VIR_FROM_THIS VIR_FROM_BHYVE
+
+VIR_LOG_INIT("bhyve.bhyve_device");
+
+static int
+bhyveCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
+ virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
+ virDomainDeviceInfoPtr info,
+ void *opaque)
+{
+ int ret = -1;
+ virDomainPCIAddressSetPtr addrs = opaque;
+ virDevicePCIAddressPtr addr = &info->addr.pci;
+
+ if (addr->domain == 0 && addr->bus == 0) {
+ if (addr->slot == 0) {
+ return 0;
+ } else if (addr->slot == 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("PCI bus 0 slot 1 is reserved for the implicit "
+ "LPC PCI-ISA bridge"));
+ return -1;
+ }
+ }
+
+ if (virDomainPCIAddressReserveSlot(addrs, addr, VIR_PCI_CONNECT_TYPE_PCI) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ return ret;
+}
+
+virDomainPCIAddressSetPtr
+bhyveDomainPCIAddressSetCreate(virDomainDefPtr def ATTRIBUTE_UNUSED, unsigned int nbuses)
+{
+ virDomainPCIAddressSetPtr addrs;
+
+ if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL)
+ return NULL;
+
+ if (virDomainPCIAddressBusSetModel(&addrs->buses[0],
+ VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0)
+ goto error;
+
+ if (virDomainDeviceInfoIterate(def, bhyveCollectPCIAddress, addrs) < 0)
+ goto error;
+
+ return addrs;
+
+ error:
+ virDomainPCIAddressSetFree(addrs);
+ return NULL;
+}
+
+static int
+bhyveAssignDevicePCISlots(virDomainDefPtr def,
+ virDomainPCIAddressSetPtr addrs)
+{
+ size_t i;
+ virDevicePCIAddress lpc_addr;
+
+ /* explicitly reserve slot 1 for LPC-ISA bridge */
+ memset(&lpc_addr, 0, sizeof(lpc_addr));
+ lpc_addr.slot = 0x1;
+
+ if (virDomainPCIAddressReserveSlot(addrs, &lpc_addr, VIR_PCI_CONNECT_TYPE_PCI) < 0)
+ goto error;
+
+ for (i = 0; i < def->nnets; i++) {
+ if (def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+ continue;
+ if (virDomainPCIAddressReserveNextSlot(addrs,
+ &def->nets[i]->info,
+ VIR_PCI_CONNECT_TYPE_PCI) < 0)
+ goto error;
+ }
+
+ for (i = 0; i < def->ndisks; i++) {
+ if (def->disks[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+ def->disks[i]->info.addr.pci.slot != 0)
+ continue;
+ if (virDomainPCIAddressReserveNextSlot(addrs,
+ &def->disks[i]->info,
+ VIR_PCI_CONNECT_TYPE_PCI) < 0)
+ goto error;
+ }
+
+ for (i = 0; i < def->ncontrollers; i++) {
+ if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
+ if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+ continue;
+ if (def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT)
+ continue;
+
+ if (virDomainPCIAddressReserveNextSlot(addrs,
+ &def->controllers[i]->info,
+ VIR_PCI_CONNECT_TYPE_PCI) < 0)
+ goto error;
+ }
+
+ }
+
+ return 0;
+
+ error:
+ return -1;
+}
+
+int bhyveDomainAssignPCIAddresses(virDomainDefPtr def,
+ virDomainObjPtr obj)
+{
+ virDomainPCIAddressSetPtr addrs = NULL;
+ bhyveDomainObjPrivatePtr priv = NULL;
+
+ int ret = -1;
+
+ if (!(addrs = bhyveDomainPCIAddressSetCreate(def, 1)))
+ goto cleanup;
+
+ if (bhyveAssignDevicePCISlots(def, addrs) < 0)
+ goto cleanup;
+
+ if (obj && obj->privateData) {
+ priv = obj->privateData;
+ if (addrs) {
+ virDomainPCIAddressSetFree(priv->pciaddrs);
+ priv->persistentAddrs = 1;
+ priv->pciaddrs = addrs;
+ } else {
+ priv->persistentAddrs = 0;
+ }
+ }
+
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+
+int bhyveDomainAssignAddresses(virDomainDefPtr def, virDomainObjPtr obj)
+{
+ return bhyveDomainAssignPCIAddresses(def, obj);
+}
--- /dev/null
+/*
+ * bhyve_device.h: bhyve device management headers
+ *
+ * Copyright (C) 2014 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/>.
+ *
+ * Author: Roman Bogorodskiy
+ */
+
+#ifndef __BHYVE_DEVICE_H__
+# define __BHYVE_DEVICE_H__
+
+# include "domain_conf.h"
+# include "virpci.h"
+# include "bhyve_domain.h"
+
+int bhyveDomainAssignPCIAddresses(virDomainDefPtr def, virDomainObjPtr obj);
+
+virDomainPCIAddressSetPtr bhyveDomainPCIAddressSetCreate(virDomainDefPtr def,
+ unsigned int nbuses);
+
+int bhyveDomainAssignAddresses(virDomainDefPtr def, virDomainObjPtr obj)
+ ATTRIBUTE_NONNULL(1);
+
+#endif /* __BHYVE_DEVICE_H__ */
--- /dev/null
+/*
+ * bhyve_domain.c: bhyve domain private state
+ *
+ * Copyright (C) 2014 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/>.
+ *
+ * Author: Roman Bogorodskiy
+ */
+
+#include <config.h>
+
+#include "bhyve_device.h"
+#include "bhyve_domain.h"
+#include "viralloc.h"
+#include "virlog.h"
+
+#define VIR_FROM_THIS VIR_FROM_BHYVE
+
+VIR_LOG_INIT("bhyve.bhyve_domain");
+
+static void *
+bhyveDomainObjPrivateAlloc(void)
+{
+ bhyveDomainObjPrivatePtr priv;
+
+ if (VIR_ALLOC(priv) < 0)
+ return NULL;
+
+ return priv;
+}
+
+static void
+bhyveDomainObjPrivateFree(void *data)
+{
+ bhyveDomainObjPrivatePtr priv = data;
+
+ virDomainPCIAddressSetFree(priv->pciaddrs);
+
+ VIR_FREE(priv);
+}
+
+virDomainXMLPrivateDataCallbacks virBhyveDriverPrivateDataCallbacks = {
+ .alloc = bhyveDomainObjPrivateAlloc,
+ .free = bhyveDomainObjPrivateFree,
+};
+
+static int
+bhyveDomainDefPostParse(virDomainDefPtr def,
+ virCapsPtr caps ATTRIBUTE_UNUSED,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ /* Add an implicit PCI root controller */
+ if (virDomainDefMaybeAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0,
+ VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0)
+ return -1;
+
+ return 0;
+}
+
+virDomainDefParserConfig virBhyveDriverDomainDefParserConfig = {
+ .domainPostParseCallback = bhyveDomainDefPostParse,
+};
--- /dev/null
+/*
+ * bhyve_domain.h: bhyve domain private state headers
+ *
+ * Copyright (C) 2014 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/>.
+ *
+ * Author: Roman Bogorodskiy
+ */
+
+#ifndef __BHYVE_DOMAIN_H__
+# define __BHYVE_DOMAIN_H__
+
+# include "domain_addr.h"
+# include "domain_conf.h"
+
+typedef struct _bhyveDomainObjPrivate bhyveDomainObjPrivate;
+typedef bhyveDomainObjPrivate *bhyveDomainObjPrivatePtr;
+struct _bhyveDomainObjPrivate {
+ virDomainPCIAddressSetPtr pciaddrs;
+ bool persistentAddrs;
+};
+
+extern virDomainXMLPrivateDataCallbacks virBhyveDriverPrivateDataCallbacks;
+extern virDomainDefParserConfig virBhyveDriverDomainDefParserConfig;
+
+#endif /* __BHYVE_DOMAIN_H__ */
#include "viraccessapicheck.h"
#include "nodeinfo.h"
+#include "bhyve_device.h"
#include "bhyve_driver.h"
#include "bhyve_command.h"
+#include "bhyve_domain.h"
#include "bhyve_process.h"
#include "bhyve_utils.h"
#include "bhyve_capabilities.h"
if (virDomainDefineXMLEnsureACL(conn, def) < 0)
goto cleanup;
+ if (bhyveDomainAssignAddresses(def, NULL) < 0)
+ goto cleanup;
+
if (!(vm = virDomainObjListAdd(privconn->domains, def,
privconn->xmlopt,
0, &oldDef)))
VIR_DOMAIN_XML_INACTIVE)))
goto cleanup;
+ if (bhyveDomainAssignAddresses(def, NULL) < 0)
+ goto cleanup;
+
if (!(loadcmd = virBhyveProcessBuildLoadCmd(privconn, def)))
goto cleanup;
if (virDomainCreateXMLEnsureACL(conn, def) < 0)
goto cleanup;
+ if (bhyveDomainAssignAddresses(def, NULL) < 0)
+ goto cleanup;
+
if (!(vm = virDomainObjListAdd(privconn->domains, def,
privconn->xmlopt,
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, NULL)))
if (!(bhyve_driver->caps = virBhyveCapsBuild()))
goto cleanup;
- if (!(bhyve_driver->xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL)))
+ if (!(bhyve_driver->xmlopt = virDomainXMLOptionNew(&virBhyveDriverDomainDefParserConfig,
+ &virBhyveDriverPrivateDataCallbacks,
+ NULL)))
goto cleanup;
if (!(bhyve_driver->domains = virDomainObjListNew()))
#include <net/if.h>
#include <net/if_tap.h>
+#include "bhyve_device.h"
#include "bhyve_process.h"
#include "bhyve_command.h"
#include "datatypes.h"
goto cleanup;
}
+ if (bhyveDomainAssignAddresses(vm->def, NULL) < 0)
+ goto cleanup;
+
/* Call bhyve to start the VM */
if (!(cmd = virBhyveProcessBuildBhyveCmd(driver,
vm->def,
/usr/sbin/bhyve -c 1 -m 214 -A -I -H -P -s 0:0,hostbridge \
--s 1:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
+-s 3:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
-s 2:0,ahci-hd,/tmp/freebsd.img bhyve
<driver name='file' type='raw'/>
<source file='/tmp/freebsd.img'/>
<target dev='hda' bus='sata'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</disk>
<interface type='bridge'>
<model type='virtio'/>
<source bridge="virbr0"/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
</devices>
</domain>
/usr/sbin/bhyve -c 1 -m 214 -H -P -s 0:0,hostbridge \
--s 1:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
+-s 3:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
-s 2:0,ahci-hd,/tmp/freebsd.img bhyve
<driver name='file' type='raw'/>
<source file='/tmp/freebsd.img'/>
<target dev='hda' bus='sata'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</disk>
<interface type='bridge'>
<model type='virtio'/>
<source bridge="virbr0"/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
</devices>
</domain>
/usr/sbin/bhyve -c 1 -m 214 -H -P -s 0:0,hostbridge \
--s 1:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
+-s 3:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
-s 2:0,ahci-hd,/tmp/freebsd.img \
--s 31,lpc -l com1,/dev/nmdm0A bhyve
+-s 1,lpc -l com1,/dev/nmdm0A bhyve
<driver name='file' type='raw'/>
<source file='/tmp/freebsd.img'/>
<target dev='hda' bus='sata'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</disk>
<interface type='bridge'>
<model type='virtio'/>
<source bridge="virbr0"/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<console type='nmdm'>
<source master='/dev/nmdm0A' slave='/dev/nmdm0B'/>
/usr/sbin/bhyve -c 1 -m 214 -H -P -s 0:0,hostbridge \
--s 1:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
+-s 3:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
-s 2:0,virtio-blk,/tmp/freebsd.img bhyve
<driver name='file' type='raw'/>
<source file='/tmp/freebsd.img'/>
<target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</disk>
<interface type='bridge'>
<model type='virtio'/>
<source bridge="virbr0"/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
</devices>
</domain>
/usr/sbin/bhyve -c 1 -m 214 -H -P -s 0:0,hostbridge \
--s 1:0,virtio-net,faketapdev,mac=52:54:00:22:ee:11 \
+-s 3:0,virtio-net,faketapdev,mac=52:54:00:22:ee:11 \
-s 2:0,ahci-hd,/tmp/freebsd.img bhyve
<driver name='file' type='raw'/>
<source file='/tmp/freebsd.img'/>
<target dev='hda' bus='sata'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</disk>
<interface type='bridge'>
<mac address="52:54:00:22:ee:11"/>
<model type='virtio'/>
<source bridge="virbr0"/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
</devices>
</domain>
/usr/sbin/bhyve -c 1 -m 214 -H -P -s 0:0,hostbridge \
--s 1:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
+-s 3:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
-s 2:0,ahci-hd,/tmp/freebsd.img \
--s 31,lpc -l com1,/dev/nmdm0A bhyve
+-s 1,lpc -l com1,/dev/nmdm0A bhyve
<driver name='file' type='raw'/>
<source file='/tmp/freebsd.img'/>
<target dev='hda' bus='sata'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</disk>
<interface type='bridge'>
<model type='virtio'/>
<source bridge="virbr0"/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='nmdm'>
<source master='/dev/nmdm0A' slave='/dev/nmdm0B'/>