network: tc: add more options for TBF

This commit is contained in:
Yu Watanabe 2019-12-08 05:54:33 +09:00
parent fb4b0465ab
commit dcfc23ae77
8 changed files with 202 additions and 3 deletions

View file

@ -2380,6 +2380,15 @@
</listitem>
</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>
@ -2399,6 +2408,33 @@
</listitem>
</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>

View file

@ -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 */

View file

@ -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),

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -272,5 +272,9 @@ NetworkEmulatorDuplicateRate=
NetworkEmulatorPacketLimit=
TokenBufferFilterRate=
TokenBufferFilterBurst=
TokenBufferFilterLimitSize=
TokenBufferFilterMTUBytes=
TokenBufferFilterMPUBytes=
TokenBufferFilterPeakRate=
TokenBufferFilterLatencySec=
StochasticFairnessQueueingPerturbPeriodSec=