[libvirt] [PATCH v2] bhyve: implement PCI address allocation

Roman Bogorodskiy bogorodskiy at gmail.com
Sun Apr 20 16:15:15 UTC 2014


Automatically allocate PCI addresses for devices instead
of hardcoding them in the driver code. The current
allocation schema is to dedicate an entire slot for each devices.

Also, allow having arbitrary number of devices.
---
 po/POTFILES.in                                     |   1 +
 src/Makefile.am                                    |   4 +
 src/bhyve/bhyve_command.c                          | 131 ++++-----
 src/bhyve/bhyve_device.c                           | 308 +++++++++++++++++++++
 src/bhyve/bhyve_device.h                           |  41 +++
 src/bhyve/bhyve_domain.c                           |  75 +++++
 src/bhyve/bhyve_domain.h                           |  41 +++
 src/bhyve/bhyve_driver.c                           |   9 +-
 .../bhyvexml2argvdata/bhyvexml2argv-acpiapic.args  |   2 +-
 tests/bhyvexml2argvdata/bhyvexml2argv-acpiapic.xml |   2 +
 tests/bhyvexml2argvdata/bhyvexml2argv-base.args    |   2 +-
 tests/bhyvexml2argvdata/bhyvexml2argv-base.xml     |   2 +
 tests/bhyvexml2argvdata/bhyvexml2argv-console.args |   4 +-
 tests/bhyvexml2argvdata/bhyvexml2argv-console.xml  |   2 +
 .../bhyvexml2argv-disk-virtio.args                 |   2 +-
 .../bhyvexml2argv-disk-virtio.xml                  |   2 +
 tests/bhyvexml2argvdata/bhyvexml2argv-macaddr.args |   2 +-
 tests/bhyvexml2argvdata/bhyvexml2argv-macaddr.xml  |   2 +
 tests/bhyvexml2argvdata/bhyvexml2argv-serial.args  |   4 +-
 tests/bhyvexml2argvdata/bhyvexml2argv-serial.xml   |   2 +
 20 files changed, 559 insertions(+), 79 deletions(-)
 create mode 100644 src/bhyve/bhyve_device.c
 create mode 100644 src/bhyve/bhyve_device.h
 create mode 100644 src/bhyve/bhyve_domain.c
 create mode 100644 src/bhyve/bhyve_domain.h

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 122b853..d1eefef 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -9,6 +9,7 @@ gnulib/lib/regcomp.c
 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
diff --git a/src/Makefile.am b/src/Makefile.am
index 21d56fc..6c77ef0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -782,6 +782,10 @@ BHYVE_DRIVER_SOURCES =						\
 		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				\
diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c
index a2da34a..8b2501e 100644
--- a/src/bhyve/bhyve_command.c
+++ b/src/bhyve/bhyve_command.c
@@ -41,21 +41,14 @@ VIR_LOG_INIT("bhyve.bhyve_command");
 static int
 bhyveBuildNetArgStr(const virDomainDef *def, virCommandPtr cmd)
 {
-    virDomainNetDefPtr net = NULL;
-    char *brname = NULL;
-    char *realifname = NULL;
-    int *tapfd = NULL;
     char macaddr[VIR_MAC_STRING_BUFLEN];
+    size_t i;
 
-    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) {
+    for (i = 0; i < def->nnets; i++) {
+        char *realifname = NULL;
+        int *tapfd = NULL;
+        char *brname = NULL;
+        virDomainNetDefPtr net = net = def->nets[i];;
         int actualType = virDomainNetGetActualType(net);
 
         if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
@@ -87,30 +80,31 @@ bhyveBuildNetArgStr(const virDomainDef *def, virCommandPtr cmd)
             VIR_FREE(brname);
             return -1;
         }
-    }
 
-    realifname = virNetDevTapGetRealDeviceName(net->ifname);
+        realifname = virNetDevTapGetRealDeviceName(net->ifname);
 
-    if (realifname == NULL) {
-        VIR_FREE(net->ifname);
-        VIR_FREE(brname);
-        return -1;
-    }
+        if (realifname == NULL) {
+            VIR_FREE(net->ifname);
+            VIR_FREE(brname);
+            return -1;
+        }
 
-    VIR_DEBUG("%s -> %s", net->ifname, realifname);
-    /* 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;
-    }
+        VIR_DEBUG("%s -> %s", net->ifname, realifname);
+        /* 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");
-    virCommandAddArgFormat(cmd, "1:0,virtio-net,%s,mac=%s",
-                           realifname, virMacAddrFormat(&net->mac, macaddr));
+        virCommandAddArg(cmd, "-s");
+        virCommandAddArgFormat(cmd, "%d:0,virtio-net,%s,mac=%s",
+                               net->info.addr.pci.slot,
+                               realifname, virMacAddrFormat(&net->mac, macaddr));
+    }
 
     return 0;
 }
@@ -139,7 +133,7 @@ bhyveBuildConsoleArgStr(const virDomainDef *def, virCommandPtr cmd)
         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);
@@ -150,46 +144,43 @@ bhyveBuildConsoleArgStr(const virDomainDef *def, virCommandPtr cmd)
 static int
 bhyveBuildDiskArgStr(const virDomainDef *def, virCommandPtr cmd)
 {
-    virDomainDiskDefPtr disk;
     const char *bus_type;
+    size_t i;
+
+    for (i = 0; i < def->ndisks; i++) {
+        virDomainDiskDefPtr disk = def->disks[i];
+
+        switch (disk->bus) {
+        case VIR_DOMAIN_DISK_BUS_SATA:
+            bus_type = "ahci-hd";
+            break;
+        case VIR_DOMAIN_DISK_BUS_VIRTIO:
+            bus_type = "virtio-blk";
+            break;
+        default:
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("unsupported disk bus type"));
+            return -1;
+        }
 
-    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";
-        break;
-    case VIR_DOMAIN_DISK_BUS_VIRTIO:
-        bus_type = "virtio-blk";
-        break;
-    default:
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("unsupported disk bus type"));
-        return -1;
-    }
+        if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("unsupported disk device"));
+            return -1;
+        }
 
-    if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("unsupported disk device"));
-        return -1;
-    }
+        if (virDomainDiskGetType(disk) != VIR_STORAGE_TYPE_FILE) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("unsupported disk type"));
+            return -1;
+        }
 
-    if (virDomainDiskGetType(disk) != VIR_STORAGE_TYPE_FILE) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("unsupported disk type"));
-        return -1;
+        virCommandAddArg(cmd, "-s");
+        virCommandAddArgFormat(cmd, "%d:0,%s,%s",
+                               disk->info.addr.pci.slot, bus_type,
+                               virDomainDiskGetSource(disk));
     }
 
-    virCommandAddArg(cmd, "-s");
-    virCommandAddArgFormat(cmd, "2:0,%s,%s", bus_type,
-                           virDomainDiskGetSource(disk));
-
     return 0;
 }
 
@@ -272,9 +263,9 @@ virBhyveProcessBuildLoadCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED,
     virCommandPtr cmd;
     virDomainDiskDefPtr disk;
 
-    if (vm->def->ndisks != 1) {
+    if (vm->def->ndisks < 1) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("domain should have one and only one disk defined"));
+                       _("domain should have more than one disk defined"));
         return NULL;
     }
 
diff --git a/src/bhyve/bhyve_device.c b/src/bhyve/bhyve_device.c
new file mode 100644
index 0000000..ef4043e
--- /dev/null
+++ b/src/bhyve/bhyve_device.c
@@ -0,0 +1,308 @@
+/*
+ * 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 "viralloc.h"
+#include "virlog.h"
+#include "virstring.h"
+
+#define VIR_FROM_THIS VIR_FROM_BHYVE
+
+VIR_LOG_INIT("bhyve.bhyve_device");
+
+#define BHYVE_PCI_ADDRESS_SLOT_LAST 31
+
+typedef struct {
+    virDomainControllerModelPCI model;
+
+    size_t minSlot, maxSlot; /* usually 0,0 or 1,31 */
+    uint8_t slots[BHYVE_PCI_ADDRESS_SLOT_LAST + 1];
+} bhyveDomainPCIAddressBus;
+
+typedef bhyveDomainPCIAddressBus *bhyveDomainPCIAddressBusPtr;
+
+struct _bhyveDomainPCIAddressSet {
+    bhyveDomainPCIAddressBus *buses;
+    size_t nbuses;
+    virDevicePCIAddress lastaddr;
+};
+
+static char *
+bhyveDomainPCIAddressAsString(virDevicePCIAddressPtr addr)
+{
+    char *str;
+
+    ignore_value(virAsprintf(&str, "%.4x:%.2x:%.2x.%.1x",
+                             addr->domain,
+                             addr->bus,
+                             addr->slot,
+                             addr->function));
+
+    return str;
+}
+
+static int
+bhyveDomainPCIAddressReserveSlot(bhyveDomainPCIAddressSetPtr addrs,
+                                 virDevicePCIAddressPtr addr,
+                                 int opaque ATTRIBUTE_UNUSED)
+{
+    int ret = -1;
+    char *addrStr = NULL;
+    bhyveDomainPCIAddressBusPtr bus = &addrs->buses[addr->bus];
+
+    if (!(addrStr = bhyveDomainPCIAddressAsString(addr)))
+        goto cleanup;
+
+    if (bus->slots[addr->slot]) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("Attempted double use of PCI slot %s"), addrStr);
+        goto cleanup;
+    }
+
+    bus->slots[addr->slot] = 0xFF;
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(addrStr);
+    return ret;
+}
+
+static int
+bhyveDomainPCIAddressBusSetModel(bhyveDomainPCIAddressBusPtr bus,
+                                 virDomainControllerModelPCI model)
+{
+    switch (model) {
+         case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+             bus->minSlot = 2;
+             bus->maxSlot = BHYVE_PCI_ADDRESS_SLOT_LAST;
+             break;
+         default:
+             virReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Invalid PCI controller model %d"), model);
+             return -1;
+    }
+
+    bus->model = model;
+    return 0;
+}
+
+static int
+bhyveCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
+                       virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
+                       virDomainDeviceInfoPtr info,
+                       void *opaque)
+{
+    int ret = -1;
+    bhyveDomainPCIAddressSetPtr 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 (bhyveDomainPCIAddressReserveSlot(addrs, addr, 0) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    return ret;
+}
+
+void bhyveDomainPCIAddressSetFree(bhyveDomainPCIAddressSetPtr addrs)
+{
+    if (!addrs)
+        return;
+
+    VIR_FREE(addrs->buses);
+    VIR_FREE(addrs);
+}
+
+bhyveDomainPCIAddressSetPtr
+bhyveDomainPCIAddressSetCreate(virDomainDefPtr def ATTRIBUTE_UNUSED, unsigned int nbuses)
+{
+    bhyveDomainPCIAddressSetPtr addrs;
+
+    if (VIR_ALLOC(addrs) < 0)
+        goto error;
+
+    if (VIR_ALLOC_N(addrs->buses, nbuses) < 0)
+        goto error;
+
+    addrs->nbuses = nbuses;
+
+    if (bhyveDomainPCIAddressBusSetModel(&addrs->buses[0],
+                                         VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0)
+        goto error;
+
+    if (virDomainDeviceInfoIterate(def, bhyveCollectPCIAddress, addrs) < 0)
+        goto error;
+
+    return addrs;
+
+ error:
+    bhyveDomainPCIAddressSetFree(addrs);
+    return NULL;
+}
+
+static int
+bhyveAssignDevicePCISlots(virDomainDefPtr def,
+                          bhyveDomainPCIAddressSetPtr addrs)
+{
+    size_t i;
+
+    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 (bhyveDomainPCIAddressReserveNextSlot(addrs,
+                                                 &def->disks[i]->info) < 0)
+            goto error;
+    }
+
+    for (i = 0; i < def->nnets; i++) {
+        if (def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+            continue;
+        if (bhyveDomainPCIAddressReserveNextSlot(addrs,
+                                                 &def->nets[i]->info) < 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 (bhyveDomainPCIAddressReserveNextSlot(addrs,
+                                                     &def->controllers[i]->info) < 0)
+                goto error;
+        }
+
+    }
+
+    return 0;
+
+ error:
+    return -1;
+}
+
+int bhyveDomainAssignPCIAddresses(virDomainDefPtr def,
+                                  virDomainObjPtr obj)
+{
+    bhyveDomainPCIAddressSetPtr 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) {
+            bhyveDomainPCIAddressSetFree(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);
+}
+
+static bool
+bhyveDomainPCIAddressSlotInUse(bhyveDomainPCIAddressSetPtr addrs,
+                               virDevicePCIAddressPtr addr)
+{
+    return !!addrs->buses[addr->bus].slots[addr->slot];
+}
+
+static int
+bhyveDomainPCIAddressGetNextSlot(bhyveDomainPCIAddressSetPtr addrs,
+                                 virDevicePCIAddressPtr next_addr,
+                                 int opaque ATTRIBUTE_UNUSED)
+{
+    virDevicePCIAddress a = { 0, 0, 0, 0, false };
+
+    if (addrs->nbuses == 0) {
+        virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available"));
+        return -1;
+    }
+
+    for (; a.bus < addrs->nbuses; a.bus++) {
+        for (a.slot = addrs->buses[a.bus].minSlot; a.slot <= BHYVE_PCI_ADDRESS_SLOT_LAST; a.slot++) {
+            if (!bhyveDomainPCIAddressSlotInUse(addrs, &a))
+                goto success;
+
+            VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use",
+                      a.domain, a.bus, a.slot);
+        }
+    }
+
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                   "%s", _("No more available PCI slots"));
+
+ success:
+    VIR_DEBUG("Found free PCI slot %.4x:%.2x:%.2x",
+              a.domain, a.bus, a.slot);
+    *next_addr = a;
+    return 0;
+}
+
+int
+bhyveDomainPCIAddressReserveNextSlot(bhyveDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev)
+{
+    virDevicePCIAddress addr;
+    if (bhyveDomainPCIAddressGetNextSlot(addrs, &addr, 0) < 0)
+        return -1;
+
+    if (bhyveDomainPCIAddressReserveSlot(addrs, &addr, 0) < 0)
+        return -1;
+
+    dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+    dev->addr.pci = addr;
+    addrs->lastaddr = addr;
+    return 0;
+}
diff --git a/src/bhyve/bhyve_device.h b/src/bhyve/bhyve_device.h
new file mode 100644
index 0000000..adc25e9
--- /dev/null
+++ b/src/bhyve/bhyve_device.h
@@ -0,0 +1,41 @@
+/*
+ * 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 "bhyve_domain.h"
+
+int bhyveDomainAssignPCIAddresses(virDomainDefPtr def, virDomainObjPtr obj);
+
+bhyveDomainPCIAddressSetPtr bhyveDomainPCIAddressSetCreate(virDomainDefPtr def,
+                                                           unsigned int nbuses);
+
+int bhyveDomainAssignAddresses(virDomainDefPtr def, virDomainObjPtr obj)
+    ATTRIBUTE_NONNULL(1);
+
+void bhyveDomainPCIAddressSetFree(bhyveDomainPCIAddressSetPtr addrs);
+
+int bhyveDomainPCIAddressReserveNextSlot(bhyveDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev);
+
+#endif /* __BHYVE_DEVICE_H__ */
diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c
new file mode 100644
index 0000000..284140c
--- /dev/null
+++ b/src/bhyve/bhyve_domain.c
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+    bhyveDomainPCIAddressSetFree(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,
+};
diff --git a/src/bhyve/bhyve_domain.h b/src/bhyve/bhyve_domain.h
new file mode 100644
index 0000000..5085759
--- /dev/null
+++ b/src/bhyve/bhyve_domain.h
@@ -0,0 +1,41 @@
+/*
+ * 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_conf.h"
+
+typedef struct _bhyveDomainPCIAddressSet bhyveDomainPCIAddressSet;
+typedef bhyveDomainPCIAddressSet *bhyveDomainPCIAddressSetPtr;
+
+typedef struct _bhyveDomainObjPrivate bhyveDomainObjPrivate;
+typedef bhyveDomainObjPrivate *bhyveDomainObjPrivatePtr;
+struct _bhyveDomainObjPrivate {
+    bhyveDomainPCIAddressSetPtr pciaddrs;
+    int persistentAddrs;
+};
+
+extern virDomainXMLPrivateDataCallbacks virBhyveDriverPrivateDataCallbacks;
+extern virDomainDefParserConfig virBhyveDriverDomainDefParserConfig;
+
+#endif /* __BHYVE_DOMAIN_H__ */
diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c
index 0cafe4c..7bf6a2e 100644
--- a/src/bhyve/bhyve_driver.c
+++ b/src/bhyve/bhyve_driver.c
@@ -52,7 +52,9 @@
 #include "viraccessapicheck.h"
 #include "nodeinfo.h"
 
+#include "bhyve_device.h"
 #include "bhyve_driver.h"
+#include "bhyve_domain.h"
 #include "bhyve_process.h"
 #include "bhyve_utils.h"
 #include "bhyve_capabilities.h"
@@ -465,6 +467,9 @@ bhyveDomainDefineXML(virConnectPtr conn, const char *xml)
     if (virDomainDefineXMLEnsureACL(conn, def) < 0)
         goto cleanup;
 
+    if (bhyveDomainAssignAddresses(def, NULL) < 0)
+        goto cleanup;
+
     if (!(vm = virDomainObjListAdd(privconn->domains, def,
                                    privconn->xmlopt,
                                    0, &oldDef)))
@@ -1009,7 +1014,9 @@ bhyveStateInitialize(bool priveleged ATTRIBUTE_UNUSED,
     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()))
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-acpiapic.args b/tests/bhyvexml2argvdata/bhyvexml2argv-acpiapic.args
index 60a56b9..79f8e88 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-acpiapic.args
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-acpiapic.args
@@ -1,3 +1,3 @@
 /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
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-acpiapic.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-acpiapic.xml
index b429fef..2be970e 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-acpiapic.xml
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-acpiapic.xml
@@ -15,10 +15,12 @@
       <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>
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-base.args b/tests/bhyvexml2argvdata/bhyvexml2argv-base.args
index 9d4faa5..4122e62 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-base.args
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-base.args
@@ -1,3 +1,3 @@
 /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
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-base.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-base.xml
index 8c96f77..3d23375 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-base.xml
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-base.xml
@@ -11,10 +11,12 @@
       <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>
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-console.args b/tests/bhyvexml2argvdata/bhyvexml2argv-console.args
index 1e09fb4..df50290 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-console.args
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-console.args
@@ -1,4 +1,4 @@
 /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
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-console.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-console.xml
index 64073f0..35206b5 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-console.xml
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-console.xml
@@ -11,10 +11,12 @@
       <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'/>
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-disk-virtio.args b/tests/bhyvexml2argvdata/bhyvexml2argv-disk-virtio.args
index 54ad2b8..1638d54 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-disk-virtio.args
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-disk-virtio.args
@@ -1,3 +1,3 @@
 /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
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-disk-virtio.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-disk-virtio.xml
index 8cfb518..773d55e 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-disk-virtio.xml
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-disk-virtio.xml
@@ -11,10 +11,12 @@
       <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>
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-macaddr.args b/tests/bhyvexml2argvdata/bhyvexml2argv-macaddr.args
index 1a06abd..f914865 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-macaddr.args
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-macaddr.args
@@ -1,3 +1,3 @@
 /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
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-macaddr.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-macaddr.xml
index 41a42b0..b262eb7 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-macaddr.xml
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-macaddr.xml
@@ -11,11 +11,13 @@
       <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>
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-serial.args b/tests/bhyvexml2argvdata/bhyvexml2argv-serial.args
index 1e09fb4..df50290 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-serial.args
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-serial.args
@@ -1,4 +1,4 @@
 /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
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-serial.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-serial.xml
index bfecbb9..cd4f25b 100644
--- a/tests/bhyvexml2argvdata/bhyvexml2argv-serial.xml
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-serial.xml
@@ -11,10 +11,12 @@
       <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'/>
-- 
1.9.0




More information about the libvir-list mailing list