|
|
7711c0 |
From 17d3f9b474fe65d1b4fc128d18e3a7a52b32c62d Mon Sep 17 00:00:00 2001
|
|
|
7711c0 |
From: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Date: Wed, 27 Mar 2019 17:22:48 +0100
|
|
|
7711c0 |
Subject: [PATCH 110/163] nbd/client: Split handshake into two functions
|
|
|
7711c0 |
|
|
|
7711c0 |
RH-Author: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Message-id: <20190327172308.31077-36-jsnow@redhat.com>
|
|
|
7711c0 |
Patchwork-id: 85213
|
|
|
7711c0 |
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 35/55] nbd/client: Split handshake into two functions
|
|
|
7711c0 |
Bugzilla: 1691009
|
|
|
7711c0 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
7711c0 |
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
|
|
7711c0 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
7711c0 |
|
|
|
7711c0 |
From: Eric Blake <eblake@redhat.com>
|
|
|
7711c0 |
|
|
|
7711c0 |
An upcoming patch will add the ability for qemu-nbd to list
|
|
|
7711c0 |
the services provided by an NBD server. Share the common
|
|
|
7711c0 |
code of the TLS handshake by splitting the initial exchange
|
|
|
7711c0 |
into a separate function, leaving only the export handling
|
|
|
7711c0 |
in the original function. Functionally, there should be no
|
|
|
7711c0 |
change in behavior in this patch, although some of the code
|
|
|
7711c0 |
motion may be difficult to follow due to indentation changes
|
|
|
7711c0 |
(view with 'git diff -w' for a smaller changeset).
|
|
|
7711c0 |
|
|
|
7711c0 |
I considered an enum for the return code coordinating state
|
|
|
7711c0 |
between the two functions, but in the end just settled with
|
|
|
7711c0 |
ample comments.
|
|
|
7711c0 |
|
|
|
7711c0 |
Signed-off-by: Eric Blake <eblake@redhat.com>
|
|
|
7711c0 |
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
|
|
|
7711c0 |
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
|
|
7711c0 |
Message-Id: <20190117193658.16413-15-eblake@redhat.com>
|
|
|
7711c0 |
(cherry picked from commit 10b89988d6b0f5f2aed794bed5b4e774858548f4)
|
|
|
7711c0 |
Signed-off-by: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
7711c0 |
---
|
|
|
7711c0 |
nbd/client.c | 145 ++++++++++++++++++++++++++++++++++++-------------------
|
|
|
7711c0 |
nbd/trace-events | 2 +-
|
|
|
7711c0 |
2 files changed, 96 insertions(+), 51 deletions(-)
|
|
|
7711c0 |
|
|
|
7711c0 |
diff --git a/nbd/client.c b/nbd/client.c
|
|
|
7711c0 |
index 9028fd0..77cc123 100644
|
|
|
7711c0 |
--- a/nbd/client.c
|
|
|
7711c0 |
+++ b/nbd/client.c
|
|
|
7711c0 |
@@ -809,22 +809,26 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc,
|
|
|
7711c0 |
return received;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
-int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
- const char *hostname, QIOChannel **outioc,
|
|
|
7711c0 |
- NBDExportInfo *info, Error **errp)
|
|
|
7711c0 |
+/*
|
|
|
7711c0 |
+ * nbd_start_negotiate:
|
|
|
7711c0 |
+ * Start the handshake to the server. After a positive return, the server
|
|
|
7711c0 |
+ * is ready to accept additional NBD_OPT requests.
|
|
|
7711c0 |
+ * Returns: negative errno: failure talking to server
|
|
|
7711c0 |
+ * 0: server is oldstyle, client must still parse export size
|
|
|
7711c0 |
+ * 1: server is newstyle, but can only accept EXPORT_NAME
|
|
|
7711c0 |
+ * 2: server is newstyle, but lacks structured replies
|
|
|
7711c0 |
+ * 3: server is newstyle and set up for structured replies
|
|
|
7711c0 |
+ */
|
|
|
7711c0 |
+static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
+ const char *hostname, QIOChannel **outioc,
|
|
|
7711c0 |
+ bool structured_reply, bool *zeroes,
|
|
|
7711c0 |
+ Error **errp)
|
|
|
7711c0 |
{
|
|
|
7711c0 |
uint64_t magic;
|
|
|
7711c0 |
- bool zeroes = true;
|
|
|
7711c0 |
- bool structured_reply = info->structured_reply;
|
|
|
7711c0 |
- bool base_allocation = info->base_allocation;
|
|
|
7711c0 |
|
|
|
7711c0 |
- trace_nbd_receive_negotiate(tlscreds, hostname ? hostname : "<null>");
|
|
|
7711c0 |
-
|
|
|
7711c0 |
- assert(info->name);
|
|
|
7711c0 |
- trace_nbd_receive_negotiate_name(info->name);
|
|
|
7711c0 |
- info->structured_reply = false;
|
|
|
7711c0 |
- info->base_allocation = false;
|
|
|
7711c0 |
+ trace_nbd_start_negotiate(tlscreds, hostname ? hostname : "<null>");
|
|
|
7711c0 |
|
|
|
7711c0 |
+ *zeroes = true;
|
|
|
7711c0 |
if (outioc) {
|
|
|
7711c0 |
*outioc = NULL;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
@@ -868,7 +872,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
clientflags |= NBD_FLAG_C_FIXED_NEWSTYLE;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
if (globalflags & NBD_FLAG_NO_ZEROES) {
|
|
|
7711c0 |
- zeroes = false;
|
|
|
7711c0 |
+ *zeroes = false;
|
|
|
7711c0 |
clientflags |= NBD_FLAG_C_NO_ZEROES;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
/* client requested flags */
|
|
|
7711c0 |
@@ -890,7 +894,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
}
|
|
|
7711c0 |
}
|
|
|
7711c0 |
if (fixedNewStyle) {
|
|
|
7711c0 |
- int result;
|
|
|
7711c0 |
+ int result = 0;
|
|
|
7711c0 |
|
|
|
7711c0 |
if (structured_reply) {
|
|
|
7711c0 |
result = nbd_request_simple_option(ioc,
|
|
|
7711c0 |
@@ -899,39 +903,85 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
if (result < 0) {
|
|
|
7711c0 |
return -EINVAL;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
- info->structured_reply = result == 1;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
+ return 2 + result;
|
|
|
7711c0 |
+ } else {
|
|
|
7711c0 |
+ return 1;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ } else if (magic == NBD_CLIENT_MAGIC) {
|
|
|
7711c0 |
+ if (tlscreds) {
|
|
|
7711c0 |
+ error_setg(errp, "Server does not support STARTTLS");
|
|
|
7711c0 |
+ return -EINVAL;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ return 0;
|
|
|
7711c0 |
+ } else {
|
|
|
7711c0 |
+ error_setg(errp, "Bad server magic received: 0x%" PRIx64, magic);
|
|
|
7711c0 |
+ return -EINVAL;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+}
|
|
|
7711c0 |
|
|
|
7711c0 |
- if (info->structured_reply && base_allocation) {
|
|
|
7711c0 |
- result = nbd_negotiate_simple_meta_context(ioc, info, errp);
|
|
|
7711c0 |
- if (result < 0) {
|
|
|
7711c0 |
- return -EINVAL;
|
|
|
7711c0 |
- }
|
|
|
7711c0 |
- info->base_allocation = result == 1;
|
|
|
7711c0 |
- }
|
|
|
7711c0 |
+/*
|
|
|
7711c0 |
+ * nbd_receive_negotiate:
|
|
|
7711c0 |
+ * Connect to server, complete negotiation, and move into transmission phase.
|
|
|
7711c0 |
+ * Returns: negative errno: failure talking to server
|
|
|
7711c0 |
+ * 0: server is connected
|
|
|
7711c0 |
+ */
|
|
|
7711c0 |
+int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
+ const char *hostname, QIOChannel **outioc,
|
|
|
7711c0 |
+ NBDExportInfo *info, Error **errp)
|
|
|
7711c0 |
+{
|
|
|
7711c0 |
+ int result;
|
|
|
7711c0 |
+ bool zeroes;
|
|
|
7711c0 |
+ bool base_allocation = info->base_allocation;
|
|
|
7711c0 |
+ uint32_t oldflags;
|
|
|
7711c0 |
|
|
|
7711c0 |
- /* Try NBD_OPT_GO first - if it works, we are done (it
|
|
|
7711c0 |
- * also gives us a good message if the server requires
|
|
|
7711c0 |
- * TLS). If it is not available, fall back to
|
|
|
7711c0 |
- * NBD_OPT_LIST for nicer error messages about a missing
|
|
|
7711c0 |
- * export, then use NBD_OPT_EXPORT_NAME. */
|
|
|
7711c0 |
- result = nbd_opt_go(ioc, info, errp);
|
|
|
7711c0 |
+ assert(info->name);
|
|
|
7711c0 |
+ trace_nbd_receive_negotiate_name(info->name);
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ result = nbd_start_negotiate(ioc, tlscreds, hostname, outioc,
|
|
|
7711c0 |
+ info->structured_reply, &zeroes, errp);
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ info->structured_reply = false;
|
|
|
7711c0 |
+ info->base_allocation = false;
|
|
|
7711c0 |
+ if (tlscreds && *outioc) {
|
|
|
7711c0 |
+ ioc = *outioc;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ switch (result) {
|
|
|
7711c0 |
+ case 3: /* newstyle, with structured replies */
|
|
|
7711c0 |
+ info->structured_reply = true;
|
|
|
7711c0 |
+ if (base_allocation) {
|
|
|
7711c0 |
+ result = nbd_negotiate_simple_meta_context(ioc, info, errp);
|
|
|
7711c0 |
if (result < 0) {
|
|
|
7711c0 |
return -EINVAL;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
- if (result > 0) {
|
|
|
7711c0 |
- return 0;
|
|
|
7711c0 |
- }
|
|
|
7711c0 |
- /* Check our desired export is present in the
|
|
|
7711c0 |
- * server export list. Since NBD_OPT_EXPORT_NAME
|
|
|
7711c0 |
- * cannot return an error message, running this
|
|
|
7711c0 |
- * query gives us better error reporting if the
|
|
|
7711c0 |
- * export name is not available.
|
|
|
7711c0 |
- */
|
|
|
7711c0 |
- if (nbd_receive_query_exports(ioc, info->name, errp) < 0) {
|
|
|
7711c0 |
- return -EINVAL;
|
|
|
7711c0 |
- }
|
|
|
7711c0 |
+ info->base_allocation = result == 1;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ /* fall through */
|
|
|
7711c0 |
+ case 2: /* newstyle, try OPT_GO */
|
|
|
7711c0 |
+ /* Try NBD_OPT_GO first - if it works, we are done (it
|
|
|
7711c0 |
+ * also gives us a good message if the server requires
|
|
|
7711c0 |
+ * TLS). If it is not available, fall back to
|
|
|
7711c0 |
+ * NBD_OPT_LIST for nicer error messages about a missing
|
|
|
7711c0 |
+ * export, then use NBD_OPT_EXPORT_NAME. */
|
|
|
7711c0 |
+ result = nbd_opt_go(ioc, info, errp);
|
|
|
7711c0 |
+ if (result < 0) {
|
|
|
7711c0 |
+ return -EINVAL;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
+ if (result > 0) {
|
|
|
7711c0 |
+ return 0;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ /* Check our desired export is present in the
|
|
|
7711c0 |
+ * server export list. Since NBD_OPT_EXPORT_NAME
|
|
|
7711c0 |
+ * cannot return an error message, running this
|
|
|
7711c0 |
+ * query gives us better error reporting if the
|
|
|
7711c0 |
+ * export name is not available.
|
|
|
7711c0 |
+ */
|
|
|
7711c0 |
+ if (nbd_receive_query_exports(ioc, info->name, errp) < 0) {
|
|
|
7711c0 |
+ return -EINVAL;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ /* fall through */
|
|
|
7711c0 |
+ case 1: /* newstyle, but limited to EXPORT_NAME */
|
|
|
7711c0 |
/* write the export name request */
|
|
|
7711c0 |
if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, info->name,
|
|
|
7711c0 |
errp) < 0) {
|
|
|
7711c0 |
@@ -950,17 +1000,12 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
return -EINVAL;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
info->flags = be16_to_cpu(info->flags);
|
|
|
7711c0 |
- } else if (magic == NBD_CLIENT_MAGIC) {
|
|
|
7711c0 |
- uint32_t oldflags;
|
|
|
7711c0 |
-
|
|
|
7711c0 |
+ break;
|
|
|
7711c0 |
+ case 0: /* oldstyle, parse length and flags */
|
|
|
7711c0 |
if (*info->name) {
|
|
|
7711c0 |
error_setg(errp, "Server does not support non-empty export names");
|
|
|
7711c0 |
return -EINVAL;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
- if (tlscreds) {
|
|
|
7711c0 |
- error_setg(errp, "Server does not support STARTTLS");
|
|
|
7711c0 |
- return -EINVAL;
|
|
|
7711c0 |
- }
|
|
|
7711c0 |
|
|
|
7711c0 |
if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) {
|
|
|
7711c0 |
error_prepend(errp, "Failed to read export length: ");
|
|
|
7711c0 |
@@ -978,9 +1023,9 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
return -EINVAL;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
info->flags = oldflags;
|
|
|
7711c0 |
- } else {
|
|
|
7711c0 |
- error_setg(errp, "Bad server magic received: 0x%" PRIx64, magic);
|
|
|
7711c0 |
- return -EINVAL;
|
|
|
7711c0 |
+ break;
|
|
|
7711c0 |
+ default:
|
|
|
7711c0 |
+ return result;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
trace_nbd_receive_negotiate_size_flags(info->size, info->flags);
|
|
|
7711c0 |
diff --git a/nbd/trace-events b/nbd/trace-events
|
|
|
7711c0 |
index b4802c1..663d116 100644
|
|
|
7711c0 |
--- a/nbd/trace-events
|
|
|
7711c0 |
+++ b/nbd/trace-events
|
|
|
7711c0 |
@@ -14,7 +14,7 @@ nbd_receive_starttls_new_client(void) "Setting up TLS"
|
|
|
7711c0 |
nbd_receive_starttls_tls_handshake(void) "Starting TLS handshake"
|
|
|
7711c0 |
nbd_opt_meta_request(const char *optname, const char *context, const char *export) "Requesting %s %s for export %s"
|
|
|
7711c0 |
nbd_opt_meta_reply(const char *optname, const char *context, uint32_t id) "Received %s mapping of %s to id %" PRIu32
|
|
|
7711c0 |
-nbd_receive_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s"
|
|
|
7711c0 |
+nbd_start_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s"
|
|
|
7711c0 |
nbd_receive_negotiate_magic(uint64_t magic) "Magic is 0x%" PRIx64
|
|
|
7711c0 |
nbd_receive_negotiate_server_flags(uint32_t globalflags) "Global flags are 0x%" PRIx32
|
|
|
7711c0 |
nbd_receive_negotiate_name(const char *name) "Requesting NBD export name '%s'"
|
|
|
7711c0 |
--
|
|
|
7711c0 |
1.8.3.1
|
|
|
7711c0 |
|