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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list