diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 20723bfbfa..a2ac24059a 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2395,6 +2395,13 @@ + + StochasticFairnessQueueingPerturbPeriodSec= + + Specifies the interval in seconds for queue algorithm perturbation. Defaults to unset. + + + diff --git a/src/network/meson.build b/src/network/meson.build index 3633694577..e2324a01b3 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -109,6 +109,8 @@ 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 diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 32c6afc49e..1bfd76ec73 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -244,15 +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.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.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) diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index e8703399a7..717a0cfd38 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -161,6 +161,16 @@ int qdisc_configure(Link *link, QDisc *qdisc) { 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; + } + if (tca_kind) { r = sd_netlink_message_append_string(req, TCA_KIND, tca_kind); if (r < 0) diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index 4810b87600..1d06dc53f4 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -7,6 +7,7 @@ #include "networkd-link.h" #include "networkd-network.h" #include "networkd-util.h" +#include "sfq.h" #include "tbf.h" typedef struct QDisc { @@ -22,9 +23,11 @@ typedef struct QDisc { bool has_network_emulator:1; bool has_token_buffer_filter:1; + bool has_stochastic_fairness_queueing:1; NetworkEmulator ne; TokenBufferFilter tbf; + StochasticFairnessQueueing sfq; } QDisc; void qdisc_free(QDisc *qdisc); diff --git a/src/network/tc/sfq.c b/src/network/tc/sfq.c new file mode 100644 index 0000000000..393b0e12e1 --- /dev/null +++ b/src/network/tc/sfq.c @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: LGPL-2.1+ + * Copyright © 2019 VMware, Inc. */ + +#include + +#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; +} diff --git a/src/network/tc/sfq.h b/src/network/tc/sfq.h new file mode 100644 index 0000000000..8c00e0e713 --- /dev/null +++ b/src/network/tc/sfq.h @@ -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); diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 1cdbc07a24..2a6f111d83 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -273,3 +273,4 @@ NetworkEmulatorPacketLimit= TokenBufferFilterRate= TokenBufferFilterBurst= TokenBufferFilterLatencySec= +StochasticFairnessQueueingPerturbPeriodSec=