network: tc: support more attributes for FQ-CoDel

This commit is contained in:
Yu Watanabe 2019-12-12 17:25:29 +09:00
parent 3d85f19ced
commit ac810b75c1
7 changed files with 355 additions and 9 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=