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=