--- docs/formatdomain.html.in | 27 ++++ docs/schemas/domain.rng | 13 ++ src/conf/domain_conf.c | 157 +++++++++++++++++++++- src/conf/domain_conf.h | 20 +++ src/libvirt_private.syms | 2 + src/qemu/qemu_capabilities.c | 3 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 56 ++++++++- src/qemu/qemu_command.h | 1 + tests/qemuhelptest.c | 9 +- tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args | 1 + tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml | 19 +++ tests/qemuxml2argvtest.c | 3 + 13 files changed, 307 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 633cea1..e35b76b 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2084,6 +2084,33 @@ qemu-kvm -net nic,model=? /dev/null device to a particular PCI slot. </p> + <h4><a name="elementsHub">Hub devices</a></h4> + + <p> + A hub is a device that expands a single port into several so + that there are more ports available to connect devices to a host + system. + </p> + +<pre> + ... + <devices> + <hub type='usb'/> + </devices> + ...</pre> + + <dl> + <dt><code>hub</code></dt> + <dd>The <code>hub</code> element has one mandatory attribute, + the <code>type</code> whose value can only be 'usb'.</dd> + </dl> + + <p> + The <code>hub</code> element has an optional + sub-element <code><address></code> which can tie the + device to a particular controller. + </p> + <h4><a name="elementsGraphics">Graphical framebuffers</a></h4> <p> diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 455f57d..16e9687 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -1962,6 +1962,18 @@ </optional> </element> </define> + <define name="hub"> + <element name="hub"> + <attribute name="type"> + <choice> + <value>usb</value> + </choice> + </attribute> + <optional> + <ref name="address"/> + </optional> + </element> + </define> <define name="hostdev"> <element name="hostdev"> <optional> @@ -2125,6 +2137,7 @@ <ref name="serial"/> <ref name="channel"/> <ref name="smartcard"/> + <ref name="hub"/> </choice> </zeroOrMore> <optional> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 5ef062a..bd05c2a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -126,7 +126,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST, "hostdev", "watchdog", "controller", - "graphics") + "graphics", + "usb") VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "none", @@ -436,6 +437,9 @@ VIR_ENUM_IMPL(virDomainState, VIR_DOMAIN_CRASHED+1, "shutoff", "crashed") +VIR_ENUM_IMPL(virDomainHub, VIR_DOMAIN_HUB_TYPE_LAST, + "usb") + #define VIR_DOMAIN_NOSTATE_LAST (VIR_DOMAIN_NOSTATE_UNKNOWN + 1) VIR_ENUM_IMPL(virDomainNostateReason, VIR_DOMAIN_NOSTATE_LAST, "unknown") @@ -999,6 +1003,15 @@ void virDomainHostdevDefFree(virDomainHostdevDefPtr def) VIR_FREE(def); } +void virDomainHubDefFree(virDomainHubDefPtr def) +{ + if (!def) + return; + + virDomainDeviceInfoClear(&def->info); + VIR_FREE(def); +} + void virDomainDeviceDefFree(virDomainDeviceDefPtr def) { if (!def) @@ -1035,6 +1048,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) case VIR_DOMAIN_DEVICE_GRAPHICS: virDomainGraphicsDefFree(def->data.graphics); break; + case VIR_DOMAIN_DEVICE_HUB: + virDomainHubDefFree(def->data.hub); + break; } VIR_FREE(def); @@ -1144,6 +1160,10 @@ void virDomainDefFree(virDomainDefPtr def) virDomainHostdevDefFree(def->hostdevs[i]); VIR_FREE(def->hostdevs); + for (i = 0 ; i < def->nhubs ; i++) + virDomainHubDefFree(def->hubs[i]); + VIR_FREE(def->hubs); + VIR_FREE(def->os.type); VIR_FREE(def->os.arch); VIR_FREE(def->os.machine); @@ -1527,6 +1547,9 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def, if (def->console) if (cb(def, &def->console->info, opaque) < 0) return -1; + for (i = 0; i < def->nhubs ; i++) + if (cb(def, &def->hubs[i]->info, opaque) < 0) + return -1; return 0; } @@ -1591,6 +1614,12 @@ virDomainDeviceInfoFormat(virBufferPtr buf, info->addr.ccid.slot); break; + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB: + virBufferAsprintf(buf, " bus='%d' port='%d'", + info->addr.usb.bus, + info->addr.usb.port); + break; + default: virDomainReportError(VIR_ERR_INTERNAL_ERROR, _("unknown address type '%d'"), info->type); @@ -3990,6 +4019,47 @@ error: } +/* Parse the XML definition for an hub device */ +static virDomainHubDefPtr +virDomainHubDefParseXML(xmlNodePtr node, unsigned int flags) +{ + virDomainHubDefPtr def; + char *type = NULL; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + return NULL; + } + + type = virXMLPropString(node, "type"); + + if (!type) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing hub device type")); + goto error; + } + + if ((def->type = virDomainHubTypeFromString(type)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown hub device type '%s'"), type); + goto error; + } + + if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0) + goto error; + +cleanup: + VIR_FREE(type); + + return def; + +error: + virDomainHubDefFree(def); + def = NULL; + goto cleanup; +} + + /* Parse the XML definition for a clock timer */ static virDomainTimerDefPtr virDomainTimerDefParseXML(const xmlNodePtr node, @@ -5567,6 +5637,10 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps, dev->type = VIR_DOMAIN_DEVICE_GRAPHICS; if (!(dev->data.graphics = virDomainGraphicsDefParseXML(node, ctxt, flags))) goto error; + } else if (xmlStrEqual(node->name, BAD_CAST "hub")) { + dev->type = VIR_DOMAIN_DEVICE_HUB; + if (!(dev->data.hub = virDomainHubDefParseXML(node, flags))) + goto error; } else { virDomainReportError(VIR_ERR_XML_ERROR, "%s", _("unknown device type")); @@ -6971,6 +7045,21 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, } } + /* analysis of the hub devices */ + if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0) { + goto error; + } + if (n && VIR_ALLOC_N(def->hubs, n) < 0) + goto no_memory; + for (i = 0 ; i < n ; i++) { + virDomainHubDefPtr hub = virDomainHubDefParseXML(nodes[i], flags); + if (!hub) + goto error; + + def->hubs[def->nhubs++] = hub; + } + VIR_FREE(nodes); + /* analysis of security label */ if (virSecurityLabelDefParseXML(def, ctxt, flags) == -1) goto error; @@ -7881,6 +7970,29 @@ cleanup: } +static bool virDomainHubDefCheckABIStability(virDomainHubDefPtr src, + virDomainHubDefPtr dst) +{ + bool identical = false; + + if (src->type != dst->type) { + virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target hub device type %s does not match source %s"), + virDomainHubTypeToString(dst->type), + virDomainHubTypeToString(src->type)); + goto cleanup; + } + + if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info)) + goto cleanup; + + identical = true; + +cleanup: + return identical; +} + + /* This compares two configurations and looks for any differences * which will affect the guest ABI. This is primarily to allow * validation of custom XML config passed in during migration @@ -8114,6 +8226,17 @@ bool virDomainDefCheckABIStability(virDomainDefPtr src, goto cleanup; } + if (src->nhubs != dst->nhubs) { + virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target domain hub device count %d does not match source %d"), + dst->nhubs, src->nhubs); + goto cleanup; + } + + for (i = 0 ; i < src->nhubs ; i++) + if (!virDomainHubDefCheckABIStability(src->hubs[i], dst->hubs[i])) + goto cleanup; + if (src->console && !virDomainConsoleDefCheckABIStability(src->console, dst->console)) goto cleanup; @@ -10027,6 +10150,34 @@ virDomainHostdevDefFormat(virBufferPtr buf, } +static int +virDomainHubDefFormat(virBufferPtr buf, + virDomainHubDefPtr def, + unsigned int flags) +{ + const char *type = virDomainHubTypeToString(def->type); + + if (!type) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected hub type %d"), def->type); + return -1; + } + + virBufferAsprintf(buf, " <hub type='%s'", type); + + if (virDomainDeviceInfoIsSet(&def->info, flags)) { + virBufferAddLit(buf, ">\n"); + if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0) + return -1; + virBufferAddLit(buf, " </hub>\n"); + } else { + virBufferAddLit(buf, "/>\n"); + } + + return 0; +} + + #define DUMPXML_FLAGS \ (VIR_DOMAIN_XML_SECURE | \ VIR_DOMAIN_XML_INACTIVE | \ @@ -10432,6 +10583,10 @@ virDomainDefFormatInternal(virDomainDefPtr def, if (virDomainHostdevDefFormat(&buf, def->hostdevs[n], flags) < 0) goto cleanup; + for (n = 0 ; n < def->nhubs ; n++) + if (virDomainHubDefFormat(&buf, def->hubs[n], flags) < 0) + goto cleanup; + if (def->watchdog) virDomainWatchdogDefFormat (&buf, def->watchdog, flags); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 07d60a4..f880264 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -616,6 +616,13 @@ struct _virDomainSmartcardDef { virDomainDeviceInfo info; }; +typedef struct _virDomainHubDef virDomainHubDef; +typedef virDomainHubDef *virDomainHubDefPtr; +struct _virDomainHubDef { + int type; + virDomainDeviceInfo info; +}; + enum virDomainInputType { VIR_DOMAIN_INPUT_TYPE_MOUSE, VIR_DOMAIN_INPUT_TYPE_TABLET, @@ -825,6 +832,12 @@ enum virDomainGraphicsListenType { VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST, }; +enum virDomainHubType { + VIR_DOMAIN_HUB_TYPE_USB, + + VIR_DOMAIN_HUB_TYPE_LAST, +}; + typedef struct _virDomainGraphicsListenDef virDomainGraphicsListenDef; typedef virDomainGraphicsListenDef *virDomainGraphicsListenDefPtr; struct _virDomainGraphicsListenDef { @@ -965,6 +978,7 @@ enum virDomainDeviceType { VIR_DOMAIN_DEVICE_WATCHDOG, VIR_DOMAIN_DEVICE_CONTROLLER, VIR_DOMAIN_DEVICE_GRAPHICS, + VIR_DOMAIN_DEVICE_HUB, VIR_DOMAIN_DEVICE_LAST, }; @@ -985,6 +999,7 @@ struct _virDomainDeviceDef { virDomainHostdevDefPtr hostdev; virDomainWatchdogDefPtr watchdog; virDomainGraphicsDefPtr graphics; + virDomainHubDefPtr hub; } data; }; @@ -1312,6 +1327,9 @@ struct _virDomainDef { size_t nleases; virDomainLeaseDefPtr *leases; + int nhubs; + virDomainHubDefPtr *hubs; + /* Only 1 */ virDomainChrDefPtr console; virSecurityLabelDef seclabel; @@ -1458,6 +1476,7 @@ void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def); void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def); void virDomainVideoDefFree(virDomainVideoDefPtr def); void virDomainHostdevDefFree(virDomainHostdevDefPtr def); +void virDomainHubDefFree(virDomainHubDefPtr def); void virDomainDeviceDefFree(virDomainDeviceDefPtr def); int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info, int type); @@ -1738,6 +1757,7 @@ VIR_ENUM_DECL(virDomainWatchdogAction) VIR_ENUM_DECL(virDomainVideo) VIR_ENUM_DECL(virDomainHostdevMode) VIR_ENUM_DECL(virDomainHostdevSubsys) +VIR_ENUM_DECL(virDomainHub) VIR_ENUM_DECL(virDomainInput) VIR_ENUM_DECL(virDomainInputBus) VIR_ENUM_DECL(virDomainGraphics) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 74948b8..6642ba9 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -327,6 +327,8 @@ virDomainGraphicsTypeToString; virDomainHostdevDefFree; virDomainHostdevModeTypeToString; virDomainHostdevSubsysTypeToString; +virDomainHubTypeFromString; +virDomainHubTypeToString; virDomainInputDefFree; virDomainIoEventFdTypeFromString; virDomainIoEventFdTypeToString; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index a776a0c..5b72a60 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -134,6 +134,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "pci-ohci", /* 70 */ "usb-redir", + "usb-hub", ); struct qemu_feature_flags { @@ -1220,6 +1221,8 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags) qemuCapsSet(flags, QEMU_CAPS_PCI_OHCI); if (strstr(str, "name \"usb-redir\"")) qemuCapsSet(flags, QEMU_CAPS_USB_REDIR); + if (strstr(str, "name \"usb-hub\"")) + qemuCapsSet(flags, QEMU_CAPS_USB_HUB); /* Prefer -chardev spicevmc (detected earlier) over -device spicevmc */ if (!qemuCapsGet(flags, QEMU_CAPS_CHARDEV_SPICEVMC) && diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index f4bb368..c9b9b45 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -108,6 +108,7 @@ enum qemuCapsFlags { QEMU_CAPS_VT82C686B_USB_UHCI = 69, /* -device vt82c686b-usb-uhci */ QEMU_CAPS_PCI_OHCI = 70, /* -device pci-ohci */ QEMU_CAPS_USB_REDIR = 71, /* -device usb-redir */ + QEMU_CAPS_USB_HUB = 72, /* -device usb-hub */ QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 835d06f..9b09daa 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -689,6 +689,10 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virBitmapPtr qemuCaps) if (virAsprintf(&def->smartcards[i]->info.alias, "smartcard%d", i) < 0) goto no_memory; } + for (i = 0; i < def->nhubs ; i++) { + if (virAsprintf(&def->hubs[i]->info.alias, "hub%d", i) < 0) + goto no_memory; + } if (def->console) { if (virAsprintf(&def->console->info.alias, "console%d", i) < 0) goto no_memory; @@ -1272,6 +1276,9 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) for (i = 0; i < def->nchannels ; i++) { /* Nada - none are PCI based (yet) */ } + for (i = 0; i < def->nhubs ; i++) { + /* Nada - none are PCI based (yet) */ + } return 0; @@ -1767,7 +1774,6 @@ qemuBuildUSBControllerDevStr(virDomainControllerDefPtr def, virBufferAsprintf(buf, ",id=usb%d", def->idx); } - return 0; } @@ -2336,6 +2342,43 @@ error: char * +qemuBuildHubDevStr(virDomainHubDefPtr dev, + virBitmapPtr qemuCaps) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (dev->type != VIR_DOMAIN_HUB_TYPE_USB) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hub type %s not supported"), + virDomainHubTypeToString(dev->type)); + goto error; + } + + if (!qemuCapsGet(qemuCaps, QEMU_CAPS_USB_HUB)) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("usb-hub not supported by QEMU binary")); + goto error; + } + + virBufferAddLit(&buf, "usb-hub"); + virBufferAsprintf(&buf, ",id=%s", dev->info.alias); + if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0) + goto error; + + if (virBufferError(&buf)) { + virReportOOMError(); + goto error; + } + + return virBufferContentAndReset(&buf); + +error: + virBufferFreeAndReset(&buf); + return NULL; +} + + +char * qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev) { char *ret = NULL; @@ -4245,6 +4288,17 @@ qemuBuildCommandLine(virConnectPtr conn, if (usbcontroller == 0) virCommandAddArg(cmd, "-usb"); + for (i = 0 ; i < def->nhubs ; i++) { + virDomainHubDefPtr hub = def->hubs[i]; + char *optstr; + + virCommandAddArg(cmd, "-device"); + if (!(optstr = qemuBuildHubDevStr(hub, qemuCaps))) + goto error; + virCommandAddArg(cmd, optstr); + VIR_FREE(optstr); + } + for (i = 0 ; i < def->ninputs ; i++) { virDomainInputDefPtr input = def->inputs[i]; diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index de09577..22bc15d 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -119,6 +119,7 @@ char * qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev); char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev, virBitmapPtr qemuCaps); +char * qemuBuildHubDevStr(virDomainHubDefPtr dev, virBitmapPtr qemuCaps); int qemuNetworkIfaceConnect(virDomainDefPtr def, diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c index d57e499..ffd30e2 100644 --- a/tests/qemuhelptest.c +++ b/tests/qemuhelptest.c @@ -349,7 +349,8 @@ mymain(void) QEMU_CAPS_DRIVE_AIO, QEMU_CAPS_DEVICE_SPICEVMC, QEMU_CAPS_PIIX3_USB_UHCI, - QEMU_CAPS_PIIX4_USB_UHCI); + QEMU_CAPS_PIIX4_USB_UHCI, + QEMU_CAPS_USB_HUB); DO_TEST("qemu-kvm-0.12.3", 12003, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -437,7 +438,8 @@ mymain(void) QEMU_CAPS_PIIX3_USB_UHCI, QEMU_CAPS_PIIX4_USB_UHCI, QEMU_CAPS_VT82C686B_USB_UHCI, - QEMU_CAPS_PCI_OHCI); + QEMU_CAPS_PCI_OHCI, + QEMU_CAPS_USB_HUB); DO_TEST("qemu-kvm-0.12.1.2-rhel61", 12001, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -484,7 +486,8 @@ mymain(void) QEMU_CAPS_VIRTIO_TX_ALG, QEMU_CAPS_VIRTIO_IOEVENTFD, QEMU_CAPS_PIIX3_USB_UHCI, - QEMU_CAPS_PIIX4_USB_UHCI); + QEMU_CAPS_PIIX4_USB_UHCI, + QEMU_CAPS_USB_HUB); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args new file mode 100644 index 0000000..4911dd4 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -usb -device usb-hub,id=hub0,bus=usb.0,port=1 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml new file mode 100644 index 0000000..5e0b256 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml @@ -0,0 +1,19 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'/> + <memballoon model='virtio'/> + <hub type='usb'> + <address type='usb' bus='0' port='1'/> + </hub> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 33588d0..a053693 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -498,6 +498,9 @@ mymain(void) DO_TEST("usb-ich9-companion", false, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1); + DO_TEST("usb-hub", false, + QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_USB_HUB, + QEMU_CAPS_NODEFCONFIG); DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE); -- 1.7.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list