[libvirt] [PATCH 4/4] conf: permit auto-assignment of controller indexes

Cole Robinson crobinso at redhat.com
Sun May 15 18:29:35 UTC 2016


On 05/14/2016 10:56 AM, Cole Robinson wrote:
> On 05/11/2016 10:58 AM, Laine Stump wrote:
>> 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 */
>>
> 
> I agree with the goal of the patch, but I think all the index assignment code
> should be moved to somewhere in the PostParse call path. The fact that the
> controller ParseXML now needs to act on the entire domain def is a giveaway
> that it's in the wrong place.
> 
> Also this seems like it should have test suite changes too

Also, formatdomain.html.in has a reference to 'index' being mandatory

- Cole




More information about the libvir-list mailing list