Add nbdkit rate filter.
This commit is contained in:
parent
df26f1b46f
commit
18f1736652
@ -1,7 +1,7 @@
|
|||||||
From d77c93b1cc42fc6cbda1b2abf941b001ad741cba Mon Sep 17 00:00:00 2001
|
From d77c93b1cc42fc6cbda1b2abf941b001ad741cba Mon Sep 17 00:00:00 2001
|
||||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||||
Date: Sat, 2 Mar 2019 08:28:04 +0000
|
Date: Sat, 2 Mar 2019 08:28:04 +0000
|
||||||
Subject: [PATCH] common: utils: Use include/ directory to get
|
Subject: [PATCH 1/2] common: utils: Use include/ directory to get
|
||||||
<nbdkit-plugin.h>
|
<nbdkit-plugin.h>
|
||||||
|
|
||||||
This worked before because nbdkit was installed by the system package
|
This worked before because nbdkit was installed by the system package
|
||||||
|
844
0002-Add-new-filter-for-rate-limiting-connections.patch
Normal file
844
0002-Add-new-filter-for-rate-limiting-connections.patch
Normal file
@ -0,0 +1,844 @@
|
|||||||
|
From 53d75b09d9873c69a2d0e7f514a24af746f14292 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||||
|
Date: Tue, 5 Mar 2019 06:24:29 +0000
|
||||||
|
Subject: [PATCH 2/2] Add new filter for rate-limiting connections.
|
||||||
|
|
||||||
|
As an example this creates a RAM disk with the rate filter on top,
|
||||||
|
then copies the data out to a local file:
|
||||||
|
|
||||||
|
$ time ./nbdkit --filter=rate memory size=50M rate=10M \
|
||||||
|
--run 'qemu-img convert $nbd /var/tmp/disk.img'
|
||||||
|
|
||||||
|
real 0m40.023s
|
||||||
|
user 0m0.032s
|
||||||
|
sys 0m0.081s
|
||||||
|
|
||||||
|
The size of the RAM disk is 8*50 = 400 Mbits, and we copy out at a
|
||||||
|
rate of 10 Mbps, so it takes exactly 40 seconds.
|
||||||
|
---
|
||||||
|
filters/delay/nbdkit-delay-filter.pod | 4 +-
|
||||||
|
filters/rate/nbdkit-rate-filter.pod | 86 ++++++++++
|
||||||
|
configure.ac | 2 +
|
||||||
|
filters/rate/bucket.h | 71 ++++++++
|
||||||
|
filters/rate/bucket.c | 166 ++++++++++++++++++
|
||||||
|
filters/rate/rate.c | 231 ++++++++++++++++++++++++++
|
||||||
|
TODO | 9 +
|
||||||
|
filters/rate/Makefile.am | 64 +++++++
|
||||||
|
tests/Makefile.am | 6 +-
|
||||||
|
tests/test-rate.sh | 60 +++++++
|
||||||
|
10 files changed, 697 insertions(+), 2 deletions(-)
|
||||||
|
create mode 100644 filters/rate/nbdkit-rate-filter.pod
|
||||||
|
create mode 100644 filters/rate/bucket.h
|
||||||
|
create mode 100644 filters/rate/bucket.c
|
||||||
|
create mode 100644 filters/rate/rate.c
|
||||||
|
create mode 100644 filters/rate/Makefile.am
|
||||||
|
create mode 100755 tests/test-rate.sh
|
||||||
|
|
||||||
|
diff --git a/filters/delay/nbdkit-delay-filter.pod b/filters/delay/nbdkit-delay-filter.pod
|
||||||
|
index 7009a8c..c2eb172 100644
|
||||||
|
--- a/filters/delay/nbdkit-delay-filter.pod
|
||||||
|
+++ b/filters/delay/nbdkit-delay-filter.pod
|
||||||
|
@@ -17,6 +17,7 @@ nbdkit-delay-filter - nbdkit delay filter
|
||||||
|
C<nbdkit-delay-filter> is a filter that delays read and write requests
|
||||||
|
by some seconds or milliseconds. This is used to simulate a slow or
|
||||||
|
remote server, or to test certain kinds of race conditions in Linux.
|
||||||
|
+To limit server bandwidth use L<nbdkit-rate-filter(1)> instead.
|
||||||
|
|
||||||
|
=head1 EXAMPLES
|
||||||
|
|
||||||
|
@@ -74,7 +75,8 @@ milliseconds.
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
L<nbdkit(1)>,
|
||||||
|
-L<nbdkit-filter(3)>.
|
||||||
|
+L<nbdkit-filter(3)>,
|
||||||
|
+L<nbdkit-rate-filter(1)>.
|
||||||
|
|
||||||
|
=head1 AUTHORS
|
||||||
|
|
||||||
|
diff --git a/filters/rate/nbdkit-rate-filter.pod b/filters/rate/nbdkit-rate-filter.pod
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..99a0373
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/filters/rate/nbdkit-rate-filter.pod
|
||||||
|
@@ -0,0 +1,86 @@
|
||||||
|
+=head1 NAME
|
||||||
|
+
|
||||||
|
+nbdkit-rate-filter - limit bandwidth by connection or server
|
||||||
|
+
|
||||||
|
+=head1 SYNOPSIS
|
||||||
|
+
|
||||||
|
+ nbdkit --filter=rate PLUGIN [PLUGIN-ARGS...]
|
||||||
|
+ [rate=BITSPERSEC]
|
||||||
|
+ [connection-rate=BITSPERSEC]
|
||||||
|
+
|
||||||
|
+=head1 DESCRIPTION
|
||||||
|
+
|
||||||
|
+C<nbdkit-rate-filter> is a filter that limits the bandwidth that can
|
||||||
|
+be used by the server. Limits can be applied per connection and/or
|
||||||
|
+for the server as a whole.
|
||||||
|
+
|
||||||
|
+=head1 EXAMPLES
|
||||||
|
+
|
||||||
|
+=over 4
|
||||||
|
+
|
||||||
|
+=item nbdkit --filter=rate memory size=64M rate=1M
|
||||||
|
+
|
||||||
|
+Create a 64M RAM disk and limit server bandwidth as a whole to a
|
||||||
|
+maximum of S<1 Mbps> (megabit per second).
|
||||||
|
+
|
||||||
|
+=item nbdkit --filter=rate memory size=64M connection-rate=50K
|
||||||
|
+
|
||||||
|
+Limit each connection to S<50 Kbps> (kilobits per second). However as
|
||||||
|
+there is no limit to the number of simultaneous connections this does
|
||||||
|
+not limit overall server bandwidth.
|
||||||
|
+
|
||||||
|
+=item nbdkit --filter=rate memory size=64M connection-rate=50K rate=1M
|
||||||
|
+
|
||||||
|
+Limit each connection to S<50 Kbps>. Additionally the total bandwidth
|
||||||
|
+across all connections to the server is limited to S<1 Mbps>.
|
||||||
|
+
|
||||||
|
+=back
|
||||||
|
+
|
||||||
|
+=head1 PARAMETERS
|
||||||
|
+
|
||||||
|
+=over 4
|
||||||
|
+
|
||||||
|
+=item B<connection-rate=>BITSPERSEC
|
||||||
|
+
|
||||||
|
+Limit each connection to C<BITSPERSEC>.
|
||||||
|
+
|
||||||
|
+=item B<rate=>BITSPERSEC
|
||||||
|
+
|
||||||
|
+Limit total bandwidth across all connections to C<BITSPERSEC>.
|
||||||
|
+
|
||||||
|
+=back
|
||||||
|
+
|
||||||
|
+C<BITSPERSEC> can be specified as a simple number, or you can use a
|
||||||
|
+number followed by C<K>, C<M> etc to mean kilobits, megabits and so
|
||||||
|
+on.
|
||||||
|
+
|
||||||
|
+=head1 NOTES
|
||||||
|
+
|
||||||
|
+You can specify C<rate> and C<connection-rate> on their own or
|
||||||
|
+together. If you specify neither, the filter is turned off.
|
||||||
|
+
|
||||||
|
+The rate filter approximates the bandwidth used by the NBD protocol on
|
||||||
|
+the wire. Some operations such as zeroing and trimming are
|
||||||
|
+effectively free (because only a tiny NBD message is sent over the
|
||||||
|
+network) and so do not count against the bandwidth limit. NBD and TCP
|
||||||
|
+protocol overhead is not included, so you may find that other tools
|
||||||
|
+such as L<tc(8)> and L<iptables(8)> give more accurate results.
|
||||||
|
+
|
||||||
|
+here are separate bandwidth limits for read and write (ie. download
|
||||||
|
+and upload to the server).
|
||||||
|
+
|
||||||
|
+=head1 SEE ALSO
|
||||||
|
+
|
||||||
|
+L<nbdkit(1)>,
|
||||||
|
+L<nbdkit-delay-filter(1)>,
|
||||||
|
+L<nbdkit-filter(3)>,
|
||||||
|
+L<iptables(8)>,
|
||||||
|
+L<tc(8)>.
|
||||||
|
+
|
||||||
|
+=head1 AUTHORS
|
||||||
|
+
|
||||||
|
+Richard W.M. Jones
|
||||||
|
+
|
||||||
|
+=head1 COPYRIGHT
|
||||||
|
+
|
||||||
|
+Copyright (C) 2019 Red Hat Inc.
|
||||||
|
diff --git a/configure.ac b/configure.ac
|
||||||
|
index 9e7e5ca..467d48f 100644
|
||||||
|
--- a/configure.ac
|
||||||
|
+++ b/configure.ac
|
||||||
|
@@ -819,6 +819,7 @@ filters="\
|
||||||
|
nozero \
|
||||||
|
offset \
|
||||||
|
partition \
|
||||||
|
+ rate \
|
||||||
|
truncate \
|
||||||
|
xz \
|
||||||
|
"
|
||||||
|
@@ -889,6 +890,7 @@ AC_CONFIG_FILES([Makefile
|
||||||
|
filters/nozero/Makefile
|
||||||
|
filters/offset/Makefile
|
||||||
|
filters/partition/Makefile
|
||||||
|
+ filters/rate/Makefile
|
||||||
|
filters/truncate/Makefile
|
||||||
|
filters/xz/Makefile
|
||||||
|
fuzzing/Makefile
|
||||||
|
diff --git a/filters/rate/bucket.h b/filters/rate/bucket.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..bc36fc1
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/filters/rate/bucket.h
|
||||||
|
@@ -0,0 +1,71 @@
|
||||||
|
+/* nbdkit
|
||||||
|
+ * Copyright (C) 2018-2019 Red Hat Inc.
|
||||||
|
+ * All rights reserved.
|
||||||
|
+ *
|
||||||
|
+ * Redistribution and use in source and binary forms, with or without
|
||||||
|
+ * modification, are permitted provided that the following conditions are
|
||||||
|
+ * met:
|
||||||
|
+ *
|
||||||
|
+ * * Redistributions of source code must retain the above copyright
|
||||||
|
+ * notice, this list of conditions and the following disclaimer.
|
||||||
|
+ *
|
||||||
|
+ * * Redistributions in binary form must reproduce the above copyright
|
||||||
|
+ * notice, this list of conditions and the following disclaimer in the
|
||||||
|
+ * documentation and/or other materials provided with the distribution.
|
||||||
|
+ *
|
||||||
|
+ * * Neither the name of Red Hat nor the names of its contributors may be
|
||||||
|
+ * used to endorse or promote products derived from this software without
|
||||||
|
+ * specific prior written permission.
|
||||||
|
+ *
|
||||||
|
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
|
||||||
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
|
||||||
|
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
+ * SUCH DAMAGE.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef NBDKIT_BUCKET_H
|
||||||
|
+#define NBDKIT_BUCKET_H
|
||||||
|
+
|
||||||
|
+#include <stdint.h>
|
||||||
|
+#include <time.h>
|
||||||
|
+#include <sys/time.h>
|
||||||
|
+
|
||||||
|
+/* A token bucket. */
|
||||||
|
+struct bucket {
|
||||||
|
+ uint64_t rate; /* Fill rate. 0 = no limit set. */
|
||||||
|
+ uint64_t capacity; /* Maximum capacity of the bucket. */
|
||||||
|
+ uint64_t level; /* How full is the bucket now? */
|
||||||
|
+ struct timeval tv; /* Last time we updated the level. */
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/* Initialize the bucket structure. Capacity is expressed in
|
||||||
|
+ * rate-equivalent seconds.
|
||||||
|
+ */
|
||||||
|
+extern void bucket_init (struct bucket *bucket,
|
||||||
|
+ uint64_t rate, double capacity);
|
||||||
|
+
|
||||||
|
+/* Take up to N tokens from the bucket. Returns the number
|
||||||
|
+ * of tokens remaining (that could not be taken from the bucket),
|
||||||
|
+ * or 0 if we were able to take all N tokens from the bucket.
|
||||||
|
+ *
|
||||||
|
+ * In the case that the return value > 0, *TS is initialized with the
|
||||||
|
+ * estimated length of time you should sleep. Note that *TS is _NOT_
|
||||||
|
+ * initialized if the return value == 0, because the caller should not
|
||||||
|
+ * sleep in that case.
|
||||||
|
+ *
|
||||||
|
+ * In the case where the caller needs to sleep, it must make a further
|
||||||
|
+ * call to bucket_run before proceeding, since another thread may have
|
||||||
|
+ * "stolen" the tokens while you were sleeping.
|
||||||
|
+ */
|
||||||
|
+extern uint64_t bucket_run (struct bucket *bucket, uint64_t n,
|
||||||
|
+ struct timespec *ts);
|
||||||
|
+
|
||||||
|
+#endif /* NBDKIT_BUCKET_H */
|
||||||
|
diff --git a/filters/rate/bucket.c b/filters/rate/bucket.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..b68d7b3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/filters/rate/bucket.c
|
||||||
|
@@ -0,0 +1,166 @@
|
||||||
|
+/* nbdkit
|
||||||
|
+ * Copyright (C) 2018-2019 Red Hat Inc.
|
||||||
|
+ * All rights reserved.
|
||||||
|
+ *
|
||||||
|
+ * Redistribution and use in source and binary forms, with or without
|
||||||
|
+ * modification, are permitted provided that the following conditions are
|
||||||
|
+ * met:
|
||||||
|
+ *
|
||||||
|
+ * * Redistributions of source code must retain the above copyright
|
||||||
|
+ * notice, this list of conditions and the following disclaimer.
|
||||||
|
+ *
|
||||||
|
+ * * Redistributions in binary form must reproduce the above copyright
|
||||||
|
+ * notice, this list of conditions and the following disclaimer in the
|
||||||
|
+ * documentation and/or other materials provided with the distribution.
|
||||||
|
+ *
|
||||||
|
+ * * Neither the name of Red Hat nor the names of its contributors may be
|
||||||
|
+ * used to endorse or promote products derived from this software without
|
||||||
|
+ * specific prior written permission.
|
||||||
|
+ *
|
||||||
|
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
|
||||||
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
|
||||||
|
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
+ * SUCH DAMAGE.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+/* This filter is implemented using a Token Bucket
|
||||||
|
+ * (https://en.wikipedia.org/wiki/Token_bucket). There are two
|
||||||
|
+ * buckets per connection (one each for reading and writing) and two
|
||||||
|
+ * global buckets (also for reading and writing).
|
||||||
|
+ *
|
||||||
|
+ * We add tokens at the desired rate (the per-connection rate for the
|
||||||
|
+ * connection buckets, and the global rate for the global buckets).
|
||||||
|
+ * Note that we don't actually keep the buckets updated in real time
|
||||||
|
+ * because as a filter we are called asynchronously. Instead for each
|
||||||
|
+ * bucket we store the last time we were called and add the
|
||||||
|
+ * appropriate number of tokens when we are called next.
|
||||||
|
+ *
|
||||||
|
+ * The bucket capacity controls the burstiness allowed. This is
|
||||||
|
+ * hard-coded at the moment but could be configurable. All buckets
|
||||||
|
+ * start off full.
|
||||||
|
+ *
|
||||||
|
+ * When a packet is to be read or written, if there are sufficient
|
||||||
|
+ * tokens in the bucket then the packet may be immediately passed
|
||||||
|
+ * through to the underlying plugin. The number of bits used is
|
||||||
|
+ * deducted from the appropriate per-connection and global bucket.
|
||||||
|
+ *
|
||||||
|
+ * If there are insufficient tokens then the packet must be delayed.
|
||||||
|
+ * This is done by inserting a sleep which has an estimated length
|
||||||
|
+ * that is long enough based on the rate at which enough tokens will
|
||||||
|
+ * replenish the bucket to allow the packet to be sent next time.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <config.h>
|
||||||
|
+
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <stdint.h>
|
||||||
|
+#include <inttypes.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <time.h>
|
||||||
|
+#include <sys/time.h>
|
||||||
|
+
|
||||||
|
+#include <nbdkit-filter.h>
|
||||||
|
+
|
||||||
|
+#include "minmax.h"
|
||||||
|
+
|
||||||
|
+#include "bucket.h"
|
||||||
|
+
|
||||||
|
+int rate_debug_bucket; /* -D rate.bucket=1 */
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+bucket_init (struct bucket *bucket, uint64_t rate, double capacity)
|
||||||
|
+{
|
||||||
|
+ bucket->rate = rate;
|
||||||
|
+
|
||||||
|
+ /* Capacity is expressed in seconds, but we want to know the
|
||||||
|
+ * capacity in tokens, so multiply by the rate to get this.
|
||||||
|
+ */
|
||||||
|
+ bucket->capacity = rate * capacity;
|
||||||
|
+
|
||||||
|
+ /* Buckets start off full. */
|
||||||
|
+ bucket->level = capacity;
|
||||||
|
+
|
||||||
|
+ gettimeofday (&bucket->tv, NULL);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Return the number of microseconds in y - x. */
|
||||||
|
+static int64_t
|
||||||
|
+tvdiff (const struct timeval *x, const struct timeval *y)
|
||||||
|
+{
|
||||||
|
+ int64_t usec;
|
||||||
|
+
|
||||||
|
+ usec = (y->tv_sec - x->tv_sec) * 1000000;
|
||||||
|
+ usec += y->tv_usec - x->tv_usec;
|
||||||
|
+ return usec;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+uint64_t
|
||||||
|
+bucket_run (struct bucket *bucket, uint64_t n, struct timespec *ts)
|
||||||
|
+{
|
||||||
|
+ struct timeval now;
|
||||||
|
+ int64_t usec;
|
||||||
|
+ uint64_t add, nsec;
|
||||||
|
+
|
||||||
|
+ /* rate == 0 is a special case meaning that there is no limit being
|
||||||
|
+ * enforced.
|
||||||
|
+ */
|
||||||
|
+ if (bucket->rate == 0)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ gettimeofday (&now, NULL);
|
||||||
|
+
|
||||||
|
+ /* Work out how much time has elapsed since we last added tokens to
|
||||||
|
+ * the bucket, and add the correct number of tokens.
|
||||||
|
+ */
|
||||||
|
+ usec = tvdiff (&bucket->tv, &now);
|
||||||
|
+ if (usec < 0) /* Maybe happens if system time not monotonic? */
|
||||||
|
+ usec = 0;
|
||||||
|
+
|
||||||
|
+ add = bucket->rate * usec / 1000000;
|
||||||
|
+ add = MIN (add, bucket->capacity - bucket->level);
|
||||||
|
+ if (rate_debug_bucket)
|
||||||
|
+ nbdkit_debug ("bucket %p: adding %" PRIu64 " tokens, new level %" PRIu64,
|
||||||
|
+ bucket, add, bucket->level + add);
|
||||||
|
+ bucket->level += add;
|
||||||
|
+ bucket->tv = now;
|
||||||
|
+
|
||||||
|
+ /* Can we deduct N tokens from the bucket? If yes then we're good,
|
||||||
|
+ * and we can return 0 which means the caller won't sleep.
|
||||||
|
+ */
|
||||||
|
+ if (bucket->level >= n) {
|
||||||
|
+ if (rate_debug_bucket)
|
||||||
|
+ nbdkit_debug ("bucket %p: deducting %" PRIu64 " tokens", bucket, n);
|
||||||
|
+ bucket->level -= n;
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (rate_debug_bucket)
|
||||||
|
+ nbdkit_debug ("bucket %p: deducting %" PRIu64 " tokens, bucket empty, "
|
||||||
|
+ "need another %" PRIu64 " tokens",
|
||||||
|
+ bucket, bucket->level, n - bucket->level);
|
||||||
|
+
|
||||||
|
+ n -= bucket->level;
|
||||||
|
+ bucket->level = 0;
|
||||||
|
+
|
||||||
|
+ /* Now we need to estimate how long it will take to add N tokens to
|
||||||
|
+ * the bucket, which is how long the caller must sleep for.
|
||||||
|
+ */
|
||||||
|
+ nsec = 1000000000 * n / bucket->rate;
|
||||||
|
+ ts->tv_sec = nsec / 1000000000;
|
||||||
|
+ ts->tv_nsec = nsec % 1000000000;
|
||||||
|
+
|
||||||
|
+ if (rate_debug_bucket)
|
||||||
|
+ nbdkit_debug ("bucket %p: sleeping for %.1f seconds", bucket,
|
||||||
|
+ nsec / 1000000000.);
|
||||||
|
+
|
||||||
|
+ return n;
|
||||||
|
+}
|
||||||
|
diff --git a/filters/rate/rate.c b/filters/rate/rate.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..a0c6ae3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/filters/rate/rate.c
|
||||||
|
@@ -0,0 +1,231 @@
|
||||||
|
+/* nbdkit
|
||||||
|
+ * Copyright (C) 2018-2019 Red Hat Inc.
|
||||||
|
+ * All rights reserved.
|
||||||
|
+ *
|
||||||
|
+ * Redistribution and use in source and binary forms, with or without
|
||||||
|
+ * modification, are permitted provided that the following conditions are
|
||||||
|
+ * met:
|
||||||
|
+ *
|
||||||
|
+ * * Redistributions of source code must retain the above copyright
|
||||||
|
+ * notice, this list of conditions and the following disclaimer.
|
||||||
|
+ *
|
||||||
|
+ * * Redistributions in binary form must reproduce the above copyright
|
||||||
|
+ * notice, this list of conditions and the following disclaimer in the
|
||||||
|
+ * documentation and/or other materials provided with the distribution.
|
||||||
|
+ *
|
||||||
|
+ * * Neither the name of Red Hat nor the names of its contributors may be
|
||||||
|
+ * used to endorse or promote products derived from this software without
|
||||||
|
+ * specific prior written permission.
|
||||||
|
+ *
|
||||||
|
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
|
||||||
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
|
||||||
|
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
+ * SUCH DAMAGE.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+/* For a note on the implementation of this filter, see bucket.c. */
|
||||||
|
+
|
||||||
|
+#include <config.h>
|
||||||
|
+
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <stdint.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <time.h>
|
||||||
|
+#include <sys/time.h>
|
||||||
|
+
|
||||||
|
+#include <pthread.h>
|
||||||
|
+
|
||||||
|
+#include <nbdkit-filter.h>
|
||||||
|
+
|
||||||
|
+#include "bucket.h"
|
||||||
|
+
|
||||||
|
+#define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
|
||||||
|
+
|
||||||
|
+/* Per-connection and global limit, both in bits per second, with zero
|
||||||
|
+ * meaning not set / not enforced.
|
||||||
|
+ */
|
||||||
|
+static uint64_t connection_rate = 0;
|
||||||
|
+static uint64_t rate = 0;
|
||||||
|
+
|
||||||
|
+/* Bucket capacity controls the burst rate. It is expressed as the
|
||||||
|
+ * length of time in "rate-equivalent seconds" that the client can
|
||||||
|
+ * burst for after a period of inactivity. This could be adjustable
|
||||||
|
+ * in future.
|
||||||
|
+ */
|
||||||
|
+#define BUCKET_CAPACITY 2.0
|
||||||
|
+
|
||||||
|
+/* Global read and write buckets. */
|
||||||
|
+static struct bucket read_bucket;
|
||||||
|
+static pthread_mutex_t read_bucket_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
+static struct bucket write_bucket;
|
||||||
|
+static pthread_mutex_t write_bucket_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
+
|
||||||
|
+/* Per-connection handle. */
|
||||||
|
+struct rate_handle {
|
||||||
|
+ /* Per-connection read and write buckets. */
|
||||||
|
+ struct bucket read_bucket;
|
||||||
|
+ pthread_mutex_t read_bucket_lock;
|
||||||
|
+ struct bucket write_bucket;
|
||||||
|
+ pthread_mutex_t write_bucket_lock;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/* Called for each key=value passed on the command line. */
|
||||||
|
+static int
|
||||||
|
+rate_config (nbdkit_next_config *next, void *nxdata,
|
||||||
|
+ const char *key, const char *value)
|
||||||
|
+{
|
||||||
|
+ if (strcmp (key, "rate") == 0) {
|
||||||
|
+ if (rate > 0) {
|
||||||
|
+ nbdkit_error ("rate set twice on the command line");
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ rate = nbdkit_parse_size (value);
|
||||||
|
+ if (rate == -1)
|
||||||
|
+ return -1;
|
||||||
|
+ if (rate == 0) {
|
||||||
|
+ nbdkit_error ("rate cannot be set to 0");
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ else if (strcmp (key, "connection-rate") == 0) {
|
||||||
|
+ if (connection_rate > 0) {
|
||||||
|
+ nbdkit_error ("connection-rate set twice on the command line");
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ connection_rate = nbdkit_parse_size (value);
|
||||||
|
+ if (connection_rate == -1)
|
||||||
|
+ return -1;
|
||||||
|
+ if (connection_rate == 0) {
|
||||||
|
+ nbdkit_error ("connection-rate cannot be set to 0");
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ return next (nxdata, key, value);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+rate_config_complete (nbdkit_next_config_complete *next, void *nxdata)
|
||||||
|
+{
|
||||||
|
+ /* Initialize the global buckets. */
|
||||||
|
+ bucket_init (&read_bucket, rate, BUCKET_CAPACITY);
|
||||||
|
+ bucket_init (&write_bucket, rate, BUCKET_CAPACITY);
|
||||||
|
+
|
||||||
|
+ return next (nxdata);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define rate_config_help \
|
||||||
|
+ "rate=BITSPERSEC Limit total bandwidth.\n" \
|
||||||
|
+ "connection-rate=BITSPERSEC Limit per-connection bandwidth."
|
||||||
|
+
|
||||||
|
+/* Create the per-connection handle. */
|
||||||
|
+static void *
|
||||||
|
+rate_open (nbdkit_next_open *next, void *nxdata, int readonly)
|
||||||
|
+{
|
||||||
|
+ struct rate_handle *h;
|
||||||
|
+
|
||||||
|
+ if (next (nxdata, readonly) == -1)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ h = malloc (sizeof *h);
|
||||||
|
+ if (h == NULL) {
|
||||||
|
+ nbdkit_error ("malloc: %m");
|
||||||
|
+ return NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ bucket_init (&h->read_bucket, connection_rate, BUCKET_CAPACITY);
|
||||||
|
+ bucket_init (&h->write_bucket, connection_rate, BUCKET_CAPACITY);
|
||||||
|
+ pthread_mutex_init (&h->read_bucket_lock, NULL);
|
||||||
|
+ pthread_mutex_init (&h->write_bucket_lock, NULL);
|
||||||
|
+
|
||||||
|
+ return h;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Free up the per-connection handle. */
|
||||||
|
+static void
|
||||||
|
+rate_close (void *handle)
|
||||||
|
+{
|
||||||
|
+ struct rate_handle *h = handle;
|
||||||
|
+
|
||||||
|
+ pthread_mutex_destroy (&h->read_bucket_lock);
|
||||||
|
+ pthread_mutex_destroy (&h->write_bucket_lock);
|
||||||
|
+ free (h);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void
|
||||||
|
+maybe_sleep (struct bucket *bucket, pthread_mutex_t *lock, uint32_t count)
|
||||||
|
+{
|
||||||
|
+ struct timespec ts;
|
||||||
|
+ uint64_t bits;
|
||||||
|
+
|
||||||
|
+ /* Count is in bytes, but we rate limit using bits. We could
|
||||||
|
+ * multiply this by 10 to include start/stop but let's not
|
||||||
|
+ * second-guess the transport layers underneath.
|
||||||
|
+ */
|
||||||
|
+ bits = count * UINT64_C(8);
|
||||||
|
+
|
||||||
|
+ while (bits > 0) {
|
||||||
|
+ /* Run the token bucket algorithm. */
|
||||||
|
+ pthread_mutex_lock (lock);
|
||||||
|
+ bits = bucket_run (bucket, bits, &ts);
|
||||||
|
+ pthread_mutex_unlock (lock);
|
||||||
|
+
|
||||||
|
+ if (bits > 0)
|
||||||
|
+ nanosleep (&ts, NULL);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Read data. */
|
||||||
|
+static int
|
||||||
|
+rate_pread (struct nbdkit_next_ops *next_ops, void *nxdata,
|
||||||
|
+ void *handle, void *buf, uint32_t count, uint64_t offset,
|
||||||
|
+ uint32_t flags, int *err)
|
||||||
|
+{
|
||||||
|
+ struct rate_handle *h = handle;
|
||||||
|
+
|
||||||
|
+ maybe_sleep (&read_bucket, &read_bucket_lock, count);
|
||||||
|
+ maybe_sleep (&h->read_bucket, &h->read_bucket_lock, count);
|
||||||
|
+
|
||||||
|
+ return next_ops->pread (nxdata, buf, count, offset, flags, err);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Write data. */
|
||||||
|
+static int
|
||||||
|
+rate_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata,
|
||||||
|
+ void *handle,
|
||||||
|
+ const void *buf, uint32_t count, uint64_t offset, uint32_t flags,
|
||||||
|
+ int *err)
|
||||||
|
+{
|
||||||
|
+ struct rate_handle *h = handle;
|
||||||
|
+
|
||||||
|
+ maybe_sleep (&write_bucket, &write_bucket_lock, count);
|
||||||
|
+ maybe_sleep (&h->write_bucket, &h->write_bucket_lock, count);
|
||||||
|
+
|
||||||
|
+ return next_ops->pwrite (nxdata, buf, count, offset, flags, err);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct nbdkit_filter filter = {
|
||||||
|
+ .name = "rate",
|
||||||
|
+ .longname = "nbdkit rate filter",
|
||||||
|
+ .version = PACKAGE_VERSION,
|
||||||
|
+ .config = rate_config,
|
||||||
|
+ .config_complete = rate_config_complete,
|
||||||
|
+ .config_help = rate_config_help,
|
||||||
|
+ .open = rate_open,
|
||||||
|
+ .close = rate_close,
|
||||||
|
+ .pread = rate_pread,
|
||||||
|
+ .pwrite = rate_pwrite,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+NBDKIT_REGISTER_FILTER(filter)
|
||||||
|
diff --git a/TODO b/TODO
|
||||||
|
index 59590a1..b589127 100644
|
||||||
|
--- a/TODO
|
||||||
|
+++ b/TODO
|
||||||
|
@@ -129,6 +129,15 @@ Suggestions for filters
|
||||||
|
* nbdkit-cache-filter should handle ENOSPC errors automatically by
|
||||||
|
reclaiming blocks from the cache
|
||||||
|
|
||||||
|
+nbdkit-rate-filter:
|
||||||
|
+
|
||||||
|
+* allow other kinds of traffic shaping such as VBR
|
||||||
|
+
|
||||||
|
+* limit traffic per client (ie. per IP address)
|
||||||
|
+
|
||||||
|
+* split large requests to avoid long, lumpy sleeps when request size
|
||||||
|
+ is much larger than rate limit
|
||||||
|
+
|
||||||
|
Filters for security
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
diff --git a/filters/rate/Makefile.am b/filters/rate/Makefile.am
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..c39aa01
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/filters/rate/Makefile.am
|
||||||
|
@@ -0,0 +1,64 @@
|
||||||
|
+# nbdkit
|
||||||
|
+# Copyright (C) 2018-2019 Red Hat Inc.
|
||||||
|
+# All rights reserved.
|
||||||
|
+#
|
||||||
|
+# Redistribution and use in source and binary forms, with or without
|
||||||
|
+# modification, are permitted provided that the following conditions are
|
||||||
|
+# met:
|
||||||
|
+#
|
||||||
|
+# * Redistributions of source code must retain the above copyright
|
||||||
|
+# notice, this list of conditions and the following disclaimer.
|
||||||
|
+#
|
||||||
|
+# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
+# notice, this list of conditions and the following disclaimer in the
|
||||||
|
+# documentation and/or other materials provided with the distribution.
|
||||||
|
+#
|
||||||
|
+# * Neither the name of Red Hat nor the names of its contributors may be
|
||||||
|
+# used to endorse or promote products derived from this software without
|
||||||
|
+# specific prior written permission.
|
||||||
|
+#
|
||||||
|
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
|
||||||
|
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
|
||||||
|
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
+# SUCH DAMAGE.
|
||||||
|
+
|
||||||
|
+include $(top_srcdir)/common-rules.mk
|
||||||
|
+
|
||||||
|
+EXTRA_DIST = nbdkit-rate-filter.pod
|
||||||
|
+
|
||||||
|
+filter_LTLIBRARIES = nbdkit-rate-filter.la
|
||||||
|
+
|
||||||
|
+nbdkit_rate_filter_la_SOURCES = \
|
||||||
|
+ bucket.c \
|
||||||
|
+ bucket.h \
|
||||||
|
+ rate.c \
|
||||||
|
+ $(top_srcdir)/include/nbdkit-filter.h
|
||||||
|
+
|
||||||
|
+nbdkit_rate_filter_la_CPPFLAGS = \
|
||||||
|
+ -I$(top_srcdir)/include \
|
||||||
|
+ -I$(top_srcdir)/common/include
|
||||||
|
+nbdkit_rate_filter_la_CFLAGS = \
|
||||||
|
+ $(WARNINGS_CFLAGS)
|
||||||
|
+nbdkit_rate_filter_la_LDFLAGS = \
|
||||||
|
+ -module -avoid-version -shared \
|
||||||
|
+ -Wl,--version-script=$(top_srcdir)/filters/filters.syms
|
||||||
|
+
|
||||||
|
+if HAVE_POD
|
||||||
|
+
|
||||||
|
+man_MANS = nbdkit-rate-filter.1
|
||||||
|
+CLEANFILES += $(man_MANS)
|
||||||
|
+
|
||||||
|
+nbdkit-rate-filter.1: nbdkit-rate-filter.pod
|
||||||
|
+ $(PODWRAPPER) --section=1 --man $@ \
|
||||||
|
+ --html $(top_builddir)/html/$@.html \
|
||||||
|
+ $<
|
||||||
|
+
|
||||||
|
+endif HAVE_POD
|
||||||
|
diff --git a/tests/Makefile.am b/tests/Makefile.am
|
||||||
|
index 3992d9b..d1e6f0e 100644
|
||||||
|
--- a/tests/Makefile.am
|
||||||
|
+++ b/tests/Makefile.am
|
||||||
|
@@ -1,5 +1,5 @@
|
||||||
|
# nbdkit
|
||||||
|
-# Copyright (C) 2013-2018 Red Hat Inc.
|
||||||
|
+# Copyright (C) 2013-2019 Red Hat Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
@@ -97,6 +97,7 @@ EXTRA_DIST = \
|
||||||
|
test-python-exception.sh \
|
||||||
|
test.pl \
|
||||||
|
test.py \
|
||||||
|
+ test-rate.sh \
|
||||||
|
test.rb \
|
||||||
|
test.tcl \
|
||||||
|
test-shebang-perl.sh \
|
||||||
|
@@ -810,6 +811,9 @@ if HAVE_GUESTFISH
|
||||||
|
TESTS += test-partition2.sh
|
||||||
|
endif HAVE_GUESTFISH
|
||||||
|
|
||||||
|
+# rate filter test.
|
||||||
|
+TESTS += test-rate.sh
|
||||||
|
+
|
||||||
|
# truncate filter tests.
|
||||||
|
TESTS += \
|
||||||
|
test-truncate1.sh \
|
||||||
|
diff --git a/tests/test-rate.sh b/tests/test-rate.sh
|
||||||
|
new file mode 100755
|
||||||
|
index 0000000..010ef19
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/test-rate.sh
|
||||||
|
@@ -0,0 +1,60 @@
|
||||||
|
+#!/usr/bin/env bash
|
||||||
|
+# nbdkit
|
||||||
|
+# Copyright (C) 2018-2019 Red Hat Inc.
|
||||||
|
+# All rights reserved.
|
||||||
|
+#
|
||||||
|
+# Redistribution and use in source and binary forms, with or without
|
||||||
|
+# modification, are permitted provided that the following conditions are
|
||||||
|
+# met:
|
||||||
|
+#
|
||||||
|
+# * Redistributions of source code must retain the above copyright
|
||||||
|
+# notice, this list of conditions and the following disclaimer.
|
||||||
|
+#
|
||||||
|
+# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
+# notice, this list of conditions and the following disclaimer in the
|
||||||
|
+# documentation and/or other materials provided with the distribution.
|
||||||
|
+#
|
||||||
|
+# * Neither the name of Red Hat nor the names of its contributors may be
|
||||||
|
+# used to endorse or promote products derived from this software without
|
||||||
|
+# specific prior written permission.
|
||||||
|
+#
|
||||||
|
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
|
||||||
|
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
|
||||||
|
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
+# SUCH DAMAGE.
|
||||||
|
+
|
||||||
|
+source ./functions.sh
|
||||||
|
+set -e
|
||||||
|
+set -x
|
||||||
|
+
|
||||||
|
+requires qemu-img --version
|
||||||
|
+
|
||||||
|
+files="rate.img rate.time rate.err"
|
||||||
|
+rm -f $files
|
||||||
|
+cleanup_fn rm -f $files
|
||||||
|
+
|
||||||
|
+# This should take no less than 20 seconds to run:
|
||||||
|
+# (8 * 25 * 1024 * 1024) / (10 * 1024 * 1024) = 20
|
||||||
|
+
|
||||||
|
+# We are using the bash time builtin, so setting TIMEFORMAT will
|
||||||
|
+# control the output format of the time builtin. For strange use of
|
||||||
|
+# { ; } here, see: https://stackoverflow.com/a/13356654
|
||||||
|
+set +x
|
||||||
|
+{ TIMEFORMAT="%0R" ; time nbdkit --filter=rate memory size=25M rate=10M --run 'qemu-img convert -p $nbd rate.img' 2>rate.err ; } 2>rate.time
|
||||||
|
+set -x
|
||||||
|
+
|
||||||
|
+cat rate.err ||:
|
||||||
|
+
|
||||||
|
+seconds="$( cat rate.time )"
|
||||||
|
+if [ "$seconds" -lt 20 ]; then
|
||||||
|
+ echo "$0: rate filter failed: command took $seconds seconds, expected > 20"
|
||||||
|
+ exit 1
|
||||||
|
+fi
|
||||||
|
--
|
||||||
|
2.20.1
|
||||||
|
|
11
nbdkit.spec
11
nbdkit.spec
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
Name: nbdkit
|
Name: nbdkit
|
||||||
Version: 1.11.6
|
Version: 1.11.6
|
||||||
Release: 1%{?dist}
|
Release: 2%{?dist}
|
||||||
Summary: NBD server
|
Summary: NBD server
|
||||||
|
|
||||||
License: BSD
|
License: BSD
|
||||||
@ -47,6 +47,8 @@ Source2: libguestfs.keyring
|
|||||||
|
|
||||||
# Upstream fix to include directory.
|
# Upstream fix to include directory.
|
||||||
Patch1: 0001-common-utils-Use-include-directory-to-get-nbdkit-plu.patch
|
Patch1: 0001-common-utils-Use-include-directory-to-get-nbdkit-plu.patch
|
||||||
|
# Posted but not upstream patch to add nbdkit-rate-filter.
|
||||||
|
Patch2: 0002-Add-new-filter-for-rate-limiting-connections.patch
|
||||||
|
|
||||||
%if 0%{patches_touch_autotools}
|
%if 0%{patches_touch_autotools}
|
||||||
BuildRequires: autoconf, automake, libtool
|
BuildRequires: autoconf, automake, libtool
|
||||||
@ -546,6 +548,8 @@ nbdkit-offset-filter Serve an offset and range.
|
|||||||
|
|
||||||
nbdkit-partition-filter Serve a single partition.
|
nbdkit-partition-filter Serve a single partition.
|
||||||
|
|
||||||
|
nbdkit-rate-filter Limit bandwidth by connection or server.
|
||||||
|
|
||||||
nbdkit-truncate-filter Truncate, expand, round up or round down size.
|
nbdkit-truncate-filter Truncate, expand, round up or round down size.
|
||||||
|
|
||||||
|
|
||||||
@ -938,6 +942,7 @@ popd
|
|||||||
%{_libdir}/%{name}/filters/nbdkit-nozero-filter.so
|
%{_libdir}/%{name}/filters/nbdkit-nozero-filter.so
|
||||||
%{_libdir}/%{name}/filters/nbdkit-offset-filter.so
|
%{_libdir}/%{name}/filters/nbdkit-offset-filter.so
|
||||||
%{_libdir}/%{name}/filters/nbdkit-partition-filter.so
|
%{_libdir}/%{name}/filters/nbdkit-partition-filter.so
|
||||||
|
%{_libdir}/%{name}/filters/nbdkit-rate-filter.so
|
||||||
%{_libdir}/%{name}/filters/nbdkit-truncate-filter.so
|
%{_libdir}/%{name}/filters/nbdkit-truncate-filter.so
|
||||||
%{_mandir}/man1/nbdkit-blocksize-filter.1*
|
%{_mandir}/man1/nbdkit-blocksize-filter.1*
|
||||||
%{_mandir}/man1/nbdkit-cache-filter.1*
|
%{_mandir}/man1/nbdkit-cache-filter.1*
|
||||||
@ -949,6 +954,7 @@ popd
|
|||||||
%{_mandir}/man1/nbdkit-nozero-filter.1*
|
%{_mandir}/man1/nbdkit-nozero-filter.1*
|
||||||
%{_mandir}/man1/nbdkit-offset-filter.1*
|
%{_mandir}/man1/nbdkit-offset-filter.1*
|
||||||
%{_mandir}/man1/nbdkit-partition-filter.1*
|
%{_mandir}/man1/nbdkit-partition-filter.1*
|
||||||
|
%{_mandir}/man1/nbdkit-rate-filter.1*
|
||||||
%{_mandir}/man1/nbdkit-truncate-filter.1*
|
%{_mandir}/man1/nbdkit-truncate-filter.1*
|
||||||
|
|
||||||
|
|
||||||
@ -986,6 +992,9 @@ popd
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Mar 05 2019 Richard W.M. Jones <rjones@redhat.com> - 1.11.6-2
|
||||||
|
- Add nbdkit rate filter.
|
||||||
|
|
||||||
* Fri Mar 01 2019 Richard W.M. Jones <rjones@redhat.com> - 1.11.6-1
|
* Fri Mar 01 2019 Richard W.M. Jones <rjones@redhat.com> - 1.11.6-1
|
||||||
- New upstream version 1.11.6.
|
- New upstream version 1.11.6.
|
||||||
- Add linuxdisk plugin.
|
- Add linuxdisk plugin.
|
||||||
|
Loading…
Reference in New Issue
Block a user