From: Michal Privoznik Date: Tue, 12 May 2015 14:47:49 +0000 (+0200) Subject: virSysinfo: Introduce SMBIOS type 2 support X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=a9a27e602cf790a1513e9bb07f70acebc3d2fb3b;p=libvirt.git virSysinfo: Introduce SMBIOS type 2 support https://bugzilla.redhat.com/show_bug.cgi?id=1220527 This type of information defines attributes of a system baseboard. With one exception: board type is yet not implemented in qemu so it's not introduced here either. Signed-off-by: Michal Privoznik --- diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 4e85b51040..6a524dfdb9 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -375,6 +375,12 @@ <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> + </baseBoard> </sysinfo> ... @@ -435,11 +441,32 @@
family
Identify the family a particular computer belongs to.
- NB: Incorrectly supplied entries in either the bios - or system blocks will be ignored without error. - Other than uuid validation and date - format checking, all values are passed as strings to the - hypervisor driver. + +
baseBoard
+
+ This is block 2 of SMBIOS. This element can be repeated multiple + times to describe all the base boards; however, not all + hypervisors necessarily support the repetition. The element can + have the following children: +
+
manufacturer
+
Manufacturer of BIOS
+
product
+
Product Name
+
version
+
Version of the product
+
serial
+
Serial number
+
asset
+
Asset tag
+
location
+
Location in chassis
+
+ NB: Incorrectly supplied entries for the + bios, system or baseBoard + blocks will be ignored without error. Other than uuid + validation and date format checking, all values are + passed as strings to the hypervisor driver.
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index f0f740068a..ca3bcfcb8d 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4249,6 +4249,18 @@ + + + + + + + + + + + + @@ -4274,6 +4286,17 @@ + + + manufacturer + product + version + serial + asset + location + + + [a-zA-Z0-9/\-_\. \(\)]+ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index ca559815f6..f8407b6b7c 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -11241,6 +11241,61 @@ virSysinfoSystemParseXML(xmlNodePtr node, return ret; } +static int +virSysinfoBaseBoardParseXML(xmlXPathContextPtr ctxt, + virSysinfoBaseBoardDefPtr *baseBoard, + size_t *nbaseBoard) +{ + int ret = -1; + virSysinfoBaseBoardDefPtr boards = NULL; + size_t i, nboards = 0; + xmlNodePtr *nodes = NULL, oldnode = ctxt->node; + int n; + + if ((n = virXPathNodeSet("./baseBoard", ctxt, &nodes)) < 0) + return ret; + + if (n && VIR_ALLOC_N(boards, n) < 0) + goto cleanup; + + for (i = 0; i < n; i++) { + virSysinfoBaseBoardDefPtr def = boards + nboards; + + ctxt->node = nodes[i]; + + 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); + + if (!def->manufacturer && !def->product && !def->version && + !def->serial && !def->asset && !def->location) { + /* nada */ + } else { + nboards++; + } + } + + *baseBoard = boards; + *nbaseBoard = nboards; + boards = NULL; + nboards = 0; + ret = 0; + cleanup: + VIR_FREE(boards); + VIR_FREE(nodes); + ctxt->node = oldnode; + return ret; +} + static virSysinfoDefPtr virSysinfoParseXML(xmlNodePtr node, xmlXPathContextPtr ctxt, @@ -11295,6 +11350,10 @@ virSysinfoParseXML(xmlNodePtr node, ctxt->node = oldnode; } + /* Extract system base board metadata */ + if (virSysinfoBaseBoardParseXML(ctxt, &def->baseBoard, &def->nbaseBoard) < 0) + goto error; + cleanup: VIR_FREE(type); return def; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f7373afff2..cd347ac6ad 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2183,6 +2183,7 @@ virVasprintfInternal; # util/virsysinfo.h +virSysinfoBaseBoardDefClear; virSysinfoBIOSDefFree; virSysinfoDefFree; virSysinfoFormat; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 3886b4fc63..3be7e85271 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6786,6 +6786,45 @@ 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"); + + /* 2:Manufacturer */ + if (def->manufacturer) + virBufferAsprintf(&buf, ",manufacturer=%s", + def->manufacturer); + /* 2:Product Name */ + if (def->product) + virBufferAsprintf(&buf, ",product=%s", def->product); + /* 2:Version */ + if (def->version) + virBufferAsprintf(&buf, ",version=%s", def->version); + /* 2:Serial Number */ + if (def->serial) + virBufferAsprintf(&buf, ",serial=%s", def->serial); + /* 2:Asset Tag */ + if (def->asset) + virBufferAsprintf(&buf, ",asset=%s", def->asset); + /* 2:Location */ + if (def->location) + virBufferAsprintf(&buf, ",location=%s", def->location); + + if (virBufferCheckError(&buf) < 0) + goto error; + + return virBufferContentAndReset(&buf); + + error: + virBufferFreeAndReset(&buf); + return NULL; +} + static char * qemuBuildClockArgStr(virDomainClockDefPtr def) { @@ -9064,6 +9103,21 @@ qemuBuildCommandLine(virConnectPtr conn, virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL); VIR_FREE(smbioscmd); } + + if (source->nbaseBoard > 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("qemu does not support more than " + "one entry to Type 2 in SMBIOS table")); + goto error; + } + + for (i = 0; i < source->nbaseBoard; i++) { + if (!(smbioscmd = qemuBuildSmbiosBaseBoardStr(source->baseBoard + i))) + goto error; + + virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL); + VIR_FREE(smbioscmd); + } } } diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c index 42cd946575..05d33a8ce2 100644 --- a/src/util/virsysinfo.c +++ b/src/util/virsysinfo.c @@ -91,6 +91,18 @@ void virSysinfoSystemDefFree(virSysinfoSystemDefPtr def) VIR_FREE(def); } +void virSysinfoBaseBoardDefClear(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); +} /** * virSysinfoDefFree: @@ -109,6 +121,10 @@ void virSysinfoDefFree(virSysinfoDefPtr def) virSysinfoBIOSDefFree(def->bios); virSysinfoSystemDefFree(def->system); + for (i = 0; i < def->nbaseBoard; i++) + virSysinfoBaseBoardDefClear(def->baseBoard + i); + VIR_FREE(def->baseBoard); + for (i = 0; i < def->nprocessor; i++) { VIR_FREE(def->processor[i].processor_socket_destination); VIR_FREE(def->processor[i].processor_type); @@ -716,6 +732,84 @@ virSysinfoParseSystem(const char *base, virSysinfoSystemDefPtr *sysdef) return ret; } +static int +virSysinfoParseBaseBoard(const char *base, + virSysinfoBaseBoardDefPtr *baseBoard, + size_t *nbaseBoard) +{ + int ret = -1; + const char *cur, *eol = NULL; + virSysinfoBaseBoardDefPtr boards = NULL; + size_t nboards = 0; + char *board_type = NULL; + + while (base && (cur = strstr(base, "Base Board Information"))) { + virSysinfoBaseBoardDefPtr def; + + if (VIR_EXPAND_N(boards, nboards, 1) < 0) + goto cleanup; + + def = &boards[nboards - 1]; + + base = cur + 22; + 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 (!def->manufacturer && !def->product && !def->version && + !def->serial && !def->asset && !def->location) + nboards--; + } + + /* This is safe, as we can be only shrinking the memory */ + ignore_value(VIR_REALLOC_N(boards, nboards)); + + *baseBoard = boards; + *nbaseBoard = nboards; + boards = NULL; + nboards = 0; + ret = 0; + cleanup: + while (nboards--) + virSysinfoBaseBoardDefClear(&boards[nboards]); + VIR_FREE(boards); + VIR_FREE(board_type); + return ret; +} + static int virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret) { @@ -938,7 +1032,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) @@ -955,6 +1049,9 @@ virSysinfoRead(void) if (virSysinfoParseSystem(outbuf, &ret->system) < 0) goto error; + if (virSysinfoParseBaseBoard(outbuf, &ret->baseBoard, &ret->nbaseBoard) < 0) + goto error; + ret->nprocessor = 0; ret->processor = NULL; if (virSysinfoParseProcessor(outbuf, ret) < 0) @@ -1024,6 +1121,36 @@ virSysinfoSystemFormat(virBufferPtr buf, virSysinfoSystemDefPtr def) virBufferAddLit(buf, "\n"); } +static void +virSysinfoBaseBoardFormat(virBufferPtr buf, + virSysinfoBaseBoardDefPtr baseBoard, + size_t nbaseBoard) +{ + virSysinfoBaseBoardDefPtr def; + size_t i; + + for (i = 0; i < nbaseBoard; i++) { + def = baseBoard + i; + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + virBufferEscapeString(buf, "%s\n", + def->manufacturer); + virBufferEscapeString(buf, "%s\n", + def->product); + virBufferEscapeString(buf, "%s\n", + def->version); + virBufferEscapeString(buf, "%s\n", + def->serial); + virBufferEscapeString(buf, "%s\n", + def->asset); + virBufferEscapeString(buf, "%s\n", + def->location); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + } +} + static void virSysinfoProcessorFormat(virBufferPtr buf, virSysinfoDefPtr def) { @@ -1157,6 +1284,7 @@ virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def) virSysinfoBIOSFormat(&childrenBuf, def->bios); virSysinfoSystemFormat(&childrenBuf, def->system); + virSysinfoBaseBoardFormat(&childrenBuf, def->baseBoard, def->nbaseBoard); virSysinfoProcessorFormat(&childrenBuf, def); virSysinfoMemoryFormat(&childrenBuf, def); @@ -1241,12 +1369,40 @@ 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; + } + + 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"); + + identical = true; + cleanup: + return identical; +} + #undef CHECK_FIELD bool virSysinfoIsEqual(virSysinfoDefPtr src, virSysinfoDefPtr dst) { bool identical = false; + size_t i; if (!src && !dst) return true; @@ -1271,6 +1427,18 @@ bool virSysinfoIsEqual(virSysinfoDefPtr src, if (!virSysinfoSystemIsEqual(src->system, dst->system)) goto cleanup; + if (src->nbaseBoard != dst->nbaseBoard) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target sysinfo base board count '%zu' does not match source '%zu'"), + dst->nbaseBoard, src->nbaseBoard); + goto cleanup; + } + + for (i = 0; i < src->nbaseBoard; i++) + if (!virSysinfoBaseBoardIsEqual(src->baseBoard + i, + dst->baseBoard + i)) + goto cleanup; + identical = true; cleanup: diff --git a/src/util/virsysinfo.h b/src/util/virsysinfo.h index c8cc1e8979..1e51d2cafa 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; + /* XXX board type */ +}; + typedef struct _virSysinfoDef virSysinfoDef; typedef virSysinfoDef *virSysinfoDefPtr; struct _virSysinfoDef { @@ -94,6 +106,9 @@ struct _virSysinfoDef { virSysinfoBIOSDefPtr bios; virSysinfoSystemDefPtr system; + size_t nbaseBoard; + virSysinfoBaseBoardDefPtr baseBoard; + size_t nprocessor; virSysinfoProcessorDefPtr processor; @@ -105,6 +120,7 @@ virSysinfoDefPtr virSysinfoRead(void); void virSysinfoBIOSDefFree(virSysinfoBIOSDefPtr def); void virSysinfoSystemDefFree(virSysinfoSystemDefPtr def); +void virSysinfoBaseBoardDefClear(virSysinfoBaseBoardDefPtr def); void virSysinfoDefFree(virSysinfoDefPtr def); int virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def) diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smbios-multiple-type2.xml b/tests/qemuxml2argvdata/qemuxml2argv-smbios-multiple-type2.xml new file mode 100644 index 0000000000..1f6aec1ac0 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-smbios-multiple-type2.xml @@ -0,0 +1,58 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219100 + 219100 + 1 + + + LENOVO + 6FET82WW (3.12 ) + + + Fedora + Virt-Manager + 0.8.2-3.fc14 + 32dfcb37-5af1-552b-357c-be8c3aa38310 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 1234567890 + Red Hat + + + Hewlett-Packard + 0B4Ch + D + CZC1065993 + CZC1065993 + Upside down + + + Lenovo + 20BE0061MC + 0B98401 Pro + W1KS427111E + Not Available + + + + hvm + + + + + destroy + restart + destroy + + /usr/bin/qemu + + + +
+ + + + + + + diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smbios.args b/tests/qemuxml2argvdata/qemuxml2argv-smbios.args index e939acadc9..209cf2089c 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' \ -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 a2caeeaf3f..30888ae757 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-smbios.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-smbios.xml @@ -18,6 +18,14 @@ 1234567890 Red Hat + + Hewlett-Packard + 0B4Ch + D + CZC1065993 + CZC1065993 + Upside down + hvm diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 44b388c43a..3287ea37d5 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -614,6 +614,7 @@ mymain(void) DO_TEST_DIFFERENT("tap-vhost-incorrect"); DO_TEST("shmem"); DO_TEST("smbios"); + DO_TEST("smbios-multiple-type2"); DO_TEST("aarch64-aavmf-virtio-mmio"); DO_TEST("memory-hotplug");