On 01/17/2018 12:37 PM, Daniel P. Berrange wrote:
The OEM strings table in SMBIOS allows the vendor to pass arbitrary
strings into the guest OS. This can be used as a way to pass data to an
application like cloud-init, or potentially as an alternative to the
kernel command line for OS installers where you can't modify the install
ISO image to change the kernel args.
As an example, consider if cloud-init and anaconda supported OEM strings
you could use something like
<oemStrings>
<entry>cloud-init:ds=nocloud-net;s=http://10.10.0.1:8000/</entry>
<
entry>anaconda:method=http://dl.fedoraproject.org/pub/fedora/linux/rel...
</oemStrings>
use of a application specific prefix as illustrated above is
recommended, but not mandated, so that an app can reliably identify
which of the many OEM strings are targetted at it.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
docs/formatdomain.html.in | 13 ++++++++++++
docs/schemas/domaincommon.rng | 9 +++++++++
src/conf/domain_conf.c | 47 +++++++++++++++++++++++++++++++++++++++++++
src/util/virsysinfo.c | 33 ++++++++++++++++++++++++++++++
src/util/virsysinfo.h | 10 +++++++++
5 files changed, 112 insertions(+)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index d272cc1ba6..6af2d26209 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -411,6 +411,10 @@
<entry name='version'>0B98401 Pro</entry>
<entry name='serial'>W1KS427111E</entry>
</baseBoard>
+ <oemStrings>
+ <entry>myappname:some arbitrary data</entry>
+ <entry>otherappname:more arbitrary data</entry>
+ </oemStrings>
</sysinfo>
...</pre>
@@ -498,6 +502,15 @@
validation and <code>date</code> format checking, all values
are
passed as strings to the hypervisor driver.
</dd>
+ <dt><code>oemStrings</code></dt>
+ <dd>
+ This is block 11 of SMBIOS. This element should appear once and
+ can have multiple <code>entry</code> child elements, each
providing
+ arbitrary string data. There are no restrictions on what data can
+ be provided in the entries, however, if the data is intended to be
s/, however/; however
+ consumed by an application in the guest, it is
recommended to use
+ the application name as a prefix in the string.
Add the <span class="since">Since 4.1.0</span>
+ </dd>
</dl>
</dd>
</dl>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index f22c932f6c..a154b5a462 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4857,6 +4857,15 @@
</oneOrMore>
</element>
</zeroOrMore>
+ <optional>
+ <element name="oemStrings">
+ <oneOrMore>
+ <element name="entry">
+ <ref name="sysinfo-value"/>
+ </element>
+ </oneOrMore>
+ </element>
+ </optional>
</interleave>
</element>
</define>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index a1c25060f9..6c0ad1ed7d 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -14461,6 +14461,42 @@ virSysinfoBaseBoardParseXML(xmlXPathContextPtr ctxt,
return ret;
}
We've been doing the 2 blank lines between functions more recently -
although it's not officially in the hacking doc.
+static int
+virSysinfoOEMStringsParseXML(xmlNodePtr node,
@node is not used in this context so the compiler tells me ;-)
+ xmlXPathContextPtr ctxt,
+ virSysinfoOEMStringsDefPtr *oem)
+{
+ int ret = -1;
+ virSysinfoOEMStringsDefPtr def;
+ xmlNodePtr *strings = NULL;
+ int nstrings;
+ size_t i;
+
+ nstrings = virXPathNodeSet("./entry", ctxt, &strings);
+ if (nstrings < 0)
+ return -1;
+ if (nstrings == 0)
+ return 0;
+
+ if (VIR_ALLOC(def) < 0)
+ goto cleanup;
+
+ if (VIR_ALLOC_N(def->values, nstrings) < 0)
+ goto cleanup;
+
+ def->nvalues = nstrings;
+ for (i = 0; i < nstrings; i++)
+ def->values[i] = virXMLNodeContentString(strings[i]);
+
+ *oem = def;
+ def = NULL;
+ ret = 0;
+ cleanup:
+ VIR_FREE(strings);
+ virSysinfoOEMStringsDefFree(def);
Coverity notes @def is leaked... [1]...
+ return ret;
+}
+
static virSysinfoDefPtr
virSysinfoParseXML(xmlNodePtr node,
xmlXPathContextPtr ctxt,
@@ -14519,6 +14555,17 @@ virSysinfoParseXML(xmlNodePtr node,
if (virSysinfoBaseBoardParseXML(ctxt, &def->baseBoard,
&def->nbaseBoard) < 0)
goto error;
+ /* Extract system related metadata */
+ if ((tmpnode = virXPathNode("./oemStrings[1]", ctxt)) != NULL) {
+ oldnode = ctxt->node;
+ ctxt->node = tmpnode;
+ if (virSysinfoOEMStringsParseXML(tmpnode, ctxt, &def->oemStrings) < 0)
{
+ ctxt->node = oldnode;
+ goto error;
+ }
+ ctxt->node = oldnode;
+ }
+
cleanup:
VIR_FREE(type);
return def;
diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c
index 1fbdd778f9..60765c38de 100644
--- a/src/util/virsysinfo.c
+++ b/src/util/virsysinfo.c
@@ -108,6 +108,18 @@ void virSysinfoBaseBoardDefClear(virSysinfoBaseBoardDefPtr def)
VIR_FREE(def->location);
}
+void virSysinfoOEMStringsDefFree(virSysinfoOEMStringsDefPtr def)
+{
+ size_t i;
+
+ if (def == NULL)
+ return;
+
+ for (i = 0; i < def->nvalues; i++)
+ VIR_FREE(def->values[i]);
+ VIR_FREE(def->values);
[1] ... because @def is not VIR_FREE'd here.
With the adjustments,
Reviewed-by: John Ferlan <jferlan(a)redhat.com>
John
+}
+
/**
* virSysinfoDefFree:
* @def: a sysinfo structure
@@ -157,6 +169,8 @@ void virSysinfoDefFree(virSysinfoDefPtr def)
}
VIR_FREE(def->memory);
+ virSysinfoOEMStringsDefFree(def->oemStrings);
+
VIR_FREE(def);
}
@@ -1294,6 +1308,24 @@ virSysinfoMemoryFormat(virBufferPtr buf, virSysinfoDefPtr def)
}
}
+static void
+virSysinfoOEMStringsFormat(virBufferPtr buf, virSysinfoOEMStringsDefPtr def)
+{
+ size_t i;
+
+ if (!def)
+ return;
+
+ virBufferAddLit(buf, "<oemStrings>\n");
+ virBufferAdjustIndent(buf, 2);
+ for (i = 0; i < def->nvalues; i++) {
+ virBufferEscapeString(buf, "<entry>%s</entry>\n",
+ def->values[i]);
+ }
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</oemStrings>\n");
+}
+
/**
* virSysinfoFormat:
* @buf: buffer to append output to (may use auto-indentation)
@@ -1324,6 +1356,7 @@ virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def)
virSysinfoBaseBoardFormat(&childrenBuf, def->baseBoard, def->nbaseBoard);
virSysinfoProcessorFormat(&childrenBuf, def);
virSysinfoMemoryFormat(&childrenBuf, def);
+ virSysinfoOEMStringsFormat(&childrenBuf, def->oemStrings);
virBufferAsprintf(buf, "<sysinfo type='%s'", type);
if (virBufferUse(&childrenBuf)) {
diff --git a/src/util/virsysinfo.h b/src/util/virsysinfo.h
index 1e51d2cafa..ecb3a36eb8 100644
--- a/src/util/virsysinfo.h
+++ b/src/util/virsysinfo.h
@@ -98,6 +98,13 @@ struct _virSysinfoBaseBoardDef {
/* XXX board type */
};
+typedef struct _virSysinfoOEMStringsDef virSysinfoOEMStringsDef;
+typedef virSysinfoOEMStringsDef *virSysinfoOEMStringsDefPtr;
+struct _virSysinfoOEMStringsDef {
+ size_t nvalues;
+ char **values;
+};
+
typedef struct _virSysinfoDef virSysinfoDef;
typedef virSysinfoDef *virSysinfoDefPtr;
struct _virSysinfoDef {
@@ -114,6 +121,8 @@ struct _virSysinfoDef {
size_t nmemory;
virSysinfoMemoryDefPtr memory;
+
+ virSysinfoOEMStringsDefPtr oemStrings;
};
virSysinfoDefPtr virSysinfoRead(void);
@@ -121,6 +130,7 @@ virSysinfoDefPtr virSysinfoRead(void);
void virSysinfoBIOSDefFree(virSysinfoBIOSDefPtr def);
void virSysinfoSystemDefFree(virSysinfoSystemDefPtr def);
void virSysinfoBaseBoardDefClear(virSysinfoBaseBoardDefPtr def);
+void virSysinfoOEMStringsDefFree(virSysinfoOEMStringsDefPtr def);
void virSysinfoDefFree(virSysinfoDefPtr def);
int virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def)