diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2020-02-06 17:52:24 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2020-02-07 17:41:49 +0900 |
commit | 9b749c11e20bae3e70258dfdc217462003f73534 (patch) | |
tree | f8f8ba25f2596a093c2fccf628d07f749f497afa | |
parent | ab9dc1db477e4810c7da4548604b6a6b72388342 (diff) | |
download | systemd-9b749c11e20bae3e70258dfdc217462003f73534.tar.gz |
network: tc: support teql
Closes #14792.
-rw-r--r-- | man/systemd.network.xml | 25 | ||||
-rw-r--r-- | src/network/meson.build | 2 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 2 | ||||
-rw-r--r-- | src/network/networkd-network.c | 3 | ||||
-rw-r--r-- | src/network/tc/qdisc.c | 21 | ||||
-rw-r--r-- | src/network/tc/qdisc.h | 3 | ||||
-rw-r--r-- | src/network/tc/teql.c | 90 | ||||
-rw-r--r-- | src/network/tc/teql.h | 16 | ||||
-rw-r--r-- | test/fuzz/fuzz-network-parser/directives.network | 3 |
9 files changed, 158 insertions, 7 deletions
diff --git a/man/systemd.network.xml b/man/systemd.network.xml index d8485f736f..6a2dd0d04c 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2678,6 +2678,31 @@ </refsect1> <refsect1> + <title>[TrivialLinkEqualizer] Section Options</title> + <para>The <literal>[TrivialLinkEqualizer]</literal> section manages the queueing discipline (qdisc) of + trivial link equalizer (teql).</para> + + <variablelist class='network-directives'> + <varlistentry> + <term><varname>Parent=</varname></term> + <listitem> + <para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>, + <literal>clsact</literal> or <literal>ingress</literal>. Defaults to <literal>root</literal>.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>Id=</varname></term> + <listitem> + <para>Specifies the interface ID <literal>N</literal> of teql. Defaults to <literal>0</literal>. + Note that when teql is used, currently, the module <constant>sch_teql</constant> with + <constant>max_equalizers=N+1</constant> option must be loaded before + <command>systemd-networkd</command> is started.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> <title>[BridgeVLAN] Section Options</title> <para>The <literal>[BridgeVLAN]</literal> section manages the VLAN ID configuration of a bridge port and accepts the following keys. Specify several <literal>[BridgeVLAN]</literal> sections to configure several VLAN entries. diff --git a/src/network/meson.build b/src/network/meson.build index 7cb1bb5a38..c1c02cfda1 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -123,6 +123,8 @@ sources = files(''' tc/tbf.h tc/tc-util.c tc/tc-util.h + tc/teql.c + tc/teql.h '''.split()) systemd_networkd_sources = files('networkd.c') diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 81ce9ee1e4..3e2d8d8ee9 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -293,6 +293,8 @@ TokenBucketFilter.MTUBytes, config_parse_token_bucket_filter_si TokenBucketFilter.MPUBytes, config_parse_token_bucket_filter_size, QDISC_KIND_TBF, 0 TokenBucketFilter.PeakRate, config_parse_token_bucket_filter_size, QDISC_KIND_TBF, 0 TokenBucketFilter.LatencySec, config_parse_token_bucket_filter_latency, QDISC_KIND_TBF, 0 +TrivialLinkEqualizer.Parent, config_parse_qdisc_parent, QDISC_KIND_TEQL, 0 +TrivialLinkEqualizer.Id, config_parse_trivial_link_equalizer_id, QDISC_KIND_TEQL, 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) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 96f9c785ba..b06ae75c05 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -488,7 +488,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi "FairQueueingControlledDelay\0" "NetworkEmulator\0" "StochasticFairnessQueueing\0" - "TokenBucketFilter\0", + "TokenBucketFilter\0" + "TrivialLinkEqualizer\0", config_item_perf_lookup, network_network_gperf_lookup, CONFIG_PARSE_WARN, network); if (r < 0) diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index f1527cc1f5..0d622c8aaf 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -20,6 +20,7 @@ const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = { [QDISC_KIND_NETEM] = &netem_vtable, [QDISC_KIND_SFQ] = &sfq_vtable, [QDISC_KIND_TBF] = &tbf_vtable, + [QDISC_KIND_TEQL] = &teql_vtable, }; static int qdisc_new(QDiscKind kind, QDisc **ret) { @@ -176,13 +177,21 @@ int qdisc_configure(Link *link, QDisc *qdisc) { } if (QDISC_VTABLE(qdisc)) { - r = sd_netlink_message_append_string(req, TCA_KIND, QDISC_VTABLE(qdisc)->tca_kind); - if (r < 0) - return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m"); + if (QDISC_VTABLE(qdisc)->fill_tca_kind) { + r = QDISC_VTABLE(qdisc)->fill_tca_kind(link, qdisc, req); + if (r < 0) + return r; + } else { + r = sd_netlink_message_append_string(req, TCA_KIND, QDISC_VTABLE(qdisc)->tca_kind); + if (r < 0) + return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m"); + } - r = QDISC_VTABLE(qdisc)->fill_message(link, qdisc, req); - if (r < 0) - return r; + if (QDISC_VTABLE(qdisc)->fill_message) { + r = QDISC_VTABLE(qdisc)->fill_message(link, qdisc, req); + if (r < 0) + return r; + } } else { r = sd_netlink_message_append_string(req, TCA_KIND, qdisc->tca_kind); if (r < 0) diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index bae4d1ab3f..b1753e4d95 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -14,6 +14,7 @@ typedef enum QDiscKind { QDISC_KIND_NETEM, QDISC_KIND_SFQ, QDISC_KIND_TBF, + QDISC_KIND_TEQL, _QDISC_KIND_MAX, _QDISC_KIND_INVALID = -1, } QDiscKind; @@ -35,6 +36,7 @@ typedef struct QDiscVTable { const char *tca_kind; /* called in qdisc_new() */ int (*init)(QDisc *qdisc); + int (*fill_tca_kind)(Link *link, QDisc *qdisc, sd_netlink_message *m); int (*fill_message)(Link *link, QDisc *qdisc, sd_netlink_message *m); int (*verify)(QDisc *qdisc); } QDiscVTable; @@ -71,3 +73,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_parent); #include "netem.h" #include "sfq.h" #include "tbf.h" +#include "teql.h" diff --git a/src/network/tc/teql.c b/src/network/tc/teql.c new file mode 100644 index 0000000000..aac9499616 --- /dev/null +++ b/src/network/tc/teql.c @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "macro.h" +#include "netlink-util.h" +#include "parse-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "teql.h" + +static int trivial_link_equalizer_fill_tca_kind(Link *link, QDisc *qdisc, sd_netlink_message *req) { + char kind[STRLEN("teql") + DECIMAL_STR_MAX(unsigned)]; + TrivialLinkEqualizer *teql; + int r; + + assert(link); + assert(qdisc); + assert(req); + + teql = TEQL(qdisc); + + xsprintf(kind, "teql%u", teql->id); + r = sd_netlink_message_append_string(req, TCA_KIND, kind); + if (r < 0) + return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m"); + + return 0; +} + +const QDiscVTable teql_vtable = { + .object_size = sizeof(TrivialLinkEqualizer), + .fill_tca_kind = trivial_link_equalizer_fill_tca_kind, +}; + +int config_parse_trivial_link_equalizer_id( + 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; + TrivialLinkEqualizer *teql; + Network *network = data; + unsigned id; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = qdisc_new_static(QDISC_KIND_TEQL, 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"); + + teql = TEQL(qdisc); + + if (isempty(rvalue)) { + teql->id = 0; + + qdisc = NULL; + return 0; + } + + r = safe_atou(rvalue, &id); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse '%s=', ignoring assignment: %s", + lvalue, rvalue); + return 0; + } + if (id > INT_MAX) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "'%s=' is too large, ignoring assignment: %s", + lvalue, rvalue); + } + + teql->id = id; + + qdisc = NULL; + return 0; +} diff --git a/src/network/tc/teql.h b/src/network/tc/teql.h new file mode 100644 index 0000000000..5b091aaf0f --- /dev/null +++ b/src/network/tc/teql.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "conf-parser.h" +#include "qdisc.h" + +typedef struct TrivialLinkEqualizer { + QDisc meta; + + unsigned id; +} TrivialLinkEqualizer; + +DEFINE_QDISC_CAST(TEQL, TrivialLinkEqualizer); +extern const QDiscVTable teql_vtable; + +CONFIG_PARSER_PROTOTYPE(config_parse_trivial_link_equalizer_id); diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 5b04fefeb5..cfee5db02f 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -326,3 +326,6 @@ NetworkEmulatorDelayJitterSec= NetworkEmulatorLossRate= NetworkEmulatorDuplicateRate= NetworkEmulatorPacketLimit= +[TrivialLinkEqualizer] +Parent= +Id= |