[libvirt] [PATCH] npiv: Auto-generate WWNs if it's not specified

Osier Yang jyang at redhat.com
Tue Dec 6 10:52:54 UTC 2011


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




More information about the libvir-list mailing list