[PATCH 1/5] conf: add xen hypervisor feature 'passthrough'

Jim Fehlig jfehlig at suse.com
Fri Apr 17 22:29:35 UTC 2020


'passthrough' is Xen-Specific guest configuration option new to Xen 4.13
that enables IOMMU mappings for a guest and hence whether it supports PCI
passthrough. The default is disabled. See the xl.cfg(5) man page and
xen.git commit babde47a3fe for more details.

The default state of disabled prevents hotlugging PCI devices. However,
if the guest configuration contains a PCI passthrough device at time of
creation, libxl will automatically enable 'passthrough' and subsequent
hotplugging of PCI devices will also be possible. It is not possible to
unconditionally enable 'passthrough' since it would introduce a migration
incompatibility due to guest ABI change. Instead, introduce another Xen
hypervisor feature that can be used to enable guest PCI passthrough

  <features>
    <xen>
      <passthrough state='on'/>
    </xen>
  </features>

To allow finer control over how IOMMU maps to guest P2M table, the
passthrough element also supports a 'mode' attribute with values
restricted to snyc_pt and share_pt, similar to xl.cfg(5) 'passthrough'
setting .

Signed-off-by: Jim Fehlig <jfehlig at suse.com>
---
 docs/formatdomain.html.in     |   7 +++
 docs/schemas/domaincommon.rng |  12 ++++
 src/conf/domain_conf.c        | 115 ++++++++++++++++++++++++++--------
 src/conf/domain_conf.h        |  11 ++++
 4 files changed, 119 insertions(+), 26 deletions(-)

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 81060d6730..9ccae54e04 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2063,6 +2063,7 @@
   </kvm>
   <xen>
     <e820_host state='on'/>
+    <passthrough state='on' mode='share_pt'/>
   </xen>
   <pvspinlock state='on'/>
   <gic version='2'/>
@@ -2260,6 +2261,12 @@
           <td>on, off</td>
           <td><span class="since">6.3.0</span></td>
         </tr>
+        <tr>
+          <td>passthrough</td>
+          <td>Enable IOMMU mappings allowing PCI passthrough)</td>
+          <td>on, off; mode - optional string sync_pt or share_pt</td>
+          <td><span class="since">6.3.0</span></td>
+        </tr>
       </table>
       </dd>
       <dt><code>pmu</code></dt>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 2b5f844658..a6f6e8ab83 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -6349,6 +6349,18 @@
             <ref name="featurestate"/>
           </element>
         </optional>
+        <optional>
+          <element name="passthrough">
+            <ref name="featurestate"/>
+            <optional>
+              <attribute name="mode">
+                <data type="string">
+                  <param name='pattern'>(sync_pt|share_pt)</param>
+                </data>
+              </attribute>
+            </optional>
+          </element>
+        </optional>
       </interleave>
     </element>
   </define>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index dabbceb265..9f3362c934 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -209,7 +209,15 @@ VIR_ENUM_IMPL(virDomainKVM,
 
 VIR_ENUM_IMPL(virDomainXen,
               VIR_DOMAIN_XEN_LAST,
-              "e820_host"
+              "e820_host",
+              "passthrough",
+);
+
+VIR_ENUM_IMPL(virDomainXenPassthroughMode,
+              VIR_DOMAIN_XEN_PASSTHROUGH_MODE_LAST,
+              "default",
+              "sync_pt",
+              "share_pt",
 );
 
 VIR_ENUM_IMPL(virDomainMsrsUnknown,
@@ -21182,6 +21190,8 @@ virDomainDefParseXML(xmlDocPtr xml,
     if (def->features[VIR_DOMAIN_FEATURE_XEN] == VIR_TRISTATE_SWITCH_ON) {
         int feature;
         int value;
+        g_autofree char *ptval = NULL;
+
         if ((n = virXPathNodeSet("./features/xen/*", ctxt, &nodes)) < 0)
             goto error;
 
@@ -21194,27 +21204,53 @@ virDomainDefParseXML(xmlDocPtr xml,
                 goto error;
             }
 
+            if (!(tmp = virXMLPropString(nodes[i], "state"))) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("missing 'state' attribute for "
+                                 "Xen feature '%s'"),
+                               nodes[i]->name);
+                goto error;
+            }
+
+            if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("invalid value of state argument "
+                                 "for Xen feature '%s'"),
+                               nodes[i]->name);
+                goto error;
+            }
+
+            VIR_FREE(tmp);
+            def->xen_features[feature] = value;
+
             switch ((virDomainXen) feature) {
                 case VIR_DOMAIN_XEN_E820_HOST:
-                    if (!(tmp = virXMLPropString(nodes[i], "state"))) {
-                        virReportError(VIR_ERR_XML_ERROR,
-                                       _("missing 'state' attribute for "
-                                         "Xen feature '%s'"),
-                                       nodes[i]->name);
-                        goto error;
-                    }
+                    break;
 
-                    if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
+            case VIR_DOMAIN_XEN_PASSTHROUGH:
+                if (value != VIR_TRISTATE_SWITCH_ON)
+                    break;
+
+                if ((ptval = virXMLPropString(nodes[i], "mode"))) {
+                    int mode = virDomainXenPassthroughModeTypeFromString(ptval);
+
+                    if (mode < 0) {
                         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                       _("invalid value of state argument "
-                                         "for Xen feature '%s'"),
-                                       nodes[i]->name);
+                                       _("unsupported mode '%s' for Xen passthrough feature"),
+                                       ptval);
                         goto error;
                     }
 
-                    VIR_FREE(tmp);
-                    def->xen_features[feature] = value;
-                    break;
+                    if (mode != VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SYNC_PT &&
+                        mode != VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SHARE_PT) {
+                        virReportError(VIR_ERR_XML_ERROR, "%s",
+                                       _("'mode' attribute for Xen feature "
+                                         "'passthrough' must be 'sync_pt' or 'share_pt'"));
+                        goto error;
+                    }
+                    def->xen_passthrough_mode = mode;
+                }
+                break;
 
                 /* coverity[dead_error_begin] */
                 case VIR_DOMAIN_XEN_LAST:
@@ -23400,18 +23436,28 @@ virDomainDefFeaturesCheckABIStability(virDomainDefPtr src,
     /* xen */
     if (src->features[VIR_DOMAIN_FEATURE_XEN] == VIR_TRISTATE_SWITCH_ON) {
         for (i = 0; i < VIR_DOMAIN_XEN_LAST; i++) {
+            if (src->xen_features[i] != dst->xen_features[i]) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("State of Xen feature '%s' differs: "
+                                 "source: '%s', destination: '%s'"),
+                               virDomainXenTypeToString(i),
+                               virTristateSwitchTypeToString(src->xen_features[i]),
+                               virTristateSwitchTypeToString(dst->xen_features[i]));
+                return false;
+            }
             switch ((virDomainXen) i) {
             case VIR_DOMAIN_XEN_E820_HOST:
-                if (src->xen_features[i] != dst->xen_features[i]) {
+                break;
+
+            case VIR_DOMAIN_XEN_PASSTHROUGH:
+                if (src->xen_passthrough_mode != dst->xen_passthrough_mode) {
                     virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                   _("State of Xen feature '%s' differs: "
+                                   _("'mode' of Xen passthrough feature differs: "
                                      "source: '%s', destination: '%s'"),
-                                   virDomainXenTypeToString(i),
-                                   virTristateSwitchTypeToString(src->xen_features[i]),
-                                   virTristateSwitchTypeToString(dst->xen_features[i]));
+                                   virDomainXenPassthroughModeTypeToString(src->xen_passthrough_mode),
+                                   virDomainXenPassthroughModeTypeToString(dst->xen_passthrough_mode));
                     return false;
                 }
-
                 break;
 
             /* coverity[dead_error_begin] */
@@ -29047,13 +29093,30 @@ virDomainDefFormatFeatures(virBufferPtr buf,
             virBufferAddLit(&childBuf, "<xen>\n");
             virBufferAdjustIndent(&childBuf, 2);
             for (j = 0; j < VIR_DOMAIN_XEN_LAST; j++) {
+                if (def->xen_features[j] == VIR_TRISTATE_SWITCH_ABSENT)
+                    continue;
+
+                virBufferAsprintf(&childBuf, "<%s state='%s'",
+                                      virDomainXenTypeToString(j),
+                                      virTristateSwitchTypeToString(
+                                          def->xen_features[j]));
+
                 switch ((virDomainXen) j) {
                 case VIR_DOMAIN_XEN_E820_HOST:
-                    if (def->xen_features[j])
-                        virBufferAsprintf(&childBuf, "<%s state='%s'/>\n",
-                                          virDomainXenTypeToString(j),
-                                          virTristateSwitchTypeToString(
-                                              def->xen_features[j]));
+                    virBufferAddLit(&childBuf, "/>\n");
+                    break;
+                case VIR_DOMAIN_XEN_PASSTHROUGH:
+                    if (def->xen_features[j] != VIR_TRISTATE_SWITCH_ON) {
+                        virBufferAddLit(&childBuf, "/>\n");
+                        break;
+                    }
+                    if (def->xen_passthrough_mode == VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SYNC_PT ||
+                        def->xen_passthrough_mode == VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SHARE_PT) {
+                        virBufferEscapeString(&childBuf, " mode='%s'/>\n",
+                                              virDomainXenPassthroughModeTypeToString(def->xen_passthrough_mode));
+                    } else {
+                        virBufferAddLit(&childBuf, "/>\n");
+                    }
                     break;
 
                 /* coverity[dead_error_begin] */
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 0374494076..dabcd5197d 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1862,10 +1862,19 @@ typedef enum {
 
 typedef enum {
     VIR_DOMAIN_XEN_E820_HOST = 0,
+    VIR_DOMAIN_XEN_PASSTHROUGH,
 
     VIR_DOMAIN_XEN_LAST
 } virDomainXen;
 
+typedef enum {
+    VIR_DOMAIN_XEN_PASSTHROUGH_MODE_DEFAULT = 0,
+    VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SYNC_PT,
+    VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SHARE_PT,
+
+    VIR_DOMAIN_XEN_PASSTHROUGH_MODE_LAST
+} virDomainXenPassthroughMode;
+
 typedef enum {
     VIR_DOMAIN_CAPABILITIES_POLICY_DEFAULT = 0,
     VIR_DOMAIN_CAPABILITIES_POLICY_ALLOW,
@@ -2492,6 +2501,7 @@ struct _virDomainDef {
     int kvm_features[VIR_DOMAIN_KVM_LAST];
     int msrs_features[VIR_DOMAIN_MSRS_LAST];
     int xen_features[VIR_DOMAIN_XEN_LAST];
+    int xen_passthrough_mode;
     unsigned int hyperv_spinlocks;
     int hyperv_stimer_direct;
     virGICVersion gic_version;
@@ -3538,6 +3548,7 @@ VIR_ENUM_DECL(virDomainGraphicsVNCSharePolicy);
 VIR_ENUM_DECL(virDomainHyperv);
 VIR_ENUM_DECL(virDomainKVM);
 VIR_ENUM_DECL(virDomainXen);
+VIR_ENUM_DECL(virDomainXenPassthroughMode);
 VIR_ENUM_DECL(virDomainMsrsUnknown);
 VIR_ENUM_DECL(virDomainRNGModel);
 VIR_ENUM_DECL(virDomainRNGBackend);
-- 
2.26.0





More information about the libvir-list mailing list