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