[Libguestfs] [PATCH nbdkit v2] New filter: limit: Limit number of clients that can connect.

Eric Blake eblake at redhat.com
Fri Mar 6 23:23:31 UTC 2020


On 3/4/20 1:44 PM, Richard W.M. Jones wrote:
> ---
>   docs/nbdkit-service.pod                     |   1 +
>   filters/exitlast/nbdkit-exitlast-filter.pod |   1 +
>   filters/ip/nbdkit-ip-filter.pod             |   1 +
>   filters/limit/nbdkit-limit-filter.pod       |  61 +++++++++
>   filters/rate/nbdkit-rate-filter.pod         |   1 +
>   configure.ac                                |   2 +
>   filters/limit/Makefile.am                   |  66 ++++++++++
>   tests/Makefile.am                           |   3 +
>   filters/limit/limit.c                       | 129 ++++++++++++++++++++
>   tests/test-limit.sh                         |  81 ++++++++++++
>   TODO                                        |   2 -
>   11 files changed, 346 insertions(+), 2 deletions(-)
> 

> +++ b/filters/limit/nbdkit-limit-filter.pod
> @@ -0,0 +1,61 @@
> +=head1 NAME
> +
> +nbdkit-limit-filter - limit number of clients that can connect

Is this number of clients that can connect in parallel, or number of 
clients that connect in series?

> +
> +=head1 SYNOPSIS
> +
> + nbdkit --filter=limit PLUGIN [limit=N]
> +
> +=head1 DESCRIPTION
> +
> +C<nbdkit-limit-filter> is an nbdkit filter that limits the number of
> +clients which can connect concurrently.  If more than C<limit=N>
> +(default: 1) clients try to connect at the same time then later
> +clients are rejected.
> +
> +=head1 PARAMETERS
> +
> +=over 4
> +
> +=item B<limit=>N
> +
> +Limit the number of concurrent clients to C<N>.  This parameter is
> +optional.  If not specified then the limit defaults to 1.  You can
> +also set this to 0 to make the number of clients unlimited (ie.
> +disable the filter).
> +

To some extent, you can also disable parallel connections with the 
noparallel-filter set to serialize=connections (but in that mode, the 
second client blocks waiting for its turn to connect, rather than the 
server dropping the second client immediately).  Probably worth 
cross-linking the two man pages to highlight this difference in behavior.

> +=head1 SEE ALSO
> +
> +L<nbdkit(1)>,
> +L<nbdkit-exitlast-filter(1)>,
> +L<nbdkit-ip-filter(1)>,
> +L<nbdkit-noparallel-filter(1)>,
> +L<nbdkit-rate-filter(1)>,
> +L<nbdkit-filter(3)>,
> +L<nbdkit-plugin(3)>.

Hmm - you did link to noparallel here, but noparallel doesn't link back.

> +++ b/filters/limit/limit.c

> +
> +/* Counts client connections. */
> +static unsigned connections;
> +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
> +
> +/* Client limit (0 = filter is disabled). */
> +static unsigned limit = 1;
> +
> +static int
> +limit_config (nbdkit_next_config *next, nbdkit_backend *nxdata,
> +              const char *key, const char *value)
> +{
> +  if (strcmp (key, "limit") == 0) {
> +    if (nbdkit_parse_unsigned ("limit", value, &limit) == -1)
> +      return -1;
> +    return 0;
> +  }
> +
> +  return next (nxdata, key, value);
> +}
> +
> +static void
> +too_many_clients_error (void)
> +{
> +  nbdkit_error ("limit: too many clients connected, connection rejected");
> +}
> +
> +/* We limit connections in the preconnect stage (in particular before
> + * any heavyweight NBD or TLS negotiations has been done).  However we
> + * count connections in the open/close calls since clients can drop
> + * out between preconnect and open.
> + */

Seems reasonable.

> +static int
> +limit_preconnect (nbdkit_next_preconnect *next, nbdkit_backend *nxdata,
> +                  int readonly)
> +{
> +  if (next (nxdata, readonly) == -1)
> +    return -1;
> +
> +  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
> +
> +  if (limit > 0 && connections >= limit) {
> +    too_many_clients_error ();
> +    return -1;
> +  }
> +
> +  return 0;
> +}
> +
> +static void *
> +limit_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
> +            int readonly)
> +{
> +  if (next (nxdata, readonly) == -1)
> +    return NULL;
> +
> +  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
> +
> +  /* We have to check again because clients can artificially slow down
> +   * the NBD negotiation in order to bypass the limit otherwise.
> +   */
> +  if (limit > 0 && connections >= limit) {
> +    too_many_clients_error ();
> +    return NULL;
> +  }
> +
> +  connections++;
> +  return NBDKIT_HANDLE_NOT_NEEDED;
> +}
> +
> +static void
> +limit_close (void *handle)
> +{
> +  ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
> +  connections--;
> +}

Overall looks good.  As you say, we may want to enhance nbdkit with a 
way to enforce that a client complete handshake within a given time 
limit rather than dragging their feet, but that is separate from this 
filter.

ACK.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




More information about the Libguestfs mailing list