Similar to --no-sr, it can be handy for testing a client implementation to have a server that can easily be forced into older behaviors, without having to recompile a one-off hack into a server or dig up an older server binary that lacked a newer feature.
To see the patch in action, try things like: $ ./nbdkit -U - -fv --mask-handshake=0 null \ --run 'qemu-nbd --list -k $unixsocket' Signed-off-by: Eric Blake <ebl...@redhat.com> --- docs/nbdkit-protocol.pod | 25 ++++++++++++++++++----- docs/synopsis.txt | 2 +- server/internal.h | 1 + server/options.h | 2 ++ server/main.c | 30 ++++++++++++++++++---------- server/protocol-handshake-newstyle.c | 4 ++-- 6 files changed, 45 insertions(+), 19 deletions(-) diff --git a/docs/nbdkit-protocol.pod b/docs/nbdkit-protocol.pod index 3ae89063..272f4e5b 100644 --- a/docs/nbdkit-protocol.pod +++ b/docs/nbdkit-protocol.pod @@ -4,8 +4,8 @@ nbdkit - which parts of the NBD protocol nbdkit supports =head1 SYNOPSIS - nbdkit [-n|--newstyle] [--no-sr] [-o|--oldstyle] [-e|--exportname EXPORTNAME] - [...] + nbdkit [-n|--newstyle] [--mask-handshake MASK] [--no-sr] [-o|--oldstyle] + [-e|--exportname EXPORTNAME] [...] =head1 DESCRIPTION @@ -24,15 +24,30 @@ newstyle protocol is better in every respect than the oldstyle protocol and you should prefer it if possible. The newstyle protocol also includes an extension where a client may request structured replies for even more capabilities, such as sparse reads or obtaining -block status. +block status. By default, nbdkit advertises as many features as it +can support (in some cases, this can be limited by what callbacks the +plugin handles), even if the client does not negotiate to use all +advertised features. Use the I<-e> or I<--exportname> flag to set the optional exportname for the newstyle protocol. -Use the I<--no-sr> flag to force the newstyle protocol to decline any -client request for structured replies. +Nbdkit also includes some options that are useful mainly when +performing integration tests, for proving whether clients have sane +fallback behavior when dealing various older servers permitted by the +NBD protocol. Use the I<--no-sr> flag to force the newstyle protocol +to decline any client request for structured replies. Use the +I<--mask-handshake> parameter to mask off particular global features +which are advertised during new-style handshake (defaulting to all +supported bits set). Clearing bit 0 (the low order bit) limits a +client to using just C<NBD_OPT_EXPORT_NAME> (and is incompatible with +TLS or structured replies); clearing bit 1 causes the handshake to +send more padding bytes in response to C<NBD_OPT_EXPORT_NAME>. Other +bits in the mask will only have an effect if the NBD protocol is +extended in the future to define other global bits. Use the I<-o> or I<--oldstyle> flag to force the oldstyle protocol. +In this mode, I<--no-sr> and I<--mask-handshake> have no effect. =head2 Common clients and the protocol they require diff --git a/docs/synopsis.txt b/docs/synopsis.txt index 04cd136d..5fc57fd1 100644 --- a/docs/synopsis.txt +++ b/docs/synopsis.txt @@ -3,7 +3,7 @@ nbdkit [-D|--debug PLUGIN|FILTER.FLAG=N] [--filter FILTER ...] [-f|--foreground] [-g|--group GROUP] [-i|--ipaddr IPADDR] [--log stderr|syslog] - [-n|--newstyle] [--no-sr] [-o|--oldstyle] + [-n|--newstyle] [--mask-handshake MASK] [--no-sr] [-o|--oldstyle] [-P|--pidfile PIDFILE] [-p|--port PORT] [-r|--readonly] [--run CMD] [-s|--single] [--selinux-label LABEL] diff --git a/server/internal.h b/server/internal.h index 9314e8ff..5da3e3c3 100644 --- a/server/internal.h +++ b/server/internal.h @@ -90,6 +90,7 @@ extern const char *exportname; extern bool foreground; extern const char *ipaddr; extern enum log_to log_to; +extern unsigned mask_handshake; extern bool newstyle; extern bool no_sr; extern const char *port; diff --git a/server/options.h b/server/options.h index a69f413a..c74e0b8b 100644 --- a/server/options.h +++ b/server/options.h @@ -46,6 +46,7 @@ enum { FILTER_OPTION, LOG_OPTION, LONG_OPTIONS_OPTION, + MASK_HANDSHAKE_OPTION, NO_SR_OPTION, RUN_OPTION, SELINUX_LABEL_OPTION, @@ -74,6 +75,7 @@ static const struct option long_options[] = { { "ipaddr", required_argument, NULL, 'i' }, { "log", required_argument, NULL, LOG_OPTION }, { "long-options", no_argument, NULL, LONG_OPTIONS_OPTION }, + { "mask-handshake", required_argument, NULL, MASK_HANDSHAKE_OPTION }, { "new-style", no_argument, NULL, 'n' }, { "newstyle", no_argument, NULL, 'n' }, { "no-sr", no_argument, NULL, NO_SR_OPTION }, diff --git a/server/main.c b/server/main.c index 22cf8d33..d433c1fa 100644 --- a/server/main.c +++ b/server/main.c @@ -67,6 +67,7 @@ const char *exportname; /* -e */ bool foreground; /* -f */ const char *ipaddr; /* -i */ enum log_to log_to = LOG_TO_DEFAULT; /* --log */ +unsigned mask_handshake = ~0U; /* --mask-handshake */ bool newstyle = true; /* false = -o, true = -n */ bool no_sr; /* --no-sr */ char *pidfile; /* -P */ @@ -148,6 +149,7 @@ main (int argc, char *argv[]) } *filter_filenames = NULL; size_t i; const char *magic_config_key; + char *end; /* Refuse to run if stdin/out/err are closed, whether or not -s is used. */ if (fcntl (STDERR_FILENO, F_GETFL) == -1) { @@ -348,6 +350,16 @@ main (int argc, char *argv[]) ipaddr = optarg; break; + case MASK_HANDSHAKE_OPTION: + errno = 0; + mask_handshake = strtoul (optarg, &end, 0); + if (errno || *end) { + fprintf (stderr, "%s: cannot parse '%s' into mask-handshake\n", + program_name, optarg); + exit (EXIT_FAILURE); + } + break; + case 'n': newstyle = true; break; @@ -389,18 +401,14 @@ main (int argc, char *argv[]) break; case 't': - { - char *end; - - errno = 0; - threads = strtoul (optarg, &end, 0); - if (errno || *end) { - fprintf (stderr, "%s: cannot parse '%s' into threads\n", - program_name, optarg); - exit (EXIT_FAILURE); - } - /* XXX Worth a maximimum limit on threads? */ + errno = 0; + threads = strtoul (optarg, &end, 0); + if (errno || *end) { + fprintf (stderr, "%s: cannot parse '%s' into threads\n", + program_name, optarg); + exit (EXIT_FAILURE); } + /* XXX Worth a maximimum limit on threads? */ break; case 'U': diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c index 486d416f..9801f7c2 100644 --- a/server/protocol-handshake-newstyle.c +++ b/server/protocol-handshake-newstyle.c @@ -673,7 +673,7 @@ protocol_handshake_newstyle (struct connection *conn) struct new_handshake handshake; uint16_t gflags; - gflags = NBD_FLAG_FIXED_NEWSTYLE | NBD_FLAG_NO_ZEROES; + gflags = (NBD_FLAG_FIXED_NEWSTYLE | NBD_FLAG_NO_ZEROES) & mask_handshake; debug ("newstyle negotiation: flags: global 0x%x", gflags); @@ -694,7 +694,7 @@ protocol_handshake_newstyle (struct connection *conn) /* ... which we check for accuracy. */ debug ("newstyle negotiation: client flags: 0x%x", conn->cflags); if (conn->cflags & ~gflags) { - nbdkit_error ("client requested unknown flags 0x%x", conn->cflags); + nbdkit_error ("client requested unexpected flags 0x%x", conn->cflags); return -1; } -- 2.21.0 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs