
On 07/22/2015 03:30 PM, John Ferlan wrote:
On 07/17/2015 02:43 PM, Laine Stump wrote:
This new subelement is used in PCI controllers: the toplevel *attribute* "model" of a controller denotes what kind of PCI controller is being described, e.g. a "dmi-to-pci-bridge", "pci-bridge", or "pci-root". But in the future there will be different implementations of some of those types of PCI controllers, which behave similarly from libvirt's point of view (and so should have the same model), but use a different device in qemu (and present themselves as a different piece of hardware in the guest). In an ideal world we (i.e. "I") would have thought of that back when the pci controllers were added, and used some sort of type/class/model notation (where class was used in the way we are now using model, and model was used for the actual manufacturer's model number of a particular family of PCI controller), but that opportunity is long past, so as an alternative, this patch allows selecting a particular implementation of a pci controller with the "type" attribute of the <model> subelement, e.g.:
<controller type='pci' model='dmi-to-pci-bridge' index='1'> <model type='i82801b11-bridge'/> </controller>
In this case, "dmi-to-pci-bridge" is the kind of controller (one that has a single PCIe port upstream, and 32 standard PCI ports downstream, which are not hotpluggable), and the qemu device to be used to implement this kind of controller is named "i82801b11-bridge".
Implementing the above now will allow us in the future to add a new kind of dmi-to-pci-bridge that doesn't use qemu's i82801b11-bridge device, but instead uses something else (which doesn't yet exist, but qemu people have been discussing it), all without breaking existing configs.
(note that for the existing "pci-bridge" type of PCI controller, both the model attribute and <model> type are 'pci-bridge'. This is just a coincidence, since it turns out that in this case the device name in qemu really is a generic 'pci-bridge' rather than being the name of some real-world chip) --- new in V2 (previously was a part of the patch to add pcie-root-port)
docs/formatdomain.html.in | 12 ++++++++++++ docs/schemas/domaincommon.rng | 13 +++++++++++++ src/conf/domain_conf.c | 23 +++++++++++++++++++++-- src/conf/domain_conf.h | 8 ++++++++ tests/qemuxml2argvdata/qemuxml2argv-q35.xml | 8 ++++++-- tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml | 8 ++++++-- 6 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 8cd8d09..fa46276 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -3037,6 +3037,18 @@ (set to 0). <span class="since">Since 1.1.2 (QEMU only)</span> </p> <p> + PCI controllers also have an optional + subelement <code><model></code> with an attribute named + "type". The type attribute holds the name of the specific device The <code>type</code> attribute...
+ that qemu is emulating (e.g. "i82801b11-bridge") rather than + simply the class of device ("dmi-to-pci-bridge", "pci-bridge"), + which is set in the controller element's model <b>attribute</b>. + In almost all cases, you should not manually add + a <code><model></code> subelement to a controller, nor + should you modify one that is automatically generated by + libvirt. <span class="since">Since 1.3.0 (QEMU only).</span> 1.2.18 (at least for now)
NB: As I read the code, only the *first* <model type='%s'> listed will be used, as virDomainControllerDefParseXML not parse a second entry nor does a second entry cause an error
There are so many examples of this in the code (including the parsing of the <driver> subelement just preceding this new parsing of <model>), it's easy to replicate it in new code :-P I've fixed it in mine, but maybe this should go on a list somewhere of nice beginner patches (I remember someone mentioning that idea - where was it going to go?)
+ </p> + <p> For machine types which provide an implicit PCI bus, the pci-root controller with index=0 is auto-added and required to use PCI devices. pci-root has no address. diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 1120003..66518f9 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1731,6 +1731,19 @@ <attribute name="type"> <value>pci</value> </attribute> + <optional> + <element name="model"> + <attribute name="type"> + <choice> + <!-- implementations of 'pci-bridge' --> + <value>pci-bridge</value> + <!-- implementations of 'dmi-to-pci-bridge' --> + <value>i82801b11-bridge</value> + </choice> + </attribute> + <empty/> + </element> + </optional> <!-- *-root controllers have an optional element "pcihole64"--> <choice> <group> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 8dd4bf0..380b758 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7637,6 +7637,7 @@ virDomainControllerDefParseXML(xmlNodePtr node, char *queues = NULL; char *cmd_per_lun = NULL; char *max_sectors = NULL; + char *guestModel = NULL; xmlNodePtr saved = ctxt->node; int rc;
@@ -7682,6 +7683,9 @@ virDomainControllerDefParseXML(xmlNodePtr node, queues = virXMLPropString(cur, "queues"); cmd_per_lun = virXMLPropString(cur, "cmd_per_lun"); max_sectors = virXMLPropString(cur, "max_sectors"); + } else if (xmlStrEqual(cur->name, BAD_CAST "model")) { + if (!guestModel) + guestModel = virXMLPropString(cur, "type"); So subsequent "<model type='%s'>" are gleefully ignored? Should there be an error? IDC either way, as long as it's described/noted because you know there's someone from QA looking to add two <model...> entries and expecting the second one to be used or an error to be generated.
Of course scrolling back to the RNG - syntactically there can only be one it seems.
But of course validation against the RNG isn't always done.
} } cur = cur->next; @@ -7790,6 +7794,11 @@ virDomainControllerDefParseXML(xmlNodePtr node, def->opts.pciopts.pcihole64size = VIR_DIV_UP(bytes, 1024); } } + if (guestModel) { + def->opts.pciopts.type = guestModel; + guestModel = 0;
s/0/NULL/
Done.
+ } + break;
default: break; @@ -7814,6 +7823,7 @@ virDomainControllerDefParseXML(xmlNodePtr node, VIR_FREE(queues); VIR_FREE(cmd_per_lun); VIR_FREE(max_sectors); + VIR_FREE(guestModel);
return def;
@@ -18823,7 +18833,7 @@ virDomainControllerDefFormat(virBufferPtr buf, { const char *type = virDomainControllerTypeToString(def->type); const char *model = NULL; - bool pcihole64 = false; + bool pcihole64 = false, pciModel = false;
if (!type) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -18863,17 +18873,26 @@ virDomainControllerDefFormat(virBufferPtr buf, case VIR_DOMAIN_CONTROLLER_TYPE_PCI: if (def->opts.pciopts.pcihole64) pcihole64 = true; + if (def->opts.pciopts.type) + pciModel = true; break;
default: break; }
- if (def->queues || def->cmd_per_lun || def->max_sectors || + if (pciModel || + def->queues || def->cmd_per_lun || def->max_sectors || virDomainDeviceInfoNeedsFormat(&def->info, flags) || pcihole64) { virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2);
+ if (pciModel) { + virBufferAddLit(buf, "<model"); + virBufferEscapeString(buf, " type='%s'", def->opts.pciopts.type); + virBufferAddLit(buf, "/>\n"); + } + if (def->queues || def->cmd_per_lun || def->max_sectors) { virBufferAddLit(buf, "<driver"); if (def->queues) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 50750c1..09fe3c0 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -797,6 +797,14 @@ typedef virDomainPCIControllerOpts *virDomainPCIControllerOptsPtr; struct _virDomainPCIControllerOpts { bool pcihole64; unsigned long pcihole64size; + + /* the type is in the "model" subelement, e.g.: + * <controller type='pci' model='pcie-root-port'> + * <model type='ioh3420''/> + * ... + * similar to the model of <interface> devices. + */ + char *type; /* the exact name of the device in hypervisor */ };
/* Stores the virtual disk controller configuration */ Since examples still exist that do not have the <model type='%s'> I suppose it's OK to hijack an existing test, but having a "new" test probably would have been better
I try to not add new test cases when an existing and related case can be made to serve the purpose *without eliminating testing of any other code paths*. It already takes enough time to run make check.
ACK - with the adjustments - whether you update/add a new test is your call.
I've changed it from "type" to "name", and made that into an enum, so it will need to be reviewed again anyway.