From patchwork Wed Sep 28 20:55:56 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Max Reitz X-Patchwork-Id: 9354891 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 956036086A for ; Wed, 28 Sep 2016 21:01:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 85B4A2956F for ; Wed, 28 Sep 2016 21:01:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7A3682975E; Wed, 28 Sep 2016 21:01:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 7F0A62956F for ; Wed, 28 Sep 2016 21:01:28 +0000 (UTC) Received: from localhost ([::1]:33120 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bpLyp-0000EM-2G for patchwork-qemu-devel@patchwork.kernel.org; Wed, 28 Sep 2016 17:01:27 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40667) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bpLu3-0004sA-1B for qemu-devel@nongnu.org; Wed, 28 Sep 2016 16:56:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bpLty-0006mD-Ty for qemu-devel@nongnu.org; Wed, 28 Sep 2016 16:56:30 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57866) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bpLtu-0006kq-FU; Wed, 28 Sep 2016 16:56:22 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id DA38774A2F; Wed, 28 Sep 2016 20:56:21 +0000 (UTC) Received: from localhost (ovpn-116-200.phx2.redhat.com [10.3.116.200]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u8SKuJEa015286 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Wed, 28 Sep 2016 16:56:20 -0400 From: Max Reitz To: qemu-block@nongnu.org Date: Wed, 28 Sep 2016 22:55:56 +0200 Message-Id: <20160928205602.17275-7-mreitz@redhat.com> In-Reply-To: <20160928205602.17275-1-mreitz@redhat.com> References: <20160928205602.17275-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Wed, 28 Sep 2016 20:56:21 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 06/12] block/nbd: Accept SocketAddress X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , qemu-devel@nongnu.org, Markus Armbruster , Paolo Bonzini , Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Add a new option "address" to the NBD block driver which accepts a SocketAddress. "path", "host" and "port" are still supported as legacy options and are mapped to their corresponding SocketAddress representation. Signed-off-by: Max Reitz --- block/nbd.c | 166 ++++++++++++++++++++++++++---------------- tests/qemu-iotests/051.out | 4 +- tests/qemu-iotests/051.pc.out | 4 +- 3 files changed, 106 insertions(+), 68 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index cdab20f..449f94e 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -32,6 +32,9 @@ #include "qemu/uri.h" #include "block/block_int.h" #include "qemu/module.h" +#include "qapi-visit.h" +#include "qapi/qmp-input-visitor.h" +#include "qapi/qmp-output-visitor.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qjson.h" #include "qapi/qmp/qint.h" @@ -44,7 +47,8 @@ typedef struct BDRVNBDState { NbdClientSession client; /* For nbd_refresh_filename() */ - char *path, *host, *port, *export, *tlscredsid; + SocketAddress *saddr; + char *export, *tlscredsid; } BDRVNBDState; static int nbd_parse_uri(const char *filename, QDict *options) @@ -131,7 +135,9 @@ static bool nbd_has_filename_options_conflict(QDict *options, Error **errp) if (!strcmp(e->key, "host") || !strcmp(e->key, "port") || !strcmp(e->key, "path") || - !strcmp(e->key, "export")) + !strcmp(e->key, "export") || + !strcmp(e->key, "address") || + !strncmp(e->key, "address.", 8)) { error_setg(errp, "Option '%s' cannot be used with a file name", e->key); @@ -205,50 +211,67 @@ out: g_free(file); } -static SocketAddress *nbd_config(BDRVNBDState *s, QemuOpts *opts, Error **errp) +static bool nbd_process_legacy_socket_options(QDict *output_options, + QemuOpts *legacy_opts, + Error **errp) { - SocketAddress *saddr; - - s->path = g_strdup(qemu_opt_get(opts, "path")); - s->host = g_strdup(qemu_opt_get(opts, "host")); - s->port = g_strdup(qemu_opt_get(opts, "port")); - - if (!s->path == !s->host) { - if (s->path) { - error_setg(errp, "path and host may not be used at the same time"); - } else { - error_setg(errp, "one of path and host must be specified"); + const char *path = qemu_opt_get(legacy_opts, "path"); + const char *host = qemu_opt_get(legacy_opts, "host"); + const char *port = qemu_opt_get(legacy_opts, "port"); + + if (path && host) { + error_setg(errp, "path and host may not be used at the same time"); + return false; + } else if (path) { + if (port) { + error_setg(errp, "port may not be used without host"); + return false; } - return NULL; + + qdict_put(output_options, "address.type", qstring_from_str("unix")); + qdict_put(output_options, "address.data.path", qstring_from_str(path)); + } else if (host) { + qdict_put(output_options, "address.type", qstring_from_str("inet")); + qdict_put(output_options, "address.data.host", qstring_from_str(host)); + qdict_put(output_options, "address.data.port", + qstring_from_str(port ?: stringify(NBD_DEFAULT_PORT))); } - if (s->port && !s->host) { - error_setg(errp, "port may not be used without host"); - return NULL; + + return true; +} + +static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, Error **errp) +{ + SocketAddress *saddr = NULL; + QDict *addr = NULL; + QObject *crumpled_addr = NULL; + Visitor *iv = NULL; + Error *local_err = NULL; + + qdict_extract_subqdict(options, &addr, "address."); + if (!qdict_size(addr)) { + error_setg(errp, "NBD server address missing"); + goto done; } - saddr = g_new0(SocketAddress, 1); + crumpled_addr = qdict_crumple(addr, true, errp); + if (!crumpled_addr) { + goto done; + } - if (s->path) { - UnixSocketAddress *q_unix; - saddr->type = SOCKET_ADDRESS_KIND_UNIX; - q_unix = saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1); - q_unix->path = g_strdup(s->path); - } else { - InetSocketAddress *inet; - - saddr->type = SOCKET_ADDRESS_KIND_INET; - inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1); - inet->host = g_strdup(s->host); - inet->port = g_strdup(s->port); - if (!inet->port) { - inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT); - } + iv = qmp_input_visitor_new(crumpled_addr, true); + visit_type_SocketAddress(iv, NULL, &saddr, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto done; } s->client.is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX; - s->export = g_strdup(qemu_opt_get(opts, "export")); - +done: + QDECREF(addr); + qobject_decref(crumpled_addr); + visit_free(iv); return saddr; } @@ -349,7 +372,6 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, QemuOpts *opts = NULL; Error *local_err = NULL; QIOChannelSocket *sioc = NULL; - SocketAddress *saddr = NULL; QCryptoTLSCreds *tlscreds = NULL; const char *hostname = NULL; int ret = -EINVAL; @@ -361,12 +383,19 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, goto error; } + /* Translate @host, @port, and @path to a SocketAddress */ + if (!nbd_process_legacy_socket_options(options, opts, errp)) { + goto error; + } + /* Pop the config into our state object. Exit if invalid. */ - saddr = nbd_config(s, opts, errp); - if (!saddr) { + s->saddr = nbd_config(s, options, errp); + if (!s->saddr) { goto error; } + s->export = g_strdup(qemu_opt_get(opts, "export")); + s->tlscredsid = g_strdup(qemu_opt_get(opts, "tls-creds")); if (s->tlscredsid) { tlscreds = nbd_get_tls_creds(s->tlscredsid, errp); @@ -374,17 +403,17 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, goto error; } - if (saddr->type != SOCKET_ADDRESS_KIND_INET) { + if (s->saddr->type != SOCKET_ADDRESS_KIND_INET) { error_setg(errp, "TLS only supported over IP sockets"); goto error; } - hostname = saddr->u.inet.data->host; + hostname = s->saddr->u.inet.data->host; } /* establish TCP connection, return error if it fails * TODO: Configurable retry-until-timeout behaviour. */ - sioc = nbd_establish_connection(saddr, errp); + sioc = nbd_establish_connection(s->saddr, errp); if (!sioc) { ret = -ECONNREFUSED; goto error; @@ -401,13 +430,10 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, object_unref(OBJECT(tlscreds)); } if (ret < 0) { - g_free(s->path); - g_free(s->host); - g_free(s->port); + qapi_free_SocketAddress(s->saddr); g_free(s->export); g_free(s->tlscredsid); } - qapi_free_SocketAddress(saddr); qemu_opts_del(opts); return ret; } @@ -429,9 +455,7 @@ static void nbd_close(BlockDriverState *bs) nbd_client_close(bs); - g_free(s->path); - g_free(s->host); - g_free(s->port); + qapi_free_SocketAddress(s->saddr); g_free(s->export); g_free(s->tlscredsid); } @@ -458,30 +482,43 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options) { BDRVNBDState *s = bs->opaque; QDict *opts = qdict_new(); - const char *port = s->port ?: stringify(NBD_DEFAULT_PORT); + QObject *saddr_qdict; + Visitor *ov; + const char *host = NULL, *port = NULL, *path = NULL; + + if (s->saddr->type == SOCKET_ADDRESS_KIND_INET) { + const InetSocketAddress *inet = s->saddr->u.inet.data; + if (!inet->has_ipv4 && !inet->has_ipv6 && !inet->has_to) { + host = inet->host; + port = inet->port; + } + } else if (s->saddr->type == SOCKET_ADDRESS_KIND_UNIX) { + path = s->saddr->u.q_unix.data->path; + } qdict_put(opts, "driver", qstring_from_str("nbd")); - if (s->path && s->export) { + if (path && s->export) { snprintf(bs->exact_filename, sizeof(bs->exact_filename), - "nbd+unix:///%s?socket=%s", s->export, s->path); - } else if (s->path && !s->export) { + "nbd+unix:///%s?socket=%s", s->export, path); + } else if (path && !s->export) { snprintf(bs->exact_filename, sizeof(bs->exact_filename), - "nbd+unix://?socket=%s", s->path); - } else if (!s->path && s->export) { + "nbd+unix://?socket=%s", path); + } else if (host && s->export) { snprintf(bs->exact_filename, sizeof(bs->exact_filename), - "nbd://%s:%s/%s", s->host, port, s->export); - } else if (!s->path && !s->export) { + "nbd://%s:%s/%s", host, port, s->export); + } else if (host && !s->export) { snprintf(bs->exact_filename, sizeof(bs->exact_filename), - "nbd://%s:%s", s->host, port); + "nbd://%s:%s", host, port); } - if (s->path) { - qdict_put(opts, "path", qstring_from_str(s->path)); - } else { - qdict_put(opts, "host", qstring_from_str(s->host)); - qdict_put(opts, "port", qstring_from_str(port)); - } + ov = qmp_output_visitor_new(&saddr_qdict); + visit_type_SocketAddress(ov, NULL, &s->saddr, &error_abort); + visit_complete(ov, &saddr_qdict); + assert(qobject_type(saddr_qdict) == QTYPE_QDICT); + + qdict_put_obj(opts, "address", saddr_qdict); + if (s->export) { qdict_put(opts, "export", qstring_from_str(s->export)); } @@ -489,6 +526,7 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options) qdict_put(opts, "tls-creds", qstring_from_str(s->tlscredsid)); } + qdict_flatten(opts); bs->full_open_options = opts; } diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 9e584fe..42bf416 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -222,7 +222,7 @@ Testing: -drive driver=file QEMU_PROG: -drive driver=file: The 'file' block driver requires a file name Testing: -drive driver=nbd -QEMU_PROG: -drive driver=nbd: one of path and host must be specified +QEMU_PROG: -drive driver=nbd: NBD server address missing Testing: -drive driver=raw QEMU_PROG: -drive driver=raw: Can't use 'raw' as a block driver for the protocol level @@ -231,7 +231,7 @@ Testing: -drive file.driver=file QEMU_PROG: -drive file.driver=file: The 'file' block driver requires a file name Testing: -drive file.driver=nbd -QEMU_PROG: -drive file.driver=nbd: one of path and host must be specified +QEMU_PROG: -drive file.driver=nbd: NBD server address missing Testing: -drive file.driver=raw QEMU_PROG: -drive file.driver=raw: Can't use 'raw' as a block driver for the protocol level diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out index 6395a30..603bb76 100644 --- a/tests/qemu-iotests/051.pc.out +++ b/tests/qemu-iotests/051.pc.out @@ -316,7 +316,7 @@ Testing: -drive driver=file QEMU_PROG: -drive driver=file: The 'file' block driver requires a file name Testing: -drive driver=nbd -QEMU_PROG: -drive driver=nbd: one of path and host must be specified +QEMU_PROG: -drive driver=nbd: NBD server address missing Testing: -drive driver=raw QEMU_PROG: -drive driver=raw: Can't use 'raw' as a block driver for the protocol level @@ -325,7 +325,7 @@ Testing: -drive file.driver=file QEMU_PROG: -drive file.driver=file: The 'file' block driver requires a file name Testing: -drive file.driver=nbd -QEMU_PROG: -drive file.driver=nbd: one of path and host must be specified +QEMU_PROG: -drive file.driver=nbd: NBD server address missing Testing: -drive file.driver=raw QEMU_PROG: -drive file.driver=raw: Can't use 'raw' as a block driver for the protocol level