[Libguestfs] [PATCH libnbd 2/2] api: New API for reading NBD protocol.

Richard W.M. Jones rjones at redhat.com
Tue Sep 17 10:02:33 UTC 2019


This commit adds a new API which can be used from the connected to
state to read back which NBD protocol (eg. oldstyle, newstyle-fixed)
we are using.

It was helpful to add a new state in newstyle negotiation
(%NEWSTYLE.FINISHED) so we can route all successful option
negotiations through a single path before moving to the %READY state,
allowing us to set h->protocol in one place.
---
 generator/generator                         | 25 +++++++++++++++++++++
 generator/states-newstyle-opt-export-name.c |  2 +-
 generator/states-newstyle-opt-go.c          |  2 +-
 generator/states-newstyle.c                 |  9 ++++++++
 generator/states-oldstyle.c                 |  2 ++
 lib/handle.c                                | 12 ++++++++++
 lib/internal.h                              |  5 ++++-
 tests/get-size.c                            | 13 ++++++++++-
 tests/oldstyle.c                            |  9 ++++++++
 9 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/generator/generator b/generator/generator
index 28248ed..21aae3b 100755
--- a/generator/generator
+++ b/generator/generator
@@ -357,6 +357,16 @@ and newstyle_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);
+
+  (* When option parsing has successfully finished negotiation
+   * it will jump to this state for final steps before moving to
+   * the %READY state.
+   *)
+  State {
+    default_state with
+    name = "FINISHED";
+    comment = "Finish off newstyle negotiation";
+  };
 ]
 
 (* Fixed newstyle NBD_OPT_STARTTLS option. *)
@@ -1574,6 +1584,20 @@ are free to pass in other contexts."
                 "L<nbd_block_status(3)>"; "L<nbd_aio_block_status(3)>"];
   };
 
+  "get_protocol", {
+    default_call with
+    args = []; ret = RStaticString;
+    permitted_states = [ Connected; Closed ];
+    shortdesc = "return the NBD protocol variant";
+    longdesc = "\
+Return the NBD protocol variant in use on the connection.  At
+the moment this returns one of the strings C<\"oldstyle\">,
+C<\"newstyle\"> or C<\"newstyle-fixed\">.  Other strings might
+be returned in future.  Most modern NBD servers use C<\"newstyle-fixed\">.
+"
+^ non_blocking_test_call_description
+  };
+
   "get_size", {
     default_call with
     args = []; ret = RInt64;
@@ -2553,6 +2577,7 @@ let first_version = [
   "set_request_structured_replies", (1, 2);
   "get_request_structured_replies", (1, 2);
   "get_tls_negotiated", (1, 2);
+  "get_protocol", (1, 2);
 
   (* These calls are proposed for a future version of libnbd, but
    * have not been added to any released version so far.
diff --git a/generator/states-newstyle-opt-export-name.c b/generator/states-newstyle-opt-export-name.c
index ec73136..1c6b443 100644
--- a/generator/states-newstyle-opt-export-name.c
+++ b/generator/states-newstyle-opt-export-name.c
@@ -68,7 +68,7 @@
     SET_NEXT_STATE (%.DEAD);
     return 0;
   }
-  SET_NEXT_STATE (%.READY);
+  SET_NEXT_STATE (%^FINISHED);
   return 0;
 
 } /* END STATE MACHINE */
diff --git a/generator/states-newstyle-opt-go.c b/generator/states-newstyle-opt-go.c
index 49875a5..d0d2123 100644
--- a/generator/states-newstyle-opt-go.c
+++ b/generator/states-newstyle-opt-go.c
@@ -108,7 +108,7 @@
 
   switch (reply) {
   case NBD_REP_ACK:
-    SET_NEXT_STATE (%.READY);
+    SET_NEXT_STATE (%^FINISHED);
     return 0;
   case NBD_REP_INFO:
     if (len > maxpayload /* see RECV_NEWSTYLE_OPT_GO_REPLY */)
diff --git a/generator/states-newstyle.c b/generator/states-newstyle.c
index c8f817e..7742ea3 100644
--- a/generator/states-newstyle.c
+++ b/generator/states-newstyle.c
@@ -155,4 +155,13 @@ handle_reply_error (struct nbd_handle *h)
   }
   return 0;
 
+ NEWSTYLE.FINISHED:
+  if ((h->gflags & NBD_FLAG_FIXED_NEWSTYLE) == 0)
+    h->protocol = "newstyle";
+  else
+    h->protocol = "newstyle-fixed";
+
+  SET_NEXT_STATE (%.READY);
+  return 0;
+
 } /* END STATE MACHINE */
diff --git a/generator/states-oldstyle.c b/generator/states-oldstyle.c
index 1aff185..cb4f0da 100644
--- a/generator/states-oldstyle.c
+++ b/generator/states-oldstyle.c
@@ -64,6 +64,8 @@
     return 0;
   }
 
+  h->protocol = "oldstyle";
+
   SET_NEXT_STATE (%.READY);
 
   return 0;
diff --git a/lib/handle.c b/lib/handle.c
index bc4206c..85d10cd 100644
--- a/lib/handle.c
+++ b/lib/handle.c
@@ -315,3 +315,15 @@ nbd_unlocked_supports_uri (struct nbd_handle *h)
   return 0;
 #endif
 }
+
+const char *
+nbd_unlocked_get_protocol (struct nbd_handle *h)
+{
+  /* I believe that if we reach the Connected or Closed permitted
+   * states, then the state machine must have set h->protocol.  So if
+   * this assertion is hit then it indicates a bug in libnbd.
+   */
+  assert (h->protocol);
+
+  return h->protocol;
+}
diff --git a/lib/internal.h b/lib/internal.h
index eb76ac1..87b413d 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -87,7 +87,10 @@ struct nbd_handle {
   uint64_t exportsize;
   uint16_t eflags;
 
-  /* Flag set by the state machine to tell whether TLS was negotiated. */
+  /* Flags set by the state machine to tell what protocol and whether
+   * TLS was negotiated.
+   */
+  const char *protocol;
   bool tls_negotiated;
 
   int64_t unique;               /* Used for generating cookie numbers. */
diff --git a/tests/get-size.c b/tests/get-size.c
index f10597c..e6f44f7 100644
--- a/tests/get-size.c
+++ b/tests/get-size.c
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <inttypes.h>
+#include <string.h>
 
 #include <libnbd.h>
 
@@ -38,8 +39,10 @@ main (int argc, char *argv[])
 {
   struct nbd_handle *nbd;
   int64_t r;
-  char *args[] = { "nbdkit", "-s", "--exit-with-parent", "-v",
+  /* -n forces newstyle even if someone is still using nbdkit < 1.3 */
+  char *args[] = { "nbdkit", "-s", "--exit-with-parent", "-n", "-v",
                    "null", "size=" STR(SIZE), NULL };
+  const char *s;
 
   nbd = nbd_create ();
   if (nbd == NULL) {
@@ -51,6 +54,14 @@ main (int argc, char *argv[])
     exit (EXIT_FAILURE);
   }
 
+  /* Even ancient versions of nbdkit only supported newstyle-fixed. */
+  s = nbd_get_protocol (nbd);
+  if (strcmp (s, "newstyle-fixed") != 0) {
+    fprintf (stderr,
+             "incorrect protocol \"%s\", expected \"newstyle-fixed\"\n", s);
+    exit (EXIT_FAILURE);
+  }
+
   if ((r = nbd_get_size (nbd)) == -1) {
     fprintf (stderr, "%s\n", nbd_get_error ());
     exit (EXIT_FAILURE);
diff --git a/tests/oldstyle.c b/tests/oldstyle.c
index c179c45..b90b775 100644
--- a/tests/oldstyle.c
+++ b/tests/oldstyle.c
@@ -84,6 +84,7 @@ main (int argc, char *argv[])
   char *args[] = { "nbdkit", "-s", "-o", "--exit-with-parent", "-v",
                    "memory", "size=" STR(SIZE), NULL };
   int calls = 0;
+  const char *s;
 
   progname = argv[0];
 
@@ -114,6 +115,14 @@ main (int argc, char *argv[])
     exit (EXIT_FAILURE);
   }
 
+  /* Protocol should be "oldstyle". */
+  s = nbd_get_protocol (nbd);
+  if (strcmp (s, "oldstyle") != 0) {
+    fprintf (stderr,
+             "incorrect protocol \"%s\", expected \"oldstyle\"\n", s);
+    exit (EXIT_FAILURE);
+  }
+
   if ((r = nbd_get_size (nbd)) == -1) {
     fprintf (stderr, "%s\n", nbd_get_error ());
     exit (EXIT_FAILURE);
-- 
2.23.0




More information about the Libguestfs mailing list