]> xenbits.xensource.com Git - libvirt.git/commitdiff
nodedev: Add the ability to create vHBA by parent wwnn/wwpn or fabric_wwn
authorJohn Ferlan <jferlan@redhat.com>
Thu, 17 Nov 2016 16:09:09 +0000 (11:09 -0500)
committerJohn Ferlan <jferlan@redhat.com>
Fri, 6 Jan 2017 22:14:12 +0000 (17:14 -0500)
https://bugzilla.redhat.com/show_bug.cgi?id=1349696

When creating a vHBA, the process is to feed XML to nodeDeviceCreateXML
that lists the <parent> scsi_hostX to use to create the vHBA. However,
between reboots, it's possible that the <parent> changes its scsi_hostX
to scsi_hostY and saved XML to perform the creation will either fail or
create a vHBA using the wrong parent.

So add the ability to provide "wwnn" and "wwpn" or "fabric_wwn" to
the <parent> instead of a name of the scsi_hostN that is the parent.
The allowed XML will thus be:

  <parent>scsi_host3</parent>  (current)

or

  <parent wwnn='$WWNN' wwpn='$WWPN'/>

or

  <parent fabric_wwn='$WWNN'/>

Using the wwnn/wwpn or fabric_wwn ensures the same 'scsi_hostN' is
selected between hardware reconfigs or host reboots. The fabric_wwn
Using the wwnn/wwpn pair will provide the most specific search option,
while fabric_wwn will at least ensure usage of the same SAN, but maybe
not the same scsi_hostN.

This patch will add the new fields to the nodedev.rng for input purposes
only since the input XML is essentially thrown away, no need to Format
the values since they'd already be printed as part of the scsi_host
data block.

New API virNodeDeviceGetParentHostByWWNs will take the parent "wwnn" and
"wwpn" in order to search the list of devices for matching capability
data fields wwnn and wwpn.

New API virNodeDeviceGetParentHostByFabricWWN will take the parent "fabric_wwn"
in order to search the list of devices for matching capability data field
fabric_wwn.

docs/schemas/nodedev.rng
src/conf/node_device_conf.c
src/conf/node_device_conf.h
src/libvirt_private.syms
src/node_device/node_device_driver.c

index 93a88d883056bc18cad14becba7837dfd1248f99..9c9840207c93590e86d987adf74d4bcb7f56f798 100644 (file)
@@ -16,7 +16,7 @@
         <element name="path"><text/></element>
       </optional>
       <optional>
-        <element name="parent"><text/></element>
+        <ref name="parent"/>
       </optional>
 
       <optional>
     </element>
   </define>
 
+  <define name='parent'>
+    <element name='parent'>
+      <choice>
+        <group>
+          <attribute name='wwnn'>
+            <ref name='wwn'/>
+          </attribute>
+          <attribute name='wwpn'>
+            <ref name='wwn'/>
+          </attribute>
+          <empty/>
+        </group>
+        <group>
+          <attribute name='fabric_wwn'>
+            <ref name='wwn'/>
+          </attribute>
+          <empty/>
+        </group>
+        <text/>
+      </choice>
+    </element>
+  </define>
+
   <define name='capability'>
     <element name="capability">
       <choice>
index b13cb6b9899aca129f6b842f35a4fc9f637f5ff6..4d3268f12e30483e91d873169f329a194025f9fb 100644 (file)
@@ -97,6 +97,30 @@ int virNodeDeviceHasCap(const virNodeDeviceObj *dev, const char *cap)
 }
 
 
+/* virNodeDeviceFindFCCapDef:
+ * @dev: Pointer to current device
+ *
+ * Search the device object 'caps' array for fc_host capability.
+ *
+ * Returns:
+ * Pointer to the caps or NULL if not found
+ */
+static virNodeDevCapsDefPtr
+virNodeDeviceFindFCCapDef(const virNodeDeviceObj *dev)
+{
+    virNodeDevCapsDefPtr caps = dev->def->caps;
+
+    while (caps) {
+        if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST &&
+            (caps->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST))
+            break;
+
+        caps = caps->next;
+    }
+    return caps;
+}
+
+
 /* virNodeDeviceFindVPORTCapDef:
  * @dev: Pointer to current device
  *
@@ -156,6 +180,46 @@ virNodeDeviceObjPtr virNodeDeviceFindByName(virNodeDeviceObjListPtr devs,
 }
 
 
+static virNodeDeviceObjPtr
+virNodeDeviceFindByWWNs(virNodeDeviceObjListPtr devs,
+                        const char *parent_wwnn,
+                        const char *parent_wwpn)
+{
+    size_t i;
+
+    for (i = 0; i < devs->count; i++) {
+        virNodeDevCapsDefPtr cap;
+        virNodeDeviceObjLock(devs->objs[i]);
+        if ((cap = virNodeDeviceFindFCCapDef(devs->objs[i])) &&
+            STREQ_NULLABLE(cap->data.scsi_host.wwnn, parent_wwnn) &&
+            STREQ_NULLABLE(cap->data.scsi_host.wwpn, parent_wwpn))
+            return devs->objs[i];
+        virNodeDeviceObjUnlock(devs->objs[i]);
+    }
+
+    return NULL;
+}
+
+
+static virNodeDeviceObjPtr
+virNodeDeviceFindByFabricWWN(virNodeDeviceObjListPtr devs,
+                             const char *parent_fabric_wwn)
+{
+    size_t i;
+
+    for (i = 0; i < devs->count; i++) {
+        virNodeDevCapsDefPtr cap;
+        virNodeDeviceObjLock(devs->objs[i]);
+        if ((cap = virNodeDeviceFindFCCapDef(devs->objs[i])) &&
+            STREQ_NULLABLE(cap->data.scsi_host.fabric_wwn, parent_fabric_wwn))
+            return devs->objs[i];
+        virNodeDeviceObjUnlock(devs->objs[i]);
+    }
+
+    return NULL;
+}
+
+
 static virNodeDeviceObjPtr
 virNodeDeviceFindByCap(virNodeDeviceObjListPtr devs,
                        const char *cap)
@@ -182,6 +246,9 @@ void virNodeDeviceDefFree(virNodeDeviceDefPtr def)
 
     VIR_FREE(def->name);
     VIR_FREE(def->parent);
+    VIR_FREE(def->parent_wwnn);
+    VIR_FREE(def->parent_wwpn);
+    VIR_FREE(def->parent_fabric_wwn);
     VIR_FREE(def->driver);
     VIR_FREE(def->sysfs_path);
     VIR_FREE(def->parent_sysfs_path);
@@ -1657,6 +1724,16 @@ virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
 
     /* Extract device parent, if any */
     def->parent = virXPathString("string(./parent[1])", ctxt);
+    def->parent_wwnn = virXPathString("string(./parent[1]/@wwnn)", ctxt);
+    def->parent_wwpn = virXPathString("string(./parent[1]/@wwpn)", ctxt);
+    if ((def->parent_wwnn && !def->parent_wwpn) ||
+        (!def->parent_wwnn && def->parent_wwpn)) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("must supply both wwnn and wwpn for parent"));
+        goto error;
+    }
+    def->parent_fabric_wwn = virXPathString("string(./parent[1]/@fabric_wwn)",
+                                            ctxt);
 
     /* Parse device capabilities */
     nodes = NULL;
@@ -1851,6 +1928,55 @@ virNodeDeviceGetParentHost(virNodeDeviceObjListPtr devs,
 }
 
 
+int
+virNodeDeviceGetParentHostByWWNs(virNodeDeviceObjListPtr devs,
+                                 const char *dev_name,
+                                 const char *parent_wwnn,
+                                 const char *parent_wwpn,
+                                 int *parent_host)
+{
+    virNodeDeviceObjPtr parent = NULL;
+    int ret;
+
+    if (!(parent = virNodeDeviceFindByWWNs(devs, parent_wwnn, parent_wwpn))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Could not find parent device for '%s'"),
+                       dev_name);
+        return -1;
+    }
+
+    ret = virNodeDeviceFindFCParentHost(parent, parent_host);
+
+    virNodeDeviceObjUnlock(parent);
+
+    return ret;
+}
+
+
+int
+virNodeDeviceGetParentHostByFabricWWN(virNodeDeviceObjListPtr devs,
+                                      const char *dev_name,
+                                      const char *parent_fabric_wwn,
+                                      int *parent_host)
+{
+    virNodeDeviceObjPtr parent = NULL;
+    int ret;
+
+    if (!(parent = virNodeDeviceFindByFabricWWN(devs, parent_fabric_wwn))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Could not find parent device for '%s'"),
+                       dev_name);
+        return -1;
+    }
+
+    ret = virNodeDeviceFindFCParentHost(parent, parent_host);
+
+    virNodeDeviceObjUnlock(parent);
+
+    return ret;
+}
+
+
 int
 virNodeDeviceFindVportParentHost(virNodeDeviceObjListPtr devs,
                                  int *parent_host)
index 2b2aed758d5fc667883d9105e8faa6137b7b5809..1634483339f1b698822a30486c01ddd784cebd5b 100644 (file)
@@ -200,6 +200,9 @@ struct _virNodeDeviceDef {
     char *sysfs_path;                   /* udev name/sysfs path */
     char *parent;                      /* optional parent device name */
     char *parent_sysfs_path;            /* udev parent name/sysfs path */
+    char *parent_wwnn;                 /* optional parent wwnn */
+    char *parent_wwpn;                 /* optional parent wwpn */
+    char *parent_fabric_wwn;           /* optional parent fabric_wwn */
     char *driver;                       /* optional driver name */
     virNodeDevCapsDefPtr caps;         /* optional device capabilities */
 };
@@ -273,6 +276,17 @@ int virNodeDeviceGetParentHost(virNodeDeviceObjListPtr devs,
                                const char *parent_name,
                                int *parent_host);
 
+int virNodeDeviceGetParentHostByWWNs(virNodeDeviceObjListPtr devs,
+                                     const char *dev_name,
+                                     const char *parent_wwnn,
+                                     const char *parent_wwpn,
+                                     int *parent_host);
+
+int virNodeDeviceGetParentHostByFabricWWN(virNodeDeviceObjListPtr devs,
+                                          const char *dev_name,
+                                          const char *parent_fabric_wwn,
+                                          int *parent_host);
+
 int virNodeDeviceFindVportParentHost(virNodeDeviceObjListPtr devs,
                                      int *parent_host);
 
index a928e9055d40729ef716f5b0cdb7729f75ca4b67..8e4e52d1cae01ec9c5ab32094528ae799f512212 100644 (file)
@@ -702,6 +702,8 @@ virNodeDeviceFindByName;
 virNodeDeviceFindBySysfsPath;
 virNodeDeviceFindVportParentHost;
 virNodeDeviceGetParentHost;
+virNodeDeviceGetParentHostByFabricWWN;
+virNodeDeviceGetParentHostByWWNs;
 virNodeDeviceGetWWNs;
 virNodeDeviceHasCap;
 virNodeDeviceObjListExport;
index 474b71365f7fc5f5c25a792f081146982b5e8b2d..5238e231de0ed521932ee00e27909c9431a737e3 100644 (file)
@@ -590,6 +590,19 @@ nodeDeviceCreateXML(virConnectPtr conn,
                                        def->parent,
                                        &parent_host) < 0)
             goto cleanup;
+    } else if (def->parent_wwnn && def->parent_wwpn) {
+        if (virNodeDeviceGetParentHostByWWNs(&driver->devs,
+                                             def->name,
+                                             def->parent_wwnn,
+                                             def->parent_wwpn,
+                                             &parent_host) < 0)
+            goto cleanup;
+    } else if (def->parent_fabric_wwn) {
+        if (virNodeDeviceGetParentHostByFabricWWN(&driver->devs,
+                                                  def->name,
+                                                  def->parent_fabric_wwn,
+                                                  &parent_host) < 0)
+            goto cleanup;
     } else {
         /* Try to find a vport capable scsi_host when no parent supplied */
         if (virNodeDeviceFindVportParentHost(&driver->devs, &parent_host) < 0)