Merge pull request #14320 from yuwata/network-tc-fq_codel-more

network: tc: introduce more FQ-CoDel settings
This commit is contained in:
Yu Watanabe
2019-12-13 11:09:36 +09:00
committed by GitHub
9 changed files with 363 additions and 10 deletions

View File

@@ -2450,6 +2450,64 @@
</listitem>
</varlistentry>
<varlistentry>
<term><varname>FairQueuingControlledDelayMemoryLimit=</varname></term>
<listitem>
<para>Specifies the limit on the total number of bytes that can be queued in this FQ-CoDel instance.
When suffixed with K, M, or G, the specified size is parsed as Kilobytes, Megabytes, or Gigabytes,
respectively, to the base of 1024. Defaults to unset and kernel's default is used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>FairQueuingControlledDelayFlows=</varname></term>
<listitem>
<para>Specifies the number of flows into which the incoming packets are classified.
Defaults to unset and kernel's default is used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>FairQueuingControlledDelayTargetSec=</varname></term>
<listitem>
<para>Takes a timespan. Specifies the acceptable minimum standing/persistent queue delay.
Defaults to unset and kernel's default is used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>FairQueuingControlledDelayIntervalSec=</varname></term>
<listitem>
<para>Takes a timespan. This is used to ensure that the measured minimum delay does not
become too stale. Defaults to unset and kernel's default is used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>FairQueuingControlledDelayQuantum=</varname></term>
<listitem>
<para>Specifies the number of bytes used as 'deficit' in the fair queuing algorithmtimespan.
When suffixed with K, M, or G, the specified size is parsed as Kilobytes, Megabytes, or Gigabytes,
respectively, to the base of 1024. Defaults to unset and kernel's default is used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>FairQueuingControlledDelayECN=</varname></term>
<listitem>
<para>Takes a boolean. This can be used to mark packets instead of dropping them. Defaults to
unset and kernel's default is used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>FairQueuingControlledDelayCEThresholdSec=</varname></term>
<listitem>
<para>Takes a timespan. This sets a threshold above which all packets are marked with ECN
Congestion Experienced (CE). Defaults to unset and kernel's default is used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>FairQueueTrafficPolicingPacketLimit=</varname></term>
<listitem>

View File

@@ -258,7 +258,14 @@ TrafficControlQueueingDiscipline.TokenBufferFilterMPUBytes, con
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
TrafficControlQueueingDiscipline.FairQueuingControlledDelayPacketLimit, config_parse_tc_fair_queuing_controlled_delay_limit, 0, 0
TrafficControlQueueingDiscipline.FairQueuingControlledDelayPacketLimit, config_parse_tc_fair_queuing_controlled_delay_u32, 0, 0
TrafficControlQueueingDiscipline.FairQueuingControlledDelayMemoryLimit, config_parse_tc_fair_queuing_controlled_delay_size, 0, 0
TrafficControlQueueingDiscipline.FairQueuingControlledDelayFlows, config_parse_tc_fair_queuing_controlled_delay_u32, 0, 0
TrafficControlQueueingDiscipline.FairQueuingControlledDelayQuantum, config_parse_tc_fair_queuing_controlled_delay_size, 0, 0
TrafficControlQueueingDiscipline.FairQueuingControlledDelayTargetSec, config_parse_tc_fair_queuing_controlled_delay_usec, 0, 0
TrafficControlQueueingDiscipline.FairQueuingControlledDelayIntervalSec, config_parse_tc_fair_queuing_controlled_delay_usec, 0, 0
TrafficControlQueueingDiscipline.FairQueuingControlledDelayCEThresholdSec, config_parse_tc_fair_queuing_controlled_delay_usec, 0, 0
TrafficControlQueueingDiscipline.FairQueuingControlledDelayECN, config_parse_tc_fair_queuing_controlled_delay_bool, 0, 0
TrafficControlQueueingDiscipline.FairQueueTrafficPolicingPacketLimit, config_parse_tc_fair_queue_traffic_policing_packet_limit, 0, 0
/* backwards compatibility: do not add new entries to this section */
Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local)

View File

@@ -10,6 +10,20 @@
#include "qdisc.h"
#include "string-util.h"
static int fair_queuing_controlled_delay_init(QDisc *qdisc) {
FairQueuingControlledDelay *fqcd;
assert(qdisc);
fqcd = FQ_CODEL(qdisc);
fqcd->memory_limit = UINT32_MAX;
fqcd->ce_threshold_usec = USEC_INFINITY;
fqcd->ecn = -1;
return 0;
}
static int fair_queuing_controlled_delay_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
FairQueuingControlledDelay *fqcd;
int r;
@@ -24,9 +38,53 @@ static int fair_queuing_controlled_delay_fill_message(Link *link, QDisc *qdisc,
if (r < 0)
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_LIMIT, fqcd->limit);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_LIMIT attribute: %m");
if (fqcd->packet_limit > 0) {
r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_LIMIT, fqcd->packet_limit);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_LIMIT attribute: %m");
}
if (fqcd->flows > 0) {
r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_FLOWS, fqcd->flows);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_FLOWS attribute: %m");
}
if (fqcd->quantum > 0) {
r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_QUANTUM, fqcd->quantum);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_QUANTUM attribute: %m");
}
if (fqcd->interval_usec > 0) {
r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_INTERVAL, fqcd->interval_usec);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_INTERVAL attribute: %m");
}
if (fqcd->target_usec > 0) {
r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_TARGET, fqcd->target_usec);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_TARGET attribute: %m");
}
if (fqcd->ecn >= 0) {
r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_ECN, fqcd->ecn);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_ECN attribute: %m");
}
if (fqcd->ce_threshold_usec != USEC_INFINITY) {
r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_CE_THRESHOLD, fqcd->ce_threshold_usec);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_CE_THRESHOLD attribute: %m");
}
if (fqcd->memory_limit != UINT32_MAX) {
r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_MEMORY_LIMIT, fqcd->memory_limit);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_MEMORY_LIMIT attribute: %m");
}
r = sd_netlink_message_close_container(req);
if (r < 0)
@@ -35,7 +93,130 @@ static int fair_queuing_controlled_delay_fill_message(Link *link, QDisc *qdisc,
return 0;
}
int config_parse_tc_fair_queuing_controlled_delay_limit(
int config_parse_tc_fair_queuing_controlled_delay_u32(
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;
FairQueuingControlledDelay *fqcd;
Network *network = data;
uint32_t *p;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_syntax(unit, LOG_ERR, filename, line, r,
"More than one kind of queueing discipline, ignoring assignment: %m");
fqcd = FQ_CODEL(qdisc);
if (streq(lvalue, "FairQueuingControlledDelayPacketLimit"))
p = &fqcd->packet_limit;
else if (streq(lvalue, "FairQueuingControlledDelayFlows"))
p = &fqcd->flows;
else
assert_not_reached("Invalid lvalue.");
if (isempty(rvalue)) {
*p = 0;
qdisc = NULL;
return 0;
}
r = safe_atou32(rvalue, p);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse '%s=', ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
qdisc = NULL;
return 0;
}
int config_parse_tc_fair_queuing_controlled_delay_usec(
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;
FairQueuingControlledDelay *fqcd;
Network *network = data;
usec_t *p;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_syntax(unit, LOG_ERR, filename, line, r,
"More than one kind of queueing discipline, ignoring assignment: %m");
fqcd = FQ_CODEL(qdisc);
if (streq(lvalue, "FairQueuingControlledDelayTargetSec"))
p = &fqcd->target_usec;
else if (streq(lvalue, "FairQueuingControlledDelayIntervalSec"))
p = &fqcd->interval_usec;
else if (streq(lvalue, "FairQueuingControlledDelayCEThresholdSec"))
p = &fqcd->ce_threshold_usec;
else
assert_not_reached("Invalid lvalue.");
if (isempty(rvalue)) {
if (streq(lvalue, "FairQueuingControlledDelayCEThresholdSec"))
*p = USEC_INFINITY;
else
*p = 0;
qdisc = NULL;
return 0;
}
r = parse_sec(rvalue, p);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse '%s=', ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
qdisc = NULL;
return 0;
}
int config_parse_tc_fair_queuing_controlled_delay_bool(
const char *unit,
const char *filename,
unsigned line,
@@ -67,13 +248,13 @@ int config_parse_tc_fair_queuing_controlled_delay_limit(
fqcd = FQ_CODEL(qdisc);
if (isempty(rvalue)) {
fqcd->limit = 0;
fqcd->ecn = -1;
qdisc = NULL;
return 0;
}
r = safe_atou32(rvalue, &fqcd->limit);
r = parse_boolean(rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse '%s=', ignoring assignment: %s",
@@ -81,6 +262,77 @@ int config_parse_tc_fair_queuing_controlled_delay_limit(
return 0;
}
fqcd->ecn = r;
qdisc = NULL;
return 0;
}
int config_parse_tc_fair_queuing_controlled_delay_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;
FairQueuingControlledDelay *fqcd;
Network *network = data;
uint64_t sz;
uint32_t *p;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_syntax(unit, LOG_ERR, filename, line, r,
"More than one kind of queueing discipline, ignoring assignment: %m");
fqcd = FQ_CODEL(qdisc);
if (streq(lvalue, "FairQueuingControlledDelayMemoryLimit"))
p = &fqcd->memory_limit;
else if (streq(lvalue, "FairQueuingControlledDelayQuantum"))
p = &fqcd->quantum;
else
assert_not_reached("Invalid lvalue.");
if (isempty(rvalue)) {
if (streq(lvalue, "FairQueuingControlledMemoryLimit"))
*p = UINT32_MAX;
else
*p = 0;
qdisc = NULL;
return 0;
}
r = parse_size(rvalue, 1024, &sz);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse '%s=', ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
if (sz >= UINT32_MAX) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Specified '%s=' is too large, ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
*p = sz;
qdisc = NULL;
return 0;
@@ -89,5 +341,6 @@ int config_parse_tc_fair_queuing_controlled_delay_limit(
const QDiscVTable fq_codel_vtable = {
.object_size = sizeof(FairQueuingControlledDelay),
.tca_kind = "fq_codel",
.init = fair_queuing_controlled_delay_init,
.fill_message = fair_queuing_controlled_delay_fill_message,
};

View File

@@ -4,13 +4,25 @@
#include "conf-parser.h"
#include "qdisc.h"
#include "time-util.h"
typedef struct FairQueuingControlledDelay {
QDisc meta;
uint32_t limit;
uint32_t packet_limit;
uint32_t flows;
uint32_t quantum;
uint32_t memory_limit;
usec_t target_usec;
usec_t interval_usec;
usec_t ce_threshold_usec;
int ecn;
} FairQueuingControlledDelay;
DEFINE_QDISC_CAST(FQ_CODEL, FairQueuingControlledDelay);
extern const QDiscVTable fq_codel_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_tc_fair_queuing_controlled_delay_limit);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_fair_queuing_controlled_delay_u32);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_fair_queuing_controlled_delay_usec);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_fair_queuing_controlled_delay_bool);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_fair_queuing_controlled_delay_size);

View File

@@ -23,6 +23,7 @@ const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = {
static int qdisc_new(QDiscKind kind, QDisc **ret) {
QDisc *qdisc;
int r;
if (kind == _QDISC_KIND_INVALID) {
qdisc = new(QDisc, 1);
@@ -42,6 +43,12 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) {
qdisc->family = AF_UNSPEC;
qdisc->parent = TC_H_ROOT;
qdisc->kind = kind;
if (QDISC_VTABLE(qdisc)->init) {
r = QDISC_VTABLE(qdisc)->init(qdisc);
if (r < 0)
return r;
}
}
*ret = TAKE_PTR(qdisc);

View File

@@ -32,6 +32,8 @@ typedef struct QDisc {
typedef struct QDiscVTable {
size_t object_size;
const char *tca_kind;
/* called in qdisc_new() */
int (*init)(QDisc *qdisc);
int (*fill_message)(Link *link, QDisc *qdisc, sd_netlink_message *m);
int (*verify)(QDisc *qdisc);
} QDiscVTable;

View File

@@ -279,4 +279,11 @@ TokenBufferFilterPeakRate=
TokenBufferFilterLatencySec=
StochasticFairnessQueueingPerturbPeriodSec=
FairQueuingControlledDelayPacketLimit=
FairQueuingControlledDelayMemoryLimit=
FairQueuingControlledDelayFlows=
FairQueuingControlledDelayQuantum=
FairQueuingControlledDelayTargetSec=
FairQueuingControlledDelayIntervalSec=
FairQueuingControlledDelayCEThresholdSec=
FairQueuingControlledDelayECN=
FairQueueTrafficPolicingPacketLimit=

View File

@@ -15,3 +15,10 @@ NetworkEmulatorPacketLimit=100
[TrafficControlQueueingDiscipline]
Parent=ingress
FairQueuingControlledDelayPacketLimit=20480
FairQueuingControlledDelayMemoryLimit=64M
FairQueuingControlledDelayFlows=2048
FairQueuingControlledDelayTargetSec=10ms
FairQueuingControlledDelayIntervalSec=200ms
FairQueuingControlledDelayQuantum=1400
FairQueuingControlledDelayECN=yes
FairQueuingControlledDelayCEThresholdSec=100ms

View File

@@ -2095,7 +2095,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'qdisc netem')
self.assertRegex(output, 'limit 100 delay 50.0ms 10.0ms loss 20%')
self.assertRegex(output, 'qdisc fq_codel')
self.assertRegex(output, 'limit 20480p')
self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
output = check_output('tc qdisc show dev test1')
print(output)
self.assertRegex(output, 'qdisc tbf')