[Libguestfs] [PATCH libnbd 2/2] api: Add support for AF_VSOCK.

Richard W.M. Jones rjones at redhat.com
Fri Oct 18 15:39:13 UTC 2019


This adds a new API for connecting to AF_VSOCK protocol
(https://wiki.qemu.org/Features/VirtioVsock).

For example:

  nbd_connect_vsock (nbd, 2, 10809);

There is no test of this feature because it only works between guest
and host.  You cannot start a server and client on the host and talk
between them, which is what we'd need to write a sane test.
---
 configure.ac               |  2 ++
 fuse/nbdfuse.c             | 26 +++++++++++++++++++
 fuse/nbdfuse.pod           |  8 ++++++
 generator/generator        | 51 ++++++++++++++++++++++++++++++++++++--
 generator/states-connect.c | 22 ++++++++++++++++
 lib/connect.c              | 20 +++++++++++++++
 lib/internal.h             |  3 +++
 7 files changed, 130 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index a84580d..95ffca7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -77,6 +77,8 @@ AC_CHECK_HEADERS([\
     stdatomic.h \
     sys/endian.h])
 
+AC_CHECK_HEADERS([linux/vm_sockets.h], [], [], [#include <sys/socket.h>])
+
 dnl Check for functions, all optional.
 AC_CHECK_FUNCS([\
     execvpe])
diff --git a/fuse/nbdfuse.c b/fuse/nbdfuse.c
index 75bb0be..c0aee79 100644
--- a/fuse/nbdfuse.c
+++ b/fuse/nbdfuse.c
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <inttypes.h>
 #include <string.h>
 #include <getopt.h>
 #include <limits.h>
@@ -97,6 +98,7 @@ usage (FILE *fp, int exitcode)
 "    nbdfuse MOUNTPOINT[/FILENAME] --fd N\n"
 "    nbdfuse MOUNTPOINT[/FILENAME] --tcp HOST PORT\n"
 "    nbdfuse MOUNTPOINT[/FILENAME] --unix SOCKET\n"
+"    nbdfuse MOUNTPOINT[/FILENAME] --vsock CID PORT\n"
 "\n"
 "Please read the nbdfuse(1) manual page for full usage.\n"
 "\n"
@@ -139,6 +141,7 @@ main (int argc, char *argv[])
     MODE_SOCKET_ACTIVATION,
     MODE_TCP,
     MODE_UNIX,
+    MODE_VSOCK,
   } mode = MODE_URI;
   enum {
     HELP_OPTION = CHAR_MAX + 1,
@@ -161,6 +164,7 @@ main (int argc, char *argv[])
     { NULL }
   };
   int c, fd, r;
+  uint32_t cid, port;
   int64_t ssize;
   const char *s;
   struct fuse_args fuse_args = FUSE_ARGS_INIT (0, NULL);
@@ -262,6 +266,10 @@ main (int argc, char *argv[])
     mode = MODE_UNIX;
     optind++;
   }
+  else if (strcmp (argv[optind], "--vsock") == 0) {
+    mode = MODE_VSOCK;
+    optind++;
+  }
   /* This is undocumented, but allow either URI or --uri URI. */
   else if (strcmp (argv[optind], "--uri") == 0) {
     mode = MODE_URI;
@@ -289,6 +297,7 @@ main (int argc, char *argv[])
       usage (stderr, EXIT_FAILURE);
     break;
   case MODE_TCP:
+  case MODE_VSOCK:
     if (argc - optind != 2)
       usage (stderr, EXIT_FAILURE);
     break;
@@ -357,6 +366,23 @@ main (int argc, char *argv[])
       exit (EXIT_FAILURE);
     }
     break;
+
+  case MODE_VSOCK:
+    if (sscanf (argv[optind], "%" SCNu32, &cid) != 1) {
+      fprintf (stderr, "%s: could not parse vsock cid: %s\n\n",
+               argv[0], argv[optind]);
+      exit (EXIT_FAILURE);
+    }
+    if (sscanf (argv[optind+1], "%" SCNu32, &port) != 1) {
+      fprintf (stderr, "%s: could not parse vsock port: %s\n\n",
+               argv[0], argv[optind]);
+      exit (EXIT_FAILURE);
+    }
+    if (nbd_connect_vsock (nbd, cid, port) == -1) {
+      fprintf (stderr, "%s\n", nbd_get_error ());
+      exit (EXIT_FAILURE);
+    }
+    break;
   }
 
   ssize = nbd_get_size (nbd);
diff --git a/fuse/nbdfuse.pod b/fuse/nbdfuse.pod
index 3187822..3a7401c 100644
--- a/fuse/nbdfuse.pod
+++ b/fuse/nbdfuse.pod
@@ -19,6 +19,8 @@ Other modes:
 
  nbdfuse MOUNTPOINT[/FILENAME] --unix SOCKET
 
+ nbdfuse MOUNTPOINT[/FILENAME] --vsock CID PORT
+
 =head1 DESCRIPTION
 
 nbdfuse presents a Network Block Device as a local file inside a FUSE
@@ -230,6 +232,11 @@ unencrypted TCP socket.  See also L<nbd_connect_tcp(3)>.
 Select Unix mode.  Connect to an NBD server on a Unix domain socket.
 See also L<nbd_connect_unix(3)>.
 
+=item B<--vsock> CID PORT
+
+Select vsock mode.  Connect to an NBD server on a C<AF_VSOCK> socket.
+See also L<nbd_connect_vsock(3)>.
+
 =back
 
 =head1 NOTES
@@ -294,6 +301,7 @@ L<nbd_connect_socket(3)>,
 L<nbd_connect_systemd_socket_activation(3)>,
 L<nbd_connect_tcp(3)>,
 L<nbd_connect_unix(3)>,
+L<nbd_connect_vsock(3)>,
 L<libguestfs(3)>,
 L<guestfish(1)>,
 L<guestmount(1)>,
diff --git a/generator/generator b/generator/generator
index 54a8eb7..89dd52a 100755
--- a/generator/generator
+++ b/generator/generator
@@ -93,6 +93,7 @@ type external_event =
   | CmdCreate                   (* [nbd_create] function called *)
   | CmdConnectSockAddr          (* [nbd_aio_connect] function called *)
   | CmdConnectUnix              (* [nbd_aio_connect_unix] *)
+  | CmdConnectVSock             (* [nbd_aio_connect_vsock] *)
   | CmdConnectTCP               (* [nbd_aio_connect_tcp] *)
   | CmdConnectCommand           (* [nbd_aio_connect_command] *)
   | CmdConnectSA                (* [nbd_aio_connect_systemd_socket_activation]*)
@@ -169,6 +170,7 @@ let rec state_machine = [
     external_events = [ CmdCreate, "";
                         CmdConnectSockAddr, "CONNECT.START";
                         CmdConnectUnix, "CONNECT_UNIX.START";
+                        CmdConnectVSock, "CONNECT_VSOCK.START";
                         CmdConnectTCP, "CONNECT_TCP.START";
                         CmdConnectCommand, "CONNECT_COMMAND.START";
                         CmdConnectSA, "CONNECT_SA.START";
@@ -177,6 +179,7 @@ let rec state_machine = [
 
   Group ("CONNECT", connect_state_machine);
   Group ("CONNECT_UNIX", connect_unix_state_machine);
+  Group ("CONNECT_VSOCK", connect_vsock_state_machine);
   Group ("CONNECT_TCP", connect_tcp_state_machine);
   Group ("CONNECT_COMMAND", connect_command_state_machine);
   Group ("CONNECT_SA", connect_sa_state_machine);
@@ -236,6 +239,16 @@ and connect_unix_state_machine = [
   };
 ]
 
+(* State machine implementing [nbd_aio_connect_vsock]. *)
+and connect_vsock_state_machine = [
+  State {
+    default_state with
+    name = "START";
+    comment = "Connect to an AF_VSOCK socket";
+    external_events = [];
+  };
+]
+
 (* State machine implementing [nbd_aio_connect_tcp]. *)
 and connect_tcp_state_machine = [
   State {
@@ -1491,6 +1504,20 @@ when the connection has been made.";
     example = Some "examples/fetch-first-sector.c";
   };
 
+  "connect_vsock", {
+    default_call with
+    args = [ UInt32 "cid"; UInt32 "port" ]; ret = RErr;
+    permitted_states = [ Created ];
+    shortdesc = "connect to NBD server over AF_VSOCK protocol";
+    longdesc = "\
+Connect (synchronously) over the C<AF_VSOCK> protocol from a
+virtual machine to an NBD server, usually running on the host.  The
+C<cid> and C<port> parameters specify the server address.  Usually
+C<cid> should be C<2> (to connect to the host), and C<port> might be
+C<10809> or another port number assigned to you by the host
+administrator.  This call returns when the connection has been made.";
+  };
+
   "connect_tcp", {
     default_call with
     args = [ String "hostname"; String "port" ]; ret = RErr;
@@ -2148,6 +2175,22 @@ on the connection.";
     example = Some "examples/aio-connect-read.c";
   };
 
+  "aio_connect_vsock", {
+    default_call with
+    args = [ UInt32 "cid"; UInt32 "port" ]; ret = RErr;
+    permitted_states = [ Created ];
+    shortdesc = "connect to the NBD server over AF_VSOCK socket";
+    longdesc = "\
+Begin connecting to the NBD server over the C<AF_VSOCK>
+protocol to the server C<cid:port>.  Parameters behave as documented in
+L<nbd_connect_vsock(3)>.
+
+You can check if the connection is still connecting by calling
+L<nbd_aio_is_connecting(3)>, or if it has connected to the server
+and completed the NBD handshake by calling L<nbd_aio_is_ready(3)>,
+on the connection.";
+  };
+
   "aio_connect_tcp", {
     default_call with
     args = [ String "hostname"; String "port" ]; ret = RErr;
@@ -2793,6 +2836,8 @@ let first_version = [
   "aio_connect_systemd_socket_activation", (1, 2);
   "connect_socket", (1, 2);
   "aio_connect_socket", (1, 2);
+  "connect_vsock", (1, 2);
+  "aio_connect_vsock", (1, 2);
 
   (* These calls are proposed for a future version of libnbd, but
    * have not been added to any released version so far.
@@ -3151,7 +3196,7 @@ end = struct
 let all_external_events =
   [NotifyRead; NotifyWrite;
    CmdCreate;
-   CmdConnectSockAddr; CmdConnectUnix; CmdConnectTCP;
+   CmdConnectSockAddr; CmdConnectUnix; CmdConnectVSock; CmdConnectTCP;
    CmdConnectCommand; CmdConnectSA; CmdConnectSocket;
    CmdIssue]
 
@@ -3161,6 +3206,7 @@ let string_of_external_event = function
   | CmdCreate -> "CmdCreate"
   | CmdConnectSockAddr -> "CmdConnectSockAddr"
   | CmdConnectUnix -> "CmdConnectUnix"
+  | CmdConnectVSock -> "CmdConnectVSock"
   | CmdConnectTCP -> "CmdConnectTCP"
   | CmdConnectCommand -> "CmdConnectCommand"
   | CmdConnectSA -> "CmdConnectSA"
@@ -3173,6 +3219,7 @@ let c_string_of_external_event = function
   | CmdCreate -> "cmd_create"
   | CmdConnectSockAddr -> "cmd_connect_sockaddr"
   | CmdConnectUnix -> "cmd_connect_unix"
+  | CmdConnectVSock -> "cmd_connect_vsock"
   | CmdConnectTCP -> "cmd_connect_tcp"
   | CmdConnectCommand -> "cmd_connect_command"
   | CmdConnectSA -> "cmd_connect_sa"
@@ -3624,7 +3671,7 @@ let generate_lib_states_run_c () =
           | NotifyWrite -> pr "    r |= LIBNBD_AIO_DIRECTION_WRITE;\n"
           | CmdCreate
           | CmdConnectSockAddr
-          | CmdConnectUnix | CmdConnectTCP
+          | CmdConnectUnix | CmdConnectVSock | CmdConnectTCP
           | CmdConnectCommand | CmdConnectSA | CmdConnectSocket
           | CmdIssue -> ()
       ) events;
diff --git a/generator/states-connect.c b/generator/states-connect.c
index d62b0f5..e4658a7 100644
--- a/generator/states-connect.c
+++ b/generator/states-connect.c
@@ -37,6 +37,10 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
+#ifdef HAVE_LINUX_VM_SOCKETS_H
+#include <linux/vm_sockets.h>
+#endif
+
 /* Disable Nagle's algorithm on the socket, but don't fail. */
 static void
 disable_nagle (int sock)
@@ -118,6 +122,24 @@ STATE_MACHINE {
   SET_NEXT_STATE (%^CONNECT.START);
   return 0;
 
+ CONNECT_VSOCK.START:
+#ifdef AF_VSOCK
+  struct sockaddr_vm svm = {
+    .svm_family = AF_VSOCK,
+    .svm_cid = h->svm_cid,
+    .svm_port = h->svm_port,
+  };
+  const socklen_t len = sizeof svm;
+
+  memcpy (&h->connaddr, &svm, len);
+  h->connaddrlen = len;
+  SET_NEXT_STATE (%^CONNECT.START);
+  return 0;
+#else
+  set_error (ENOTSUP, "AF_VSOCK protocol is not supported");
+  SET_NEXT_STATE (%.DEAD);
+#endif
+
  CONNECT_TCP.START:
   int r;
 
diff --git a/lib/connect.c b/lib/connect.c
index a0ef5f1..d8bb121 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -92,6 +92,16 @@ nbd_unlocked_connect_unix (struct nbd_handle *h, const char *unixsocket)
   return wait_until_connected (h);
 }
 
+/* Connect to a vsock. */
+int
+nbd_unlocked_connect_vsock (struct nbd_handle *h, uint32_t cid, uint32_t port)
+{
+  if (nbd_unlocked_aio_connect_vsock (h, cid, port) == -1)
+    return -1;
+
+  return wait_until_connected (h);
+}
+
 /* Connect to a TCP port. */
 int
 nbd_unlocked_connect_tcp (struct nbd_handle *h,
@@ -388,6 +398,16 @@ nbd_unlocked_aio_connect_unix (struct nbd_handle *h, const char *unixsocket)
   return nbd_internal_run (h, cmd_connect_unix);
 }
 
+int
+nbd_unlocked_aio_connect_vsock (struct nbd_handle *h,
+                                uint32_t cid, uint32_t port)
+{
+  h->svm_cid = cid;
+  h->svm_port = port;
+
+  return nbd_internal_run (h, cmd_connect_vsock);
+}
+
 int
 nbd_unlocked_aio_connect_tcp (struct nbd_handle *h,
                               const char *hostname, const char *port)
diff --git a/lib/internal.h b/lib/internal.h
index 6433183..ba053c2 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -197,6 +197,9 @@ struct nbd_handle {
   /* When connecting to Unix domain socket. */
   char *unixsocket;
 
+  /* When connecting to a vsock. */
+  uint32_t svm_cid, svm_port;
+
   /* When connecting to TCP ports, these fields are used. */
   char *hostname, *port;
   struct addrinfo hints;
-- 
2.23.0




More information about the Libguestfs mailing list