]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
conf: Add support to parse/format <source> for NVRAM
authorRohit Kumar <rohit.kumar3@nutanix.com>
Wed, 4 May 2022 16:51:12 +0000 (09:51 -0700)
committerPeter Krempa <pkrempa@redhat.com>
Tue, 14 Jun 2022 13:53:11 +0000 (15:53 +0200)
This patch introduces the logic to format and parse remote NVRAM.

Update NVRAM element schema, and docs for supporting network backed
NVRAM. NVRAM backed over network would give the flexibility to start
the VM on any host without having to worry about where to get the latest
nvram image.

<nvram type='network'>
  <source protocol='iscsi' name='iqn.2013-07.com.example:iscsi-nopool/0'>
    <host name='example.com' port='6000'/>
  </source>
</nvram>

or

<nvram type='file'>
  <source file='/var/lib/libvirt/nvram/guest_VARS.fd'/>
</nvram>

In the qemu driver we will support the new definition only with qemu's
supporting -blockdev.

Signed-off-by: Prerna Saxena <prerna.saxena@nutanix.com>
Signed-off-by: Florian Schmidt <flosch@nutanix.com>
Signed-off-by: Rohit Kumar <rohit.kumar3@nutanix.com>
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Tested-by: Rohit Kumar <rohit.kumar3@nutanix.com>
docs/formatdomain.rst
src/conf/domain_conf.c
src/conf/domain_conf.h
src/conf/schemas/domaincommon.rng
src/qemu/qemu_validate.c

index 7da625380cda213eef74d89aa7c2c2be48615e83..b6a34950936fdbc1664bc1a2c80ecc0bb09a09a4 100644 (file)
@@ -135,6 +135,35 @@ harddisk, cdrom, network) determining where to obtain/find the boot image.
    </os>
    ...
 
+   <!-- QEMU with UEFI manual firmware, secure boot and with NVRAM type 'file'-->
+   ...
+   <os>
+     <type>hvm</type>
+     <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
+     <nvram type='file' template='/usr/share/OVMF/OVMF_VARS.fd'>
+       <source file='/var/lib/libvirt/nvram/guest_VARS.fd'/>
+     </nvram>
+     <boot dev='hd'/>
+   </os>
+   ...
+
+   <!-- QEMU with UEFI manual firmware, secure boot and with network backed NVRAM'-->
+   ...
+   <os>
+     <type>hvm</type>
+     <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
+     <nvram type='network'>
+       <source protocol='iscsi' name='iqn.2013-07.com.example:iscsi-nopool/0'>
+         <host name='example.com' port='6000'/>
+         <auth username='myname'>
+           <secret type='iscsi' usage='mycluster_myname'/>
+         </auth>
+       </source>
+     </nvram>
+     <boot dev='hd'/>
+   </os>
+   ...
+
    <!-- QEMU with automatic UEFI firmware and secure boot -->
    ...
    <os firmware='efi'>
@@ -224,6 +253,15 @@ harddisk, cdrom, network) determining where to obtain/find the boot image.
    if the NVRAM file has been created by libvirt it is left behind and it is
    management application's responsibility to save and remove file (if needed to
    be persistent). :since:`Since 1.2.8`
+
+   :since:`Since 8.5.0`,  it's possible for the element to have ``type`` attribute
+   (accepts values ``file``, ``block`` and ``network``) in that case the NVRAM
+   storage is described by a ``<source>`` sub-element with the same syntax as
+   ``disk``'s source. See `Hard drives, floppy disks, CDROMs`_.
+
+   **Note:** ``network`` backed NVRAM the variables are not instantiated from
+   the ``template`` and it's user's responsibility to provide a valid NVRAM image.
+
 ``boot``
    The ``dev`` attribute takes one of the values "fd", "hd", "cdrom" or
    "network" and is used to specify the next boot device to consider. The
index 21e383c148d09ff9067dd26988236ee1efbe00bd..d3aa827accd4bdd09c9ecd8d38674b0e2835bbea 100644 (file)
@@ -18013,6 +18013,51 @@ virDomainLoaderDefParseXML(xmlNodePtr node,
 }
 
 
+static int
+virDomainNvramDefParseXML(virDomainLoaderDef *loader,
+                          xmlXPathContextPtr ctxt,
+                          virDomainXMLOption *xmlopt,
+                          unsigned int flags)
+{
+    g_autofree char *nvramType = virXPathString("string(./os/nvram/@type)", ctxt);
+    g_autoptr(virStorageSource) src = virStorageSourceNew();
+
+    src->type = VIR_STORAGE_TYPE_FILE;
+    src->format = VIR_STORAGE_FILE_RAW;
+
+    if (!nvramType) {
+        char *nvramPath = NULL;
+
+        if (!(nvramPath = virXPathString("string(./os/nvram[1])", ctxt)))
+            return 0; /* no nvram */
+
+        src->path = nvramPath;
+    } else {
+        xmlNodePtr sourceNode;
+
+        if ((src->type = virStorageTypeFromString(nvramType)) <= 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("unknown disk type '%s'"), nvramType);
+            return -1;
+        }
+
+        if (!(sourceNode = virXPathNode("./os/nvram/source[1]", ctxt))) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("Missing source element for nvram"));
+            return -1;
+        }
+
+        if (virDomainStorageSourceParse(sourceNode, ctxt, src, flags, xmlopt) < 0)
+            return -1;
+
+        loader->newStyleNVRAM = true;
+    }
+
+    loader->nvram = g_steal_pointer(&src);
+    return 0;
+}
+
+
 static int
 virDomainSchedulerParseCommonAttrs(xmlNodePtr node,
                                    virProcessSchedPolicy *policy,
@@ -18398,11 +18443,12 @@ virDomainDefParseBootFirmwareOptions(virDomainDef *def,
 
 static int
 virDomainDefParseBootLoaderOptions(virDomainDef *def,
-                                   xmlXPathContextPtr ctxt)
+                                   xmlXPathContextPtr ctxt,
+                                   virDomainXMLOption *xmlopt,
+                                   unsigned int flags)
 {
     xmlNodePtr loader_node = virXPathNode("./os/loader[1]", ctxt);
     const bool fwAutoSelect = def->os.firmware != VIR_DOMAIN_OS_DEF_FIRMWARE_NONE;
-    g_autofree char *nvramPath = NULL;
 
     if (!loader_node)
         return 0;
@@ -18414,12 +18460,8 @@ virDomainDefParseBootLoaderOptions(virDomainDef *def,
                                    fwAutoSelect) < 0)
         return -1;
 
-    if ((nvramPath = virXPathString("string(./os/nvram[1])", ctxt))) {
-        def->os.loader->nvram = virStorageSourceNew();
-        def->os.loader->nvram->path = g_steal_pointer(&nvramPath);
-        def->os.loader->nvram->type = VIR_STORAGE_TYPE_FILE;
-        def->os.loader->nvram->format = VIR_STORAGE_FILE_RAW;
-    }
+    if (virDomainNvramDefParseXML(def->os.loader, ctxt, xmlopt, flags) < 0)
+        return -1;
 
     if (!fwAutoSelect)
         def->os.loader->nvramTemplate = virXPathString("string(./os/nvram[1]/@template)", ctxt);
@@ -18474,7 +18516,9 @@ virDomainDefParseBootAcpiOptions(virDomainDef *def,
 
 static int
 virDomainDefParseBootOptions(virDomainDef *def,
-                             xmlXPathContextPtr ctxt)
+                             xmlXPathContextPtr ctxt,
+                             virDomainXMLOption *xmlopt,
+                             unsigned int flags)
 {
     /*
      * Booting options for different OS types....
@@ -18492,7 +18536,7 @@ virDomainDefParseBootOptions(virDomainDef *def,
         if (virDomainDefParseBootFirmwareOptions(def, ctxt) < 0)
             return -1;
 
-        if (virDomainDefParseBootLoaderOptions(def, ctxt) < 0)
+        if (virDomainDefParseBootLoaderOptions(def, ctxt, xmlopt, flags) < 0)
             return -1;
 
         if (virDomainDefParseBootAcpiOptions(def, ctxt) < 0)
@@ -18508,7 +18552,7 @@ virDomainDefParseBootOptions(virDomainDef *def,
     case VIR_DOMAIN_OSTYPE_UML:
         virDomainDefParseBootKernelOptions(def, ctxt);
 
-        if (virDomainDefParseBootLoaderOptions(def, ctxt) < 0)
+        if (virDomainDefParseBootLoaderOptions(def, ctxt, xmlopt, flags) < 0)
             return -1;
 
         break;
@@ -19808,7 +19852,7 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt,
     if (virDomainDefClockParse(def, ctxt) < 0)
         return NULL;
 
-    if (virDomainDefParseBootOptions(def, ctxt) < 0)
+    if (virDomainDefParseBootOptions(def, ctxt, xmlopt, flags) < 0)
         return NULL;
 
     /* analysis of the disk devices */
@@ -27161,26 +27205,48 @@ virDomainHugepagesFormat(virBuffer *buf,
 }
 
 
-static void
+static int
 virDomainLoaderDefFormatNvram(virBuffer *buf,
-                              virDomainLoaderDef *loader)
+                              virDomainLoaderDef *loader,
+                              virDomainXMLOption *xmlopt,
+                              unsigned int flags)
 {
     g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
-    g_auto(virBuffer) childBuf = VIR_BUFFER_INITIALIZER;
+    g_auto(virBuffer) childBufDirect = VIR_BUFFER_INITIALIZER;
+    g_auto(virBuffer) childBufChild = VIR_BUFFER_INIT_CHILD(buf);
+    virBuffer *childBuf = &childBufDirect;
+    bool childNewline = false;
 
     virBufferEscapeString(&attrBuf, " template='%s'", loader->nvramTemplate);
+
     if (loader->nvram) {
-        if (loader->nvram->type == VIR_STORAGE_TYPE_FILE)
-            virBufferEscapeString(&childBuf, "%s", loader->nvram->path);
+        virStorageSource *src = loader->nvram;
+
+        if (!loader->newStyleNVRAM) {
+            virBufferEscapeString(&childBufDirect, "%s", src->path);
+        } else {
+            childNewline = true;
+            childBuf = &childBufChild;
+
+            virBufferAsprintf(&attrBuf, " type='%s'", virStorageTypeToString(src->type));
+
+            if (virDomainDiskSourceFormat(&childBufChild, src, "source", 0,
+                                          false, flags, false, false, xmlopt) < 0)
+                return -1;
+        }
     }
 
-    virXMLFormatElementInternal(buf, "nvram", &attrBuf, &childBuf, false, false);
+    virXMLFormatElementInternal(buf, "nvram", &attrBuf, childBuf, false, childNewline);
+
+    return 0;
 }
 
 
-static void
+static int
 virDomainLoaderDefFormat(virBuffer *buf,
-                         virDomainLoaderDef *loader)
+                         virDomainLoaderDef *loader,
+                         virDomainXMLOption *xmlopt,
+                         unsigned int flags)
 {
     g_auto(virBuffer) loaderAttrBuf = VIR_BUFFER_INITIALIZER;
     g_auto(virBuffer) loaderChildBuf = VIR_BUFFER_INITIALIZER;
@@ -27201,7 +27267,10 @@ virDomainLoaderDefFormat(virBuffer *buf,
 
     virXMLFormatElementInternal(buf, "loader", &loaderAttrBuf, &loaderChildBuf, false, false);
 
-    virDomainLoaderDefFormatNvram(buf, loader);
+    if (virDomainLoaderDefFormatNvram(buf, loader, xmlopt, flags) < 0)
+        return -1;
+
+    return 0;
 }
 
 static void
@@ -28454,8 +28523,9 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def,
     if (def->os.initgroup)
         virBufferAsprintf(buf, "<initgroup>%s</initgroup>\n", def->os.initgroup);
 
-    if (def->os.loader)
-        virDomainLoaderDefFormat(buf, def->os.loader);
+    if (def->os.loader &&
+        virDomainLoaderDefFormat(buf, def->os.loader, xmlopt, flags) < 0)
+        return -1;
     virBufferEscapeString(buf, "<kernel>%s</kernel>\n",
                           def->os.kernel);
     virBufferEscapeString(buf, "<initrd>%s</initrd>\n",
index 1b0ec8385757e0a6cea440f1228af3d64c46e1fa..292fd62beb14c95c53e651d9e2123f9973b77545 100644 (file)
@@ -2254,6 +2254,7 @@ struct _virDomainLoaderDef {
     virDomainLoader type;
     virTristateBool secure;
     virStorageSource *nvram;
+    bool newStyleNVRAM;
     char *nvramTemplate;   /* user override of path to master nvram */
 };
 
index efd49cfa0168a12508f2bb5071ae787773355bda..3ba4da46a4bba4dbd65d50a2da8888972751e328 100644 (file)
               </attribute>
             </optional>
             <optional>
-              <ref name="absFilePath"/>
+              <choice>
+                <group>
+                  <ref name="absFilePath"/>
+                </group>
+                <group>
+                  <ref name="diskSource"/>
+                </group>
+              </choice>
             </optional>
           </element>
         </optional>
index cf3968413c15654f544a7864b0ebaea18dd98a2f..f8aa83c1cbcb0f0e581a0d9643629940d9544506 100644 (file)
@@ -609,6 +609,13 @@ qemuValidateDomainDefNvram(const virDomainDef *def,
     if (!src)
         return 0;
 
+    if (def->os.loader->newStyleNVRAM &&
+        !virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("modern nvram specification is not supported by this qemu"));
+        return -1;
+    }
+
     switch (src->type) {
     case VIR_STORAGE_TYPE_FILE:
     case VIR_STORAGE_TYPE_BLOCK: