[libvirt] [PATCH] npiv: Auto-generate WWNs if it's not specified
by Osier Yang
To not change the old API behavior (if no WWNs is specified, error
is throwed and the device creation quits), this patch introduce
an new flag (VIR_NODE_DEVICE_CREATE_XML_GENERATE_WWN), which indicates
the WWNs will be generated automatically by libvirt if they are not
specified, and it's ignored if the the WWNs are specified.
The auto-generated WWN comply with the new addressing schema of WWN:
<quote>
the first nibble is either hex 5 or 6 followed by a 3-byte vendor
identifier and 36 bits for a vendor-specified serial number.
</quote>
We choose hex 5 for the first nibble. And use Qumranet's OUI
(00:1A:4A) as the 3-byte vendor indentifier. The last 36 bits
are auto-generated.
Also new option "--generate-wwn" is introduced for virsh command
"nodedev-create".
---
Perhaps "--generate-wwn" is not good option name, considering
virNodeDeviceCreateXML will support other device type?
---
include/libvirt/libvirt.h.in | 13 +++++
src/conf/node_device_conf.c | 99 +++++++++++++++++++++------------
src/conf/node_device_conf.h | 9 ++-
src/libvirt_private.syms | 1 +
src/node_device/node_device_driver.c | 4 +-
src/qemu/qemu_driver.c | 2 +-
src/test/test_driver.c | 8 ++--
src/util/util.c | 20 +++++++
src/util/util.h | 1 +
tests/nodedevxml2xmltest.c | 2 +-
tools/virsh.c | 7 ++-
tools/virsh.pod | 4 +-
12 files changed, 121 insertions(+), 49 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 2480add..dd3e891 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2270,6 +2270,19 @@ int virNodeDeviceDettach (virNodeDevicePtr dev);
int virNodeDeviceReAttach (virNodeDevicePtr dev);
int virNodeDeviceReset (virNodeDevicePtr dev);
+/**
+ * virNodeDeviceCreateXMLFlags
+ *
+ * Flags OR'ed together to provide specific behaviour when creating a
+ * node device.
+ */
+typedef enum {
+ /* Default behavior */
+ VIR_NODE_DEVICE_CREATE_XML_NONE = 0,
+ /* Generate WWN if no WWN is specified. */
+ VIR_NODE_DEVICE_CREATE_XML_GENERATE_WWN = (1 << 0),
+} virNodeDeviceCreateXMLFlags;
+
virNodeDevicePtr virNodeDeviceCreateXML (virConnectPtr conn,
const char *xmlDesc,
unsigned int flags);
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index 084121f..9d48ff8 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -63,20 +63,13 @@ VIR_ENUM_IMPL(virNodeDevHBACap, VIR_NODE_DEV_CAP_HBA_LAST,
static int
virNodeDevCapsDefParseString(const char *xpath,
xmlXPathContextPtr ctxt,
- char **string,
- virNodeDeviceDefPtr def,
- const char *missing_error_fmt)
+ char **string)
{
char *s;
- s = virXPathString(xpath, ctxt);
- if (s == NULL) {
- virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR,
- missing_error_fmt,
- def->name);
+ if (!(s = virXPathString(xpath, ctxt)))
return -1;
- }
-
+
*string = s;
return 0;
}
@@ -715,7 +708,8 @@ virNodeDevCapScsiHostParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
union _virNodeDevCapData *data,
- int create)
+ int create,
+ unsigned int flags)
{
xmlNodePtr orignode, *nodes = NULL;
int ret = -1, n = 0, i;
@@ -759,20 +753,46 @@ virNodeDevCapScsiHostParseXML(xmlXPathContextPtr ctxt,
orignode2 = ctxt->node;
ctxt->node = nodes[i];
- if (virNodeDevCapsDefParseString("string(./wwnn[1])",
- ctxt,
- &data->scsi_host.wwnn,
- def,
- _("no WWNN supplied for '%s'")) < 0) {
- goto out;
- }
+ if (flags & VIR_NODE_DEVICE_CREATE_XML_GENERATE_WWN) {
+ if (virNodeDevCapsDefParseString("string(./wwnn[1])",
+ ctxt,
+ &data->scsi_host.wwnn) < 0) {
+ if (virGenerateWWN(&data->scsi_host.wwnn) < 0) {
+ virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR,
+ _("no WWNN supplied for '%s', and automate "
+ "generation failed"), def->name);
+ goto out;
+ }
+ }
- if (virNodeDevCapsDefParseString("string(./wwpn[1])",
- ctxt,
- &data->scsi_host.wwpn,
- def,
- _("no WWPN supplied for '%s'")) < 0) {
- goto out;
+ if (virNodeDevCapsDefParseString("string(./wwpn[1])",
+ ctxt,
+ &data->scsi_host.wwpn) < 0) {
+ if (virGenerateWWN(&data->scsi_host.wwpn) < 0) {
+ virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR,
+ _("no WWPN supplied for '%s', and automate "
+ "generation failed"), def->name);
+ goto out;
+ }
+ }
+ } else {
+ if (virNodeDevCapsDefParseString("string(./wwnn[1])",
+ ctxt,
+ &data->scsi_host.wwnn) < 0) {
+ virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR,
+ _("no WWNN supplied for '%s'"),
+ def->name);
+ goto out;
+ }
+
+ if (virNodeDevCapsDefParseString("string(./wwpn[1])",
+ ctxt,
+ &data->scsi_host.wwpn) < 0) {
+ virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR,
+ _("no WWPN supplied for '%s'"),
+ def->name);
+ goto out;
+ }
}
ctxt->node = orignode2;
@@ -1058,7 +1078,8 @@ static virNodeDevCapsDefPtr
virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
- int create)
+ int create,
+ unsigned int flags)
{
virNodeDevCapsDefPtr caps;
char *tmp;
@@ -1102,7 +1123,7 @@ virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
ret = virNodeDevCapNetParseXML(ctxt, def, node, &caps->data);
break;
case VIR_NODE_DEV_CAP_SCSI_HOST:
- ret = virNodeDevCapScsiHostParseXML(ctxt, def, node, &caps->data, create);
+ ret = virNodeDevCapScsiHostParseXML(ctxt, def, node, &caps->data, create, flags);
break;
case VIR_NODE_DEV_CAP_SCSI_TARGET:
ret = virNodeDevCapScsiTargetParseXML(ctxt, def, node, &caps->data);
@@ -1131,7 +1152,9 @@ error:
}
static virNodeDeviceDefPtr
-virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt, int create)
+virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
+ int create,
+ unsigned int flags)
{
virNodeDeviceDefPtr def;
virNodeDevCapsDefPtr *next_cap;
@@ -1178,7 +1201,7 @@ virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt, int create)
next_cap = &def->caps;
for (i = 0 ; i < n ; i++) {
- *next_cap = virNodeDevCapsDefParseXML(ctxt, def, nodes[i], create);
+ *next_cap = virNodeDevCapsDefParseXML(ctxt, def, nodes[i], create, flags);
if (!*next_cap) {
VIR_FREE(nodes);
goto error;
@@ -1198,7 +1221,8 @@ virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt, int create)
virNodeDeviceDefPtr
virNodeDeviceDefParseNode(xmlDocPtr xml,
xmlNodePtr root,
- int create)
+ int create,
+ unsigned int flags)
{
xmlXPathContextPtr ctxt = NULL;
virNodeDeviceDefPtr def = NULL;
@@ -1218,7 +1242,7 @@ virNodeDeviceDefParseNode(xmlDocPtr xml,
}
ctxt->node = root;
- def = virNodeDeviceDefParseXML(ctxt, create);
+ def = virNodeDeviceDefParseXML(ctxt, create, flags);
cleanup:
xmlXPathFreeContext(ctxt);
@@ -1228,13 +1252,14 @@ cleanup:
static virNodeDeviceDefPtr
virNodeDeviceDefParse(const char *str,
const char *filename,
- int create)
+ int create,
+ unsigned int flags)
{
xmlDocPtr xml;
virNodeDeviceDefPtr def = NULL;
if ((xml = virXMLParse(filename, str, _("(node_device_definition)")))) {
- def = virNodeDeviceDefParseNode(xml, xmlDocGetRootElement(xml), create);
+ def = virNodeDeviceDefParseNode(xml, xmlDocGetRootElement(xml), create, flags);
xmlFreeDoc(xml);
}
@@ -1243,16 +1268,18 @@ virNodeDeviceDefParse(const char *str,
virNodeDeviceDefPtr
virNodeDeviceDefParseString(const char *str,
- int create)
+ int create,
+ unsigned int flags)
{
- return virNodeDeviceDefParse(str, NULL, create);
+ return virNodeDeviceDefParse(str, NULL, create, flags);
}
virNodeDeviceDefPtr
virNodeDeviceDefParseFile(const char *filename,
- int create)
+ int create,
+ unsigned int flags)
{
- return virNodeDeviceDefParse(NULL, filename, create);
+ return virNodeDeviceDefParse(NULL, filename, create, flags);
}
/*
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index 17be031..e317354 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -233,12 +233,15 @@ void virNodeDeviceObjRemove(virNodeDeviceObjListPtr devs,
char *virNodeDeviceDefFormat(const virNodeDeviceDefPtr def);
virNodeDeviceDefPtr virNodeDeviceDefParseString(const char *str,
- int create);
+ int create,
+ unsigned int flags);
virNodeDeviceDefPtr virNodeDeviceDefParseFile(const char *filename,
- int create);
+ int create,
+ unsigned int flags);
virNodeDeviceDefPtr virNodeDeviceDefParseNode(xmlDocPtr xml,
xmlNodePtr root,
- int create);
+ int create,
+ unsigned int flags);
int virNodeDeviceGetWWNs(virNodeDeviceDefPtr def,
char **wwnn,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 99a1099..463969d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1101,6 +1101,7 @@ virFileWriteStr;
virFindFileInPath;
virFormatMacAddr;
virGenerateMacAddr;
+virGenerateWWN;
virGetGroupID;
virGetHostname;
virGetUserDirectory;
diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c
index 681655e..ddb1236 100644
--- a/src/node_device/node_device_driver.c
+++ b/src/node_device/node_device_driver.c
@@ -559,11 +559,11 @@ nodeDeviceCreateXML(virConnectPtr conn,
int parent_host = -1;
virNodeDevicePtr dev = NULL;
- virCheckFlags(0, NULL);
+ virCheckFlags(VIR_NODE_DEVICE_CREATE_XML_GENERATE_WWN, NULL);
nodeDeviceLock(driver);
- def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE);
+ def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, flags);
if (def == NULL) {
goto cleanup;
}
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1e5ed9a..97ed1d2 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -8747,7 +8747,7 @@ qemudNodeDeviceGetPciInfo (virNodeDevicePtr dev,
if (!xml)
goto out;
- def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE);
+ def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, 0);
if (!def)
goto out;
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index ce94a17..b0bf0a3 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -607,7 +607,7 @@ static int testOpenDefault(virConnectPtr conn) {
virStoragePoolObjUnlock(poolobj);
/* Init default node device */
- if (!(nodedef = virNodeDeviceDefParseString(defaultNodeXML, 0)))
+ if (!(nodedef = virNodeDeviceDefParseString(defaultNodeXML, 0, 0)))
goto error;
if (!(nodeobj = virNodeDeviceAssignDef(&privconn->devs,
nodedef))) {
@@ -1056,12 +1056,12 @@ static int testOpenFromFile(virConnectPtr conn,
goto error;
}
- def = virNodeDeviceDefParseFile(absFile, 0);
+ def = virNodeDeviceDefParseFile(absFile, 0, 0);
VIR_FREE(absFile);
if (!def)
goto error;
} else {
- if ((def = virNodeDeviceDefParseNode(xml, devs[i], 0)) == NULL)
+ if ((def = virNodeDeviceDefParseNode(xml, devs[i], 0, 0)) == NULL)
goto error;
}
if (!(dev = virNodeDeviceAssignDef(&privconn->devs, def))) {
@@ -5311,7 +5311,7 @@ testNodeDeviceCreateXML(virConnectPtr conn,
testDriverLock(driver);
- def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE);
+ def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, 0);
if (def == NULL) {
goto cleanup;
}
diff --git a/src/util/util.c b/src/util/util.c
index 6f46d53..e6f4559 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -1837,6 +1837,26 @@ void virGenerateMacAddr(const unsigned char *prefix,
addr[5] = virRandom(256);
}
+#define QUMRANET_OUI "001a4a"
+
+int virGenerateWWN(char **wwn) {
+ int suffix[5];
+
+ suffix[0] = virRandom(16);
+ suffix[1] = virRandom(256);
+ suffix[2] = virRandom(256);
+ suffix[3] = virRandom(256);
+ suffix[4] = virRandom(256);
+
+ if (virAsprintf(wwn, "%x%s%x%02x%02x%02x%02x", 0x5, QUMRANET_OUI,
+ suffix[0], suffix[1], suffix[2],
+ suffix[3], suffix[4]) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ return 0;
+}
int virEnumFromString(const char *const*types,
unsigned int ntypes,
diff --git a/src/util/util.h b/src/util/util.h
index c9c785b..d7a0840 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -186,6 +186,7 @@ void virFormatMacAddr(const unsigned char *addr,
char *str);
void virGenerateMacAddr(const unsigned char *prefix,
unsigned char *addr);
+int virGenerateWWN(char **wwn);
int virDiskNameToIndex(const char* str);
char *virIndexToDiskName(int idx, const char *prefix);
diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
index d0deaeb..3487c7e 100644
--- a/tests/nodedevxml2xmltest.c
+++ b/tests/nodedevxml2xmltest.c
@@ -24,7 +24,7 @@ testCompareXMLToXMLFiles(const char *xml)
if (virtTestLoadFile(xml, &xmlData) < 0)
goto fail;
- if (!(dev = virNodeDeviceDefParseString(xmlData, EXISTING_DEVICE)))
+ if (!(dev = virNodeDeviceDefParseString(xmlData, EXISTING_DEVICE, 0)))
goto fail;
if (!(actual = virNodeDeviceDefFormat(dev)))
diff --git a/tools/virsh.c b/tools/virsh.c
index d02be5c..ca5b209 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -8351,6 +8351,7 @@ static const vshCmdInfo info_node_device_create[] = {
static const vshCmdOptDef opts_node_device_create[] = {
{"file", VSH_OT_DATA, VSH_OFLAG_REQ,
N_("file containing an XML description of the device")},
+ {"generate-wwn", VSH_OT_BOOL, 0, N_("generate WWN if it's not specified")},
{NULL, 0, 0, NULL}
};
@@ -8361,6 +8362,7 @@ cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
const char *from = NULL;
bool ret = true;
char *buffer;
+ unsigned int flags = 0;
if (!vshConnectionUsability(ctl, ctl->conn))
return false;
@@ -8371,7 +8373,10 @@ cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
return false;
- dev = virNodeDeviceCreateXML(ctl->conn, buffer, 0);
+ if (vshCommandOptBool(cmd, "generate-wwn"))
+ flags |= VIR_NODE_DEVICE_CREATE_XML_GENERATE_WWN;
+
+ dev = virNodeDeviceCreateXML(ctl->conn, buffer, flags);
VIR_FREE(buffer);
if (dev != NULL) {
diff --git a/tools/virsh.pod b/tools/virsh.pod
index fe92714..5130859 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1375,13 +1375,15 @@ reattach, even if the guests use the device in managed mode.
=over 4
-=item B<nodedev-create> I<FILE>
+=item B<nodedev-create> I<FILE> [I<--generate-wwn>]
Create a device on the host node that can then be assigned to virtual
machines. Normally, libvirt is able to automatically determine which
host nodes are available for use, but this allows registration of
host hardware that libvirt did not automatically detect. I<file>
contains xml for a top-level <device> description of a node device.
+I<--generate-wwn> indicates the WWNN and WWPN for a vHBA will be
+generated automatically if they are not specified.
=item B<nodedev-destroy> I<nodedev>
--
1.7.1
13 years, 6 months
[libvirt] [PATCH] npiv: Expose fabric_name outside
by Osier Yang
This patch is to expose the fabric_name of fc_host class, which
might be useful for users who wants to known which fabric the
(v)HBA connects to.
The patch also adds the missed capabilities' XML schema of scsi_host,
(of course, with fabric_wwn added), and update the documents
(docs/formatnode.html.in)
---
docs/formatnode.html.in | 7 +++++
docs/schemas/nodedev.rng | 40 +++++++++++++++++++++++++++++
src/conf/node_device_conf.c | 3 ++
src/conf/node_device_conf.h | 1 +
src/node_device/node_device_linux_sysfs.c | 10 +++++++
5 files changed, 61 insertions(+), 0 deletions(-)
diff --git a/docs/formatnode.html.in b/docs/formatnode.html.in
index 126f8de..c04d04d 100644
--- a/docs/formatnode.html.in
+++ b/docs/formatnode.html.in
@@ -126,6 +126,7 @@
<dd>A network protocol exposed by the device, where the
attribute <code>type</code> can be "80203" for IEEE
802.3, or "80211" for various flavors of IEEE 802.11.
+ </dd>
</dl>
</dd>
<dt><code>scsi_host</code></dt>
@@ -133,6 +134,12 @@
<dl>
<dt><code>host</code></dt>
<dd>The SCSI host number.</dd>
+ <dt><code>capability</code></dt>
+ <dd>Current capabilities include "vports_ops" (indicates
+ vport operations are supported) and "fc_host", the later
+ implies following sub-elements: <code>wwnn</code>,
+ <code>wwpn</code>, <code>fabric_wwn</code>.
+ </dd>
</dl>
</dd>
<dt><code>scsi</code></dt>
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
index 55191d9..1b9a2d1 100644
--- a/docs/schemas/nodedev.rng
+++ b/docs/schemas/nodedev.rng
@@ -216,6 +216,35 @@
</attribute>
</define>
+ <define name='wwn'>
+ <data type='string'>
+ <param name='pattern'>(0-9a-fA-F){16}</param>
+ </data>
+ </define>
+
+ <define name='capsfchost'>
+ <attribute name='type'>
+ <value>fc_host</value>
+ </attribute>
+
+ <element name='wwnn'>
+ <ref name='wwn'/>
+ </element>
+
+ <element name='wwpn'>
+ <ref name='wwn'/>
+ </element>
+
+ <element name='fabric_wwn'>
+ <ref name='wwn'/>
+ </element>
+ </define>
+
+ <define name='capsvports'>
+ <attribute name='type'>
+ <value>vports_ops</value>
+ </attribute>
+ </define>
<define name='capscsihost'>
<attribute name='type'>
@@ -225,6 +254,17 @@
<element name='host'>
<ref name='uint'/>
</element>
+
+ <optional>
+ <zeroOrMore>
+ <element name='capability'>
+ <choice>
+ <ref name='capsfchost'/>
+ <ref name='capsvports'/>
+ </choice>
+ </element>
+ </zeroOrMore>
+ </optional>
</define>
<define name='capscsi'>
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index 9d48ff8..ea6ebde 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -389,6 +389,8 @@ char *virNodeDeviceDefFormat(const virNodeDeviceDefPtr def)
data->scsi_host.wwnn);
virBufferEscapeString(&buf, " <wwpn>%s</wwpn>\n",
data->scsi_host.wwpn);
+ virBufferEscapeString(&buf, " <fabric_wwn>%s</fabric_wwn>\n",
+ data->scsi_host.fabric_wwn);
virBufferAddLit(&buf, " </capability>\n");
}
if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) {
@@ -1405,6 +1407,7 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
case VIR_NODE_DEV_CAP_SCSI_HOST:
VIR_FREE(data->scsi_host.wwnn);
VIR_FREE(data->scsi_host.wwpn);
+ VIR_FREE(data->scsi_host.fabric_wwn);
break;
case VIR_NODE_DEV_CAP_SCSI_TARGET:
VIR_FREE(data->scsi_target.name);
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index e317354..e787fc7 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -141,6 +141,7 @@ struct _virNodeDevCapsDef {
unsigned int host;
char *wwnn;
char *wwpn;
+ char *fabric_wwn;
unsigned int flags;
} scsi_host;
struct {
diff --git a/src/node_device/node_device_linux_sysfs.c b/src/node_device/node_device_linux_sysfs.c
index d352800..380be9c 100644
--- a/src/node_device/node_device_linux_sysfs.c
+++ b/src/node_device/node_device_linux_sysfs.c
@@ -149,10 +149,20 @@ int check_fc_host_linux(union _virNodeDevCapData *d)
retval = -1;
}
+ if (read_wwn(d->scsi_host.host,
+ "fabric_name",
+ &d->scsi_host.fabric_wwn) == -1) {
+ VIR_ERROR(_("Failed to read fabric WWN for host%d"),
+ d->scsi_host.host);
+ retval = -1;
+ goto out;
+ }
+
out:
if (retval == -1) {
VIR_FREE(d->scsi_host.wwnn);
VIR_FREE(d->scsi_host.wwpn);
+ VIR_FREE(d->scsi_host.fabric_wwn);
}
VIR_FREE(sysfs_path);
return retval;
--
1.7.1
13 years, 6 months
[libvirt] Document
by Penas Cédric
Hi,
As part of a research project for the HES-SO (/http://www.hes-so.ch/), I
produced a document on the operation of libvirt and implementation of a
libvirt cloning function to ESXi.
Currently this document is available in French
(/http://www.tdeig.ch/kvm/Libvirt.pdf/). If anyone is interestedin, I
can translate it into English.
Your remarks and comments are welcome.
Best regards,
Penas Cédric
--
_Cédric Penas
Assistant HES
Laboratoire de Transmission de Données
*hepia*
Rue de la Prairie 4
CH-1202 Genève
cedric.penas(a)hesge.ch <mailto:cedric.penas@hesge.ch>
www.hesge.ch/hepia <http://www.hesge.ch/hepia>
Tél. +41 (0)22 546 25 47
13 years, 6 months
[libvirt] KVM Call Agenda for 12/6 (Tuesday) @ 10am US/Eastern
by Anthony Liguori
Hi,
I'd like to propose that we discuss guest agent convergence in our next KVM
call. I've CC'd folks from oVirt and libvirt to join the discussion.
I think we should probably attempt to have some structure to the discussion. I
would suggest:
1. A short introduction to each of the guest agents, what guests they support,
and what verbs they support.
2. A short description of key requirements from each party (oVirt, libvirt,
QEMU) for a guest agent
3. An open discussion about possible ways to collaborate/converge.
Regards,
Anthony Liguori
13 years, 6 months
[libvirt] [PATCH v2 0/2] Guest NUMA topology support
by Bharata B Rao
Hi,
This is v2 of the patchset that adds support for specifying NUMA topology
for guests.
<cpu>
...
<topology sockets='2' cores='4' threads='2'/>
<numa>
<cell cpus='0-7' mems='512000'/>
<cell cpus='8-15' mems='512000'/>
</numa>
...
</cpu>
This change allows libvirt to generate -numa options for QEMU/KVM.
This patchset passes all tests except daemon-conf test.
Changes for v2
--------------
- Renamed mems to memory in NUMA cell specification.
- Make both cpus= and memory= mandatory in a NUMA cell.
- Reuse cpuset and memoryKB definitions for cpus and memory.
- Fix a bug in reading memory=.
- Correct error handling for usages of virXMLPropString.
- Support virsh dumpxml.
- Fix XML in domaincommon.rng so that <numa> works correctly for
both <cpu> ... <cpu> as well as <cpu match="..."> ... <cpu>
- Don't use virBufferTruncate.
- Modifiy qemuxml2argv test cases for s/mems/memory change.
- Use virBufferLit wherever possible.
- Now qemuBuildNumaCPUArgStr can't fail, hence doesn't need return val.
- Pass memory in MB to qemu.
v1 - https://www.redhat.com/archives/libvir-list/2011-November/msg00247.html
v0 - https://www.redhat.com/archives/libvir-list/2011-October/msg00025.html
RFC - http://permalink.gmane.org/gmane.comp.emulators.libvirt/44626
Regards,
Bharata.
13 years, 6 months
[libvirt] [PATCH] security: don't try to restore label on NFS if label failed
by Eric Blake
I noticed that the logs contained messages like this:
2011-12-05 23:32:40.382+0000: 26569: warning : SELinuxRestoreSecurityFileLabel:533 : cannot lookup default selinux label for /nfs/libvirt/images/dom.img
for all my domain images living on NFS. But if we would just remember
that on domain creation that we were unable to set a SELinux label (due to
NFSv3 lacking labels, or NFSv4 not being configured to expose attributes),
then we could avoid wasting the time trying to clear the label on
domain shutdown. This in turn is one less point of NFS failure,
especially since there have been documented cases of virDomainDestroy
hanging during an attempted operation on a failed NFS connection.
I tested that this works over libvirtd restart for <disk> images; it
cannot work for other labeled file types unless we also enhance those
in-memory representations to track whether a label is in force.
* src/conf/domain_conf.h (_virDomainDiskDef): Add member.
* src/conf/domain_conf.c (virDomainDiskDefParseXML): Parse it.
(virDomainDiskDefFormat): Output it.
* src/security/security_selinux.c (SELinuxSetFilecon): Move guts...
(SELinuxSetFileconHelper): ...to new function.
(SELinuxSetFileconOptional): New function.
(SELinuxSetSecurityFileLabel): Remember if labeling failed.
(SELinuxRestoreSecurityImageLabelInt): Skip relabeling on NFS.
---
This is an attempt to address the primary symptom (but NOT the
root cause) of https://bugzilla.redhat.com/746666, since that
is a documented case of a hang during the label restoration
that would be skipped had we remembered that no label was applied
at domain start. A full solution to that problem will involve
much more invasive lock refactoring, and probably the creation
of one thread per VM rather than the current approach of reusing
RPC threads for VM operations, where the per-VM thread is used
for any operation that might hang on NFS.
https://www.redhat.com/archives/libvir-list/2011-November/msg00267.html
src/conf/domain_conf.c | 5 +++++
src/conf/domain_conf.h | 1 +
src/security/security_selinux.c | 39 ++++++++++++++++++++++++++++-----------
3 files changed, 34 insertions(+), 11 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 75e51a0..38d24e0 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2774,6 +2774,9 @@ virDomainDiskDefParseXML(virCapsPtr caps,
} else if (xmlStrEqual(cur->name, BAD_CAST "transient")) {
def->transient = 1;
} else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
+ xmlStrEqual(cur->name, BAD_CAST "nolabel")) {
+ def->noSecurityLabel = 1;
+ } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
xmlStrEqual(cur->name, BAD_CAST "state")) {
/* Legacy back-compat. Don't add any more attributes here */
devaddr = virXMLPropString(cur, "devaddr");
@@ -9856,6 +9859,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
virBufferAddLit(buf, " <shareable/>\n");
if (def->transient)
virBufferAddLit(buf, " <transient/>\n");
+ if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) && def->noSecurityLabel)
+ virBufferAddLit(buf, " <nolabel/>\n");
virBufferEscapeString(buf, " <serial>%s</serial>\n", def->serial);
if (def->encryption) {
virBufferAdjustIndent(buf, 6);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index d6ed898..97786f7 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -359,6 +359,7 @@ struct _virDomainDiskDef {
unsigned int readonly : 1;
unsigned int shared : 1;
unsigned int transient : 1;
+ unsigned int noSecurityLabel : 1;
virDomainDeviceInfo info;
virStorageEncryptionPtr encryption;
};
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 78c0d45..864b35e 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -394,8 +394,11 @@ SELinuxGetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
return 0;
}
+/* Attempt to change the label of PATH to TCON. If OPTIONAL is true,
+ * return 1 if labelling was not possible. Otherwise, require a label
+ * change, and return 0 for success, -1 for failure. */
static int
-SELinuxSetFilecon(const char *path, char *tcon)
+SELinuxSetFileconHelper(const char *path, char *tcon, bool optional)
{
security_context_t econ;
@@ -408,7 +411,7 @@ SELinuxSetFilecon(const char *path, char *tcon)
if (STREQ(tcon, econ)) {
freecon(econ);
/* It's alright, there's nothing to change anyway. */
- return 0;
+ return optional ? 1 : 0;
}
freecon(econ);
}
@@ -440,12 +443,26 @@ SELinuxSetFilecon(const char *path, char *tcon)
VIR_INFO("Setting security context '%s' on '%s' not supported",
tcon, path);
}
+ if (optional)
+ return 1;
}
}
return 0;
}
static int
+SELinuxSetFileconOptional(const char *path, char *tcon)
+{
+ return SELinuxSetFileconHelper(path, tcon, true);
+}
+
+static int
+SELinuxSetFilecon(const char *path, char *tcon)
+{
+ return SELinuxSetFileconHelper(path, tcon, false);
+}
+
+static int
SELinuxFSetFilecon(int fd, char *tcon)
{
security_context_t econ;
@@ -549,7 +566,7 @@ SELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
{
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
- if (secdef->norelabel)
+ if (secdef->norelabel || disk->noSecurityLabel)
return 0;
/* Don't restore labels on readoly/shared disks, because
@@ -606,21 +623,21 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
if (depth == 0) {
if (disk->shared) {
- ret = SELinuxSetFilecon(path, default_image_context);
+ ret = SELinuxSetFileconOptional(path, default_image_context);
} else if (disk->readonly) {
- ret = SELinuxSetFilecon(path, default_content_context);
+ ret = SELinuxSetFileconOptional(path, default_content_context);
} else if (secdef->imagelabel) {
- ret = SELinuxSetFilecon(path, secdef->imagelabel);
+ ret = SELinuxSetFileconOptional(path, secdef->imagelabel);
} else {
ret = 0;
}
} else {
- ret = SELinuxSetFilecon(path, default_content_context);
+ ret = SELinuxSetFileconOptional(path, default_content_context);
+ }
+ if (ret == 1) {
+ disk->noSecurityLabel = 1;
+ ret = 0;
}
- if (ret < 0 &&
- virStorageFileIsSharedFSType(path,
- VIR_STORAGE_FILE_SHFS_NFS) == 1)
- ret = 0;
return ret;
}
--
1.7.7.3
13 years, 6 months
Re: [libvirt] [Xen-devel] [BUG] insufficient quoting between " tap-ctl list " and xend/server/BlktapController.py
by Philipp Hahn
Hello,
On Thursday 01 December 2011 19:31:04 Ian Jackson wrote:
> Philipp Hahn writes ("Re: [Xen-devel] [BUG] insufficient quoting
between "tap-ctl list" and xend/server/BlktapController.py"):
> > As a quick work-around, the attached patch fixes the problem for me. That
> > is, until tap-ctl changes it's output format.
>
> Thanks, I have applied it.
Thanks for applying.
On Thursday 01 December 2011 20:51:05 Ian Campbell wrote:
> xend is deprecated. This ultimately means that xend will go away. If you
> are dependent on these features then you need put effort into ensuring
> that they become supported in libxl and xl.
For our forthcomming release of UCS-3.0 we really wanted to switch from Xend
to xl, but be had to switch back to using Xend, because libvirt still lacks
some important features like migration; see
<http://libvirt.org/hvsupport.html> for a comparison matrix. Back at the
beginning of 2011 Univention sponsored Markus Gross to work on the xl-binding
of libvirt, but after the end of his internship I have not seen that much
work on the xl-binding in libvirt except from Jim Fehlig.
Sincerely
Philipp Hahn
--
Philipp Hahn Open Source Software Engineer hahn(a)univention.de
Univention GmbH Linux for Your Business fon: +49 421 22 232- 0
Mary-Somerville-Str.1 D-28359 Bremen fax: +49 421 22 232-99
http://www.univention.de/
13 years, 6 months
[libvirt] [PATCH] Improve error reporting when libvirtd is not installed
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
Currently if you try to connect to a local libvirtd when
libvirtd is not in $PATH, you'll get an error
error: internal error invalid use of command API
This is because remoteFindDaemonPath() returns NULL, which
causes us to pass NULL into virNetSocketConnectUNIX which
in turn causes us to pass NULL into virCommandNewArgList.
Adding missing error checks improves this to
error: internal error Unable to locate libvirtd daemon in $PATH
* src/remote/remote_driver.c: Report error if libvirtd
cannot be found
* src/rpc/virnetsocket.c: Report error if caller requested
spawning of daemon, but provided no binary path
---
src/remote/remote_driver.c | 8 +++++++-
src/rpc/virnetsocket.c | 6 ++++++
2 files changed, 13 insertions(+), 1 deletions(-)
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 1fb0eca..755275a 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -321,6 +321,7 @@ doRemoteOpen (virConnectPtr conn,
trans_ext,
trans_tcp,
} transport;
+ const char *daemonPath;
/* We handle *ALL* URIs here. The caller has rejected any
* URIs we don't care about */
@@ -588,9 +589,14 @@ doRemoteOpen (virConnectPtr conn,
VIR_DEBUG("Proceeding with sockname %s", sockname);
}
+ if (!(daemonPath = remoteFindDaemonPath())) {
+ remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to locate libvirtd daemon in $PATH"));
+ goto failed;
+ }
if (!(priv->client = virNetClientNewUNIX(sockname,
flags & VIR_DRV_OPEN_REMOTE_AUTOSTART,
- remoteFindDaemonPath())))
+ daemonPath)))
goto failed;
priv->is_secure = 1;
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
index 2747f66..e5e2473 100644
--- a/src/rpc/virnetsocket.c
+++ b/src/rpc/virnetsocket.c
@@ -481,6 +481,12 @@ int virNetSocketNewConnectUNIX(const char *path,
remoteAddr.len = sizeof(remoteAddr.data.un);
+ if (spawnDaemon && !binary) {
+ virNetError(VIR_ERR_INTERNAL_ERROR,
+ _("Auto-spawn of daemon requested, but not binary specified"));
+ return -1;
+ }
+
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
virReportSystemError(errno, "%s", _("Failed to create socket"));
goto error;
--
1.7.7.3
13 years, 6 months
[libvirt] [PATCH libvirt-glib] Allow cancelling gvir_stream_send_all & gvir_stream_receive_all
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
Add GCancellable parameters to gvir_stream_send_all and
gvir_stream_receive_all to allow I/O to be interrupted
before completion
---
libvirt-gobject/libvirt-gobject-stream.c | 23 +++++++++++++++++++++--
libvirt-gobject/libvirt-gobject-stream.h | 2 ++
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/libvirt-gobject/libvirt-gobject-stream.c b/libvirt-gobject/libvirt-gobject-stream.c
index c1ae765..7204f98 100644
--- a/libvirt-gobject/libvirt-gobject-stream.c
+++ b/libvirt-gobject/libvirt-gobject-stream.c
@@ -26,6 +26,7 @@
#include <libvirt/virterror.h>
#include <string.h>
+#include <errno.h>
#include "libvirt-glib/libvirt-glib.h"
#include "libvirt-gobject/libvirt-gobject.h"
@@ -330,6 +331,7 @@ struct stream_sink_helper {
GVirStream *self;
GVirStreamSinkFunc func;
gpointer user_data;
+ GCancellable *cancellable;
};
static int
@@ -340,12 +342,18 @@ stream_sink(virStreamPtr st G_GNUC_UNUSED,
{
struct stream_sink_helper *helper = opaque;
+ if (g_cancellable_is_cancelled(helper->cancellable)) {
+ errno = EIO;
+ return -1;
+ }
+
return helper->func(helper->self, bytes, nbytes, helper->user_data);
}
/**
* gvir_stream_receive_all:
* @stream: the stream
+ * @cancellable: cancellation notifier
* @func: (scope notified): the callback for writing data to application
* @user_data: (closure): data to be passed to @callback
* Returns: the number of bytes consumed or -1 upon error
@@ -356,6 +364,7 @@ stream_sink(virStreamPtr st G_GNUC_UNUSED,
*/
gssize
gvir_stream_receive_all(GVirStream *self,
+ GCancellable *cancellable,
GVirStreamSinkFunc func,
gpointer user_data,
GError **err)
@@ -363,7 +372,8 @@ gvir_stream_receive_all(GVirStream *self,
struct stream_sink_helper helper = {
.self = self,
.func = func,
- .user_data = user_data
+ .user_data = user_data,
+ .cancellable = cancellable,
};
int r;
@@ -433,6 +443,7 @@ struct stream_source_helper {
GVirStream *self;
GVirStreamSourceFunc func;
gpointer user_data;
+ GCancellable *cancellable;
};
static int
@@ -443,12 +454,18 @@ stream_source(virStreamPtr st G_GNUC_UNUSED,
{
struct stream_source_helper *helper = opaque;
+ if (g_cancellable_is_cancelled(helper->cancellable)) {
+ errno = EIO;
+ return -1;
+ }
+
return helper->func(helper->self, bytes, nbytes, helper->user_data);
}
/**
* gvir_stream_send_all:
* @stream: the stream
+ * @cancellable: cancellation notifier
* @func: (scope notified): the callback for writing data to application
* @user_data: (closure): data to be passed to @callback
* Returns: the number of bytes consumed or -1 upon error
@@ -459,6 +476,7 @@ stream_source(virStreamPtr st G_GNUC_UNUSED,
*/
gssize
gvir_stream_send_all(GVirStream *self,
+ GCancellable *cancellable,
GVirStreamSourceFunc func,
gpointer user_data,
GError **err)
@@ -466,7 +484,8 @@ gvir_stream_send_all(GVirStream *self,
struct stream_source_helper helper = {
.self = self,
.func = func,
- .user_data = user_data
+ .user_data = user_data,
+ .cancellable = cancellable,
};
int r;
diff --git a/libvirt-gobject/libvirt-gobject-stream.h b/libvirt-gobject/libvirt-gobject-stream.h
index 3caadc3..9a02c7a 100644
--- a/libvirt-gobject/libvirt-gobject-stream.h
+++ b/libvirt-gobject/libvirt-gobject-stream.h
@@ -115,6 +115,7 @@ guint gvir_stream_add_watch_full(GVirStream *stream,
GDestroyNotify notify);
gssize gvir_stream_receive_all(GVirStream *stream,
+ GCancellable *cancellable,
GVirStreamSinkFunc func,
gpointer user_data,
GError **error);
@@ -125,6 +126,7 @@ gssize gvir_stream_receive(GVirStream *stream,
GError **error);
gssize gvir_stream_send_all(GVirStream *stream,
+ GCancellable *cancellable,
GVirStreamSourceFunc func,
gpointer user_data,
GError **error);
--
1.7.7.3
13 years, 6 months
[libvirt] [PATCH libvirt-glib] Add flags for controling how domains are started
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
---
libvirt-gobject/libvirt-gobject-domain.h | 8 ++++++++
libvirt-gobject/libvirt-gobject.sym | 1 +
2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/libvirt-gobject/libvirt-gobject-domain.h b/libvirt-gobject/libvirt-gobject-domain.h
index 5525d9c..b9e39dd 100644
--- a/libvirt-gobject/libvirt-gobject-domain.h
+++ b/libvirt-gobject/libvirt-gobject-domain.h
@@ -80,6 +80,14 @@ typedef enum {
} GVirDomainState;
+typedef enum {
+ GVIR_DOMAIN_START_NONE = 0,
+ GVIR_DOMAIN_START_PAUSED = (1 << 0),
+ GVIR_DOMAIN_START_AUTODESTROY = (1 << 1),
+ GVIR_DOMAIN_START_BYPASS_CACHE = (1 << 2),
+ GVIR_DOMAIN_START_FORCE_BOOT = (1 << 3),
+} GVirDomainStartFlags;
+
typedef struct _GVirDomainInfo GVirDomainInfo;
struct _GVirDomainInfo
{
diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym
index 3727fb7..d0444bd 100644
--- a/libvirt-gobject/libvirt-gobject.sym
+++ b/libvirt-gobject/libvirt-gobject.sym
@@ -44,6 +44,7 @@ LIBVIRT_GOBJECT_0.0.1 {
gvir_domain_handle_get_type;
gvir_domain_info_get_type;
gvir_domain_state_get_type;
+ gvir_domain_start_flags_get_type;
gvir_domain_get_name;
gvir_domain_get_uuid;
gvir_domain_get_id;
--
1.7.7.3
13 years, 6 months