[libvirt] [PATCH v3 5/5] qemu: auto-add bridges and allow using them

Laine Stump laine at laine.org
Mon Apr 22 20:55:20 UTC 2013


(before anything else - you committed an unresolved merge conflict in
qemu_command.h. You'll need to remove the extra ">>>>>>>>> blah" text.)

Hopefully Eric can once again review the logic of the code that
determines what bridges need to be auto-added, and assign PCI addresses
to devices, since he was kind enough to review it last time :-)


On 04/22/2013 02:43 PM, Ján Tomko wrote:
> Add a "dry run" address allocation to figure out how many bridges
> will be needed for all the devices without explicit addresses.
>
> Auto-add just enough bridges to put all the devices on, or up to the
> bridge with the largest specified index.


Ah, so then we don't need to warn about gaps in the index sequence.


> ---
>  src/conf/domain_conf.c                             |  26 ++-
>  src/qemu/qemu_command.c                            | 211 +++++++++++++++++----
>  src/qemu/qemu_command.h                            |   4 +-
>  tests/qemuxml2argvdata/qemuxml2argv-pci-bridge.xml | 210 ++++++++++++++++++++
>  tests/qemuxml2xmltest.c                            |   1 +
>  5 files changed, 411 insertions(+), 41 deletions(-)
>  create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pci-bridge.xml
>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 5740009..800c0a7 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -2578,6 +2578,9 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
>                                virCapsPtr caps ATTRIBUTE_UNUSED)
>  {
>      int i;
> +    bool b;
> +    int ret = -1;
> +    virBitmapPtr bitmap = NULL;
>  
>      /* verify init path for container based domains */
>      if (STREQ(def->os.type, "exe") && !def->os.init) {
> @@ -2653,11 +2656,30 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
>          }
>      }
>  
> -    return 0;
> +    /* Verify that PCI controller indexes are unique */
> +    bitmap = virBitmapNew(def->ncontrollers);
> +    for (i = 0; i < def->ncontrollers; i++) {
> +        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
> +            ignore_value(virBitmapGetBit(bitmap, def->controllers[i]->idx, &b));
> +            if (b) {
> +                virReportError(VIR_ERR_XML_ERROR,
> +                               _("Multiple PCI controllers with index %d"),
> +                               def->controllers[i]->idx);
> +                goto cleanup;
> +            }
> +            ignore_value(virBitmapSetBit(bitmap, def->controllers[i]->idx));
> +        }
> +    }
> +    ret = 0;
> +
> +cleanup:
> +    virBitmapFree(bitmap);
> +
> +    return ret;


I don't see where we do something like this for the other controller
types. We should (separate patch though, of course :-)


>  
>  no_memory:
>      virReportOOMError();
> -    return -1;
> +    goto cleanup;
>  }
>  
>  
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 3787ff1..ec7d0e6 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -1197,6 +1197,8 @@ struct _qemuDomainPCIAddressSet {
>      qemuDomainPCIAddressBus *used;
>      virDevicePCIAddress lastaddr;
>      size_t nbuses;        /* allocation of 'used' */
> +    bool dryRun;          /* on a dry run, new buses are auto-added
> +                             and addresses aren't saved in device infos */
>  };
>  
>  
> @@ -1216,9 +1218,10 @@ static bool qemuPCIAddressValidate(qemuDomainPCIAddressSetPtr addrs ATTRIBUTE_UN
>                         _("Only PCI domain 0 is available"));
>          return false;
>      }
> -    if (addr->bus != 0) {
> -        virReportError(VIR_ERR_XML_ERROR, "%s",
> -                       _("Only PCI bus 0 is available"));
> +    if (addr->bus >= addrs->nbuses) {
> +        virReportError(VIR_ERR_XML_ERROR,
> +                       _("Only PCI buses up to %zu are available"),
> +                       addrs->nbuses - 1);
>          return false;
>      }
>      if (addr->function >= QEMU_PCI_ADDRESS_FUNCTION_LAST) {
> @@ -1233,9 +1236,46 @@ static bool qemuPCIAddressValidate(qemuDomainPCIAddressSetPtr addrs ATTRIBUTE_UN
>                         QEMU_PCI_ADDRESS_SLOT_LAST);
>          return false;
>      }
> +    if (addr->slot == 0) {
> +        if (addr->bus) {
> +            virReportError(VIR_ERR_XML_ERROR, "%s",
> +                           _("Slot 0 is unusable on PCI bridges"));
> +            return false;
> +        } else {
> +            virReportError(VIR_ERR_XML_ERROR, "%s",
> +                          _("Slot 0 on bus 0 is reserved for the host bridge"));
> +            return false;
> +        }


You can move the duplicated "return false;" out of the if and else, to a
single occurrence.


> +    }
>      return true;
>  }
>  
> +/* Ensure addr fits in the address set, by expanding it if needed.
> + * Return value:
> + * -1 = OOM
> + *  0 = no action performed
> + * >0 = number of buses added
> + */
> +static int
> +qemuDomainPCIAddressSetGrow(qemuDomainPCIAddressSetPtr addrs,
> +                      virDevicePCIAddressPtr addr)
> +{
> +    int add, i;
> +
> +    add = addr->bus - addrs->nbuses + 1;
> +    i = addrs->nbuses;
> +    if (add <= 0)
> +        return 0;
> +    if (VIR_EXPAND_N(addrs->used, addrs->nbuses, add) < 0) {
> +        virReportOOMError();
> +        return -1;
> +    }
> +    /* reserve slot 0 on the new buses */
> +    for (; i < addrs->nbuses; i++)
> +        addrs->used[i][0] = 0xFF;
> +    return add;
> +}
> +
>  
>  static char *qemuPCIAddressAsString(virDevicePCIAddressPtr addr)
>  {
> @@ -1273,6 +1313,9 @@ static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
>          return 0;
>      }
>  
> +    if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr) < 0)
> +        return -1;
> +
>      if (!qemuPCIAddressValidate(addrs, addr))
>          return -1;
>  
> @@ -1326,15 +1369,54 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
>      qemuDomainObjPrivatePtr priv = NULL;
>  
>      if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
> +        int max_idx = 0;
>          int nbuses = 0;
>          int i;
> +        int rv;
>  
>          for (i = 0; i < def->ncontrollers; i++) {
> -            if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI)
> +            if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
> +                if (def->controllers[i]->idx > max_idx)
> +                    max_idx = def->controllers[i]->idx;
>                  nbuses++;
> +            }
> +        }
> +
> +        if (nbuses > 0 && max_idx >= nbuses)
> +            nbuses = max_idx + 1;
> +
> +        if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
> +            virDomainDeviceInfo info;
> +            /* 1st pass to figure out how many PCI bridges we need */
> +            if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, true)))
> +                goto cleanup;
> +            if (qemuAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
> +                goto cleanup;
> +            /* Reserve 1 extra slot for a (potential) bridge */
> +            if (qemuDomainPCIAddressSetNextAddr(addrs, &info) < 0)
> +                goto cleanup;
> +
> +            for (i = 1; i < addrs->nbuses; i++) {
> +                if ((rv = virDomainDefMaybeAddController(
> +                        def, VIR_DOMAIN_CONTROLLER_TYPE_PCI,
> +                        i, VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE)) < 0)
> +                    goto cleanup;
> +                /* If we added a new bridge, we will need one more address */
> +                if (rv > 0 && qemuDomainPCIAddressSetNextAddr(addrs, &info) < 0)
> +                        goto cleanup;
> +            }
> +            nbuses = addrs->nbuses;
> +            qemuDomainPCIAddressSetFree(addrs);
> +            addrs = NULL;
> +
> +        } else if (nbuses > 1) {
> +            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                           _("PCI bridges are not supported "
> +                             "by this QEMU binary"));
> +            goto cleanup;
>          }
>  
> -        if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses)))
> +        if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, false)))
>              goto cleanup;
>  
>          if (qemuAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
> @@ -1380,7 +1462,8 @@ int qemuDomainAssignAddresses(virDomainDefPtr def,
>  }
>  
>  qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
> -                                                         unsigned int nbuses)
> +                                                         unsigned int nbuses,
> +                                                         bool dryRun)
>  {
>      qemuDomainPCIAddressSetPtr addrs;
>      int i;
> @@ -1392,6 +1475,7 @@ qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
>          goto no_memory;
>  
>      addrs->nbuses = nbuses;
> +    addrs->dryRun = dryRun;
>  
>      /* reserve slot 0 in every bus - it's used by the host bridge on bus 0
>       * and unusable on PCI bridges */
> @@ -1424,6 +1508,9 @@ int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
>  {
>      char *str;
>  
> +    if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr) < 0)
> +        return -1;
> +
>      if (!(str = qemuPCIAddressAsString(addr)))
>          return -1;
>  
> @@ -1450,6 +1537,9 @@ int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
>  {
>      char *str;
>  
> +    if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr) < 0)
> +        return -1;
> +
>      if (!(str = qemuPCIAddressAsString(addr)))
>          return -1;
>  
> @@ -1519,41 +1609,58 @@ void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs)
>      VIR_FREE(addrs);
>  }
>  
> -
>  static int
>  qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
>                                  virDevicePCIAddressPtr next_addr)
>  {
> -    virDevicePCIAddress tmp_addr = addrs->lastaddr;
> -    int i;
> -    char *addr;
> +    virDevicePCIAddress a = addrs->lastaddr;
>  
> -    tmp_addr.slot++;
> -    for (i = 0; i < QEMU_PCI_ADDRESS_SLOT_LAST; i++, tmp_addr.slot++) {
> -        if (QEMU_PCI_ADDRESS_SLOT_LAST <= tmp_addr.slot) {
> -            tmp_addr.slot = 0;
> -        }
> +    if (addrs->nbuses == 0) {
> +        virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available"));
> +        return -1;
> +    }
>  
> -        if (!(addr = qemuPCIAddressAsString(&tmp_addr)))
> -            return -1;
> +    /* Start the search at the last used bus and slot */
> +    for (a.slot++; a.bus < addrs->nbuses; a.bus++) {
> +        for ( ; a.slot < QEMU_PCI_ADDRESS_SLOT_LAST; a.slot++) {
> +            if (!qemuDomainPCIAddressSlotInUse(addrs, &a))
> +                goto success;
>  
> -        if (qemuDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
> -            VIR_DEBUG("PCI addr %s already in use", addr);
> -            VIR_FREE(addr);
> -            continue;
> +            VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use",
> +                      a.domain, a.bus, a.slot);
>          }
> +        a.slot = 1;
> +    }
>  
> -        VIR_DEBUG("Found free PCI addr %s", addr);
> -        VIR_FREE(addr);
> +    /* There were no free slots after the last used one */
> +    if (addrs->dryRun) {
> +        /* a is already set to the first new bus and slot 1 */
> +        if (qemuDomainPCIAddressSetGrow(addrs, &a) < 0)
> +            return -1;
> +        goto success;
> +    } else {
> +        /* Check the buses from 0 up to the last used one */
> +        for (a.bus = 0; a.bus <= addrs->lastaddr.bus; a.bus++) {
> +            for (a.slot = 1; a.slot < QEMU_PCI_ADDRESS_SLOT_LAST; a.slot++) {
> +                if (!qemuDomainPCIAddressSlotInUse(addrs, &a))
> +                    goto success;
>  
> -        addrs->lastaddr = tmp_addr;
> -        *next_addr = tmp_addr;
> -        return 0;
> +                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 addresses"));
>      return -1;
> +
> +success:
> +    VIR_DEBUG("Found free PCI slot %.4x:%.2x:%.2x",
> +              a.domain, a.bus, a.slot);
> +    *next_addr = a;
> +    return 0;
>  }
>  
>  int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
> @@ -1566,8 +1673,10 @@ int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
>      if (qemuDomainPCIAddressReserveSlot(addrs, &addr) < 0)
>          return -1;
>  
> -    dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
> -    dev->addr.pci = addr;
> +    if (!addrs->dryRun) {
> +        dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
> +        dev->addr.pci = addr;
> +    }
>  
>      addrs->lastaddr = addr;
>      return 0;
> @@ -1741,6 +1850,18 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
>          }
>      }
>  
> +    /* PCI controllers */
> +    for (i = 0; i < def->ncontrollers; i++) {
> +        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
> +            if (def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT)
> +                continue;
> +            if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
> +                continue;
> +            if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info) < 0)
> +                goto error;
> +        }
> +    }
> +
>      for (i = 0; i < def->nfss ; i++) {
>          if (def->fss[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
>              continue;
> @@ -1780,9 +1901,10 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
>  
>      /* Device controllers (SCSI, USB, but not IDE, FDC or CCID) */
>      for (i = 0; i < def->ncontrollers ; i++) {
> -        /* PCI root has no address */
> +        /* PCI controllers have been dealt with earlier */
>          if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI)
>              continue;
> +
>          /* FDC lives behind the ISA bridge; CCID is a usb device */
>          if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC ||
>              def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID)
> @@ -1972,16 +2094,29 @@ qemuBuildDeviceAddressStr(virBufferPtr buf,
>              }
>          }
>  
> -        /* XXX
> -         * When QEMU grows support for > 1 PCI bus, then pci.0 changes
> -         * to pci.1, pci.2, etc
> -         * When QEMU grows support for > 1 PCI domain, then pci.0 change
> -         * to pciNN.0  where NN is the domain number
> +        /*
> +         * PCI bridge support is required for multiple buses
> +         * 'pci.%u' is the ID of the bridge as specified in
> +         * qemuBuildControllerDevStr
> +         *
> +         * PCI_MULTIBUS capability indicates that the implicit
> +         * PCI bus is named 'pci.0' instead of 'pci'.
>           */
> -        if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_MULTIBUS))
> -            virBufferAsprintf(buf, ",bus=pci.0");
> -        else
> -            virBufferAsprintf(buf, ",bus=pci");
> +        if (info->addr.pci.bus != 0) {
> +            if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
> +                virBufferAsprintf(buf, ",bus=pci.%u", info->addr.pci.bus);
> +            } else {
> +                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                               _("Multiple PCI buses are not supported "
> +                                 "with this QEMU binary"));
> +                return -1;
> +            }
> +        } else {
> +            if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_MULTIBUS))
> +                virBufferAsprintf(buf, ",bus=pci.0");
> +            else
> +                virBufferAsprintf(buf, ",bus=pci");
> +        }
>          if (info->addr.pci.multi == VIR_DEVICE_ADDRESS_PCI_MULTI_ON)
>              virBufferAddLit(buf, ",multifunction=on");
>          else if (info->addr.pci.multi == VIR_DEVICE_ADDRESS_PCI_MULTI_OFF)
> diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
> index b05510b..5d9ae72 100644
> --- a/src/qemu/qemu_command.h
> +++ b/src/qemu/qemu_command.h
> @@ -197,7 +197,9 @@ int qemuDomainAssignPCIAddresses(virDomainDefPtr def,
>                                   virQEMUCapsPtr qemuCaps,
>                                   virDomainObjPtr obj);
>  qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
> -                                                         unsigned int nbuses);
> +                                                         unsigned int nbuses,
> +                                                         bool dryRun);
> +>>>>>>> a3dcfa9... qemu: auto-add bridges and allow using them

Oops. You've got an unresolved merge error!


>  int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
>                                      virDevicePCIAddressPtr addr);
>  int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pci-bridge.xml b/tests/qemuxml2argvdata/qemuxml2argv-pci-bridge.xml
> new file mode 100644
> index 0000000..eb20328
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-pci-bridge.xml

You should also do a test case where you haven't specified the bridges
in the "xmlIn", but only in the "xmlOut". I *think* you should be able
to do that by just putting the file that contains the bridges in
qemuxml2xmloutdata, and calling the test with DO_TEST_DIFFERENT() in
qemuxml2xmltest, AND omitting this test from qemuargv2xmltest.


> @@ -0,0 +1,210 @@
> +<domain type='qemu'>
> +  <name>fdr-br</name>
> +  <uuid>3ec6cbe1-b5a2-4515-b800-31a61855df41</uuid>
> +  <memory unit='KiB'>2097152</memory>
> +  <currentMemory unit='KiB'>2097152</currentMemory>
> +  <vcpu placement='static' cpuset='0-1'>2</vcpu>
> +  <os>
> +    <type arch='x86_64' machine='pc-1.2'>hvm</type>
> +    <boot dev='hd'/>
> +  </os>
> +  <features>
> +    <acpi/>
> +    <apic/>
> +    <pae/>
> +  </features>
> +  <clock offset='utc'/>
> +  <on_poweroff>destroy</on_poweroff>
> +  <on_reboot>restart</on_reboot>
> +  <on_crash>restart</on_crash>
> +  <devices>
> +    <emulator>/usr/libexec/qemu-kvm</emulator>
> +    <disk type='file' device='cdrom'>
> +      <driver name='qemu' type='raw'/>
> +      <source file='/var/iso/f18kde.iso'/>
> +      <target dev='hdc' bus='ide'/>
> +      <readonly/>
> +      <address type='drive' controller='0' bus='1' target='0' unit='0'/>
> +    </disk>
> +    <controller type='usb' index='0'>
> +      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
> +    </controller>
> +    <controller type='ide' index='0'>
> +      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
> +    </controller>
> +    <controller type='pci' index='0' model='pci-root'/>
> +    <controller type='pci' index='1' model='pci-bridge'/>
> +    <controller type='pci' index='2' model='pci-bridge'/>
> +    <interface type='network'>
> +      <mac address='52:54:00:f1:95:51'/>
> +      <source network='default'/>
> +      <model type='rtl8139'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:5c:c6:1a'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:39:97:ac'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:45:28:cb'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:ee:b9:a8'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:a9:f7:17'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:df:2b:f3'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:78:94:b4'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:6b:9b:06'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:17:df:bc'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:3b:d0:51'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:8d:2d:17'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:a7:66:af'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:54:ab:d7'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:1f:99:90'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:c8:43:87'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:df:22:b2'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:d2:9a:47'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:86:05:e2'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:8c:1c:c2'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:48:58:92'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:99:e5:bf'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:b1:8c:25'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:60:e0:d0'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:37:00:6a'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:c7:c8:ad'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:4e:a7:cf'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:00:79:69'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:47:00:6f'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:2a:8c:8b'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:ec:d5:e3'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <interface type='network'>
> +      <mac address='52:54:00:7e:6e:c8'/>
> +      <source network='default'/>
> +      <model type='e1000'/>
> +    </interface>
> +    <input type='mouse' bus='ps2'/>
> +    <graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'>
> +      <listen type='address' address='127.0.0.1'/>
> +    </graphics>
> +    <video>
> +      <model type='cirrus' vram='9216' heads='1'/>
> +      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
> +    </video>
> +    <memballoon model='virtio'>
> +      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
> +    </memballoon>
> +  </devices>
> +</domain>
> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
> index 7434190..04b14df 100644
> --- a/tests/qemuxml2xmltest.c
> +++ b/tests/qemuxml2xmltest.c
> @@ -276,6 +276,7 @@ mymain(void)
>      DO_TEST_DIFFERENT("metadata");
>  
>      DO_TEST("tpm-passthrough");
> +    DO_TEST("pci-bridge");
>  
>      virObjectUnref(driver.caps);
>      virObjectUnref(driver.xmlopt);

What about qemuxml2argvtest.c? (which means you also need a .args file.)




More information about the libvir-list mailing list