Merge pull request #14173 from ssahani/tc-sfq

network: tc: introduce sfq and tbf
This commit is contained in:
Anita Zhang 2019-12-04 16:14:11 -08:00 committed by GitHub
commit da4dd97405
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 478 additions and 52 deletions

View File

@ -2368,6 +2368,40 @@
</listitem>
</varlistentry>
<varlistentry>
<term><varname>TokenBufferFilterLatencySec=</varname></term>
<listitem>
<para>Specifies the latency parameter, which specifies the maximum amount of time a
packet can sit in the Token Buffer Filter (TBF). 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
can be available for instantaneous transfer. 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>TokenBufferFilterRate=</varname></term>
<listitem>
<para>Specifies the device specific bandwidth. When suffixed with K, M, or G, the specified
bandwidth 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>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -532,7 +532,6 @@ int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
assert_return(m->n_containers > 0, -EINVAL);
r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
if (r < 0)

View File

@ -109,6 +109,10 @@ sources = files('''
tc/netem.h
tc/qdisc.c
tc/qdisc.h
tc/sfq.c
tc/sfq.h
tc/tbf.c
tc/tbf.h
tc/tc-util.c
tc/tc-util.h
'''.split())

View File

@ -2585,7 +2585,7 @@ static int link_drop_config(Link *link) {
}
static int link_configure_qdiscs(Link *link) {
QDiscs *qdisc;
QDisc *qdisc;
Iterator i;
int r;
@ -2601,7 +2601,7 @@ static int link_configure_qdiscs(Link *link) {
if (link->qdisc_messages == 0)
link->qdiscs_configured = true;
else
log_link_debug(link, "Configuring QDiscs");
log_link_debug(link, "Configuring queuing discipline (qdisc)");
return 0;
}

View File

@ -244,12 +244,16 @@ CAN.BitRate, config_parse_si_size,
CAN.SamplePoint, config_parse_permille, 0, offsetof(Network, can_sample_point)
CAN.RestartSec, config_parse_sec, 0, offsetof(Network, can_restart_us)
CAN.TripleSampling, config_parse_tristate, 0, offsetof(Network, can_triple_sampling)
TrafficControlQueueingDiscipline.Parent, config_parse_tc_qdiscs_parent, 0, 0
TrafficControlQueueingDiscipline.NetworkEmulatorDelaySec, config_parse_tc_network_emulator_delay, 0, 0
TrafficControlQueueingDiscipline.NetworkEmulatorDelayJitterSec, config_parse_tc_network_emulator_delay, 0, 0
TrafficControlQueueingDiscipline.NetworkEmulatorLossRate, config_parse_tc_network_emulator_rate, 0, 0
TrafficControlQueueingDiscipline.NetworkEmulatorDuplicateRate, config_parse_tc_network_emulator_rate, 0, 0
TrafficControlQueueingDiscipline.NetworkEmulatorPacketLimit, config_parse_tc_network_emulator_packet_limit, 0, 0
TrafficControlQueueingDiscipline.Parent, config_parse_tc_qdiscs_parent, 0, 0
TrafficControlQueueingDiscipline.NetworkEmulatorDelaySec, config_parse_tc_network_emulator_delay, 0, 0
TrafficControlQueueingDiscipline.NetworkEmulatorDelayJitterSec, config_parse_tc_network_emulator_delay, 0, 0
TrafficControlQueueingDiscipline.NetworkEmulatorLossRate, config_parse_tc_network_emulator_rate, 0, 0
TrafficControlQueueingDiscipline.NetworkEmulatorDuplicateRate, config_parse_tc_network_emulator_rate, 0, 0
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.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 */
Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local)
DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)

View File

@ -154,6 +154,8 @@ int network_verify(Network *network) {
Prefix *prefix, *prefix_next;
Route *route, *route_next;
FdbEntry *fdb, *fdb_next;
QDisc *qdisc;
Iterator i;
assert(network);
assert(network->filename);
@ -313,6 +315,11 @@ int network_verify(Network *network) {
if (routing_policy_rule_section_verify(rule) < 0)
routing_policy_rule_free(rule);
bool has_root = false, has_clsact = false;
ORDERED_HASHMAP_FOREACH(qdisc, network->qdiscs_by_section, i)
if (qdisc_section_verify(qdisc, &has_root, &has_clsact) < 0)
qdisc_free(qdisc);
return 0;
}

View File

@ -2,12 +2,9 @@
* Copyright © 2019 VMware, Inc. */
#include <linux/pkt_sched.h>
#include <math.h>
#include "alloc-util.h"
#include "conf-parser.h"
#include "hashmap.h"
#include "in-addr-util.h"
#include "netem.h"
#include "netlink-util.h"
#include "networkd-manager.h"
@ -15,7 +12,6 @@
#include "qdisc.h"
#include "string-util.h"
#include "tc-util.h"
#include "util.h"
int network_emulator_new(NetworkEmulator **ret) {
NetworkEmulator *ne = NULL;
@ -34,33 +30,33 @@ int network_emulator_new(NetworkEmulator **ret) {
return 0;
}
int network_emulator_fill_message(Link *link, QDiscs *qdisc, sd_netlink_message *req) {
int network_emulator_fill_message(Link *link, const NetworkEmulator *ne, sd_netlink_message *req) {
struct tc_netem_qopt opt = {
.limit = 1000,
};
int r;
assert(link);
assert(qdisc);
assert(ne);
assert(req);
if (qdisc->ne.limit > 0)
opt.limit = qdisc->ne.limit;
if (ne->limit > 0)
opt.limit = ne->limit;
if (qdisc->ne.loss > 0)
opt.loss = qdisc->ne.loss;
if (ne->loss > 0)
opt.loss = ne->loss;
if (qdisc->ne.duplicate > 0)
opt.duplicate = qdisc->ne.duplicate;
if (ne->duplicate > 0)
opt.duplicate = ne->duplicate;
if (qdisc->ne.delay != USEC_INFINITY) {
r = tc_time_to_tick(qdisc->ne.delay, &opt.latency);
if (ne->delay != USEC_INFINITY) {
r = tc_time_to_tick(ne->delay, &opt.latency);
if (r < 0)
return log_link_error_errno(link, r, "Failed to calculate latency in TCA_OPTION: %m");
}
if (qdisc->ne.jitter != USEC_INFINITY) {
r = tc_time_to_tick(qdisc->ne.jitter, &opt.jitter);
if (ne->jitter != USEC_INFINITY) {
r = tc_time_to_tick(ne->jitter, &opt.jitter);
if (r < 0)
return log_link_error_errno(link, r, "Failed to calculate jitter in TCA_OPTION: %m");
}
@ -84,7 +80,7 @@ int config_parse_tc_network_emulator_delay(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDiscs *qdisc = NULL;
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
usec_t u;
int r;
@ -139,7 +135,7 @@ int config_parse_tc_network_emulator_rate(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDiscs *qdisc = NULL;
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
uint32_t rate;
int r;
@ -189,7 +185,7 @@ int config_parse_tc_network_emulator_packet_limit(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDiscs *qdisc = NULL;
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
int r;

View File

@ -8,8 +8,6 @@
#include "networkd-link.h"
#include "time-util.h"
typedef struct QDiscs QDiscs;
typedef struct NetworkEmulator {
usec_t delay;
usec_t jitter;
@ -20,7 +18,7 @@ typedef struct NetworkEmulator {
} NetworkEmulator;
int network_emulator_new(NetworkEmulator **ret);
int network_emulator_fill_message(Link *link, QDiscs *qdisc, sd_netlink_message *req);
int network_emulator_fill_message(Link *link, const NetworkEmulator *ne, sd_netlink_message *req);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_delay);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_rate);

View File

@ -12,16 +12,15 @@
#include "qdisc.h"
#include "set.h"
#include "string-util.h"
#include "util.h"
static int qdisc_new(QDiscs **ret) {
QDiscs *qdisc;
static int qdisc_new(QDisc **ret) {
QDisc *qdisc;
qdisc = new(QDiscs, 1);
qdisc = new(QDisc, 1);
if (!qdisc)
return -ENOMEM;
*qdisc = (QDiscs) {
*qdisc = (QDisc) {
.family = AF_UNSPEC,
.parent = TC_H_ROOT,
};
@ -31,9 +30,9 @@ static int qdisc_new(QDiscs **ret) {
return 0;
}
int qdisc_new_static(Network *network, const char *filename, unsigned section_line, QDiscs **ret) {
int qdisc_new_static(Network *network, const char *filename, unsigned section_line, QDisc **ret) {
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(qdisc_freep) QDiscs *qdisc = NULL;
_cleanup_(qdisc_freep) QDisc *qdisc = NULL;
int r;
assert(network);
@ -76,7 +75,7 @@ int qdisc_new_static(Network *network, const char *filename, unsigned section_li
return 0;
}
void qdisc_free(QDiscs *qdisc) {
void qdisc_free(QDisc *qdisc) {
if (!qdisc)
return;
@ -106,7 +105,7 @@ static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
}
if (link->route_messages == 0) {
log_link_debug(link, "QDiscs configured");
log_link_debug(link, "QDisc configured");
link->qdiscs_configured = true;
link_check_ready(link);
}
@ -114,7 +113,7 @@ static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return 1;
}
int qdisc_configure(Link *link, QDiscs *qdisc) {
int qdisc_configure(Link *link, QDisc *qdisc) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
_cleanup_free_ char *tca_kind = NULL;
int r;
@ -147,7 +146,27 @@ int qdisc_configure(Link *link, QDiscs *qdisc) {
if (r < 0)
return log_oom();
r = network_emulator_fill_message(link, qdisc, req);
r = network_emulator_fill_message(link, &qdisc->ne, req);
if (r < 0)
return r;
}
if (qdisc->has_token_buffer_filter) {
r = free_and_strdup(&tca_kind, "tbf");
if (r < 0)
return log_oom();
r = token_buffer_filter_fill_message(link, &qdisc->tbf, req);
if (r < 0)
return r;
}
if (qdisc->has_stochastic_fairness_queueing) {
r = free_and_strdup(&tca_kind, "sfq");
if (r < 0)
return log_oom();
r = stochastic_fairness_queueing_fill_message(link, &qdisc->sfq, req);
if (r < 0)
return r;
}
@ -168,6 +187,42 @@ int qdisc_configure(Link *link, QDiscs *qdisc) {
return 0;
}
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) {
unsigned i;
assert(qdisc);
assert(has_root);
assert(has_clsact);
if (section_is_invalid(qdisc->section))
return -EINVAL;
i = qdisc->has_network_emulator + qdisc->has_token_buffer_filter + qdisc->has_stochastic_fairness_queueing;
if (i > 1)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: TrafficControlQueueingDiscipline section has more than one type of discipline. "
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
qdisc->section->filename, qdisc->section->line);
if (qdisc->parent == TC_H_ROOT) {
if (*has_root)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: More than one root TrafficControlQueueingDiscipline sections are defined. "
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
qdisc->section->filename, qdisc->section->line);
*has_root = true;
} else if (qdisc->parent == TC_H_CLSACT) {
if (*has_clsact)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: More than one clsact TrafficControlQueueingDiscipline sections are defined. "
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
qdisc->section->filename, qdisc->section->line);
*has_clsact = true;
}
return 0;
}
int config_parse_tc_qdiscs_parent(
const char *unit,
const char *filename,
@ -180,7 +235,7 @@ int config_parse_tc_qdiscs_parent(
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDiscs *qdisc = NULL;
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
int r;

View File

@ -7,8 +7,10 @@
#include "networkd-link.h"
#include "networkd-network.h"
#include "networkd-util.h"
#include "sfq.h"
#include "tbf.h"
typedef struct QDiscs {
typedef struct QDisc {
NetworkConfigSection *section;
Network *network;
@ -20,15 +22,21 @@ typedef struct QDiscs {
uint32_t parent;
bool has_network_emulator:1;
bool has_token_buffer_filter:1;
bool has_stochastic_fairness_queueing:1;
NetworkEmulator ne;
} QDiscs;
TokenBufferFilter tbf;
StochasticFairnessQueueing sfq;
} QDisc;
void qdisc_free(QDiscs *qdisc);
int qdisc_new_static(Network *network, const char *filename, unsigned section_line, QDiscs **ret);
void qdisc_free(QDisc *qdisc);
int qdisc_new_static(Network *network, const char *filename, unsigned section_line, QDisc **ret);
int qdisc_configure(Link *link, QDiscs *qdisc);
int qdisc_configure(Link *link, QDisc *qdisc);
DEFINE_NETWORK_SECTION_FUNCTIONS(QDiscs, qdisc_free);
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact);
DEFINE_NETWORK_SECTION_FUNCTIONS(QDisc, qdisc_free);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_qdiscs_parent);

87
src/network/tc/sfq.c Normal file
View File

@ -0,0 +1,87 @@
/* SPDX-License-Identifier: LGPL-2.1+
* Copyright © 2019 VMware, Inc. */
#include <linux/pkt_sched.h>
#include "alloc-util.h"
#include "conf-parser.h"
#include "netlink-util.h"
#include "parse-util.h"
#include "qdisc.h"
#include "sfq.h"
#include "string-util.h"
int stochastic_fairness_queueing_new(StochasticFairnessQueueing **ret) {
StochasticFairnessQueueing *sfq = NULL;
sfq = new0(StochasticFairnessQueueing, 1);
if (!sfq)
return -ENOMEM;
*ret = TAKE_PTR(sfq);
return 0;
}
int stochastic_fairness_queueing_fill_message(Link *link, const StochasticFairnessQueueing *sfq, sd_netlink_message *req) {
struct tc_sfq_qopt_v1 opt = {};
int r;
assert(link);
assert(sfq);
assert(req);
opt.v0.perturb_period = sfq->perturb_period / USEC_PER_SEC;
r = sd_netlink_message_append_data(req, TCA_OPTIONS, &opt, sizeof(struct tc_sfq_qopt_v1));
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_OPTIONS attribute: %m");
return 0;
}
int config_parse_tc_stochastic_fairness_queueing_perturb_period(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = qdisc_new_static(network, filename, section_line, &qdisc);
if (r < 0)
return r;
if (isempty(rvalue)) {
qdisc->sfq.perturb_period = 0;
qdisc = NULL;
return 0;
}
r = parse_sec(rvalue, &qdisc->sfq.perturb_period);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse '%s=', ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
qdisc->has_stochastic_fairness_queueing = true;
qdisc = NULL;
return 0;
}

17
src/network/tc/sfq.h Normal file
View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: LGPL-2.1+
* Copyright © 2019 VMware, Inc. */
#pragma once
#include "sd-netlink.h"
#include "conf-parser.h"
#include "networkd-link.h"
typedef struct StochasticFairnessQueueing {
usec_t perturb_period;
} StochasticFairnessQueueing;
int stochastic_fairness_queueing_new(StochasticFairnessQueueing **ret);
int stochastic_fairness_queueing_fill_message(Link *link, const StochasticFairnessQueueing *sfq, sd_netlink_message *req);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_stochastic_fairness_queueing_perturb_period);

167
src/network/tc/tbf.c Normal file
View File

@ -0,0 +1,167 @@
/* SPDX-License-Identifier: LGPL-2.1+
* Copyright © 2019 VMware, Inc. */
#include <linux/pkt_sched.h>
#include <math.h>
#include "alloc-util.h"
#include "conf-parser.h"
#include "netem.h"
#include "netlink-util.h"
#include "networkd-manager.h"
#include "parse-util.h"
#include "qdisc.h"
#include "string-util.h"
#include "util.h"
int token_buffer_filter_new(TokenBufferFilter **ret) {
TokenBufferFilter *ne = NULL;
ne = new0(TokenBufferFilter, 1);
if (!ne)
return -ENOMEM;
*ret = TAKE_PTR(ne);
return 0;
}
int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, sd_netlink_message *req) {
struct tc_tbf_qopt opt = {};
int r;
assert(link);
assert(tbf);
assert(req);
opt.rate.rate = tbf->rate >= (1ULL << 32) ? ~0U : tbf->rate;
opt.limit = tbf->rate * (double) tbf->latency / USEC_PER_SEC + tbf->burst;
r = sd_netlink_message_open_array(req, TCA_OPTIONS);
if (r < 0)
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
r = sd_netlink_message_append_data(req, TCA_TBF_PARMS, &opt, sizeof(struct tc_tbf_qopt));
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_TBF_PARMS attribute: %m");
r = sd_netlink_message_append_data(req, TCA_TBF_BURST, &tbf->burst, sizeof(tbf->burst));
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_TBF_BURST attribute: %m");
if (tbf->rate >= (1ULL << 32)) {
r = sd_netlink_message_append_data(req, TCA_TBF_RATE64, &tbf->rate, sizeof(tbf->rate));
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_TBF_RATE64 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");
return 0;
}
int config_parse_tc_token_buffer_filter_size(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
uint64_t k;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = qdisc_new_static(network, filename, section_line, &qdisc);
if (r < 0)
return r;
if (isempty(rvalue)) {
if (streq(lvalue, "TokenBufferFilterRate"))
qdisc->tbf.rate = 0;
else if (streq(lvalue, "TokenBufferFilterBurst"))
qdisc->tbf.burst = 0;
qdisc = NULL;
return 0;
}
r = parse_size(rvalue, 1000, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse '%s=', ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
if (streq(lvalue, "TokenBufferFilterRate"))
qdisc->tbf.rate = k / 8;
else if (streq(lvalue, "TokenBufferFilterBurst"))
qdisc->tbf.burst = k;
qdisc->has_token_buffer_filter = true;
qdisc = NULL;
return 0;
}
int config_parse_tc_token_buffer_filter_latency(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
usec_t u;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = qdisc_new_static(network, filename, section_line, &qdisc);
if (r < 0)
return r;
if (isempty(rvalue)) {
qdisc->tbf.latency = 0;
qdisc = NULL;
return 0;
}
r = parse_sec(rvalue, &u);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse '%s=', ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
qdisc->tbf.latency = u;
qdisc->has_token_buffer_filter = true;
qdisc = NULL;
return 0;
}

21
src/network/tc/tbf.h Normal file
View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: LGPL-2.1+
* Copyright © 2019 VMware, Inc. */
#pragma once
#include "sd-netlink.h"
#include "conf-parser.h"
#include "networkd-link.h"
typedef struct TokenBufferFilter {
uint64_t rate;
uint32_t burst;
uint32_t latency;
} TokenBufferFilter;
int token_buffer_filter_new(TokenBufferFilter **ret);
int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, sd_netlink_message *req);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_latency);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_size);

View File

@ -270,3 +270,7 @@ NetworkEmulatorDelayJitterSec=
NetworkEmulatorLossRate=
NetworkEmulatorDuplicateRate=
NetworkEmulatorPacketLimit=
TokenBufferFilterRate=
TokenBufferFilterBurst=
TokenBufferFilterLatencySec=
StochasticFairnessQueueingPerturbPeriodSec=

View File

@ -0,0 +1,16 @@
[Match]
Name=test1
[Network]
IPv6AcceptRA=no
Address=10.1.2.4/16
[TrafficControlQueueingDiscipline]
Parent=root
TokenBufferFilterRate=0.5M
TokenBufferFilterBurst=5K
TokenBufferFilterLatencySec=70msec
[TrafficControlQueueingDiscipline]
Parent=clsact
StochasticFairnessQueueingPerturbPeriodSec=5sec

View File

@ -1498,7 +1498,8 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
'25-neighbor-ip-dummy.network',
'25-neighbor-ip.network',
'25-nexthop.network',
'25-qdisc.network',
'25-qdisc-netem.network',
'25-qdisc-tbf-and-sfq.network',
'25-route-ipv6-src.network',
'25-route-static.network',
'25-gateway-static.network',
@ -2057,15 +2058,23 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, '192.168.5.1')
def test_qdisc(self):
copy_unit_to_networkd_unit_path('25-qdisc.network', '12-dummy.netdev')
copy_unit_to_networkd_unit_path('25-qdisc-netem.network', '12-dummy.netdev',
'25-qdisc-tbf-and-sfq.network', '11-dummy.netdev')
start_networkd()
self.wait_online(['dummy98:routable'])
self.wait_online(['dummy98:routable', 'test1:routable'])
output = check_output('tc qdisc show dev dummy98')
print(output)
self.assertRegex(output, 'qdisc netem')
self.assertRegex(output, 'limit 100 delay 50.0ms 10.0ms loss 20%')
self.assertRegex(output, 'limit 200 delay 100.0ms 13.0ms loss 20.5%')
output = check_output('tc qdisc show dev test1')
print(output)
self.assertRegex(output, 'qdisc tbf')
self.assertRegex(output, 'rate 500Kbit burst 5000b lat 70.0ms')
self.assertRegex(output, 'qdisc sfq')
self.assertRegex(output, 'perturb 5sec')
class NetworkdStateFileTests(unittest.TestCase, Utilities):
links = [