[Libguestfs] [libnbd PATCH 4/4] states: Add NBD_OPT_EXPORT_NAME handling

Eric Blake eblake at redhat.com
Sun May 19 03:55:12 UTC 2019


Used both for servers that are not fixed newstyle, and for servers
that don't understand NBD_OPT_GO.
---
 generator/Makefile.am                       |  1 +
 generator/generator                         | 39 +++++++++++
 generator/states-newstyle-opt-export-name.c | 73 +++++++++++++++++++++
 generator/states-newstyle-opt-go.c          |  8 +--
 generator/states-newstyle.c                 | 11 +++-
 lib/internal.h                              |  1 +
 lib/nbd-protocol.h                          |  7 ++
 7 files changed, 133 insertions(+), 7 deletions(-)
 create mode 100644 generator/states-newstyle-opt-export-name.c

diff --git a/generator/Makefile.am b/generator/Makefile.am
index 8262d7c..f4c127b 100644
--- a/generator/Makefile.am
+++ b/generator/Makefile.am
@@ -26,6 +26,7 @@ states_code = \
 	states-connect.c \
 	states-issue-command.c \
 	states-magic.c \
+	states-newstyle-opt-export-name.c \
 	states-newstyle-opt-go.c \
 	states-newstyle-opt-set-meta-context.c \
 	states-newstyle-opt-starttls.c \
diff --git a/generator/generator b/generator/generator
index 4d42185..60e4c55 100755
--- a/generator/generator
+++ b/generator/generator
@@ -327,6 +327,7 @@ and newstyle_state_machine = [
   Group ("OPT_STRUCTURED_REPLY", newstyle_opt_structured_reply_state_machine);
   Group ("OPT_SET_META_CONTEXT", newstyle_opt_set_meta_context_state_machine);
   Group ("OPT_GO", newstyle_opt_go_state_machine);
+  Group ("OPT_EXPORT_NAME", newstyle_opt_export_name_state_machine);
 ]

 (* Fixed newstyle NBD_OPT_STARTTLS option. *)
@@ -565,6 +566,44 @@ and newstyle_opt_go_state_machine = [
   };
 ]

+(* Newstyle NBD_OPT_EXPORT_NAME option. *)
+and newstyle_opt_export_name_state_machine = [
+  State {
+    default_state with
+    name = "START";
+    comment = "Try to send newstyle NBD_OPT_EXPORT_NAME to end handshake";
+    external_events = [];
+  };
+
+  State {
+    default_state with
+    name = "SEND";
+    comment = "Send newstyle NBD_OPT_EXPORT_NAME to end handshake";
+    external_events = [ NotifyWrite, "" ];
+  };
+
+  State {
+    default_state with
+    name = "SEND_EXPORT";
+    comment = "Send newstyle NBD_OPT_EXPORT_NAME export name";
+    external_events = [ NotifyWrite, "" ];
+  };
+
+  State {
+    default_state with
+    name = "RECV_REPLY";
+    comment = "Receive newstyle NBD_OPT_EXPORT_NAME reply";
+    external_events = [ NotifyRead, "" ];
+  };
+
+  State {
+    default_state with
+    name = "CHECK_REPLY";
+    comment = "Check newstyle NBD_OPT_EXPORT_NAME reply";
+    external_events = [];
+  };
+]
+
 (* Sending a command to the server. *)
 and issue_command_state_machine = [
   State {
diff --git a/generator/states-newstyle-opt-export-name.c b/generator/states-newstyle-opt-export-name.c
new file mode 100644
index 0000000..6c6bce4
--- /dev/null
+++ b/generator/states-newstyle-opt-export-name.c
@@ -0,0 +1,73 @@
+/* nbd client library in userspace: state machine
+ * Copyright (C) 2013-2019 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* State machine for ending newstyle handshake with NBD_OPT_EXPORT_NAME. */
+
+/* STATE MACHINE */ {
+ NEWSTYLE.OPT_EXPORT_NAME.START:
+  conn->sbuf.option.version = htobe64 (NBD_NEW_VERSION);
+  conn->sbuf.option.option = htobe32 (NBD_OPT_EXPORT_NAME);
+  conn->sbuf.option.optlen = strlen (h->export_name);
+  conn->wbuf = &conn->sbuf;
+  conn->wlen = sizeof conn->sbuf.option;
+  SET_NEXT_STATE (%SEND);
+  return 0;
+
+ NEWSTYLE.OPT_EXPORT_NAME.SEND:
+  switch (send_from_wbuf (conn)) {
+  case -1: SET_NEXT_STATE (%.DEAD); return -1;
+  case 0:
+    conn->wbuf = h->export_name;
+    conn->wlen = strlen (h->export_name);
+    SET_NEXT_STATE (%SEND_EXPORT);
+  }
+  return 0;
+
+ NEWSTYLE.OPT_EXPORT_NAME.SEND_EXPORT:
+  switch (send_from_wbuf (conn)) {
+  case -1: SET_NEXT_STATE (%.DEAD); return -1;
+  case 0:
+    conn->rbuf = &conn->sbuf;
+    conn->rlen = sizeof conn->sbuf.export_name_reply;
+    if ((conn->gflags & NBD_FLAG_NO_ZEROES) != 0)
+      conn->rlen -= sizeof conn->sbuf.export_name_reply.zeroes;
+    SET_NEXT_STATE (%RECV_REPLY);
+  }
+  return 0;
+
+ NEWSTYLE.OPT_EXPORT_NAME.RECV_REPLY:
+  switch (recv_into_rbuf (conn)) {
+  case -1: SET_NEXT_STATE (%.DEAD); return -1;
+  case 0:  SET_NEXT_STATE (%CHECK_REPLY);
+  }
+  return 0;
+
+ NEWSTYLE.OPT_EXPORT_NAME.CHECK_REPLY:
+  conn->h->exportsize = be64toh (conn->sbuf.export_name_reply.exportsize);
+  conn->h->eflags = be16toh (conn->sbuf.export_name_reply.eflags);
+  debug (conn->h, "exportsize: %" PRIu64 " eflags: 0x%" PRIx16,
+	 conn->h->exportsize, conn->h->eflags);
+  if (conn->h->eflags == 0) {
+    SET_NEXT_STATE (%.DEAD);
+    set_error (EINVAL, "handshake: invalid eflags == 0 from server");
+    return -1;
+  }
+  SET_NEXT_STATE (%.READY);
+  return 0;
+
+} /* END STATE MACHINE */
diff --git a/generator/states-newstyle-opt-go.c b/generator/states-newstyle-opt-go.c
index 200d16f..42bae8a 100644
--- a/generator/states-newstyle-opt-go.c
+++ b/generator/states-newstyle-opt-go.c
@@ -149,10 +149,10 @@
     SET_NEXT_STATE (%RECV_REPLY);
     return 0;
   case NBD_REP_ERR_UNSUP:
-    /* XXX fall back to NBD_OPT_EXPORT_NAME */
-    SET_NEXT_STATE (%.DEAD);
-    set_error (0, "handshake: server does not support NBD_OPT_GO");
-    return -1;
+    debug (conn->h,
+	   "server is confused by NBD_OPT_GO, continuing anyway");
+    SET_NEXT_STATE (%^OPT_EXPORT_NAME.START);
+    return 0;
   default:
     SET_NEXT_STATE (%.DEAD);
     set_error (0, "handshake: unknown reply from NBD_OPT_GO: 0x%" PRIx32,
diff --git a/generator/states-newstyle.c b/generator/states-newstyle.c
index f3a07f7..d108244 100644
--- a/generator/states-newstyle.c
+++ b/generator/states-newstyle.c
@@ -36,9 +36,11 @@
   uint32_t cflags;

   conn->gflags = be16toh (conn->gflags);
-  if ((conn->gflags & NBD_FLAG_FIXED_NEWSTYLE) == 0) {
+  if ((conn->gflags & NBD_FLAG_FIXED_NEWSTYLE) == 0 &&
+      h->tls == 2) {
     SET_NEXT_STATE (%.DEAD);
-    set_error (0, "handshake: server is not a fixed newstyle NBD server");
+    set_error (ENOTSUP, "handshake: server is not fixed newstyle, "
+	       "but handle TLS setting is require (2)");
     return -1;
   }

@@ -54,7 +56,10 @@
   case -1: SET_NEXT_STATE (%.DEAD); return -1;
   case 0:
     /* Start sending options. */
-    SET_NEXT_STATE (%OPT_STARTTLS.START);
+    if ((conn->gflags & NBD_FLAG_FIXED_NEWSTYLE) == 0)
+      SET_NEXT_STATE (%OPT_EXPORT_NAME.START);
+    else
+      SET_NEXT_STATE (%OPT_STARTTLS.START);
   }
   return 0;

diff --git a/lib/internal.h b/lib/internal.h
index f154a7b..852158a 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -127,6 +127,7 @@ struct nbd_connection {
         }  __attribute__((packed)) context;
       } payload;
     }  __attribute__((packed)) or;
+    struct nbd_export_name_option_reply export_name_reply;
     struct nbd_request request;
     struct nbd_simple_reply simple_reply;
     struct {
diff --git a/lib/nbd-protocol.h b/lib/nbd-protocol.h
index 398403a..4bda056 100644
--- a/lib/nbd-protocol.h
+++ b/lib/nbd-protocol.h
@@ -74,6 +74,13 @@ struct nbd_new_option {
   /* option data follows */
 } __attribute__((packed));

+/* Newstyle handshake OPT_EXPORT_NAME reply message. */
+struct nbd_export_name_option_reply {
+  uint64_t exportsize;          /* size of export */
+  uint16_t eflags;              /* per-export flags */
+  char zeroes[124];             /* optional zeroes */
+} __attribute__((packed));;
+
 /* Fixed newstyle handshake reply message. */
 struct nbd_fixed_new_option_reply {
   uint64_t magic;             /* NBD_REP_MAGIC */
-- 
2.20.1




More information about the Libguestfs mailing list