On 11/27/2011 01:24 AM, Ronnie Sahlberg wrote: > This patch adds configuration variables for iSCSI to set > initiator-name to use when logging in to the target, > which type of header-digest to negotiate with the target > and username and password for CHAP authentication. > > This allows specifying a initiator-name either from the command line > -iscsi initiator-name=iqn.2004-01.com.example:test > or from a configuration file included with -readconfig > [iscsi] > initiator-name = iqn.2004-01.com.example:test > header-digest = CRC32C|CRC32C-NONE|NONE-CRC32C|NONE > user = CHAP username > password = CHAP password > > The patch also updates the manpage and qemu-doc > > Signed-off-by: Ronnie Sahlberg <ronniesahlb...@gmail.com> > --- > block/iscsi.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++- > qemu-config.c | 27 ++++++++++++++ > qemu-doc.texi | 28 ++++++++++++++- > qemu-options.hx | 16 ++++++-- > vl.c | 8 ++++ > 5 files changed, 179 insertions(+), 7 deletions(-) > > diff --git a/block/iscsi.c b/block/iscsi.c > index 938c568..851b804 100644 > --- a/block/iscsi.c > +++ b/block/iscsi.c > @@ -455,6 +455,97 @@ iscsi_connect_cb(struct iscsi_context *iscsi, int > status, void *command_data, > } > } > > +static void parse_chap(struct iscsi_context *iscsi) > +{ > + QemuOptsList *list; > + QemuOpts *opts; > + const char *user = NULL; > + const char *password = NULL; > + > + list = qemu_find_opts("iscsi"); > + if (!list) { > + return; > + } > + > + opts = QTAILQ_FIRST(&list->head); > + if (!opts) { > + return; > + } > + > + user = qemu_opt_get(opts, "user"); > + if (!user) { > + return; > + } > + > + password = qemu_opt_get(opts, "password"); > + if (!password) {
I think you should issue an error here. Why should a user give a user name without it's password? Orit > + return; > + } > + > + if (iscsi_set_initiator_username_pwd(iscsi, user, password)) { > + error_report("Failed to set initiator username and password"); > + return; > + } > +} > + > +static void parse_header_digest(struct iscsi_context *iscsi) > +{ > + QemuOptsList *list; > + QemuOpts *opts; > + const char *digest = NULL; > + > + list = qemu_find_opts("iscsi"); > + if (!list) { > + return; > + } > + > + opts = QTAILQ_FIRST(&list->head); > + if (!opts) { > + return; > + } > + > + digest = qemu_opt_get(opts, "header-digest"); > + if (!digest) { > + return; > + } > + > + if (!strcmp(digest, "CRC32C")) { > + iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C); > + } else if (!strcmp(digest, "NONE")) { > + iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE); > + } else if (!strcmp(digest, "CRC32C-NONE")) { > + iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C_NONE); > + } else if (!strcmp(digest, "NONE-CRC32C")) { > + iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); > + } else { > + error_report("Invalid header-digest setting : %s", digest); > + } > +} > + > +static char *parse_initiator_name(void) > +{ > + QemuOptsList *list; > + QemuOpts *opts; > + const char *name = NULL; > + > + list = qemu_find_opts("iscsi"); > + if (!list) { > + return g_strdup("iqn.2008-11.org.linux-kvm"); > + } > + > + opts = QTAILQ_FIRST(&list->head); > + if (!opts) { > + return g_strdup("iqn.2008-11.org.linux-kvm"); > + } > + > + name = qemu_opt_get(opts, "initiator-name"); > + if (!name) { > + return g_strdup("iqn.2008-11.org.linux-kvm"); > + } > + > + return g_strdup(name); > +} > + > /* > * We support iscsi url's on the form > * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun> > @@ -465,6 +556,7 @@ static int iscsi_open(BlockDriverState *bs, const char > *filename, int flags) > struct iscsi_context *iscsi = NULL; > struct iscsi_url *iscsi_url = NULL; > struct IscsiTask task; > + char *initiator_name = NULL; > int ret; > > if ((BDRV_SECTOR_SIZE % 512) != 0) { > @@ -476,8 +568,9 @@ static int iscsi_open(BlockDriverState *bs, const char > *filename, int flags) > > memset(iscsilun, 0, sizeof(IscsiLun)); > > - /* Should really append the KVM name after the ':' here */ > - iscsi = iscsi_create_context("iqn.2008-11.org.linux-kvm:"); > + initiator_name = parse_initiator_name(); > + > + iscsi = iscsi_create_context(initiator_name); > if (iscsi == NULL) { > error_report("iSCSI: Failed to create iSCSI context."); > ret = -ENOMEM; > @@ -507,6 +600,10 @@ static int iscsi_open(BlockDriverState *bs, const char > *filename, int flags) > goto failed; > } > } > + > + /* check if we got CHAP username/password via the options */ > + parse_chap(iscsi); > + > if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) { > error_report("iSCSI: Failed to set session type to normal."); > ret = -EINVAL; > @@ -515,6 +612,9 @@ static int iscsi_open(BlockDriverState *bs, const char > *filename, 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); > + > task.iscsilun = iscsilun; > task.status = 0; > task.complete = 0; > @@ -548,6 +648,9 @@ static int iscsi_open(BlockDriverState *bs, const char > *filename, int flags) > return 0; > > failed: > + if (initiator_name != NULL) { > + g_free(initiator_name); > + } > if (iscsi_url != NULL) { > iscsi_destroy_url(iscsi_url); > } > diff --git a/qemu-config.c b/qemu-config.c > index 597d7e1..8ad984d 100644 > --- a/qemu-config.c > +++ b/qemu-config.c > @@ -90,6 +90,32 @@ static QemuOptsList qemu_drive_opts = { > }, > }; > > +static QemuOptsList qemu_iscsi_opts = { > + .name = "iscsi", > + .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head), > + .desc = { > + { > + .name = "user", > + .type = QEMU_OPT_STRING, > + .help = "username for CHAP authentication to target", > + },{ > + .name = "password", > + .type = QEMU_OPT_STRING, > + .help = "password for CHAP authentication to target", > + },{ > + .name = "header-digest", > + .type = QEMU_OPT_STRING, > + .help = "HeaderDigest setting. " > + "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}", > + },{ > + .name = "initiator-name", > + .type = QEMU_OPT_STRING, > + .help = "Initiator iqn name to use when connecting", > + }, > + { /* end of list */ } > + }, > +}; > + > static QemuOptsList qemu_chardev_opts = { > .name = "chardev", > .implied_opt_name = "backend", > @@ -535,6 +561,7 @@ static QemuOptsList *vm_config_groups[32] = { > &qemu_option_rom_opts, > &qemu_machine_opts, > &qemu_boot_opts, > + &qemu_iscsi_opts, > NULL, > }; > > diff --git a/qemu-doc.texi b/qemu-doc.texi > index 9c3cb62..2116085 100644 > --- a/qemu-doc.texi > +++ b/qemu-doc.texi > @@ -731,6 +731,31 @@ export LIBISCSI_CHAP_PASSWORD=<password> > iscsi://<host>/<target-iqn-name>/<lun> > @end example > > +Various session related parameters can be set via special options, either > +in a configuration file provided via '-readconfig' or directly on the > +command line. > + > +@example > +Setting a specific initiator name to use when logging in to the target > +-iscsi initiator-name=iqn.qemu.test:my-initiator > +@end example > + > +@example > +Controlling which type of header digest to negotiate with the target > +-iscsi header-digest=CRC32C|CRC32C-NONE|NONE-CRC32C|NONE > +@end example > + > +These can also be set via a configuration file > +@example > +[iscsi] > + user = "CHAP username" > + password = "CHAP password" > + initiator-name = "iqn.qemu.test:my-initiator" > + # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE > + header-digest = "CRC32C" > +@end example > + > + > Howto set up a simple iSCSI target on loopback and accessing it via QEMU: > @example > This example shows how to set up an iSCSI target with one CDROM and one DISK > @@ -745,7 +770,8 @@ tgtadm --lld iscsi --mode logicalunit --op new --tid 1 > --lun 2 \ > -b /IMAGES/cd.iso --device-type=cd > tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL > > -qemu-system-i386 -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \ > +qemu-system-i386 -iscsi initiator-name=iqn.qemu.test:my-initiator \ > + -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \ > -cdrom iscsi://127.0.0.1/iqn.qemu.test/2 > @end example > > diff --git a/qemu-options.hx b/qemu-options.hx > index 681eaf1..669ff42 100644 > --- a/qemu-options.hx > +++ b/qemu-options.hx > @@ -1753,24 +1753,32 @@ Syntax for specifying iSCSI LUNs is > > Example (without authentication): > @example > -qemu -cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \ > ---drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 > +qemu -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \ > +-cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \ > +-drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 > @end example > > Example (CHAP username/password via URL): > @example > -qemu --drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1 > +qemu -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1 > @end example > > Example (CHAP username/password via environment variables): > @example > LIBISCSI_CHAP_USERNAME="user" \ > LIBISCSI_CHAP_PASSWORD="password" \ > -qemu --drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 > +qemu -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 > @end example > > iSCSI support is an optional feature of QEMU and only available when > compiled and linked against libiscsi. > +ETEXI > +DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi, > + "-iscsi [user=user][,password=password]\n" > + " [,header-digest=CRC32C|CR32C-NONE|NONE-CRC32C|NONE\n" > + " [,initiator-name=iqn]\n" > + " iSCSI session parameters\n", QEMU_ARCH_ALL) > +STEXI > > @item NBD > QEMU supports NBD (Network Block Devices) both using TCP protocol as well > diff --git a/vl.c b/vl.c > index f5afed4..0c553fa 100644 > --- a/vl.c > +++ b/vl.c > @@ -2496,6 +2496,14 @@ int main(int argc, char **argv, char **envp) > exit(1); > } > break; > +#ifdef CONFIG_LIBISCSI > + case QEMU_OPTION_iscsi: > + opts = qemu_opts_parse(qemu_find_opts("iscsi"), optarg, 0); > + if (!opts) { > + exit(1); > + } > + break; > +#endif > #ifdef CONFIG_SLIRP > case QEMU_OPTION_tftp: > legacy_tftp_prefix = optarg;