In an upcoming patch, virDomainNetDef will acquire a virDomainHostdevDef, and the <interface> XML will take on some of the elements of a <hostdev>. To avoid duplicating the code for parsing and formatting the <source> element (which will be nearly identical in these two cases), this patch factors those parts out of the HostdevDef's parse and format functions, and puts them into separate helper functions that are now called by the HostdevDef parser/formatter, and will soon be called by the NetDef parser/formatter. One change in behavior - previously virDomainHostdevDefParseXML() had diverged from current common coding practice by logging an error and failing if it found any subelements of <hostdev> other than those it understood (standard libvirt practice is to ignore/discard unknown elements and attributes during parse). The new helper function ignores unknown elements, and thus so does the new virDomainHostdevDefParseXML. --- V2: Unchanged from V1. src/conf/domain_conf.c | 263 +++++++++++++++++++++++++++++------------------- 1 files changed, 160 insertions(+), 103 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index eb66223..6d7c148 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2810,6 +2810,90 @@ out: return ret; } +static int +virDomainHostdevPartsParse(xmlNodePtr node, + xmlXPathContextPtr ctxt, + const char *mode, + const char *type, + virDomainHostdevDefPtr def, + unsigned int flags) +{ + xmlNodePtr sourcenode; + char *managed = NULL; + int ret = -1; + + /* @mode is passed in separately from the caller, since an + * 'intelligent hostdev' has no place for 'mode' in the XML (it is + * always 'subsys'). + */ + if (mode) { + if ((def->mode=virDomainHostdevModeTypeFromString(mode)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown hostdev mode '%s'"), mode); + goto error; + } + } else { + def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; + } + + /* @managed can be read from the xml document - it is always an + * attribute of the toplevel element, no matter what type of + * element that might be (pure hostdev, or higher level device + * (e.g. <interface>) with type='hostdev') + */ + if ((managed = virXMLPropString(node, "managed"))!= NULL) { + if (STREQ(managed, "yes")) + def->managed = 1; + } + + /* @type is passed in from the caller rather than read from the + * xml document, because it is specified in different places for + * different kinds of defs - it is an attribute of + * <source>/<address> for an intelligent hostdev (<interface>), + * but an attribute of the toplevel element for a standard + * <hostdev>. (the functions we're going to call expect address + * type to already be known). + */ + if (type) { + if ((def->source.subsys.type + = virDomainHostdevSubsysTypeFromString(type)) < 0) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("unknown host device source address type '%s'"), + type); + goto error; + } + } else { + virDomainReportError(VIR_ERR_XML_ERROR, + "%s", _("missing source address type")); + goto error; + } + + if (!(sourcenode = virXPathNode("./source", ctxt))) { + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("Missing <source> element in hostdev device")); + goto error; + } + switch (def->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + if (virDomainHostdevSubsysPciDefParseXML(sourcenode, def, flags) < 0) + goto error; + break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + if (virDomainHostdevSubsysUsbDefParseXML(sourcenode, def) < 0) + goto error; + break; + default: + virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("address type='%s' not supported in hostdev interfaces"), + virDomainHostdevSubsysTypeToString(def->source.subsys.type)); + goto error; + } + ret = 0; +error: + VIR_FREE(managed); + return ret; +} + int virDomainDiskFindControllerModel(virDomainDefPtr def, virDomainDiskDefPtr disk, @@ -6411,76 +6495,23 @@ error: static virDomainHostdevDefPtr virDomainHostdevDefParseXML(const xmlNodePtr node, + xmlXPathContextPtr ctxt, virBitmapPtr bootMap, unsigned int flags) { - xmlNodePtr cur; virDomainHostdevDefPtr def; - char *mode, *type = NULL, *managed = NULL; - - if (!(def = virDomainHostdevDefAlloc())) - return NULL; + xmlNodePtr save = ctxt->node; + char *mode = virXMLPropString(node, "mode"); + char *type = virXMLPropString(node, "type"); - mode = virXMLPropString(node, "mode"); - if (mode) { - if ((def->mode=virDomainHostdevModeTypeFromString(mode)) < 0) { - virDomainReportError(VIR_ERR_INTERNAL_ERROR, - _("unknown hostdev mode '%s'"), mode); - goto error; - } - } else { - def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; - } + ctxt->node = node; - type = virXMLPropString(node, "type"); - if (type) { - if ((def->source.subsys.type = virDomainHostdevSubsysTypeFromString(type)) < 0) { - virDomainReportError(VIR_ERR_INTERNAL_ERROR, - _("unknown host device type '%s'"), type); - goto error; - } - } else { - virDomainReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing type in hostdev")); + if (!(def = virDomainHostdevDefAlloc())) goto error; - } - managed = virXMLPropString(node, "managed"); - if (managed != NULL) { - if (STREQ(managed, "yes")) - def->managed = 1; - VIR_FREE(managed); - } - - cur = node->children; - while (cur != NULL) { - if (cur->type == XML_ELEMENT_NODE) { - if (xmlStrEqual(cur->name, BAD_CAST "source")) { - if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && - def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { - if (virDomainHostdevSubsysUsbDefParseXML(cur, def) < 0) - goto error; - } - if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && - def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { - if (virDomainHostdevSubsysPciDefParseXML(cur, def, flags) < 0) - goto error; - } - } else if (xmlStrEqual(cur->name, BAD_CAST "address")) { - /* address is parsed as part of virDomainDeviceInfoParseXML */ - } else if (xmlStrEqual(cur->name, BAD_CAST "alias")) { - /* alias is parsed as part of virDomainDeviceInfoParseXML */ - } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) { - /* boot is parsed as part of virDomainDeviceInfoParseXML */ - } else if (xmlStrEqual(cur->name, BAD_CAST "rom")) { - /* rombar is parsed as part of virDomainDeviceInfoParseXML */ - } else { - virDomainReportError(VIR_ERR_INTERNAL_ERROR, - _("unknown node %s"), cur->name); - } - } - cur = cur->next; - } + /* parse managed/mode/type, and the <source> element */ + if (virDomainHostdevPartsParse(node, ctxt, mode, type, def, flags) < 0) + goto error; if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { if (virDomainDeviceInfoParseXML(node, bootMap, def->info, @@ -6505,6 +6536,7 @@ virDomainHostdevDefParseXML(const xmlNodePtr node, cleanup: VIR_FREE(type); VIR_FREE(mode); + ctxt->node = save; return def; error: @@ -6671,7 +6703,7 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps, goto error; } else if (xmlStrEqual(node->name, BAD_CAST "hostdev")) { dev->type = VIR_DOMAIN_DEVICE_HOSTDEV; - if (!(dev->data.hostdev = virDomainHostdevDefParseXML(node, NULL, + if (!(dev->data.hostdev = virDomainHostdevDefParseXML(node, ctxt, NULL, flags))) goto error; } else if (xmlStrEqual(node->name, BAD_CAST "controller")) { @@ -8208,9 +8240,9 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, if (n && VIR_ALLOC_N(def->hostdevs, n) < 0) goto no_memory; for (i = 0 ; i < n ; i++) { - virDomainHostdevDefPtr hostdev = virDomainHostdevDefParseXML(nodes[i], - bootMap, - flags); + virDomainHostdevDefPtr hostdev; + + hostdev = virDomainHostdevDefParseXML(nodes[i], ctxt, bootMap, flags); if (!hostdev) goto error; @@ -10532,6 +10564,64 @@ virDomainFSDefFormat(virBufferPtr buf, } static int +virDomainHostdevSourceFormat(virBufferPtr buf, + virDomainHostdevDefPtr def, + unsigned int flags, + bool includeTypeInAddr) +{ + virBufferAddLit(buf, "<source>\n"); + switch (def->source.subsys.type) + { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + if (def->source.subsys.u.usb.vendor) { + virBufferAsprintf(buf, " <vendor id='0x%.4x'/>\n", + def->source.subsys.u.usb.vendor); + virBufferAsprintf(buf, " <product id='0x%.4x'/>\n", + def->source.subsys.u.usb.product); + } + if (def->source.subsys.u.usb.bus || + def->source.subsys.u.usb.device) { + virBufferAsprintf(buf, " <address %sbus='%d' device='%d'/>\n", + includeTypeInAddr ? "type='usb' " : "", + def->source.subsys.u.usb.bus, + def->source.subsys.u.usb.device); + } + break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + virBufferAsprintf(buf, " <address %sdomain='0x%.4x' bus='0x%.2x' " + "slot='0x%.2x' function='0x%.1x'/>\n", + includeTypeInAddr ? "type='pci' " : "", + def->source.subsys.u.pci.domain, + def->source.subsys.u.pci.bus, + def->source.subsys.u.pci.slot, + def->source.subsys.u.pci.function); + + if ((flags & VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES) && + (def->origstates.states.pci.unbind_from_stub || + def->origstates.states.pci.remove_slot || + def->origstates.states.pci.reprobe)) { + virBufferAddLit(buf, " <origstates>\n"); + if (def->origstates.states.pci.unbind_from_stub) + virBufferAddLit(buf, " <unbind/>\n"); + if (def->origstates.states.pci.remove_slot) + virBufferAddLit(buf, " <removeslot/>\n"); + if (def->origstates.states.pci.reprobe) + virBufferAddLit(buf, " <reprobe/>\n"); + virBufferAddLit(buf, " </origstates>\n"); + } + break; + default: + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected hostdev type %d"), + def->source.subsys.type); + return -1; + } + + virBufferAddLit(buf, "</source>\n"); + return 0; +} + +static int virDomainActualNetDefFormat(virBufferPtr buf, virDomainActualNetDefPtr def) { @@ -11549,44 +11639,11 @@ virDomainHostdevDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " <hostdev mode='%s' type='%s' managed='%s'>\n", mode, type, def->managed ? "yes" : "no"); - virBufferAddLit(buf, " <source>\n"); - if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { - if (def->source.subsys.u.usb.vendor) { - virBufferAsprintf(buf, " <vendor id='0x%.4x'/>\n", - def->source.subsys.u.usb.vendor); - virBufferAsprintf(buf, " <product id='0x%.4x'/>\n", - def->source.subsys.u.usb.product); - } - if (def->source.subsys.u.usb.bus || - def->source.subsys.u.usb.device) - virBufferAsprintf(buf, " <address bus='%d' device='%d'/>\n", - def->source.subsys.u.usb.bus, - def->source.subsys.u.usb.device); - } else if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { - virBufferAsprintf(buf, " <address domain='0x%.4x' bus='0x%.2x' " - "slot='0x%.2x' function='0x%.1x'/>\n", - def->source.subsys.u.pci.domain, - def->source.subsys.u.pci.bus, - def->source.subsys.u.pci.slot, - def->source.subsys.u.pci.function); - - if ((flags & VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES) && - (def->origstates.states.pci.unbind_from_stub || - def->origstates.states.pci.remove_slot || - def->origstates.states.pci.reprobe)) { - virBufferAddLit(buf, " <origstates>\n"); - if (def->origstates.states.pci.unbind_from_stub) - virBufferAddLit(buf, " <unbind/>\n"); - if (def->origstates.states.pci.remove_slot) - virBufferAddLit(buf, " <removeslot/>\n"); - if (def->origstates.states.pci.reprobe) - virBufferAddLit(buf, " <reprobe/>\n"); - virBufferAddLit(buf, " </origstates>\n"); - } - } - - virBufferAddLit(buf, " </source>\n"); + virBufferAdjustIndent(buf, 6); + if (virDomainHostdevSourceFormat(buf, def, flags, false) < 0) + return -1; + virBufferAdjustIndent(buf, -6); if (virDomainDeviceInfoFormat(buf, def->info, flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT -- 1.7.7.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list