The following patch set realizes the multi-IQN concept discussed in an
earlier thread
http://www.mail-archive.com/libvir-list@redhat.com/msg16706.html
The patch realizes an XML schema like the one below and allows libvirt
to read through it to create storage pools.
These XMLs when created using a virtualization manager realize unique VM
to storage LUN mappings through a single console and thus opening up
possibilities for the following scenarios -
* possibility of multiple IQNs for a single Guest
* option for hypervisor's initiator to use these IQNs on behalf of the
guest
Example Usages:
Usage 1:
VM1 - > <Init iqn1> <------------------------> <Target iqn1>
<Init iqn2> <------------------------> <Target iqn1>
<Init iqn3> <------------------------> <Target iqn1>
<Init iqn4> <------------------------> <Target iqn1>
Usage 2:
VM1 - > <Init iqn1> <------------------------> <Target iqn1>
<Init iqn2> <------------------------> <Target iqn2>
<Init iqn3> <------------------------> <Target iqn3>
<Init iqn4> <------------------------> <Target iqn4>
Usage 3:
VM1 - > <Init iqn1> <------------------------> <Target iqn1>
VM2 - > <Init iqn2> <------------------------> <Target iqn1>
Usage 4:
VM1 - > <Init iqn1> <------------------------> <Target iqn1>
VM2 - > <Init iqn2> <------------------------> <Target iqn2>
Example XML schema for an iSCSI storage pool created -- <pool
type="iscsi">
<name>dell</name>
<uuid>cf354733-b01b-8870-2040-94888640e24d</uuid>
<capacity>0</capacity>
<allocation>0</allocation>
<available>0</available>
- <source>
<initiator>
iqnname = "<initiator IQN1>">
iqnname = "<initiator IQN2>">
</initiator>
........................................
........................................
<host name="<iSCSI target hostname or Target IP address>" />
<device path="<iSCSI Target IQN name>" />
</source>
- <target>
<path>/dev/disk/by-path</path>
- <permissions>
<mode>0700</mode>
<owner>0</owner>
<group>0</group>
</permissions>
</target>
</pool>
Each initiator iqn name can be parsed to create the unique sessions.
TODO:
1) Virt Manager GUI support to allow a visual mapping of iqn->storage
pool -> VM and thus creating the XML for consumption by libvirt.
Libvirt support added above can realize the same using virsh options.
2) option for Guest's own BIOS & initiator to use the initiator IQNs
(iSCSI in Guest)
a) Libvirt support to allow iqn as an attribute for a VM's XML.
b) Qemu Support to allow Guest's bios & initiator to use these
IQNs.
Signed-off-by: Sudhir Bellad <sudhir_bellad(a)dell.com>
Signed-off-by: Shyam Iyer <shyam_iyer(a)dell.com>
diff --git a/src/storage_backend_iscsi.c b/src/storage_backend_iscsi.c
index b516add..3f2a79d 100644
--- a/src/storage_backend_iscsi.c
+++ b/src/storage_backend_iscsi.c
@@ -39,6 +39,10 @@
#include "storage_backend_iscsi.h"
#include "util.h"
#include "memory.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
#define VIR_FROM_THIS VIR_FROM_STORAGE
@@ -159,13 +163,57 @@ virStorageBackendISCSIConnection(virConnectPtr
conn,
const char *portal,
const char *action)
{
- const char *const cmdargv[] = {
- ISCSIADM, "--mode", "node", "--portal", portal,
- "--targetname", pool->def->source.devices[0].path, action, NULL
- };
-
- if (virRun(conn, cmdargv, NULL) < 0)
- return -1;
+ DIR *dir;
+ struct dirent *entry;
+
+
+ if (pool->def->source.initiator[0].iqnname != NULL) {
+ int i = 0;
+ while(pool->def->source.initiator[i].iqnname != NULL){
+ if (!(dir = opendir(IFACES_DIR))) {
+ if (errno == ENOENT)
+ return 0;
+ virReportSystemError(conn, errno,
_("Failed to open dir '%s'"),
+ IFACES_DIR);
+ return -1;
+ }
+ while ((entry = readdir(dir))) {
+ FILE *fp;
+ char path[PATH_MAX];
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ sprintf(path,"%s", IFACES_DIR);
+ strcat(path,(const char
*)entry->d_name);
+
+ if ((fp = fopen(path, "r"))){
+ char buff[256];
+ while (fp != NULL && fgets(buff,
sizeof(buff), fp) != NULL) {
+ if (strstr(buff,
pool->def->source.initiator[i].iqnname) != NULL) {
+ const char
*const cmdargv[] = {
+
ISCSIADM, "--mode", "node", "--portal", portal,
+
"--targetname", pool->def->source.devices[0].path, "-I",
entry->d_name,
action, NULL
+ };
+
+
if (virRun(conn, cmdargv, NULL) < 0)
+
return -1;
+ }
+ }
+ }
+ fclose(fp);
+ }
+ i++;
+ }
+ }
+ else{
+ const char *const cmdargv[] = {
+ ISCSIADM, "--mode", "node", "--portal",
portal,
+ "--targetname", pool->def->source.devices[0].path,
action, NULL
+ };
+ if (virRun(conn, cmdargv, NULL) < 0)
+ return -1;
+ }
return 0;
}
diff --git a/src/storage_backend_iscsi.h b/src/storage_backend_iscsi.h
index 665ed13..14c2c5c 100644
--- a/src/storage_backend_iscsi.h
+++ b/src/storage_backend_iscsi.h
@@ -25,7 +25,7 @@
#define __VIR_STORAGE_BACKEND_ISCSI_H__
#include "storage_backend.h"
-
extern virStorageBackend virStorageBackendISCSI;
+#define IFACES_DIR "/var/lib/iscsi/ifaces/"
#endif /* __VIR_STORAGE_BACKEND_ISCSI_H__ */
diff --git a/src/storage_conf.c b/src/storage_conf.c
index 788de15..0f2ace9 100644
--- a/src/storage_conf.c
+++ b/src/storage_conf.c
@@ -106,12 +106,13 @@ struct _virStorageVolOptions {
/* Flags to indicate mandatory components in the pool source */
enum {
- VIR_STORAGE_POOL_SOURCE_HOST = (1<<0),
- VIR_STORAGE_POOL_SOURCE_DEVICE = (1<<1),
- VIR_STORAGE_POOL_SOURCE_DIR = (1<<2),
- VIR_STORAGE_POOL_SOURCE_ADAPTER = (1<<3),
- VIR_STORAGE_POOL_SOURCE_NAME = (1<<4),
-};
+ VIR_STORAGE_POOL_SOURCE_HOST = (1<<0),
+ VIR_STORAGE_POOL_SOURCE_DEVICE = (1<<1),
+ VIR_STORAGE_POOL_SOURCE_DIR = (1<<2),
+ VIR_STORAGE_POOL_SOURCE_ADAPTER = (1<<3),
+ VIR_STORAGE_POOL_SOURCE_NAME = (1<<4),
+ VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN = (1<<5),
+ };
@@ -179,7 +180,8 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
{ .poolType = VIR_STORAGE_POOL_ISCSI,
.poolOptions = {
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
- VIR_STORAGE_POOL_SOURCE_DEVICE),
+ VIR_STORAGE_POOL_SOURCE_DEVICE |
+ VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN),
},
.volOptions = {
.formatToString = virStoragePoolFormatDiskTypeToString,
@@ -532,6 +534,34 @@ virStoragePoolDefParseXML(virConnectPtr conn,
goto cleanup;
}
}
+
+ if(options->flags & VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN) {
+ xmlNodePtr *nodeset = NULL;
+ int niqn, i;
+
+ if((niqn = virXPathNodeSet(conn, "./initiator/iqnname", ctxt,
&nodeset)) < 0) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("cannot extract storage pool source
devices"));
+ goto cleanup;
+ }
+ if (VIR_ALLOC_N(ret->source.initiator, niqn) < 0) {
+ VIR_FREE(nodeset);
+ virReportOOMError(conn);
+ goto cleanup;
+ }
+ for (i = 0 ; i < niqn ; i++) {
+ xmlChar *name = xmlGetProp(nodeset[i], BAD_CAST "name");
+ if (name == NULL) {
+ VIR_FREE(nodeset);
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("missing storage pool source device
path"));
+ goto cleanup;
+ }
+ ret->source.initiator[i].iqnname = (char *)name;
+ }
+ VIR_FREE(nodeset);
+ }
+
if (options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) {
xmlNodePtr *nodeset = NULL;
int nsource, i;
diff --git a/src/storage_conf.h b/src/storage_conf.h
index 9fedb12..c77d6ae 100644
--- a/src/storage_conf.h
+++ b/src/storage_conf.h
@@ -182,6 +182,13 @@ struct _virStoragePoolSourceDeviceExtent {
int type; /* free space type */
};
+typedef struct _virStoragePoolSourceInitiatorAttr
virStoragePoolSourceInitiatorAttr;
+typedef virStoragePoolSourceInitiatorAttr
*virStoragePoolSourceInitiatorAttrPtr;
+struct _virStoragePoolSourceInitiatorAttr {
+ /* Initiator iqn name */
+ char *iqnname;
+};
+
/*
* Pools can be backed by one or more devices, and some
* allow us to track free space on underlying devices.
@@ -223,6 +230,9 @@ struct _virStoragePoolSource {
/* Or a name */
char *name;
+ /* One or more initiator names */
+ virStoragePoolSourceInitiatorAttrPtr initiator;
+
int authType; /* virStoragePoolAuthType */
union {
virStoragePoolAuthChap chap;