diff mbox

[v2,for-2.6] block: convert iscsi target to a valid ID for -iscsi arg lookup

Message ID 1460564276-9750-1-git-send-email-berrange@redhat.com
State New
Headers show

Commit Message

Daniel P. Berrangé April 13, 2016, 4:17 p.m. UTC
The iSCSI block driver has a very strange approach whereby it
does not accept options directly as part of the -drive arg,
but instead takes them indirectly from a -iscsi arg. To make
up -driver and -iscsi args, it takes the iSCSI target name
and uses that as an ID value for the -iscsi arg lookup.

For example, given a -drive arg that looks like

 -drive file=iscsi://192.168.122.1:3260/iqn.2013-12.com.example%3Aiscsi-chap-netpool/1,format=raw,if=none,id=drive-virtio-disk0

The iSCSI driver will try to find the -iscsi arg with an
id of "iqn.2013-12.com.example:iscsi-chap-netpool" eg it
expects

  -iscsi id=iqn.2013-12.com.example:iscsi-chap-netpool,user=fred,password-secret=secret0

Unfortunately this is impossible to actually do in practice
because almost all iSCSI target names contain a ':' which
is not a valid ID character for QEMU:

 $ qemu-system-x86_64: -iscsi id=iqn.2013-12.com.example:iscsi-chap-netpool,user=redhat,password=123456: Parameter 'id' expects an identifier
 Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.

So for this to work we need to remove the invalid characters
in some manner. This patch takes the simplest possible approach
of just converting all invalid characters into underscores. eg
you can now use

 $ qemu-system-x86_64: -iscsi id=iqn.2013-12.com.example_iscsi-chap-netpool,user=redhat,password=123456: Parameter 'id' expects an identifier

There is theoretically the possibility for collison with this
approach if there were 2 iSCSI luns attached to the same VM
with target names that clash on the escaped char: eg

  iqn.2013-12.com.example:iscsi-chap-netpool
  iqn.2013-12.com.example_iscsi-chap-netpool

but in reality this will never happen. In addition in QEMU 2.7
the need to use the -iscsi arg will be removed by allowing all
the desired options to be listed directly with -drive. IOW this
quick stripping of invalid characters is just a short term fix
that will ultimately go away. For this reason it is not thought
worthwhile to invent a full collision-free escaping syntax for
iSCSI target IDs.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---

Note this problem was previously raised:

 http://lists.nongnu.org/archive/html/qemu-devel/2015-11/msg06501.html

and discussed the following month:

 http://lists.nongnu.org/archive/html/qemu-devel/2015-12/msg00112.html

Changed in v2:

 - Actually use the escaped target ID for all parameters,
   not just chap auth params (Pino)

 block/iscsi.c | 43 +++++++++++++++++++++++++++++++------------
 1 file changed, 31 insertions(+), 12 deletions(-)

Comments

John Ferlan April 14, 2016, 1:41 a.m. UTC | #1
On 04/13/2016 12:17 PM, Daniel P. Berrange wrote:
> The iSCSI block driver has a very strange approach whereby it
> does not accept options directly as part of the -drive arg,
> but instead takes them indirectly from a -iscsi arg. To make
> up -driver and -iscsi args, it takes the iSCSI target name
> and uses that as an ID value for the -iscsi arg lookup.
> 
> For example, given a -drive arg that looks like
> 
>  -drive file=iscsi://192.168.122.1:3260/iqn.2013-12.com.example%3Aiscsi-chap-netpool/1,format=raw,if=none,id=drive-virtio-disk0
> 
> The iSCSI driver will try to find the -iscsi arg with an
> id of "iqn.2013-12.com.example:iscsi-chap-netpool" eg it
> expects
> 
>   -iscsi id=iqn.2013-12.com.example:iscsi-chap-netpool,user=fred,password-secret=secret0
> 
> Unfortunately this is impossible to actually do in practice
> because almost all iSCSI target names contain a ':' which
> is not a valid ID character for QEMU:
> 
>  $ qemu-system-x86_64: -iscsi id=iqn.2013-12.com.example:iscsi-chap-netpool,user=redhat,password=123456: Parameter 'id' expects an identifier
>  Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.
> 
> So for this to work we need to remove the invalid characters
> in some manner. This patch takes the simplest possible approach
> of just converting all invalid characters into underscores. eg
> you can now use
> 
>  $ qemu-system-x86_64: -iscsi id=iqn.2013-12.com.example_iscsi-chap-netpool,user=redhat,password=123456: Parameter 'id' expects an identifier
> 
> There is theoretically the possibility for collison with this
> approach if there were 2 iSCSI luns attached to the same VM
> with target names that clash on the escaped char: eg
> 
>   iqn.2013-12.com.example:iscsi-chap-netpool
>   iqn.2013-12.com.example_iscsi-chap-netpool
> 
> but in reality this will never happen. In addition in QEMU 2.7
> the need to use the -iscsi arg will be removed by allowing all
> the desired options to be listed directly with -drive. IOW this
> quick stripping of invalid characters is just a short term fix
> that will ultimately go away. For this reason it is not thought
> worthwhile to invent a full collision-free escaping syntax for
> iSCSI target IDs.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
> 

Figured I'd chime in since I tripped across this today...

I think the one thing that concerns me about this '_' approach is we'd
be "stuck" with it. Eventually if 'initiator-name' is added to the
-drive command (as well as being able to parse the 'user=' and
'password-secret='), then needing to add -iscsi wouldn't be required for
libvirt. Whether this patch would be required after -drive is modified
was the other question rattling around. So I figured I'd see if I can
get things to work without it...

Using the v1 of this patch series did work for libvirt if I passed the
"id=" shown above using the '_' instead of ':'; however, taking the Pino
Toscano's series in mind, I can also start a domain using the
"initiator-name=" and "id=" parameters for '-iscsi' as follows:

...
-object
secret,id=masterKey0,format=raw,file=/var/lib/libvirt/qemu/domain-3-jaf/master-key.aes

...
-iscsi
id=iscsi-chap-netpool,initiator-name=iqn.2013-12.com.example,user=redhat,password-secret=virtio-disk1-ivKey0
-drive
file=iscsi://192.168.122.1:3260/iqn.2013-12.com.example%3Aiscsi-chap-netpool/1,format=raw,if=none,id=drive-virtio-disk1
-device
virtio-blk-pci,scsi=off,bus=pci.0,addr=0x9,drive=drive-virtio-disk1,id=virtio-disk1,bootindex=1

...

So without this patch - I should be able to get things to work starting
a domain. Long ago I tagged a libvir-list posting from Rich Jones asking
about using the '-iscsi initiator-name=' command:

http://www.redhat.com/archives/libvir-list/2014-July/msg00281.html

Since what libvirt was using worked, I just left it as one of those
someday I'll understand how/if it can be used...

John

> Note this problem was previously raised:
> 
>  http://lists.nongnu.org/archive/html/qemu-devel/2015-11/msg06501.html
> 
> and discussed the following month:
> 
>  http://lists.nongnu.org/archive/html/qemu-devel/2015-12/msg00112.html
> 
> Changed in v2:
> 
>  - Actually use the escaped target ID for all parameters,
>    not just chap auth params (Pino)
> 
>  block/iscsi.c | 43 +++++++++++++++++++++++++++++++------------
>  1 file changed, 31 insertions(+), 12 deletions(-)
> 
> diff --git a/block/iscsi.c b/block/iscsi.c
> index 302baf8..8ee2e4d 100644
> --- a/block/iscsi.c
> +++ b/block/iscsi.c
> @@ -1070,7 +1070,23 @@ retry:
>      return 0;
>  }
>  
> -static void parse_chap(struct iscsi_context *iscsi, const char *target,
> +
> +static char *convert_target_to_id(const char *target)
> +{
> +    char *id = g_strdup(target);
> +    size_t i;
> +
> +    for (i = 1; id[i]; i++) {
> +        if (!qemu_isalnum(id[i]) && !strchr("-._", id[i])) {
> +            id[i] = '_';
> +        }
> +    }
> +
> +    return id;
> +}
> +
> +
> +static void parse_chap(struct iscsi_context *iscsi, const char *targetid,
>                         Error **errp)
>  {
>      QemuOptsList *list;
> @@ -1085,7 +1101,7 @@ static void parse_chap(struct iscsi_context *iscsi, const char *target,
>          return;
>      }
>  
> -    opts = qemu_opts_find(list, target);
> +    opts = qemu_opts_find(list, targetid);
>      if (opts == NULL) {
>          opts = QTAILQ_FIRST(&list->head);
>          if (!opts) {
> @@ -1123,7 +1139,7 @@ static void parse_chap(struct iscsi_context *iscsi, const char *target,
>      g_free(secret);
>  }
>  
> -static void parse_header_digest(struct iscsi_context *iscsi, const char *target,
> +static void parse_header_digest(struct iscsi_context *iscsi, const char *targetid,
>                                  Error **errp)
>  {
>      QemuOptsList *list;
> @@ -1135,7 +1151,7 @@ static void parse_header_digest(struct iscsi_context *iscsi, const char *target,
>          return;
>      }
>  
> -    opts = qemu_opts_find(list, target);
> +    opts = qemu_opts_find(list, targetid);
>      if (opts == NULL) {
>          opts = QTAILQ_FIRST(&list->head);
>          if (!opts) {
> @@ -1161,7 +1177,7 @@ static void parse_header_digest(struct iscsi_context *iscsi, const char *target,
>      }
>  }
>  
> -static char *parse_initiator_name(const char *target)
> +static char *parse_initiator_name(const char *targetid)
>  {
>      QemuOptsList *list;
>      QemuOpts *opts;
> @@ -1171,7 +1187,7 @@ static char *parse_initiator_name(const char *target)
>  
>      list = qemu_find_opts("iscsi");
>      if (list) {
> -        opts = qemu_opts_find(list, target);
> +        opts = qemu_opts_find(list, targetid);
>          if (!opts) {
>              opts = QTAILQ_FIRST(&list->head);
>          }
> @@ -1195,7 +1211,7 @@ static char *parse_initiator_name(const char *target)
>      return iscsi_name;
>  }
>  
> -static int parse_timeout(const char *target)
> +static int parse_timeout(const char *targetid)
>  {
>      QemuOptsList *list;
>      QemuOpts *opts;
> @@ -1203,7 +1219,7 @@ static int parse_timeout(const char *target)
>  
>      list = qemu_find_opts("iscsi");
>      if (list) {
> -        opts = qemu_opts_find(list, target);
> +        opts = qemu_opts_find(list, targetid);
>          if (!opts) {
>              opts = QTAILQ_FIRST(&list->head);
>          }
> @@ -1453,6 +1469,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
>      Error *local_err = NULL;
>      const char *filename;
>      int i, ret = 0, timeout = 0;
> +    char *targetid = NULL;
>  
>      opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
>      qemu_opts_absorb_qdict(opts, options, &local_err);
> @@ -1473,7 +1490,8 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
>  
>      memset(iscsilun, 0, sizeof(IscsiLun));
>  
> -    initiator_name = parse_initiator_name(iscsi_url->target);
> +    targetid = convert_target_to_id(iscsi_url->target);
> +    initiator_name = parse_initiator_name(targetid);
>  
>      iscsi = iscsi_create_context(initiator_name);
>      if (iscsi == NULL) {
> @@ -1499,7 +1517,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
>      }
>  
>      /* check if we got CHAP username/password via the options */
> -    parse_chap(iscsi, iscsi_url->target, &local_err);
> +    parse_chap(iscsi, targetid, &local_err);
>      if (local_err != NULL) {
>          error_propagate(errp, local_err);
>          ret = -EINVAL;
> @@ -1515,7 +1533,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
>      iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
>  
>      /* check if we got HEADER_DIGEST via the options */
> -    parse_header_digest(iscsi, iscsi_url->target, &local_err);
> +    parse_header_digest(iscsi, targetid, &local_err);
>      if (local_err != NULL) {
>          error_propagate(errp, local_err);
>          ret = -EINVAL;
> @@ -1523,7 +1541,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
>      }
>  
>      /* timeout handling is broken in libiscsi before 1.15.0 */
> -    timeout = parse_timeout(iscsi_url->target);
> +    timeout = parse_timeout(targetid);
>  #if defined(LIBISCSI_API_VERSION) && LIBISCSI_API_VERSION >= 20150621
>      iscsi_set_timeout(iscsi, timeout);
>  #else
> @@ -1643,6 +1661,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
>  
>  out:
>      qemu_opts_del(opts);
> +    g_free(targetid);
>      g_free(initiator_name);
>      if (iscsi_url != NULL) {
>          iscsi_destroy_url(iscsi_url);
>
Daniel P. Berrangé April 14, 2016, 8:25 a.m. UTC | #2
On Wed, Apr 13, 2016 at 09:41:54PM -0400, John Ferlan wrote:
> 
> 
> On 04/13/2016 12:17 PM, Daniel P. Berrange wrote:
> > The iSCSI block driver has a very strange approach whereby it
> > does not accept options directly as part of the -drive arg,
> > but instead takes them indirectly from a -iscsi arg. To make
> > up -driver and -iscsi args, it takes the iSCSI target name
> > and uses that as an ID value for the -iscsi arg lookup.
> > 
> > For example, given a -drive arg that looks like
> > 
> >  -drive file=iscsi://192.168.122.1:3260/iqn.2013-12.com.example%3Aiscsi-chap-netpool/1,format=raw,if=none,id=drive-virtio-disk0
> > 
> > The iSCSI driver will try to find the -iscsi arg with an
> > id of "iqn.2013-12.com.example:iscsi-chap-netpool" eg it
> > expects
> > 
> >   -iscsi id=iqn.2013-12.com.example:iscsi-chap-netpool,user=fred,password-secret=secret0
> > 
> > Unfortunately this is impossible to actually do in practice
> > because almost all iSCSI target names contain a ':' which
> > is not a valid ID character for QEMU:
> > 
> >  $ qemu-system-x86_64: -iscsi id=iqn.2013-12.com.example:iscsi-chap-netpool,user=redhat,password=123456: Parameter 'id' expects an identifier
> >  Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.
> > 
> > So for this to work we need to remove the invalid characters
> > in some manner. This patch takes the simplest possible approach
> > of just converting all invalid characters into underscores. eg
> > you can now use
> > 
> >  $ qemu-system-x86_64: -iscsi id=iqn.2013-12.com.example_iscsi-chap-netpool,user=redhat,password=123456: Parameter 'id' expects an identifier
> > 
> > There is theoretically the possibility for collison with this
> > approach if there were 2 iSCSI luns attached to the same VM
> > with target names that clash on the escaped char: eg
> > 
> >   iqn.2013-12.com.example:iscsi-chap-netpool
> >   iqn.2013-12.com.example_iscsi-chap-netpool
> > 
> > but in reality this will never happen. In addition in QEMU 2.7
> > the need to use the -iscsi arg will be removed by allowing all
> > the desired options to be listed directly with -drive. IOW this
> > quick stripping of invalid characters is just a short term fix
> > that will ultimately go away. For this reason it is not thought
> > worthwhile to invent a full collision-free escaping syntax for
> > iSCSI target IDs.
> > 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> > 
> 
> Figured I'd chime in since I tripped across this today...
> 
> I think the one thing that concerns me about this '_' approach is we'd
> be "stuck" with it. Eventually if 'initiator-name' is added to the
> -drive command (as well as being able to parse the 'user=' and
> 'password-secret='), then needing to add -iscsi wouldn't be required for
> libvirt. Whether this patch would be required after -drive is modified
> was the other question rattling around. So I figured I'd see if I can
> get things to work without it...
> 
> Using the v1 of this patch series did work for libvirt if I passed the
> "id=" shown above using the '_' instead of ':'; however, taking the Pino
> Toscano's series in mind, I can also start a domain using the
> "initiator-name=" and "id=" parameters for '-iscsi' as follows:
> 
> ...
> -object
> secret,id=masterKey0,format=raw,file=/var/lib/libvirt/qemu/domain-3-jaf/master-key.aes
> 
> ...
> -iscsi
> id=iscsi-chap-netpool,initiator-name=iqn.2013-12.com.example,user=redhat,password-secret=virtio-disk1-ivKey0
> -drive
> file=iscsi://192.168.122.1:3260/iqn.2013-12.com.example%3Aiscsi-chap-netpool/1,format=raw,if=none,id=drive-virtio-disk1
> -device
> virtio-blk-pci,scsi=off,bus=pci.0,addr=0x9,drive=drive-virtio-disk1,id=virtio-disk1,bootindex=1
>

I don't believe that is doing what you think it is doing.

QEMU will still be using the "iqn.2013-12.com.example:iscsi-chap-netpool"
string as an ID to lookup the corresponding -iscsi arg. It will not
find it because your arg uses ID of "iscsi-chap-netpool". So, the code
will now be falling backk to just using the /first/  -iscsi arg in the
list.

IOW, if you add multiple iSCSI disks to the VM, they will all be using
the first -iscsi arg, which is certainly not what we want

Regards,
Daniel
John Ferlan April 14, 2016, 11:22 a.m. UTC | #3
[...]
>>
>> Figured I'd chime in since I tripped across this today...
>>
>> I think the one thing that concerns me about this '_' approach is we'd
>> be "stuck" with it. Eventually if 'initiator-name' is added to the
>> -drive command (as well as being able to parse the 'user=' and
>> 'password-secret='), then needing to add -iscsi wouldn't be required for
>> libvirt. Whether this patch would be required after -drive is modified
>> was the other question rattling around. So I figured I'd see if I can
>> get things to work without it...
>>
>> Using the v1 of this patch series did work for libvirt if I passed the
>> "id=" shown above using the '_' instead of ':'; however, taking the Pino
>> Toscano's series in mind, I can also start a domain using the
>> "initiator-name=" and "id=" parameters for '-iscsi' as follows:
>>
>> ...
>> -object
>> secret,id=masterKey0,format=raw,file=/var/lib/libvirt/qemu/domain-3-jaf/master-key.aes
>>
>> ...
>> -iscsi
>> id=iscsi-chap-netpool,initiator-name=iqn.2013-12.com.example,user=redhat,password-secret=virtio-disk1-ivKey0
>> -drive
>> file=iscsi://192.168.122.1:3260/iqn.2013-12.com.example%3Aiscsi-chap-netpool/1,format=raw,if=none,id=drive-virtio-disk1
>> -device
>> virtio-blk-pci,scsi=off,bus=pci.0,addr=0x9,drive=drive-virtio-disk1,id=virtio-disk1,bootindex=1
>>
> 
> I don't believe that is doing what you think it is doing.
> 
> QEMU will still be using the "iqn.2013-12.com.example:iscsi-chap-netpool"
> string as an ID to lookup the corresponding -iscsi arg. It will not
> find it because your arg uses ID of "iscsi-chap-netpool". So, the code
> will now be falling backk to just using the /first/  -iscsi arg in the
> list.
> 
> IOW, if you add multiple iSCSI disks to the VM, they will all be using
> the first -iscsi arg, which is certainly not what we want
> 

Hmm.. OK, I see... Myopia was thinking get one done first, then think
about two... Anyway, assume XML such as:

    <disk type='network' device='disk'>
      <driver name='qemu' type='raw'/>
      <auth username='redhat'>
        <secret type='iscsi' usage='libvirtiscsi'/>
      </auth>
      <source protocol='iscsi'
name='iqn.2013-12.com.example:iscsi-chap-netpool/1'>
        <host name='192.168.122.1' port='3260'/>
      </source>
      <target dev='vda' bus='virtio'/>
    </disk>
    <disk type='network' device='disk'>
      <driver name='qemu' type='raw'/>
      <auth username='redhat'>
        <secret type='iscsi' usage='libvirtiscsi'/>
      </auth>
      <source protocol='iscsi'
name='iqn.2013-12.com.example:iscsi-chap-netpool/2'>
        <host name='192.168.122.1' port='3260'/>
      </source>
      <target dev='vdb' bus='virtio'/>
    </disk>

When building the source "path" for the qemu argument, libvirt uses the
complete "name" parameter for the -drive "file=" argument.  With my
recent patches, I would add the "-iscsi id=..." using the same path.

If I use the "name" parameter as is without changing it, then even with
this patch, I get the "Parameter 'id' error...".  If I modify the name
for the "id=" to change both ":" and "/" into "_", then I can start a
vm. If I only change one, then I get the "Parameter 'id' error..."

If I try to remove the "/#", then yes, I get the "Duplicate ID
'iqn.2013-12.com.example_iscsi-chap-netpool' ..." message.

If I go back to using the "initiator-name" approach, but instead of
chopping off the "/#" lun, I convert the "/" to a "_", then I can start
the vm again, thus having:

-iscsi
id=iscsi-chap-netpool_1,initiator-name=iqn.2013-12.com.example,user=redhat,password-secret=virtio-disk0-ivKey0

and

-iscsi
id=iscsi-chap-netpool_2,initiator-name=iqn.2013-12.com.example,user=redhat,password-secret=virtio-disk1-ivKey0


If the "/#" isn't provided, the libvirt documented behaviour is to use
lun0... I haven't tried that yet, but would suspect given this approach
(e.g. convert "/" to "_"), I'd still have unique names.

I haven't tried a pass with only adding one "-iscsi" per initiator and
target name.  That is, prescan the iSCSI devices (for both disk and
hostdev) adding one "id=" and seeing if both disks can use it.

Thanks -

John
diff mbox

Patch

diff --git a/block/iscsi.c b/block/iscsi.c
index 302baf8..8ee2e4d 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -1070,7 +1070,23 @@  retry:
     return 0;
 }
 
-static void parse_chap(struct iscsi_context *iscsi, const char *target,
+
+static char *convert_target_to_id(const char *target)
+{
+    char *id = g_strdup(target);
+    size_t i;
+
+    for (i = 1; id[i]; i++) {
+        if (!qemu_isalnum(id[i]) && !strchr("-._", id[i])) {
+            id[i] = '_';
+        }
+    }
+
+    return id;
+}
+
+
+static void parse_chap(struct iscsi_context *iscsi, const char *targetid,
                        Error **errp)
 {
     QemuOptsList *list;
@@ -1085,7 +1101,7 @@  static void parse_chap(struct iscsi_context *iscsi, const char *target,
         return;
     }
 
-    opts = qemu_opts_find(list, target);
+    opts = qemu_opts_find(list, targetid);
     if (opts == NULL) {
         opts = QTAILQ_FIRST(&list->head);
         if (!opts) {
@@ -1123,7 +1139,7 @@  static void parse_chap(struct iscsi_context *iscsi, const char *target,
     g_free(secret);
 }
 
-static void parse_header_digest(struct iscsi_context *iscsi, const char *target,
+static void parse_header_digest(struct iscsi_context *iscsi, const char *targetid,
                                 Error **errp)
 {
     QemuOptsList *list;
@@ -1135,7 +1151,7 @@  static void parse_header_digest(struct iscsi_context *iscsi, const char *target,
         return;
     }
 
-    opts = qemu_opts_find(list, target);
+    opts = qemu_opts_find(list, targetid);
     if (opts == NULL) {
         opts = QTAILQ_FIRST(&list->head);
         if (!opts) {
@@ -1161,7 +1177,7 @@  static void parse_header_digest(struct iscsi_context *iscsi, const char *target,
     }
 }
 
-static char *parse_initiator_name(const char *target)
+static char *parse_initiator_name(const char *targetid)
 {
     QemuOptsList *list;
     QemuOpts *opts;
@@ -1171,7 +1187,7 @@  static char *parse_initiator_name(const char *target)
 
     list = qemu_find_opts("iscsi");
     if (list) {
-        opts = qemu_opts_find(list, target);
+        opts = qemu_opts_find(list, targetid);
         if (!opts) {
             opts = QTAILQ_FIRST(&list->head);
         }
@@ -1195,7 +1211,7 @@  static char *parse_initiator_name(const char *target)
     return iscsi_name;
 }
 
-static int parse_timeout(const char *target)
+static int parse_timeout(const char *targetid)
 {
     QemuOptsList *list;
     QemuOpts *opts;
@@ -1203,7 +1219,7 @@  static int parse_timeout(const char *target)
 
     list = qemu_find_opts("iscsi");
     if (list) {
-        opts = qemu_opts_find(list, target);
+        opts = qemu_opts_find(list, targetid);
         if (!opts) {
             opts = QTAILQ_FIRST(&list->head);
         }
@@ -1453,6 +1469,7 @@  static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
     Error *local_err = NULL;
     const char *filename;
     int i, ret = 0, timeout = 0;
+    char *targetid = NULL;
 
     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
     qemu_opts_absorb_qdict(opts, options, &local_err);
@@ -1473,7 +1490,8 @@  static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
 
     memset(iscsilun, 0, sizeof(IscsiLun));
 
-    initiator_name = parse_initiator_name(iscsi_url->target);
+    targetid = convert_target_to_id(iscsi_url->target);
+    initiator_name = parse_initiator_name(targetid);
 
     iscsi = iscsi_create_context(initiator_name);
     if (iscsi == NULL) {
@@ -1499,7 +1517,7 @@  static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     /* check if we got CHAP username/password via the options */
-    parse_chap(iscsi, iscsi_url->target, &local_err);
+    parse_chap(iscsi, targetid, &local_err);
     if (local_err != NULL) {
         error_propagate(errp, local_err);
         ret = -EINVAL;
@@ -1515,7 +1533,7 @@  static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
     iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
 
     /* check if we got HEADER_DIGEST via the options */
-    parse_header_digest(iscsi, iscsi_url->target, &local_err);
+    parse_header_digest(iscsi, targetid, &local_err);
     if (local_err != NULL) {
         error_propagate(errp, local_err);
         ret = -EINVAL;
@@ -1523,7 +1541,7 @@  static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     /* timeout handling is broken in libiscsi before 1.15.0 */
-    timeout = parse_timeout(iscsi_url->target);
+    timeout = parse_timeout(targetid);
 #if defined(LIBISCSI_API_VERSION) && LIBISCSI_API_VERSION >= 20150621
     iscsi_set_timeout(iscsi, timeout);
 #else
@@ -1643,6 +1661,7 @@  static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
 
 out:
     qemu_opts_del(opts);
+    g_free(targetid);
     g_free(initiator_name);
     if (iscsi_url != NULL) {
         iscsi_destroy_url(iscsi_url);