Blame SOURCES/kvm-nbd-client-Split-handshake-into-two-functions.patch

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