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 <mprivozn@redhat.com>
This commit is contained in:
Michal Privoznik 2015-05-12 16:47:49 +02:00
parent beca509e43
commit a9a27e602c
11 changed files with 423 additions and 6 deletions

View File

@ -375,6 +375,12 @@
&lt;entry name='product'&gt;Virt-Manager&lt;/entry&gt;
&lt;entry name='version'&gt;0.9.4&lt;/entry&gt;
&lt;/system&gt;
&lt;baseBoard&gt;
&lt;entry name='manufacturer'&gt;LENOVO&lt;/entry&gt;
&lt;entry name='product'&gt;20BE0061MC&lt;/entry&gt;
&lt;entry name='version'&gt;0B98401 Pro&lt;/entry&gt;
&lt;entry name='serial'&gt;W1KS427111E&lt;/entry&gt;
&lt;/baseBoard&gt;
&lt;/sysinfo&gt;
...</pre>
@ -435,11 +441,32 @@
<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. 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:
<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>
</dl>
NB: Incorrectly supplied entries for the
<code>bios</code>, <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>

View File

@ -4249,6 +4249,18 @@
</oneOrMore>
</element>
</optional>
<zeroOrMore>
<element name="baseBoard">
<oneOrMore>
<element name="entry">
<attribute name="name">
<ref name="sysinfo-baseBoard-name"/>
</attribute>
<ref name="sysinfo-value"/>
</element>
</oneOrMore>
</element>
</zeroOrMore>
</interleave>
</element>
</define>
@ -4274,6 +4286,17 @@
</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>
</choice>
</define>
<define name="sysinfo-value">
<data type="string">
<param name='pattern'>[a-zA-Z0-9/\-_\. \(\)]+</param>

View File

@ -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;

View File

@ -2183,6 +2183,7 @@ virVasprintfInternal;
# util/virsysinfo.h
virSysinfoBaseBoardDefClear;
virSysinfoBIOSDefFree;
virSysinfoDefFree;
virSysinfoFormat;

View File

@ -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);
}
}
}

View File

@ -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, "</system>\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, "<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);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</baseBoard>\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:

View File

@ -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)

View File

@ -0,0 +1,58 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
<vcpu placement='static'>1</vcpu>
<sysinfo type='smbios'>
<bios>
<entry name='vendor'>LENOVO</entry>
<entry name='version'>6FET82WW (3.12 )</entry>
</bios>
<system>
<entry name='manufacturer'>Fedora</entry>
<entry name='product'>Virt-Manager</entry>
<entry name='version'>0.8.2-3.fc14</entry>
<entry name='serial'>32dfcb37-5af1-552b-357c-be8c3aa38310</entry>
<entry name='uuid'>c7a5fdbd-edaf-9455-926a-d65c16db1809</entry>
<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>
</baseBoard>
<baseBoard>
<entry name='manufacturer'>Lenovo</entry>
<entry name='product'>20BE0061MC</entry>
<entry name='version'>0B98401 Pro</entry>
<entry name='serial'>W1KS427111E</entry>
<entry name='location'>Not Available</entry>
</baseBoard>
</sysinfo>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
<smbios mode='sysinfo'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu</emulator>
<disk type='block' device='disk'>
<source dev='/dev/HostVG/QEMUGuest1'/>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='ide' index='0'/>
<controller type='usb' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<memballoon model='virtio'/>
</devices>
</domain>

View File

@ -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

View File

@ -18,6 +18,14 @@
<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>
</baseBoard>
</sysinfo>
<os>
<type arch='i686' machine='pc'>hvm</type>

View File

@ -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");