All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: Hani Benhabiles <kroosec@gmail.com>
Subject: [Qemu-devel] [PULL 4/5] nbd: Handle fixed new-style clients.
Date: Fri, 27 Jun 2014 16:11:45 +0200	[thread overview]
Message-ID: <1403878306-22683-5-git-send-email-pbonzini@redhat.com> (raw)
In-Reply-To: <1403878306-22683-1-git-send-email-pbonzini@redhat.com>

From: Hani Benhabiles <kroosec@gmail.com>

When this flag is set, the server tells the client that it can send another
option if the server received a request with an option that it doesn't
understand instead of directly closing the connection.

Also add link to the most up-to-date documentation.

Signed-off-by: Hani Benhabiles <kroosec@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/block/nbd.h |   9 ++++
 nbd.c               | 151 +++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 111 insertions(+), 49 deletions(-)

diff --git a/include/block/nbd.h b/include/block/nbd.h
index 79502a0..561b70c 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -45,6 +45,15 @@ struct nbd_reply {
 #define NBD_FLAG_ROTATIONAL     (1 << 4)        /* Use elevator algorithm - rotational media */
 #define NBD_FLAG_SEND_TRIM      (1 << 5)        /* Send TRIM (discard) */
 
+/* New-style global flags. */
+#define NBD_FLAG_FIXED_NEWSTYLE     (1 << 0)    /* Fixed newstyle protocol. */
+
+/* New-style client flags. */
+#define NBD_FLAG_C_FIXED_NEWSTYLE   (1 << 0)    /* Fixed newstyle protocol. */
+
+/* Reply types. */
+#define NBD_REP_ERR_UNSUP       ((1 << 31) | 1) /* Unknown option. */
+
 #define NBD_CMD_MASK_COMMAND	0x0000ffff
 #define NBD_CMD_FLAG_FUA	(1 << 16)
 
diff --git a/nbd.c b/nbd.c
index 8d8bc40..a579e01 100644
--- a/nbd.c
+++ b/nbd.c
@@ -56,7 +56,11 @@
             __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
 } while(0)
 
-/* This is all part of the "official" NBD API */
+/* This is all part of the "official" NBD API.
+ *
+ * The most up-to-date documentation is available at:
+ * https://github.com/yoe/nbd/blob/master/doc/proto.txt
+ */
 
 #define NBD_REQUEST_SIZE        (4 + 4 + 8 + 8 + 4)
 #define NBD_REPLY_SIZE          (4 + 4 + 8)
@@ -64,6 +68,7 @@
 #define NBD_REPLY_MAGIC         0x67446698
 #define NBD_OPTS_MAGIC          0x49484156454F5054LL
 #define NBD_CLIENT_MAGIC        0x0000420281861253LL
+#define NBD_REP_MAGIC           0x3e889045565a9LL
 
 #define NBD_SET_SOCK            _IO(0xab, 0)
 #define NBD_SET_BLKSIZE         _IO(0xab, 1)
@@ -77,7 +82,8 @@
 #define NBD_SET_TIMEOUT         _IO(0xab, 9)
 #define NBD_SET_FLAGS           _IO(0xab, 10)
 
-#define NBD_OPT_EXPORT_NAME     (1 << 0)
+#define NBD_OPT_EXPORT_NAME     (1)
+#define NBD_OPT_ABORT           (2)
 
 /* Definitions for opaque data types */
 
@@ -215,59 +221,43 @@ static ssize_t write_sync(int fd, void *buffer, size_t size)
 
 */
 
-static int nbd_receive_options(NBDClient *client)
+static int nbd_send_rep(int csock, uint32_t type, uint32_t opt)
 {
-    int csock = client->sock;
-    char name[256];
-    uint32_t tmp, length;
     uint64_t magic;
-    int rc;
-
-    /* Client sends:
-        [ 0 ..   3]   reserved (0)
-        [ 4 ..  11]   NBD_OPTS_MAGIC
-        [12 ..  15]   NBD_OPT_EXPORT_NAME
-        [16 ..  19]   length
-        [20 ..  xx]   export name (length bytes)
-     */
+    uint32_t len;
 
-    rc = -EINVAL;
-    if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
-        LOG("read failed");
-        goto fail;
+    magic = cpu_to_be64(NBD_REP_MAGIC);
+    if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+        LOG("write failed (rep magic)");
+        return -EINVAL;
     }
-    TRACE("Checking reserved");
-    if (tmp != 0) {
-        LOG("Bad reserved received");
-        goto fail;
+    opt = cpu_to_be32(opt);
+    if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
+        LOG("write failed (rep opt)");
+        return -EINVAL;
     }
-
-    if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
-        LOG("read failed");
-        goto fail;
+    type = cpu_to_be32(type);
+    if (write_sync(csock, &type, sizeof(type)) != sizeof(type)) {
+        LOG("write failed (rep type)");
+        return -EINVAL;
     }
-    TRACE("Checking reserved");
-    if (magic != be64_to_cpu(NBD_OPTS_MAGIC)) {
-        LOG("Bad magic received");
-        goto fail;
+    len = cpu_to_be32(0);
+    if (write_sync(csock, &len, sizeof(len)) != sizeof(len)) {
+        LOG("write failed (rep data length)");
+        return -EINVAL;
     }
+    return 0;
+}
 
-    if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
-        LOG("read failed");
-        goto fail;
-    }
-    TRACE("Checking option");
-    if (tmp != be32_to_cpu(NBD_OPT_EXPORT_NAME)) {
-        LOG("Bad option received");
-        goto fail;
-    }
+static int nbd_handle_export_name(NBDClient *client, uint32_t length)
+{
+    int rc = -EINVAL, csock = client->sock;
+    char name[256];
 
-    if (read_sync(csock, &length, sizeof(length)) != sizeof(length)) {
-        LOG("read failed");
-        goto fail;
-    }
+    /* Client sends:
+        [20 ..  xx]   export name (length bytes)
+     */
     TRACE("Checking length");
-    length = be32_to_cpu(length);
     if (length > 255) {
         LOG("Bad length received");
         goto fail;
@@ -286,13 +276,75 @@ static int nbd_receive_options(NBDClient *client)
 
     QTAILQ_INSERT_TAIL(&client->exp->clients, client, next);
     nbd_export_get(client->exp);
-
-    TRACE("Option negotiation succeeded.");
     rc = 0;
 fail:
     return rc;
 }
 
+static int nbd_receive_options(NBDClient *client)
+{
+    while (1) {
+        int csock = client->sock;
+        uint32_t tmp, length;
+        uint64_t magic;
+
+        /* Client sends:
+            [ 0 ..   3]   client flags
+            [ 4 ..  11]   NBD_OPTS_MAGIC
+            [12 ..  15]   NBD option
+            [16 ..  19]   length
+            ...           Rest of request
+        */
+
+        if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+            LOG("read failed");
+            return -EINVAL;
+        }
+        TRACE("Checking client flags");
+        tmp = be32_to_cpu(tmp);
+        if (tmp != 0 && tmp != NBD_FLAG_C_FIXED_NEWSTYLE) {
+            LOG("Bad client flags received");
+            return -EINVAL;
+        }
+
+        if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+            LOG("read failed");
+            return -EINVAL;
+        }
+        TRACE("Checking opts magic");
+        if (magic != be64_to_cpu(NBD_OPTS_MAGIC)) {
+            LOG("Bad magic received");
+            return -EINVAL;
+        }
+
+        if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+            LOG("read failed");
+            return -EINVAL;
+        }
+
+        if (read_sync(csock, &length, sizeof(length)) != sizeof(length)) {
+            LOG("read failed");
+            return -EINVAL;
+        }
+        length = be32_to_cpu(length);
+
+        TRACE("Checking option");
+        switch (be32_to_cpu(tmp)) {
+        case NBD_OPT_ABORT:
+            return -EINVAL;
+
+        case NBD_OPT_EXPORT_NAME:
+            return nbd_handle_export_name(client, length);
+
+        default:
+            tmp = be32_to_cpu(tmp);
+            LOG("Unsupported option 0x%x", tmp);
+            nbd_send_rep(client->sock, NBD_REP_ERR_UNSUP, tmp);
+            return -EINVAL;
+        }
+    }
+}
+
 static int nbd_send_negotiate(NBDClient *client)
 {
     int csock = client->sock;
@@ -333,6 +385,7 @@ static int nbd_send_negotiate(NBDClient *client)
         cpu_to_be16w((uint16_t*)(buf + 26), client->exp->nbdflags | myflags);
     } else {
         cpu_to_be64w((uint64_t*)(buf + 8), NBD_OPTS_MAGIC);
+        cpu_to_be16w((uint16_t *)(buf + 16), NBD_FLAG_FIXED_NEWSTYLE);
     }
 
     if (client->exp) {
@@ -346,7 +399,7 @@ static int nbd_send_negotiate(NBDClient *client)
             goto fail;
         }
         rc = nbd_receive_options(client);
-        if (rc < 0) {
+        if (rc != 0) {
             LOG("option negotiation failed");
             goto fail;
         }
@@ -1174,7 +1227,7 @@ NBDClient *nbd_client_new(NBDExport *exp, int csock,
     client->refcount = 1;
     client->exp = exp;
     client->sock = csock;
-    if (nbd_send_negotiate(client) < 0) {
+    if (nbd_send_negotiate(client)) {
         g_free(client);
         return NULL;
     }
-- 
1.8.3.1

  parent reply	other threads:[~2014-06-27 14:12 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-27 14:11 [Qemu-devel] [PULL 0/5] NBD changes for 2014-06-27 Paolo Bonzini
2014-06-27 14:11 ` [Qemu-devel] [PULL 1/5] nbd: Don't export a block device with no medium Paolo Bonzini
2014-06-27 14:11 ` [Qemu-devel] [PULL 2/5] nbd: Don't validate from and len in NBD_CMD_DISC Paolo Bonzini
2014-06-27 14:11 ` [Qemu-devel] [PULL 3/5] nbd: Shutdown socket before closing Paolo Bonzini
2014-06-27 14:11 ` Paolo Bonzini [this message]
2014-06-27 14:11 ` [Qemu-devel] [PULL 5/5] nbd: Handle NBD_OPT_LIST option Paolo Bonzini
2014-06-29 11:45 ` [Qemu-devel] [PULL 0/5] NBD changes for 2014-06-27 Peter Maydell
2014-06-29 11:55   ` Hani Benhabiles
2014-06-30 12:36     ` Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1403878306-22683-5-git-send-email-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=kroosec@gmail.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.