diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 299f241ae1..77a3b240d9 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2562,7 +2562,49 @@ incoming packets are dropped. An unsigned integer ranges 0 to 4294967294. Defaults to unset and kernel's default is used. + + + + [CAKE] Section Options + The [CAKE] section manages the queueing discipline (qdisc) of + Common Applications Kept Enhanced (CAKE). + + + + Parent= + + Specifies the parent Queueing Discipline (qdisc). Takes one of root, + clsact, ingress or a class id. The class id takes the + major and minor number in hexadecimal ranges 1 to ffff separated with a colon + (major:minor). Defaults to root. + + + + + Handle= + + Specifies the major number of unique identifier of the qdisc, known as the handle. + Takes a number in hexadecimal ranges 1 to ffff. Defaults to unset. + + + + + Overhead= + + Specifies that bytes to be addeded to the size of each packet. Bytes may be negative. + Takes an integer ranges -64 to 256. Defaults to unset and kernel's default is used. + + + + + Bandwidth= + + Specifies the shaper bandwidth. When suffixed with K, M, or G, the specified size is + parsed as Kilobits, Megabits, or Gigabits, respectively, to the base of 1000. Defaults to + unset and kernel's default is used. + + diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 4a24405487..4846b6f74e 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -745,6 +745,12 @@ static const NLTypeSystem rtnl_nexthop_type_system = { .types = rtnl_nexthop_types, }; +static const NLType rtnl_tca_option_data_cake_types[] = { + [TCA_CAKE_BASE_RATE64] = { .type = NETLINK_TYPE_U64 }, + [TCA_CAKE_OVERHEAD] = { .type = NETLINK_TYPE_S32 }, + [TCA_CAKE_MPU] = { .type = NETLINK_TYPE_U32 }, +}; + static const NLType rtnl_tca_option_data_codel_types[] = { [TCA_CODEL_TARGET] = { .type = NETLINK_TYPE_U32 }, [TCA_CODEL_LIMIT] = { .type = NETLINK_TYPE_U32 }, @@ -808,6 +814,7 @@ static const NLType rtnl_tca_option_data_tbf_types[] = { }; static const char* const nl_union_tca_option_data_table[] = { + [NL_UNION_TCA_OPTION_DATA_CAKE] = "cake", [NL_UNION_TCA_OPTION_DATA_CODEL] = "codel", [NL_UNION_TCA_OPTION_DATA_FQ] = "fq", [NL_UNION_TCA_OPTION_DATA_FQ_CODEL] = "fq_codel", @@ -820,6 +827,8 @@ static const char* const nl_union_tca_option_data_table[] = { DEFINE_STRING_TABLE_LOOKUP(nl_union_tca_option_data, NLUnionTCAOptionData); static const NLTypeSystem rtnl_tca_option_data_type_systems[] = { + [NL_UNION_TCA_OPTION_DATA_CAKE] = { .count = ELEMENTSOF(rtnl_tca_option_data_cake_types), + .types = rtnl_tca_option_data_cake_types }, [NL_UNION_TCA_OPTION_DATA_CODEL] = { .count = ELEMENTSOF(rtnl_tca_option_data_codel_types), .types = rtnl_tca_option_data_codel_types }, [NL_UNION_TCA_OPTION_DATA_FQ] = { .count = ELEMENTSOF(rtnl_tca_option_data_fq_types), diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index cda99c1be0..edc4a580b8 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -96,6 +96,7 @@ const char *nl_union_link_info_data_to_string(NLUnionLinkInfoData p) _const_; NLUnionLinkInfoData nl_union_link_info_data_from_string(const char *p) _pure_; typedef enum NLUnionTCAOptionData { + NL_UNION_TCA_OPTION_DATA_CAKE, NL_UNION_TCA_OPTION_DATA_CODEL, NL_UNION_TCA_OPTION_DATA_FQ, NL_UNION_TCA_OPTION_DATA_FQ_CODEL, diff --git a/src/network/meson.build b/src/network/meson.build index 8733812279..57d3772c3e 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -107,6 +107,8 @@ sources = files(''' networkd-util.h networkd-wifi.c networkd-wifi.h + tc/cake.c + tc/cake.h tc/codel.c tc/codel.h tc/fifo.c diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 881138df1b..12a430762f 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -254,6 +254,10 @@ CAN.RestartSec, config_parse_sec, CAN.TripleSampling, config_parse_tristate, 0, offsetof(Network, can_triple_sampling) QDisc.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0 QDisc.Handle, config_parse_qdisc_handle, _QDISC_KIND_INVALID, 0 +CAKE.Parent, config_parse_qdisc_parent, QDISC_KIND_CAKE, 0 +CAKE.Handle, config_parse_qdisc_handle, QDISC_KIND_CAKE, 0 +CAKE.Bandwidth, config_parse_cake_bandwidth, QDISC_KIND_CAKE, 0 +CAKE.Overhead, config_parse_cake_overhead, QDISC_KIND_CAKE, 0 ControlledDelay.Parent, config_parse_qdisc_parent, QDISC_KIND_CODEL, 0 ControlledDelay.Handle, config_parse_qdisc_handle, QDISC_KIND_CODEL, 0 ControlledDelay.PacketLimit, config_parse_controlled_delay_u32, QDISC_KIND_CODEL, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 6762ba0569..d8049fda7b 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -484,6 +484,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi "TrafficControlQueueingDiscipline\0" "CAN\0" "QDisc\0" + "CAKE\0" "ControlledDelay\0" "PFIFO\0" "FairQueueing\0" diff --git a/src/network/tc/cake.c b/src/network/tc/cake.c new file mode 100644 index 0000000000..b499661bd3 --- /dev/null +++ b/src/network/tc/cake.c @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: LGPL-2.1+ + * Copyright © 2020 VMware, Inc. */ + +#include + +#include "alloc-util.h" +#include "cake.h" +#include "conf-parser.h" +#include "netlink-util.h" +#include "parse-util.h" +#include "qdisc.h" +#include "string-util.h" + +static int cake_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) { + CommonApplicationsKeptEnhanced *c; + int r; + + assert(link); + assert(qdisc); + assert(req); + + c = CAKE(qdisc); + + r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "cake"); + if (r < 0) + return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m"); + + if (c->bandwidth > 0) { + r = sd_netlink_message_append_u64(req, TCA_CAKE_BASE_RATE64, c->bandwidth); + if (r < 0) + return log_link_error_errno(link, r, "Could not append TCA_CAKE_BASE_RATE64 attribute: %m"); + } + + r = sd_netlink_message_append_s32(req, TCA_CAKE_OVERHEAD, c->overhead); + if (r < 0) + return log_link_error_errno(link, r, "Could not append TCA_CAKE_OVERHEAD 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_cake_bandwidth( + 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; + CommonApplicationsKeptEnhanced *c; + Network *network = data; + uint64_t k; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = qdisc_new_static(QDISC_KIND_CAKE, 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"); + + c = CAKE(qdisc); + + if (isempty(rvalue)) { + c->bandwidth = 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; + } + + c->bandwidth = k/8; + qdisc = NULL; + + return 0; +} + +int config_parse_cake_overhead( + 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; + CommonApplicationsKeptEnhanced *c; + Network *network = data; + int32_t v; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = qdisc_new_static(QDISC_KIND_CAKE, 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"); + + c = CAKE(qdisc); + + if (isempty(rvalue)) { + c->overhead = 0; + qdisc = NULL; + return 0; + } + + r = safe_atoi32(rvalue, &v); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse 'Overhead=', ignoring assignment: %s", + rvalue); + return 0; + } + if (v < -64 || v > 256) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Invalid 'Overhead=', ignoring assignment: %s", + rvalue); + return 0; + } + + c->overhead = v; + qdisc = NULL; + return 0; +} + +const QDiscVTable cake_vtable = { + .object_size = sizeof(CommonApplicationsKeptEnhanced), + .tca_kind = "cake", + .fill_message = cake_fill_message, +}; diff --git a/src/network/tc/cake.h b/src/network/tc/cake.h new file mode 100644 index 0000000000..36de5110dd --- /dev/null +++ b/src/network/tc/cake.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: LGPL-2.1+ + * Copyright © 2020 VMware, Inc. */ +#pragma once + +#include "conf-parser.h" +#include "qdisc.h" + +typedef struct CommonApplicationsKeptEnhanced { + QDisc meta; + + int overhead; + uint64_t bandwidth; + +} CommonApplicationsKeptEnhanced; + +DEFINE_QDISC_CAST(CAKE, CommonApplicationsKeptEnhanced); +extern const QDiscVTable cake_vtable; + +CONFIG_PARSER_PROTOTYPE(config_parse_cake_bandwidth); +CONFIG_PARSER_PROTOTYPE(config_parse_cake_overhead); diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index 405ff688b0..31b6a716c4 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -16,6 +16,7 @@ #include "tc-util.h" const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = { + [QDISC_KIND_CAKE] = &cake_vtable, [QDISC_KIND_CODEL] = &codel_vtable, [QDISC_KIND_FQ] = &fq_vtable, [QDISC_KIND_FQ_CODEL] = &fq_codel_vtable, diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index 79323972e3..403d6a5b53 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -9,6 +9,7 @@ #include "tc.h" typedef enum QDiscKind { + QDISC_KIND_CAKE, QDISC_KIND_CODEL, QDISC_KIND_FQ, QDISC_KIND_FQ_CODEL, @@ -77,6 +78,7 @@ DEFINE_TC_CAST(QDISC, QDisc); CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_parent); CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_handle); +#include "cake.h" #include "codel.h" #include "fifo.h" #include "fq-codel.h" diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index f20dabf4ef..66417ef2b0 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -326,6 +326,11 @@ TargetSec= IntervalSec= CEThresholdSec= ECN= +[CAKE] +Parent= +Handle= +Bandwidth= +Overhead= [TrafficControlQueueingDiscipline] Parent= NetworkEmulatorDelaySec=