[libvirt] [Patch v0.5] iSCSI Multi-IQN (Libvirt Support)

Shyam Iyer Shyam_Iyer at dell.com
Mon Dec 28 09:22:58 UTC 2009


This patch set realizes the multi-IQN concept discussed in an earlier thread http://www.mail-archive.com/libvir-list@redhat.com/msg16706.html

And here .. http://www.mail-archive.com/libvir-list@redhat.com/msg17499.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

Change Log from v0.4:
1) Set default tab space to 4(Hopefully this is corrected this time ;) )
2) Review comments from Dave Allan
    a) Use output of "iscsiadm -m iface" to search for existing iqn names in the iface files.
3) Create new unique iface file names for user provided iqn names if the iqns are not present in the existing iface files.

Change Log from v0.3:
1) Set default tab space to 4
2) Use Case Description for Commit Log
3) Review comments from Dave Allan
    a) No initiator iqn in the xml would mean use of the default initiator iqn name
    b) Initiator iqn provided would mean a unique session to be created using the provided iqn name.
    c) Single iSCSI session per pool
4) Added syntax in doc/schemas/storagepool.rng

There are no new errors introduced by this patch with "make check" and "make syntax-check" tests.

Signed-off-by: Sudhir Bellad <sudhir_bellad at dell.com>
Signed-off-by: Shyam Iyer <shyam_iyer at dell.com>
-------------- next part --------------
commit f9cf55ebe516e285f9552b6e9106458b1129c121
Author: shyam_iyer at dell.com <shyam_iyer at dell.com>
Date:   Mon Dec 28 03:13:23 2009 -0600

    [Patch v0.5] iSCSI Multi-IQN (Libvirt Support)
    
    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
    
    And here .. http://www.mail-archive.com/libvir-list@redhat.com/msg17499.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
    
    Change Log from v0.4:
    1) Set default tab space to 4(Hopefully this is corrected this time ;) )
    2) Review comments from Dave Allan
        a) Use output of "iscsiadm -m iface" to search for existing iqn names in the iface files.
    3) Create new unique iface file names for user provided iqn names if the iqns are not present in the existing iface files.
    
    Change Log from v0.3:
    1) Set default tab space to 4
    2) Use Case Description for Commit Log
    3) Review comments from Dave Allan
        a) No initiator iqn in the xml would mean use of the default initiator iqn name
        b) Initiator iqn provided would mean a unique session to be created using the provided iqn name.
        c) Single iSCSI session per pool
    4) Added syntax in doc/schemas/storagepool.rng
    
    There are no new errors introduced by this patch with "make check" and "make syntax-check" tests.
    
    Signed-off-by: Sudhir Bellad <sudhir_bellad at dell.com>
    Signed-off-by: shyam_iyer at dell.com <shyam_iyer at dell.com>

diff --git a/docs/schemas/storagepool.rng b/docs/schemas/storagepool.rng
index 249bf9c..90d16a8 100644
--- a/docs/schemas/storagepool.rng
+++ b/docs/schemas/storagepool.rng
@@ -188,6 +188,15 @@
     </element>
   </define>
 
+  <define name='initiatorinfoiqnname'>
+    <element name='iqn'>
+      <attribute name='name'>
+	<text/>
+      </attribute>
+      <empty/>
+    </element>
+  </define>
+
   <define name='devextents'>
     <oneOrMore>
       <element name='freeExtent'>
@@ -362,6 +371,7 @@
     <element name='source'>
       <ref name='sourceinfohost'/>
       <ref name='sourceinfodev'/>
+      <ref name='initiatorinfoiqnname'/>
       <optional>
         <ref name='sourceinfoauth'/>
       </optional>
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index 0aefa06..0830cce 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -106,11 +106,12 @@ 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,
@@ -283,6 +285,7 @@ virStoragePoolSourceFree(virStoragePoolSourcePtr source) {
     VIR_FREE(source->dir);
     VIR_FREE(source->name);
     VIR_FREE(source->adapter);
+    VIR_FREE(source->initiator.iqn);
 
     if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
         VIR_FREE(source->auth.chap.login);
@@ -666,6 +669,10 @@ virStoragePoolDefParseXML(virConnectPtr conn,
             goto cleanup;
         }
     }
+    
+    if (options->flags & VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN) {
+        ret->source.initiator.iqn = virXPathString(conn, "string(./initiator/iqn/@name)", ctxt);
+    }
 
     if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
         if (!ret->source.dir) {
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index a795981..afa7984 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -182,6 +182,12 @@ struct _virStoragePoolSourceDeviceExtent {
     int type;  /* free space type */
 };
 
+typedef struct _virStoragePoolSourceInitiatorAttr virStoragePoolSourceInitiatorAttr;
+struct _virStoragePoolSourceInitiatorAttr {
+    /* Initiator iqn name */
+    char *iqn;
+};
+
 /*
  * Pools can be backed by one or more devices, and some
  * allow us to track free space on underlying devices.
@@ -223,6 +229,9 @@ struct _virStoragePoolSource {
     /* Or a name */
     char *name;
 
+	/* initiator iqn name */
+    virStoragePoolSourceInitiatorAttr initiator;
+
     int authType;       /* virStoragePoolAuthType */
     union {
         virStoragePoolAuthChap chap;
diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c
index b516add..d53f6fe 100644
--- a/src/storage/storage_backend_iscsi.c
+++ b/src/storage/storage_backend_iscsi.c
@@ -33,6 +33,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <dirent.h>
+#include <sys/stat.h>
 
 #include "virterror_internal.h"
 #include "storage_backend_scsi.h"
@@ -159,13 +160,126 @@ virStorageBackendISCSIConnection(virConnectPtr conn,
                                  const char *portal,
                                  const char *action)
 {
-    const char *const cmdargv[] = {
+
+    if (pool->def->source.initiator.iqn != NULL) {
+        int fd = -1;
+        FILE *fp = NULL;
+        pid_t child = 0;
+        char line[1024];
+        char ifacename[256];
+        bool found = false;
+        const char *const prog[] = {
+        ISCSIADM, "--mode", "iface", NULL
+        };
+
+        /* Run the program and capture its output */
+        if (virExec(conn, prog, NULL, NULL,
+        	        &child, -1, &fd, NULL, VIR_EXEC_NONE) < 0) {
+            return -1;
+        }
+
+        if ((fp = fdopen(fd, "r")) == NULL) {
+        	virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+            	                  "%s", _("cannot read fd"));
+            return -1;
+        }
+
+        memset(line,'\0',1024);
+        memset(ifacename,'\0',256);
+
+        while (fgets(line, sizeof(line), fp) != NULL) {
+            int len = strlen(line);
+
+            if (len && line[len-1] == '\n')
+                line[len-1] = '\0';
+
+            if((strstr(line,pool->def->source.initiator.iqn) != NULL)){
+                char *token;
+                token = strtok(line," ");
+                strcpy(ifacename,token);
+                found=true;
+                break;
+            }
+        }
+
+        if (!found) {
+            int exitstatus = -1;
+
+            strcpy(ifacename, IFACE_PATH"iface-iqn-XXXXXX");
+            if (mktemp(ifacename) == NULL) {
+                virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                "%s", _("cannot generate iface file name"));
+                return -1;
+            }
+
+            const char *const cmdargv1[] = {
+            ISCSIADM, "--mode", "iface", "--interface", ifacename + IFACE_PATH_LENGTH,
+            "--op", "new", NULL
+            };
+
+            /* Note that we ignore the exitstatus.  Older versions of iscsiadm tools
+            * returned an exit status of > 0, even if they succeeded.  We will just
+            * rely on whether iface file got created properly.
+            */
+            if (virRun(conn, cmdargv1, &exitstatus) < 0)
+                return -1;
+
+            const char *const cmdargv2[] = {
+            ISCSIADM, "--mode", "iface", "--interface", ifacename + IFACE_PATH_LENGTH,
+            "--op", "update", "--name", "iface.initiatorname", "--value",
+            pool->def->source.initiator.iqn, NULL
+            };
+
+            /* Note that we ignore the exitstatus.  Older versions of iscsiadm tools
+            * returned an exit status of > 0, even if they succeeded.  We will just
+            * rely on whether iface file got updated properly.
+            */
+
+            if (virRun(conn, cmdargv2, &exitstatus) < 0)
+            	return -1;
+
+            const char *const cmdsendtarget[] = {
+            ISCSIADM, "--mode", "discovery", "--type", "sendtargets",
+            "--portal", portal, NULL
+            };
+
+            if (virRun(conn, cmdsendtarget, NULL) < 0)
+                return -1;
+
+            const char *const cmdargv[] = {
+            ISCSIADM, "--mode", "node", "--portal", portal,
+            "--targetname", pool->def->source.devices[0].path, "--interface",
+            ifacename + IFACE_PATH_LENGTH, action, NULL
+            };
+
+            if (virRun(conn, cmdargv, NULL) < 0)
+                return -1;
+        }
+        else {
+            const char *const cmdargv[] = {
+            ISCSIADM, "--mode", "node", "--portal", portal,
+            "--targetname", pool->def->source.devices[0].path, "--interface",
+            ifacename, action, NULL
+            };
+
+            if (virRun(conn, cmdargv, NULL) < 0)
+                return -1;
+        }
+
+        if (fp)
+            fclose(fp);
+        else
+            close(fd);
+
+    }
+    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;
+        };
+        if (virRun(conn, cmdargv, NULL) < 0)
+            return -1;
+    }
 
     return 0;
 }
diff --git a/src/storage/storage_backend_iscsi.h b/src/storage/storage_backend_iscsi.h
index 665ed13..e44de7b 100644
--- a/src/storage/storage_backend_iscsi.h
+++ b/src/storage/storage_backend_iscsi.h
@@ -28,4 +28,7 @@
 
 extern virStorageBackend virStorageBackendISCSI;
 
+#define IFACE_PATH "/var/lib/iscsi/ifaces"
+#define IFACE_PATH_LENGTH 21
+
 #endif /* __VIR_STORAGE_BACKEND_ISCSI_H__ */


More information about the libvir-list mailing list