summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2019-12-08 05:54:33 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2019-12-10 01:28:38 +0900
commitdcfc23ae7713fc728555d62c8b7e02bc8b4658f2 (patch)
tree890c16d38b38f1857203b2b64e091b704f64abcf
parentfb4b0465abbd96e6d342e5606c61c919c99a82ff (diff)
downloadsystemd-dcfc23ae7713fc728555d62c8b7e02bc8b4658f2.tar.gz
network: tc: add more options for TBF
-rw-r--r--man/systemd.network.xml36
-rw-r--r--src/network/networkd-network-gperf.gperf4
-rw-r--r--src/network/tc/qdisc.c7
-rw-r--r--src/network/tc/tbf.c109
-rw-r--r--src/network/tc/tbf.h10
-rw-r--r--src/network/tc/tc-util.c31
-rw-r--r--src/network/tc/tc-util.h4
-rw-r--r--test/fuzz/fuzz-network-parser/directives.network4
8 files changed, 202 insertions, 3 deletions
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 63dfb517b6..692a686020 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -2381,6 +2381,15 @@
</varlistentry>
<varlistentry>
+ <term><varname>TokenBufferFilterLimitSize=</varname></term>
+ <listitem>
+ <para>Takes the number of bytes that can be queued waiting for tokens to become available.
+ When the size is suffixed with K, M, or G, it is parsed as Kilobytes, Megabytes, or Gigabytes,
+ respectively, to the base of 1000. Defaults to unset.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>TokenBufferFilterBurst=</varname></term>
<listitem>
<para>Specifies the size of the bucket. This is the maximum amount of bytes that tokens
@@ -2400,6 +2409,33 @@
</varlistentry>
<varlistentry>
+ <term><varname>TokenBufferFilterMPUBytes=</varname></term>
+ <listitem>
+ <para>The Minimum Packet Unit (MPU) determines the minimal token usage (specified in bytes)
+ for a packet. When suffixed with K, M, or G, the specified size is parsed as Kilobytes,
+ Megabytes, or Gigabytes, respectively, to the base of 1000. Defaults to zero.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>TokenBufferFilterPeakRate=</varname></term>
+ <listitem>
+ <para>Takes the maximum depletion rate of the bucket. When suffixed with K, M, or G, the
+ specified size is parsed as Kilobytes, Megabytes, or Gigabytes, respectively, to the base of
+ 1000. Defaults to unset.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>TokenBufferFilterMTUBytes=</varname></term>
+ <listitem>
+ <para>Specifies the size of the peakrate bucket. When suffixed with K, M, or G, the specified
+ size is parsed as Kilobytes, Megabytes, or Gigabytes, respectively, to the base of 1000.
+ Defaults to unset.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>StochasticFairnessQueueingPerturbPeriodSec=</varname></term>
<listitem>
<para>Specifies the interval in seconds for queue algorithm perturbation. Defaults to unset.</para>
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 6f76f74ec9..ea4ba31b80 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -252,6 +252,10 @@ TrafficControlQueueingDiscipline.NetworkEmulatorDuplicateRate, con
TrafficControlQueueingDiscipline.NetworkEmulatorPacketLimit, config_parse_tc_network_emulator_packet_limit, 0, 0
TrafficControlQueueingDiscipline.TokenBufferFilterRate, config_parse_tc_token_buffer_filter_size, 0, 0
TrafficControlQueueingDiscipline.TokenBufferFilterBurst, config_parse_tc_token_buffer_filter_size, 0, 0
+TrafficControlQueueingDiscipline.TokenBufferFilterLimitSize, config_parse_tc_token_buffer_filter_size, 0, 0
+TrafficControlQueueingDiscipline.TokenBufferFilterMTUBytes, config_parse_tc_token_buffer_filter_size, 0, 0
+TrafficControlQueueingDiscipline.TokenBufferFilterMPUBytes, config_parse_tc_token_buffer_filter_size, 0, 0
+TrafficControlQueueingDiscipline.TokenBufferFilterPeakRate, config_parse_tc_token_buffer_filter_size, 0, 0
TrafficControlQueueingDiscipline.TokenBufferFilterLatencySec, config_parse_tc_token_buffer_filter_latency, 0, 0
TrafficControlQueueingDiscipline.StochasticFairnessQueueingPerturbPeriodSec, config_parse_tc_stochastic_fairness_queueing_perturb_period, 0, 0
/* backwards compatibility: do not add new entries to this section */
diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c
index bb3b127647..74b2b7a2c2 100644
--- a/src/network/tc/qdisc.c
+++ b/src/network/tc/qdisc.c
@@ -189,6 +189,7 @@ int qdisc_configure(Link *link, QDisc *qdisc) {
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) {
unsigned i;
+ int r;
assert(qdisc);
assert(has_root);
@@ -204,6 +205,12 @@ int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) {
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
qdisc->section->filename, qdisc->section->line);
+ if (qdisc->has_token_buffer_filter) {
+ r = token_buffer_filter_section_verify(&qdisc->tbf, qdisc->section);
+ if (r < 0)
+ return r;
+ }
+
if (qdisc->parent == TC_H_ROOT) {
if (*has_root)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
diff --git a/src/network/tc/tbf.c b/src/network/tc/tbf.c
index a4ef9ab299..4c15d6b4fd 100644
--- a/src/network/tc/tbf.c
+++ b/src/network/tc/tbf.c
@@ -12,6 +12,7 @@
#include "parse-util.h"
#include "qdisc.h"
#include "string-util.h"
+#include "tc-util.h"
#include "util.h"
int token_buffer_filter_new(TokenBufferFilter **ret) {
@@ -27,6 +28,7 @@ int token_buffer_filter_new(TokenBufferFilter **ret) {
}
int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, sd_netlink_message *req) {
+ uint32_t rtab[256], ptab[256];
struct tc_tbf_qopt opt = {};
int r;
@@ -35,7 +37,42 @@ int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, s
assert(req);
opt.rate.rate = tbf->rate >= (1ULL << 32) ? ~0U : tbf->rate;
- opt.limit = tbf->rate * (double) tbf->latency / USEC_PER_SEC + tbf->burst;
+ opt.peakrate.rate = tbf->peak_rate >= (1ULL << 32) ? ~0U : tbf->peak_rate;
+
+ if (tbf->limit > 0)
+ opt.limit = tbf->limit;
+ else {
+ double lim, lim2;
+
+ lim = tbf->rate * (double) tbf->latency / USEC_PER_SEC + tbf->burst;
+ if (tbf->peak_rate > 0) {
+ lim2 = tbf->peak_rate * (double) tbf->latency / USEC_PER_SEC + tbf->mtu;
+ lim = MIN(lim, lim2);
+ }
+ opt.limit = lim;
+ }
+
+ opt.rate.mpu = tbf->mpu;
+
+ r = tc_fill_ratespec_and_table(&opt.rate, rtab, tbf->mtu);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to calculate ratespec: %m");
+
+ r = tc_transmit_time(opt.rate.rate, tbf->burst, &opt.buffer);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to calculate buffer size: %m");
+
+ if (opt.peakrate.rate > 0) {
+ opt.peakrate.mpu = tbf->mpu;
+
+ r = tc_fill_ratespec_and_table(&opt.peakrate, ptab, tbf->mtu);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to calculate ratespec: %m");
+
+ r = tc_transmit_time(opt.peakrate.rate, tbf->mtu, &opt.mtu);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to calculate mtu size: %m");
+ }
r = sd_netlink_message_open_array(req, TCA_OPTIONS);
if (r < 0)
@@ -55,6 +92,26 @@ int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, s
return log_link_error_errno(link, r, "Could not append TCA_TBF_RATE64 attribute: %m");
}
+ r = sd_netlink_message_append_data(req, TCA_TBF_RTAB, rtab, sizeof(rtab));
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_TBF_RTAB attribute: %m");
+
+ if (opt.peakrate.rate > 0) {
+ if (tbf->peak_rate >= (1ULL << 32)) {
+ r = sd_netlink_message_append_data(req, TCA_TBF_PRATE64, &tbf->peak_rate, sizeof(tbf->peak_rate));
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_TBF_PRATE64 attribute: %m");
+ }
+
+ r = sd_netlink_message_append_data(req, TCA_TBF_PBURST, &tbf->mtu, sizeof(tbf->mtu));
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_TBF_PBURST attribute: %m");
+
+ r = sd_netlink_message_append_data(req, TCA_TBF_PTAB, ptab, sizeof(ptab));
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_TBF_PTAB attribute: %m");
+ }
+
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_error_errno(link, r, "Could not close container TCA_OPTIONS: %m");
@@ -93,6 +150,14 @@ int config_parse_tc_token_buffer_filter_size(
qdisc->tbf.rate = 0;
else if (streq(lvalue, "TokenBufferFilterBurst"))
qdisc->tbf.burst = 0;
+ else if (streq(lvalue, "TokenBufferFilterLimitSize"))
+ qdisc->tbf.limit = 0;
+ else if (streq(lvalue, "TokenBufferFilterMTUBytes"))
+ qdisc->tbf.mtu = 0;
+ else if (streq(lvalue, "TokenBufferFilterMPUBytes"))
+ qdisc->tbf.mpu = 0;
+ else if (streq(lvalue, "TokenBufferFilterPeakRate"))
+ qdisc->tbf.peak_rate = 0;
qdisc = NULL;
return 0;
@@ -110,6 +175,14 @@ int config_parse_tc_token_buffer_filter_size(
qdisc->tbf.rate = k / 8;
else if (streq(lvalue, "TokenBufferFilterBurst"))
qdisc->tbf.burst = k;
+ else if (streq(lvalue, "TokenBufferFilterLimitSize"))
+ qdisc->tbf.limit = k;
+ else if (streq(lvalue, "TokenBufferFilterMPUBytes"))
+ qdisc->tbf.mpu = k;
+ else if (streq(lvalue, "TokenBufferFilterMTUBytes"))
+ qdisc->tbf.mtu = k;
+ else if (streq(lvalue, "TokenBufferFilterPeakRate"))
+ qdisc->tbf.peak_rate = k / 8;
qdisc->has_token_buffer_filter = true;
qdisc = NULL;
@@ -165,3 +238,37 @@ int config_parse_tc_token_buffer_filter_latency(
return 0;
}
+
+int token_buffer_filter_section_verify(const TokenBufferFilter *tbf, const NetworkConfigSection *section) {
+ if (tbf->limit > 0 && tbf->latency > 0)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: Specifying both TokenBufferFilterLimitSize= and TokenBufferFilterLatencySec= is not allowed. "
+ "Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
+ section->filename, section->line);
+
+ if (tbf->limit == 0 && tbf->latency == 0)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: Either TokenBufferFilterLimitSize= or TokenBufferFilterLatencySec= is required. "
+ "Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
+ section->filename, section->line);
+
+ if (tbf->rate == 0)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: TokenBufferFilterRate= is mandatory. "
+ "Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
+ section->filename, section->line);
+
+ if (tbf->burst == 0)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: TokenBufferFilterBurst= is mandatory. "
+ "Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
+ section->filename, section->line);
+
+ if (tbf->peak_rate > 0 && tbf->mtu == 0)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: TokenBufferFilterMTUBytes= is mandatory when TokenBufferFilterPeakRate= is specified. "
+ "Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
+ section->filename, section->line);
+
+ return 0;
+}
diff --git a/src/network/tc/tbf.h b/src/network/tc/tbf.h
index c8ae6d057d..e0bdc3b85f 100644
--- a/src/network/tc/tbf.h
+++ b/src/network/tc/tbf.h
@@ -6,16 +6,22 @@
#include "conf-parser.h"
#include "networkd-link.h"
+#include "networkd-util.h"
+#include "tc-util.h"
typedef struct TokenBufferFilter {
uint64_t rate;
-
+ uint64_t peak_rate;
uint32_t burst;
- uint32_t latency;
+ uint32_t mtu;
+ usec_t latency;
+ size_t limit;
+ size_t mpu;
} TokenBufferFilter;
int token_buffer_filter_new(TokenBufferFilter **ret);
int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, sd_netlink_message *req);
+int token_buffer_filter_section_verify(const TokenBufferFilter *tbf, const NetworkConfigSection *section);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_latency);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_size);
diff --git a/src/network/tc/tc-util.c b/src/network/tc/tc-util.c
index 7e1cf53e11..c46550f955 100644
--- a/src/network/tc/tc-util.c
+++ b/src/network/tc/tc-util.c
@@ -61,3 +61,34 @@ int parse_tc_percent(const char *s, uint32_t *percent) {
*percent = (double) r / 1000 * UINT32_MAX;
return 0;
}
+
+int tc_transmit_time(uint64_t rate, uint32_t size, uint32_t *ret) {
+ return tc_time_to_tick(USEC_PER_SEC * ((double)size / (double)rate), ret);
+}
+
+int tc_fill_ratespec_and_table(struct tc_ratespec *rate, uint32_t *rtab, uint32_t mtu) {
+ uint32_t cell_log = 0;
+ int r;
+
+ if (mtu == 0)
+ mtu = 2047;
+
+ while ((mtu >> cell_log) > 255)
+ cell_log++;
+
+ for (size_t i = 0; i < 256; i++) {
+ uint32_t sz;
+
+ sz = (i + 1) << cell_log;
+ if (sz < rate->mpu)
+ sz = rate->mpu;
+ r = tc_transmit_time(rate->rate, sz, &rtab[i]);
+ if (r < 0)
+ return r;
+ }
+
+ rate->cell_align = -1;
+ rate->cell_log = cell_log;
+ rate->linklayer = TC_LINKLAYER_ETHERNET;
+ return 0;
+}
diff --git a/src/network/tc/tc-util.h b/src/network/tc/tc-util.h
index ce7ab40538..c901f50691 100644
--- a/src/network/tc/tc-util.h
+++ b/src/network/tc/tc-util.h
@@ -2,7 +2,11 @@
* Copyright © 2019 VMware, Inc. */
#pragma once
+#include <linux/pkt_sched.h>
+
#include "time-util.h"
int tc_time_to_tick(usec_t t, uint32_t *ret);
int parse_tc_percent(const char *s, uint32_t *percent);
+int tc_transmit_time(uint64_t rate, uint32_t size, uint32_t *ret);
+int tc_fill_ratespec_and_table(struct tc_ratespec *rate, uint32_t *rtab, uint32_t mtu);
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index 2a6f111d83..c3264522b4 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -272,5 +272,9 @@ NetworkEmulatorDuplicateRate=
NetworkEmulatorPacketLimit=
TokenBufferFilterRate=
TokenBufferFilterBurst=
+TokenBufferFilterLimitSize=
+TokenBufferFilterMTUBytes=
+TokenBufferFilterMPUBytes=
+TokenBufferFilterPeakRate=
TokenBufferFilterLatencySec=
StochasticFairnessQueueingPerturbPeriodSec=