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 <parent_wwnn> and <parent_wwpn> or
<parent_fabric_wwn> in order to use those values as more consistent
search parameters. For some providing the wwnn/wwpn pair will provide
the most specific search option, while for others providing a fabric_wwn
will at least ensure usage of the same SAN.
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
parent_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.
Signed-off-by: John Ferlan <jferlan@xxxxxxxxxx>
---
docs/schemas/nodedev.rng | 15 +++++
src/conf/node_device_conf.c | 120 +++++++++++++++++++++++++++++++++++
src/conf/node_device_conf.h | 14 ++++
src/libvirt_private.syms | 2 +
src/node_device/node_device_driver.c | 13 ++++
5 files changed, 164 insertions(+)
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
index 93a88d8..6fe49a3 100644
--- a/docs/schemas/nodedev.rng
+++ b/docs/schemas/nodedev.rng
@@ -18,6 +18,21 @@
<optional>
<element name="parent"><text/></element>
</optional>
+ <optional>
+ <element name="parent_wwnn">
+ <ref name='wwn'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="parent_wwpn">
+ <ref name='wwn'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="parent_fabric_wwn">
+ <ref name='wwn'/>
+ </element>
+ </optional>
<optional>
<element name="driver">
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index 3aa77cf..cecd915 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -92,6 +92,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
*
@@ -152,6 +176,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)
{
@@ -177,6 +241,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);
@@ -1652,6 +1719,10 @@ virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
/* Extract device parent, if any */
def->parent = virXPathString("string(./parent[1])", ctxt);
+ def->parent_wwnn = virXPathString("string(./parent_wwnn[1])", ctxt);
+ def->parent_wwpn = virXPathString("string(./parent_wwpn[1])", ctxt);
+ def->parent_fabric_wwn = virXPathString("string(./parent_fabric_wwn[1])",
+ ctxt);
/* Parse device capabilities */
nodes = NULL;
@@ -1847,6 +1918,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)
{
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index 2b2aed7..1634483 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -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);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index de14a7e..5673bda 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -701,6 +701,8 @@ virNodeDeviceFindByName;
virNodeDeviceFindBySysfsPath;
virNodeDeviceFindVportParentHost;
virNodeDeviceGetParentHost;
+virNodeDeviceGetParentHostByFabricWWN;
+virNodeDeviceGetParentHostByWWNs;
virNodeDeviceGetWWNs;
virNodeDeviceHasCap;
virNodeDeviceObjListExport;
diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c
index 0e091fe..b7bec65 100644
--- a/src/node_device/node_device_driver.c
+++ b/src/node_device/node_device_driver.c
@@ -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)