From patchwork Sun Dec 18 04:48:55 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ronnie sahlberg X-Patchwork-Id: 132033 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 51604B7049 for ; Sun, 18 Dec 2011 15:50:53 +1100 (EST) Received: from localhost ([::1]:34286 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rc8i2-0003vv-PI for incoming@patchwork.ozlabs.org; Sat, 17 Dec 2011 23:50:50 -0500 Received: from eggs.gnu.org ([140.186.70.92]:43814) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rc8hv-0003kg-Pu for qemu-devel@nongnu.org; Sat, 17 Dec 2011 23:50:45 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Rc8hu-0000sl-2m for qemu-devel@nongnu.org; Sat, 17 Dec 2011 23:50:43 -0500 Received: from mail-iy0-f173.google.com ([209.85.210.173]:60467) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rc8ht-0000sC-Qh for qemu-devel@nongnu.org; Sat, 17 Dec 2011 23:50:42 -0500 Received: by mail-iy0-f173.google.com with SMTP id j37so7604906iag.4 for ; Sat, 17 Dec 2011 20:50:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=uQht7pKop8KKz0ovLFNWhsu4G4Kk6RB4TuEfXgn6WVM=; b=vDXOL4Vyw5n0k3GpTop0EtjUAPPbynunH2unhpJEjD+xtT64D4bCTJ2pjVWwIS46B4 i2POVkrVma2aNBXcb4HMjeaJx0ZfE2kTL4o8OXDu/+AzZGpRm6BCLY++j4+G7Z5x998F DOS6ZKqn+TyIISvw9gT8BYYpOLP72BAa04aJE= Received: by 10.50.181.136 with SMTP id dw8mr18813906igc.71.1324183841505; Sat, 17 Dec 2011 20:50:41 -0800 (PST) Received: from ronniesahlberg@gmail.com (CPE-124-184-163-73.lns16.cht.bigpond.net.au. [124.184.163.73]) by mx.google.com with ESMTPS id l28sm52209570ibc.3.2011.12.17.20.50.37 (version=TLSv1/SSLv3 cipher=OTHER); Sat, 17 Dec 2011 20:50:41 -0800 (PST) Received: by ronniesahlberg@gmail.com (sSMTP sendmail emulation); Sun, 18 Dec 2011 15:49:10 +1100 From: Ronnie Sahlberg To: qemu-devel@nongnu.org Date: Sun, 18 Dec 2011 15:48:55 +1100 Message-Id: <1324183735-16930-2-git-send-email-ronniesahlberg@gmail.com> X-Mailer: git-send-email 1.7.3.1 In-Reply-To: <1324183735-16930-1-git-send-email-ronniesahlberg@gmail.com> References: <1324183735-16930-1-git-send-email-ronniesahlberg@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.210.173 Cc: kwolf@redhat.com, Ronnie Sahlberg Subject: [Qemu-devel] [PATCH] iSCSI: add configuration variables for iSCSI X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- block/iscsi.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- qemu-config.c | 27 +++++++++++++ qemu-doc.texi | 28 +++++++++++++- qemu-options.hx | 16 ++++++-- vl.c | 8 ++++ 5 files changed, 186 insertions(+), 7 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index 938c568..92c6e79 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -455,6 +455,100 @@ iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data, } } +static int 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 0; + } + + opts = QTAILQ_FIRST(&list->head); + if (!opts) { + return 0; + } + + user = qemu_opt_get(opts, "user"); + if (!user) { + return 0; + } + + password = qemu_opt_get(opts, "password"); + if (!password) { + error_report("CHAP username specified but no password was given"); + return -1; + } + + if (iscsi_set_initiator_username_pwd(iscsi, user, password)) { + error_report("Failed to set initiator username and password"); + return -1; + } + + return 0; +} + +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://[%@][:]// @@ -465,6 +559,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 +571,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 +603,14 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) goto failed; } } + + /* check if we got CHAP username/password via the options */ + if (parse_chap(iscsi) != 0) { + error_report("iSCSI: Failed to set CHAP user/password"); + ret = -EINVAL; + goto failed; + } + if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) { error_report("iSCSI: Failed to set session type to normal."); ret = -EINVAL; @@ -515,6 +619,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 +655,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 18f3020..7b59c05 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -118,6 +118,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", @@ -563,6 +589,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 11f4166..7b54329 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -730,6 +730,31 @@ export LIBISCSI_CHAP_PASSWORD= iscsi://// @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 @@ -744,7 +769,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 087a3b9..338b482 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1761,24 +1761,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 d51ac2e..8660125 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;