https://bugzilla.redhat.com/show_bug.cgi?id=1220527
This type of information defines attributes of a system
baseboard. With one caveat: in qemu they call it family, while
in the specification it's referred to as type. I'm sticking with
the latter.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
docs/formatdomain.html.in | 37 +++++-
docs/schemas/domaincommon.rng | 24 ++++
src/conf/domain_conf.c | 57 +++++++++
src/libvirt_private.syms | 1 +
src/qemu/qemu_command.c | 48 +++++++
src/util/virsysinfo.c | 160 +++++++++++++++++++++++-
src/util/virsysinfo.h | 14 +++
tests/qemuxml2argvdata/qemuxml2argv-smbios.args | 2 +
tests/qemuxml2argvdata/qemuxml2argv-smbios.xml | 9 ++
9 files changed, 346 insertions(+), 6 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index e0b6ba7..dc92aa3 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -375,6 +375,13 @@
<entry name='product'>Virt-Manager</entry>
<entry name='version'>0.9.4</entry>
</system>
+ <baseBoard>
+ <entry name='manufacturer'>LENOVO</entry>
+ <entry name='product'>20BE0061MC</entry>
+ <entry name='version'>0B98401 Pro</entry>
+ <entry name='serial'>W1KS427111E</entry>
+ <entry name='type'>Motherboard</entry>
+ </baseBoard>
</sysinfo>
...</pre>
@@ -435,11 +442,31 @@
<dt><code>family</code></dt>
<dd>Identify the family a particular computer belongs
to.</dd>
</dl>
- NB: Incorrectly supplied entries in either the <code>bios</code>
- or <code>system</code> blocks will be ignored without error.
- Other than <code>uuid</code> validation and
<code>date</code>
- format checking, all values are passed as strings to the
- hypervisor driver.
+ </dd>
+ <dt><code>baseBoard</code></dt>
+ <dd>
+ This is block 2 of SMBIOS, with entry names drawn from:
+ <dl>
+ <dt><code>manufacturer</code></dt>
+ <dd>Manufacturer of BIOS</dd>
+ <dt><code>product</code></dt>
+ <dd>Product Name</dd>
+ <dt><code>version</code></dt>
+ <dd>Version of the product</dd>
+ <dt><code>serial</code></dt>
+ <dd>Serial number</dd>
+ <dt><code>asset</code></dt>
+ <dd>Asset tag</dd>
+ <dt><code>location</code></dt>
+ <dd>Location in chassis</dd>
+ <dt><code>type</code></dt>
+ <dd>Board type</dd>
+ </dl>
+ NB: Incorrectly supplied entries in either the <code>bios</code>
or
+ <code>system</code> or <code>baseBoard</code> blocks
will be
+ ignored without error. Other than <code>uuid</code> validation
and
+ <code>date</code> format checking, all values are passed as
strings
+ to the hypervisor driver.
</dd>
</dl>
</dd>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index c151e92..2bc84b5 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4240,6 +4240,18 @@
</oneOrMore>
</element>
</optional>
+ <optional>
+ <element name="baseBoard">
+ <oneOrMore>
+ <element name="entry">
+ <attribute name="name">
+ <ref name="sysinfo-baseBoard-name"/>
+ </attribute>
+ <ref name="sysinfo-value"/>
+ </element>
+ </oneOrMore>
+ </element>
+ </optional>
</interleave>
</element>
</define>
@@ -4265,6 +4277,18 @@
</choice>
</define>
+ <define name="sysinfo-baseBoard-name">
+ <choice>
+ <value>manufacturer</value>
+ <value>product</value>
+ <value>version</value>
+ <value>serial</value>
+ <value>asset</value>
+ <value>location</value>
+ <value>type</value>
+ </choice>
+ </define>
+
<define name="sysinfo-value">
<data type="string">
<param name='pattern'>[a-zA-Z0-9/\-_\. \(\)]+</param>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 209416d..0f41375 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -10997,6 +10997,52 @@ virSysinfoSystemParseXML(xmlNodePtr node,
return ret;
}
+static int
+virSysinfoBaseBoardParseXML(xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ virSysinfoBaseBoardDefPtr *baseBoard)
+{
+ int ret = -1;
+ virSysinfoBaseBoardDefPtr def;
+
+ if (!xmlStrEqual(node->name, BAD_CAST "baseBoard")) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("XML does not contain expected 'baseBoard'
element"));
+ return ret;
+ }
+
+ if (VIR_ALLOC(def) < 0)
+ goto cleanup;
+
+ def->manufacturer =
+ virXPathString("string(entry[@name='manufacturer'])", ctxt);
+ def->product =
+ virXPathString("string(entry[@name='product'])", ctxt);
+ def->version =
+ virXPathString("string(entry[@name='version'])", ctxt);
+ def->serial =
+ virXPathString("string(entry[@name='serial'])", ctxt);
+ def->asset =
+ virXPathString("string(entry[@name='asset'])", ctxt);
+ def->location =
+ virXPathString("string(entry[@name='location'])", ctxt);
+ def->type =
+ virXPathString("string(entry[@name='type'])", ctxt);
+
+ if (!def->manufacturer && !def->product && !def->version
&&
+ !def->serial && !def->asset && !def->location &&
!def->type) {
+ virSysinfoBaseBoardDefFree(def);
+ def = NULL;
+ }
+
+ *baseBoard = def;
+ def = NULL;
+ ret = 0;
+ cleanup:
+ virSysinfoBaseBoardDefFree(def);
+ return ret;
+}
+
static virSysinfoDefPtr
virSysinfoParseXML(xmlNodePtr node,
xmlXPathContextPtr ctxt,
@@ -11051,6 +11097,17 @@ virSysinfoParseXML(xmlNodePtr node,
ctxt->node = oldnode;
}
+ /* Extract system base board metadata */
+ if ((tmpnode = virXPathNode("./baseBoard[1]", ctxt)) != NULL) {
+ oldnode = ctxt->node;
+ ctxt->node = tmpnode;
+ if (virSysinfoBaseBoardParseXML(tmpnode, ctxt, &def->baseBoard) < 0) {
+ ctxt->node = oldnode;
+ goto error;
+ }
+ ctxt->node = oldnode;
+ }
+
cleanup:
VIR_FREE(type);
return def;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index bd619d3..3178fe9 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2176,6 +2176,7 @@ virVasprintfInternal;
# util/virsysinfo.h
+virSysinfoBaseBoardDefFree;
virSysinfoBIOSDefFree;
virSysinfoDefFree;
virSysinfoFormat;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 489cab3..c13089e 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -6738,6 +6738,48 @@ static char *qemuBuildSmbiosSystemStr(virSysinfoSystemDefPtr def,
return NULL;
}
+static char *qemuBuildSmbiosBaseBoardStr(virSysinfoBaseBoardDefPtr def)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (!def)
+ return NULL;
+
+ virBufferAddLit(&buf, "type=2");
+
+ /* 1:Manufacturer */
+ if (def->manufacturer)
+ virBufferAsprintf(&buf, ",manufacturer=%s",
+ def->manufacturer);
+ /* 1:Product Name */
+ if (def->product)
+ virBufferAsprintf(&buf, ",product=%s", def->product);
+ /* 1:Version */
+ if (def->version)
+ virBufferAsprintf(&buf, ",version=%s", def->version);
+ /* 1:Serial Number */
+ if (def->serial)
+ virBufferAsprintf(&buf, ",serial=%s", def->serial);
+ /* 1:Asset Tag */
+ if (def->asset)
+ virBufferAsprintf(&buf, ",asset=%s", def->asset);
+ /* 1:Location */
+ if (def->location)
+ virBufferAsprintf(&buf, ",location=%s", def->location);
+ /* 1:Type */
+ if (def->type)
+ virBufferAsprintf(&buf, ",family=%s", def->type);
+
+ if (virBufferCheckError(&buf) < 0)
+ goto error;
+
+ return virBufferContentAndReset(&buf);
+
+ error:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
+
static char *
qemuBuildClockArgStr(virDomainClockDefPtr def)
{
@@ -8925,6 +8967,12 @@ qemuBuildCommandLine(virConnectPtr conn,
virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
VIR_FREE(smbioscmd);
}
+
+ smbioscmd = qemuBuildSmbiosBaseBoardStr(source->baseBoard);
+ if (smbioscmd != NULL) {
+ virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
+ VIR_FREE(smbioscmd);
+ }
}
}
diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c
index 4c939ec..bb21e1b 100644
--- a/src/util/virsysinfo.c
+++ b/src/util/virsysinfo.c
@@ -91,6 +91,20 @@ void virSysinfoSystemDefFree(virSysinfoSystemDefPtr def)
VIR_FREE(def);
}
+void virSysinfoBaseBoardDefFree(virSysinfoBaseBoardDefPtr def)
+{
+ if (def == NULL)
+ return;
+
+ VIR_FREE(def->manufacturer);
+ VIR_FREE(def->product);
+ VIR_FREE(def->version);
+ VIR_FREE(def->serial);
+ VIR_FREE(def->asset);
+ VIR_FREE(def->location);
+ VIR_FREE(def->type);
+ VIR_FREE(def);
+}
/**
* virSysinfoDefFree:
@@ -108,6 +122,7 @@ void virSysinfoDefFree(virSysinfoDefPtr def)
virSysinfoBIOSDefFree(def->bios);
virSysinfoSystemDefFree(def->system);
+ virSysinfoBaseBoardDefFree(def->baseBoard);
for (i = 0; i < def->nprocessor; i++) {
VIR_FREE(def->processor[i].processor_socket_destination);
@@ -719,6 +734,77 @@ virSysinfoParseSystem(const char *base, virSysinfoSystemDefPtr
*system)
}
static int
+virSysinfoParseBaseBoard(const char *base, virSysinfoBaseBoardDefPtr *baseBoard)
+{
+ int ret = -1;
+ const char *cur, *eol = NULL;
+ virSysinfoBaseBoardDefPtr def;
+
+ if ((cur = strstr(base, "Base Board Information")) == NULL)
+ return 0;
+
+ if (VIR_ALLOC(def) < 0)
+ return ret;
+
+ base = cur;
+ if ((cur = strstr(base, "Manufacturer: ")) != NULL) {
+ cur += 14;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->manufacturer, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+ if ((cur = strstr(base, "Product Name: ")) != NULL) {
+ cur += 14;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->product, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+ if ((cur = strstr(base, "Version: ")) != NULL) {
+ cur += 9;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->version, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+ if ((cur = strstr(base, "Serial Number: ")) != NULL) {
+ cur += 15;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->serial, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+ if ((cur = strstr(base, "Asset Tag: ")) != NULL) {
+ cur += 11;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->asset, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+ if ((cur = strstr(base, "Location In Chassis: ")) != NULL) {
+ cur += 21;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->location, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+ if ((cur = strstr(base, "Type: ")) != NULL) {
+ cur += 6;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->type, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+
+ if (!def->manufacturer && !def->product && !def->version
&&
+ !def->serial && !def->asset && !def->location &&
!def->type) {
+ virSysinfoBaseBoardDefFree(def);
+ def = NULL;
+ }
+
+ *baseBoard = def;
+ def = NULL;
+ ret = 0;
+ cleanup:
+ virSysinfoBaseBoardDefFree(def);
+ return ret;
+}
+
+static int
virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
{
const char *cur, *tmp_base;
@@ -940,7 +1026,7 @@ virSysinfoRead(void)
return NULL;
}
- cmd = virCommandNewArgList(path, "-q", "-t",
"0,1,4,17", NULL);
+ cmd = virCommandNewArgList(path, "-q", "-t",
"0,1,2,4,17", NULL);
VIR_FREE(path);
virCommandSetOutputBuffer(cmd, &outbuf);
if (virCommandRun(cmd, NULL) < 0)
@@ -957,6 +1043,9 @@ virSysinfoRead(void)
if (virSysinfoParseSystem(outbuf, &ret->system) < 0)
goto error;
+ if (virSysinfoParseBaseBoard(outbuf, &ret->baseBoard) < 0)
+ goto error;
+
ret->nprocessor = 0;
ret->processor = NULL;
if (virSysinfoParseProcessor(outbuf, ret) < 0)
@@ -1027,6 +1116,32 @@ virSysinfoSystemFormat(virBufferPtr buf, virSysinfoSystemDefPtr
def)
}
static void
+virSysinfoBaseBoardFormat(virBufferPtr buf, virSysinfoBaseBoardDefPtr def)
+{
+ if (!def)
+ return;
+
+ virBufferAddLit(buf, "<baseBoard>\n");
+ virBufferAdjustIndent(buf, 2);
+ virBufferEscapeString(buf, "<entry
name='manufacturer'>%s</entry>\n",
+ def->manufacturer);
+ virBufferEscapeString(buf, "<entry
name='product'>%s</entry>\n",
+ def->product);
+ virBufferEscapeString(buf, "<entry
name='version'>%s</entry>\n",
+ def->version);
+ virBufferEscapeString(buf, "<entry
name='serial'>%s</entry>\n",
+ def->serial);
+ virBufferEscapeString(buf, "<entry
name='asset'>%s</entry>\n",
+ def->asset);
+ virBufferEscapeString(buf, "<entry
name='location'>%s</entry>\n",
+ def->location);
+ virBufferEscapeString(buf, "<entry
name='type'>%s</entry>\n",
+ def->type);
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</baseBoard>\n");
+}
+
+static void
virSysinfoProcessorFormat(virBufferPtr buf, virSysinfoDefPtr def)
{
size_t i;
@@ -1157,6 +1272,7 @@ virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def)
virSysinfoBIOSFormat(buf, def->bios);
virSysinfoSystemFormat(buf, def->system);
+ virSysinfoBaseBoardFormat(buf, def->baseBoard);
virSysinfoProcessorFormat(buf, def);
virSysinfoMemoryFormat(buf, def);
@@ -1227,6 +1343,7 @@ virSysinfoSystemIsEqual(virSysinfoSystemDefPtr src,
desc, NULLSTR(src->name), NULLSTR(dst->name)); \
} \
} while (0)
+
CHECK_FIELD(manufacturer, "system vendor");
CHECK_FIELD(product, "system product");
CHECK_FIELD(version, "system version");
@@ -1241,6 +1358,44 @@ virSysinfoSystemIsEqual(virSysinfoSystemDefPtr src,
return identical;
}
+static bool
+virSysinfoBaseBoardIsEqual(virSysinfoBaseBoardDefPtr src,
+ virSysinfoBaseBoardDefPtr dst)
+{
+ bool identical = false;
+
+ if (!src && !dst)
+ return true;
+
+ if ((src && !dst) || (!src && dst)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Target base board does not match source"));
+ goto cleanup;
+ }
+
+#define CHECK_FIELD(name, desc) \
+ do { \
+ if (STRNEQ_NULLABLE(src->name, dst->name)) { \
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \
+ _("Target sysinfo %s %s does not match source %s"),
\
+ desc, NULLSTR(src->name), NULLSTR(dst->name)); \
+ } \
+ } while (0)
+
+ CHECK_FIELD(manufacturer, "base board vendor");
+ CHECK_FIELD(product, "base board product");
+ CHECK_FIELD(version, "base board version");
+ CHECK_FIELD(serial, "base board serial");
+ CHECK_FIELD(asset, "base board asset");
+ CHECK_FIELD(location, "base board location");
+ CHECK_FIELD(type, "base board type");
+#undef CHECK_FIELD
+
+ identical = true;
+ cleanup:
+ return identical;
+}
+
bool virSysinfoIsEqual(virSysinfoDefPtr src,
virSysinfoDefPtr dst)
{
@@ -1269,6 +1424,9 @@ bool virSysinfoIsEqual(virSysinfoDefPtr src,
if (!virSysinfoSystemIsEqual(src->system, dst->system))
goto cleanup;
+ if (!virSysinfoBaseBoardIsEqual(src->baseBoard, dst->baseBoard))
+ goto cleanup;
+
identical = true;
cleanup:
diff --git a/src/util/virsysinfo.h b/src/util/virsysinfo.h
index c8cc1e8..fd727a6 100644
--- a/src/util/virsysinfo.h
+++ b/src/util/virsysinfo.h
@@ -86,6 +86,18 @@ struct _virSysinfoSystemDef {
char *family;
};
+typedef struct _virSysinfoBaseBoardDef virSysinfoBaseBoardDef;
+typedef virSysinfoBaseBoardDef *virSysinfoBaseBoardDefPtr;
+struct _virSysinfoBaseBoardDef {
+ char *manufacturer;
+ char *product;
+ char *version;
+ char *serial;
+ char *asset;
+ char *location;
+ char *type;
+};
+
typedef struct _virSysinfoDef virSysinfoDef;
typedef virSysinfoDef *virSysinfoDefPtr;
struct _virSysinfoDef {
@@ -93,6 +105,7 @@ struct _virSysinfoDef {
virSysinfoBIOSDefPtr bios;
virSysinfoSystemDefPtr system;
+ virSysinfoBaseBoardDefPtr baseBoard;
size_t nprocessor;
virSysinfoProcessorDefPtr processor;
@@ -105,6 +118,7 @@ virSysinfoDefPtr virSysinfoRead(void);
void virSysinfoBIOSDefFree(virSysinfoBIOSDefPtr def);
void virSysinfoSystemDefFree(virSysinfoSystemDefPtr def);
+void virSysinfoBaseBoardDefFree(virSysinfoBaseBoardDefPtr def);
void virSysinfoDefFree(virSysinfoDefPtr def);
int virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def)
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smbios.args
b/tests/qemuxml2argvdata/qemuxml2argv-smbios.args
index e939aca..7336cbe 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-smbios.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-smbios.args
@@ -4,5 +4,7 @@ pc -m 214 -smp 1 -smbios 'type=0,vendor=LENOVO,version=6FET82WW (3.12
)' \
-smbios 'type=1,manufacturer=Fedora,product=Virt-Manager,version=0.8.2-3.fc14,\
serial=32dfcb37-5af1-552b-357c-be8c3aa38310,\
uuid=c7a5fdbd-edaf-9455-926a-d65c16db1809,sku=1234567890,family=Red Hat' \
+-smbios 'type=2,manufacturer=Hewlett-Packard,product=0B4Ch,version=D,\
+serial=CZC1065993,asset=CZC1065993,location=Upside down,family=Motherboard' \
-nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb -hda \
/dev/HostVG/QEMUGuest1 -net none -serial none -parallel none
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smbios.xml
b/tests/qemuxml2argvdata/qemuxml2argv-smbios.xml
index a2caeea..924596c 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-smbios.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-smbios.xml
@@ -18,6 +18,15 @@
<entry name='sku'>1234567890</entry>
<entry name='family'>Red Hat</entry>
</system>
+ <baseBoard>
+ <entry name='manufacturer'>Hewlett-Packard</entry>
+ <entry name='product'>0B4Ch</entry>
+ <entry name='version'>D</entry>
+ <entry name='serial'>CZC1065993</entry>
+ <entry name='asset'>CZC1065993</entry>
+ <entry name='location'>Upside down</entry>
+ <entry name='type'>Motherboard</entry>
+ </baseBoard>
</sysinfo>
<os>
<type arch='i686' machine='pc'>hvm</type>
--
2.3.6