Hand-entering indexes for 20 PCI controllers is not as tedious as manually determining and entering their PCI addresses, but it's still annoying, and the algorithm for determining the proper index is incredibly simple (in all cases except one) - just pick the lowest unused index. The one exception is USB2 controllers because multiple controllers in the same group have the same index. For these we look to see if 1) the most recently added USB controller is also a USB2 controller, and 2) the group *that* controller belongs to doesn't yet have a controller of the exact model we're just now adding - if both are true, the new controller gets the same index, but in all other cases we just assign the lowest unused index. With this patch in place and combined with the automatic PCI address assignment, we can define a PCIe switch with several ports like this: <controller type='pci' model='pcie-root-port'/> <controller type='pci' model='pcie-switch-upstream-port'/> <controller type='pci' model='pcie-switch-downstream-port'/> <controller type='pci' model='pcie-switch-downstream-port'/> <controller type='pci' model='pcie-switch-downstream-port'/> <controller type='pci' model='pcie-switch-downstream-port'/> <controller type='pci' model='pcie-switch-downstream-port'/> ... These will each get a unique index, and PCI addresses that connect them together appropriately with no pesky numbers required. --- docs/schemas/domaincommon.rng | 8 ++-- src/conf/domain_conf.c | 89 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 82 insertions(+), 15 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 273715c..6abd771 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1701,9 +1701,11 @@ </define> <define name="controller"> <element name="controller"> - <attribute name="index"> - <ref name="unsignedInt"/> - </attribute> + <optional> + <attribute name="index"> + <ref name="unsignedInt"/> + </attribute> + </optional> <interleave> <optional> <ref name="alias"/> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 728949b..85ffcac 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7850,6 +7850,7 @@ virDomainControllerModelTypeToString(virDomainControllerDefPtr def, static virDomainControllerDefPtr virDomainControllerDefParseXML(xmlNodePtr node, xmlXPathContextPtr ctxt, + virDomainDef const *dom, unsigned int flags) { virDomainControllerDefPtr def = NULL; @@ -7890,6 +7891,15 @@ virDomainControllerDefParseXML(xmlNodePtr node, if (!(def = virDomainControllerDefNew(type))) goto error; + model = virXMLPropString(node, "model"); + if (model) { + if ((def->model = virDomainControllerModelTypeFromString(def, model)) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unknown model type '%s'"), model); + goto error; + } + } + idx = virXMLPropString(node, "index"); if (idx) { if (virStrToLong_ui(idx, NULL, 10, &def->idx) < 0 || @@ -7898,15 +7908,70 @@ virDomainControllerDefParseXML(xmlNodePtr node, _("Cannot parse controller index %s"), idx); goto error; } - } + } else { + /* When no index is provided, find one by looking at what + * indexes are already used for this controller type in the + * domain. + */ + virDomainControllerDefPtr prev = NULL; + + if (IS_USB2_CONTROLLER(def)) { + /* Attempt to put new USB2 controller at the same index as + * other USB2 controllers, but only if this appears to be + * the intent. To prove intent: The last USB controller + * already on the list must also be a USB2 controller, and + * there must not yet be a controller with the exact same + * model of this one and the same index as the previously + * added controller (e.g., if this controller is a UHCI1, + * then the previous controller must be an EHCI1 or a + * UHCI[23], and there must not already be a UHCI1 + * controller with the same index as the previous + * controller). If all of these are satisfied, set this + * controller to the same index as the previous + * controller. NB: we are of course assuming that this + * new controller is about to be appended to the domain's + * controller list. + */ + int prevIdx; + size_t i; - model = virXMLPropString(node, "model"); - if (model) { - if ((def->model = virDomainControllerModelTypeFromString(def, model)) < 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unknown model type '%s'"), model); - goto error; + if (dom->ncontrollers) { + prevIdx = dom->ncontrollers - 1; + while (prevIdx >= 0 && + dom->controllers[prevIdx]->type != VIR_DOMAIN_CONTROLLER_TYPE_USB) + prevIdx--; + if (prevIdx >= 0) + prev = dom->controllers[prevIdx]; + } + /* if the last USB controller isn't USB2, that breaks + * the chain, so we need a new index for this new + * controller + */ + if (!IS_USB2_CONTROLLER(prev)) + prev = NULL; + + /* if prev != NULL, we've found a potential index to + * use. Now we need to make sure that index isn't + * already used by an existing USB2 controller of the + * same model as this new one. + */ + for (i = 0; prev && i < dom->ncontrollers; i++) { + if (dom->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && + dom->controllers[i]->idx == prev->idx && + dom->controllers[i]->model == def->model) { + /* already have a controller of this model + * with the proposed index, so we need to move + * to a new index + */ + prev = NULL; + } + } + if (prev) + def->idx = prev->idx; } + /* if none of the above applied, prev will be NULL */ + if (!prev) + def->idx = virDomainControllerFindUnusedIndex(dom, def->type); } cur = node->children; @@ -12958,7 +13023,7 @@ virDomainDeviceDefParse(const char *xmlStr, break; case VIR_DOMAIN_DEVICE_CONTROLLER: if (!(dev->data.controller = virDomainControllerDefParseXML(node, ctxt, - flags))) + def, flags))) goto error; break; case VIR_DOMAIN_DEVICE_GRAPHICS: @@ -16157,10 +16222,10 @@ virDomainDefParseXML(xmlDocPtr xml, goto error; for (i = 0; i < n; i++) { - virDomainControllerDefPtr controller = virDomainControllerDefParseXML(nodes[i], - ctxt, - flags); - if (!controller) + virDomainControllerDefPtr controller; + + if (!(controller = virDomainControllerDefParseXML(nodes[i], ctxt, + def, flags))) goto error; /* sanitize handling of "none" usb controller */ -- 2.5.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list