diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 199fcc0a58..8288534ddf 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1150,7 +1150,7 @@ Table=1234
Label=
- The label for the prefix, an unsigned integer in the range 0–4294967294.
+ The label for the prefix, an unsigned integer in the range 0…4294967294.
0xffffffff is reserved. This setting is mandatory.
@@ -1552,7 +1552,7 @@ Table=1234
TCPAdvertisedMaximumSegmentSize=
Specifies the Path MSS (in bytes) hints given on TCP layer. The usual suffixes K, M, G, are
- supported and are understood to the base of 1024. An unsigned integer in the range 1–4294967294.
+ supported and are understood to the base of 1024. An unsigned integer in the range 1…4294967294.
When unset, the kernel's default will be used.
@@ -2049,7 +2049,7 @@ Table=1234
Takes an IPv6 address with prefix length in the same format as the
Address= in the [Network] section. The DHCPv6 client will include a prefix
hint in the DHCPv6 solicitation sent to the server. The prefix length must be in the range
- 1–128. Defaults to unset.
+ 1…128. Defaults to unset.
@@ -3111,7 +3111,7 @@ Token=prefixstable:2002:da8:1::
Termination=
- Takes a boolean or a termination resistor value in ohm in the range 0–65535. When
+ Takes a boolean or a termination resistor value in ohm in the range 0…65535. When
yes, the termination resistor is set to 120 ohm. When
no or 0 is set, the termination resistor is disabled.
When unset, the kernel's default will be used.
@@ -3225,7 +3225,7 @@ Token=prefixstable:2002:da8:1::
PacketLimit=
Specifies the maximum number of packets the qdisc may hold queued at a time.
- An unsigned integer in the range 0–4294967294. Defaults to 1000.
+ An unsigned integer in the range 0…4294967294. Defaults to 1000.
@@ -3374,7 +3374,7 @@ Token=prefixstable:2002:da8:1::
PacketLimit=
Specifies the hard limit on the queue size in number of packets. When this limit is reached,
- incoming packets are dropped. An unsigned integer in the range 0–4294967294. Defaults to unset and
+ incoming packets are dropped. An unsigned integer in the range 0…4294967294. Defaults to unset and
kernel's default is used.
@@ -3436,7 +3436,7 @@ Token=prefixstable:2002:da8:1::
Specifies the hard limit on the number of packets in the FIFO queue. The size limit prevents
overflow in case the kernel is unable to dequeue packets as quickly as it receives them. When this
limit is reached, incoming packets are dropped. An unsigned integer in the range
- 0–4294967294. Defaults to unset and kernel's default is used.
+ 0…4294967294. Defaults to unset and kernel's default is used.
@@ -3479,14 +3479,6 @@ Token=prefixstable:2002:da8:1::
-
- OverheadBytes=
-
- Specifies that bytes to be addeded to the size of each packet. Bytes may be negative. Takes
- an integer in the range from -64 to 256. Defaults to unset and kernel's default is used.
-
-
-
Bandwidth=
@@ -3495,6 +3487,230 @@ Token=prefixstable:2002:da8:1::
unset and kernel's default is used.
+
+
+ AutoRateIngress=
+
+ Takes a boolean value. Enables automatic capacity estimation based on traffic arriving
+ at this qdisc. This is most likely to be useful with cellular links, which tend to change
+ quality randomly. If this setting is enabled, the Bandwidth= setting is
+ used as an initial estimate. Defaults to unset, and the kernel's default is used.
+
+
+
+
+ OverheadBytes=
+
+ Specifies that bytes to be addeded to the size of each packet. Bytes may be negative.
+ Takes an integer in the range -64…256. Defaults to unset and kernel's default is used.
+
+
+
+
+
+ MPUBytes=
+
+ Rounds each packet (including overhead) up to the specified bytes. Takes an integer in
+ the range 1…256. Defaults to unset and kernel's default is used.
+
+
+
+
+ CompensationMode=
+
+ Takes one of none, atm, or ptm.
+ Specifies the compensation mode for overhead calculation. When none, no
+ compensation is taken into account. When atm, enables the compensation for
+ ATM cell framing, which is normally found on ADSL links. When ptm, enables
+ the compensation for PTM encoding, which is normally found on VDSL2 links and uses a 64b/65b
+ encoding scheme. Defaults to unset and the kernel's default is used.
+
+
+
+
+ UseRawPacketSize=
+
+ Takes a boolean value. When true, the packet size reported by the Linux kernel will be
+ used, instead of the underlying IP packet size. Defaults to unset, and the kernel's default
+ is used.
+
+
+
+
+ FlowIsolationMode=
+
+ CAKE places packets from different flows into different queues, then packets from each
+ queue are delivered fairly. This specifies whether the fairness is based on source address,
+ destination address, individual flows, or any combination of those. The available values are:
+
+
+
+
+
+
+ The flow isolation is disabled, and all traffic passes through a single queue.
+
+
+
+
+
+ Flows are defined only by source address. Equivalnet to the srchost
+ option for tc qdisc command. See also
+ tc-cake8.
+
+
+
+
+
+ Flows are defined only by destination address. Equivalnet to the
+ srchost option for tc qdisc command. See also
+ tc-cake8.
+
+
+
+
+
+ Flows are defined by source-destination host pairs. Equivalent to the same option for
+ tc qdisc command. See also
+ tc-cake8.
+
+
+
+
+
+ Flows are defined by the entire 5-tuple of source address, destination address,
+ transport protocol, source port and destination port. Equivalent to the same option for
+ tc qdisc command. See also
+ tc-cake8.
+
+
+
+
+
+ Flows are defined by the 5-tuple (see flows in the above), and
+ fairness is applied first over source addresses, then over individual flows. Equivalnet
+ to the dual-srchost option for tc qdisc command.
+ See also
+ tc-cake8.
+
+
+
+
+
+ Flows are defined by the 5-tuple (see flows in the above), and
+ fairness is applied first over destination addresses, then over individual flows.
+ Equivalnet to the dual-dsthost option for
+ tc qdisc command. See also
+ tc-cake8.
+
+
+
+
+
+ Flows are defined by the 5-tuple (see flows), and fairness is
+ applied over source and destination addresses, and also over individual flows.
+ Equivalnet to the triple-isolate option for
+ tc qdisc command. See also
+ tc-cake8.
+
+
+
+
+ Defaults to unset and the kernel's default is used.
+
+
+
+
+ NAT=
+
+ Takes a boolean value. When true, CAKE performs a NAT lookup before applying
+ flow-isolation rules, to determine the true addresses and port numbers of the packet, to
+ improve fairness between hosts inside the NAT. This has no practical effect when
+ FlowIsolationMode= is none or flows,
+ or if NAT is performed on a different host. Defaults to unset, and the kernel's default is
+ used.
+
+
+
+
+ PriorityQueueingPreset=
+
+ CAKE divides traffic into tins, and each tin has its own independent
+ set of flow-isolation queues, bandwidth threshold, and priority. This specifies the preset of
+ tin profiles. The available values are:
+
+
+
+
+
+ Disables priority queueing by placing all traffic in one tin.
+
+
+
+
+
+ Enables priority queueing based on the legacy interpretation of TOS
+ Precedence field. Use of this preset on the modern Internet is
+ firmly discouraged.
+
+
+
+
+
+ Enables priority queueing based on the Differentiated Service
+ (DiffServ) field with eight tins: Background Traffic, High
+ Throughput, Best Effort, Video Streaming, Low Latency Transactions, Interactive Shell,
+ Minimum Latency, and Network Control.
+
+
+
+
+
+ Enables priority queueing based on the Differentiated Service
+ (DiffServ) field with four tins: Background Traffic, Best Effort,
+ Streaming Media, and Latency Sensitive.
+
+
+
+
+
+ Enables priority queueing based on the Differentiated Service
+ (DiffServ) field with three tins: Background Traffic, Best Effort,
+ and Latency Sensitive.
+
+
+
+
+ Defaults to unset, and the kernel's default is used.
+
+
+
+
+ FirewallMark=
+
+ Takes an integer in the range 1…4294967295. When specified, firewall-mark-based
+ overriding of CAKE's tin selection is enabled. Defaults to unset, and the kernel's default is
+ used.
+
+
+
+
+ Wash=
+
+ Takes a boolean value. When true, CAKE clears the DSCP fields, except for ECN bits, of
+ any packet passing through CAKE. Defaults to unset, and the kernel's default is used.
+
+
+
+
+ SplitGSO=
+
+ Takes a boolean value. When true, CAKE will split General Segmentation Offload (GSO)
+ super-packets into their on-the-wire components and dequeue them individually. Defaults to
+ unset, and the kernel's default is used.
+
+
+
@@ -3511,7 +3727,7 @@ Token=prefixstable:2002:da8:1::
PacketLimit=
Specifies the hard limit on the queue size in number of packets. When this limit is reached,
- incoming packets are dropped. An unsigned integer in the range 0–4294967294. Defaults to unset and
+ incoming packets are dropped. An unsigned integer in the range 0…4294967294. Defaults to unset and
kernel's default is used.
@@ -3595,7 +3811,7 @@ Token=prefixstable:2002:da8:1::
Bands=
- Specifies the number of bands. An unsigned integer in the range 1–16. This value has to be at
+ Specifies the number of bands. An unsigned integer in the range 1…16. This value has to be at
least large enough to cover the strict bands specified through the StrictBands=
and bandwidth-sharing bands specified in QuantumBytes=.
@@ -3605,7 +3821,7 @@ Token=prefixstable:2002:da8:1::
StrictBands=
Specifies the number of bands that should be created in strict mode. An unsigned integer in
- the range 1–16.
+ the range 1…16.
@@ -3977,7 +4193,7 @@ Token=prefixstable:2002:da8:1::
PacketLimit=
Specifies the hard limit on the queue size in number of packets. When this limit is reached,
- incoming packets are dropped. An unsigned integer in the range 0–4294967294. Defaults to unset and
+ incoming packets are dropped. An unsigned integer in the range 0…4294967294. Defaults to unset and
kernel's default is used.
@@ -4034,8 +4250,8 @@ Token=prefixstable:2002:da8:1::
VLAN=
- The VLAN ID allowed on the port. This can be either a single ID or a range M-N. VLAN IDs are valid
- from 1 to 4094.
+ The VLAN ID allowed on the port. This can be either a single ID or a range M-N. Takes
+ an integer in the range 1…4094.
diff --git a/src/libsystemd/sd-netlink/netlink-types-rtnl.c b/src/libsystemd/sd-netlink/netlink-types-rtnl.c
index 2c01751a52..85a6c79396 100644
--- a/src/libsystemd/sd-netlink/netlink-types-rtnl.c
+++ b/src/libsystemd/sd-netlink/netlink-types-rtnl.c
@@ -1028,9 +1028,23 @@ static const NLType rtnl_nexthop_types[] = {
DEFINE_TYPE_SYSTEM(rtnl_nexthop);
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 },
+ [TCA_CAKE_BASE_RATE64] = { .type = NETLINK_TYPE_U64 },
+ [TCA_CAKE_DIFFSERV_MODE] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_ATM] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_FLOW_MODE] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_OVERHEAD] = { .type = NETLINK_TYPE_S32 },
+ [TCA_CAKE_RTT] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_TARGET] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_AUTORATE] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_MEMORY] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_NAT] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_RAW] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_WASH] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_MPU] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_INGRESS] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_ACK_FILTER] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_SPLIT_GSO] = { .type = NETLINK_TYPE_U32 },
+ [TCA_CAKE_FWMARK] = { .type = NETLINK_TYPE_U32 },
};
static const NLType rtnl_tca_option_data_codel_types[] = {
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index bf58efc932..9e23007e50 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -388,7 +388,17 @@ BFIFO.LimitBytes, config_parse_bfifo_size,
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.AutoRateIngress, config_parse_cake_tristate, QDISC_KIND_CAKE, 0
CAKE.OverheadBytes, config_parse_cake_overhead, QDISC_KIND_CAKE, 0
+CAKE.MPUBytes, config_parse_cake_mpu, QDISC_KIND_CAKE, 0
+CAKE.CompensationMode, config_parse_cake_compensation_mode, QDISC_KIND_CAKE, 0
+CAKE.UseRawPacketSize, config_parse_cake_tristate, QDISC_KIND_CAKE, 0
+CAKE.FlowIsolationMode, config_parse_cake_flow_isolation_mode, QDISC_KIND_CAKE, 0
+CAKE.NAT, config_parse_cake_tristate, QDISC_KIND_CAKE, 0
+CAKE.PriorityQueueingPreset, config_parse_cake_priority_queueing_preset, QDISC_KIND_CAKE, 0
+CAKE.FirewallMark, config_parse_cake_fwmark, QDISC_KIND_CAKE, 0
+CAKE.Wash, config_parse_cake_tristate, QDISC_KIND_CAKE, 0
+CAKE.SplitGSO, config_parse_cake_tristate, 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/tc/cake.c b/src/network/tc/cake.c
index 70dd095e93..27b7f8d9f6 100644
--- a/src/network/tc/cake.c
+++ b/src/network/tc/cake.c
@@ -9,8 +9,28 @@
#include "netlink-util.h"
#include "parse-util.h"
#include "qdisc.h"
+#include "string-table.h"
#include "string-util.h"
+static int cake_init(QDisc *qdisc) {
+ CommonApplicationsKeptEnhanced *c;
+
+ assert(qdisc);
+
+ c = CAKE(qdisc);
+
+ c->autorate = -1;
+ c->compensation_mode = _CAKE_COMPENSATION_MODE_INVALID;
+ c->raw = -1;
+ c->flow_isolation_mode = _CAKE_FLOW_ISOLATION_MODE_INVALID;
+ c->nat = -1;
+ c->preset = _CAKE_PRESET_INVALID;
+ c->wash = -1;
+ c->split_gso = -1;
+
+ return 0;
+}
+
static int cake_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
CommonApplicationsKeptEnhanced *c;
int r;
@@ -31,9 +51,72 @@ static int cake_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req)
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");
+ if (c->autorate >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_AUTORATE, c->autorate);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_CAKE_AUTORATE attribute: %m");
+ }
+
+ if (c->overhead_set) {
+ 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");
+ }
+
+ if (c->mpu > 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_MPU, c->mpu);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_CAKE_MPU attribute: %m");
+ }
+
+ if (c->compensation_mode >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_ATM, c->compensation_mode);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_CAKE_ATM attribute: %m");
+ }
+
+ if (c->raw > 0) {
+ /* TCA_CAKE_RAW attribute is mostly a flag, not boolean. */
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_RAW, 0);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_CAKE_RAW attribute: %m");
+ }
+
+ if (c->flow_isolation_mode >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_FLOW_MODE, c->flow_isolation_mode);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_CAKE_FLOW_MODE attribute: %m");
+ }
+
+ if (c->nat >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_NAT, c->nat);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_CAKE_NAT attribute: %m");
+ }
+
+ if (c->preset >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_DIFFSERV_MODE, c->preset);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_CAKE_DIFFSERV_MODE attribute: %m");
+ }
+
+ if (c->fwmark > 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_FWMARK, c->fwmark);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_CAKE_FWMARK attribute: %m");
+ }
+
+ if (c->wash >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_WASH, c->wash);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_CAKE_WASH attribute: %m");
+ }
+
+ if (c->split_gso >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_SPLIT_GSO, c->wash);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_CAKE_SPLIT_GSO attribute: %m");
+ }
r = sd_netlink_message_close_container(req);
if (r < 0)
@@ -132,7 +215,7 @@ int config_parse_cake_overhead(
c = CAKE(qdisc);
if (isempty(rvalue)) {
- c->overhead = 0;
+ c->overhead_set = false;
TAKE_PTR(qdisc);
return 0;
}
@@ -152,6 +235,380 @@ int config_parse_cake_overhead(
}
c->overhead = v;
+ c->overhead_set = true;
+ TAKE_PTR(qdisc);
+ return 0;
+}
+
+int config_parse_cake_mpu(
+ 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;
+ uint32_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) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+ return 0;
+ }
+
+ c = CAKE(qdisc);
+
+ if (isempty(rvalue)) {
+ c->mpu = 0;
+ TAKE_PTR(qdisc);
+ return 0;
+ }
+
+ r = safe_atou32(rvalue, &v);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+ if (v <= 0 || v > 256) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ c->mpu = v;
+ TAKE_PTR(qdisc);
+ return 0;
+}
+
+int config_parse_cake_tristate(
+ 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;
+ int *dest, 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) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+ return 0;
+ }
+
+ c = CAKE(qdisc);
+
+ if (streq(lvalue, "AutoRateIngress"))
+ dest = &c->autorate;
+ else if (streq(lvalue, "UseRawPacketSize"))
+ dest = &c->raw;
+ else if (streq(lvalue, "NAT"))
+ dest = &c->nat;
+ else if (streq(lvalue, "Wash"))
+ dest = &c->wash;
+ else if (streq(lvalue, "SplitGSO"))
+ dest = &c->split_gso;
+ else
+ assert_not_reached();
+
+ if (isempty(rvalue)) {
+ *dest = -1;
+ TAKE_PTR(qdisc);
+ return 0;
+ }
+
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ *dest = r;
+ TAKE_PTR(qdisc);
+ return 0;
+}
+
+static const char * const cake_compensation_mode_table[_CAKE_COMPENSATION_MODE_MAX] = {
+ [CAKE_COMPENSATION_MODE_NONE] = "none",
+ [CAKE_COMPENSATION_MODE_ATM] = "atm",
+ [CAKE_COMPENSATION_MODE_PTM] = "ptm",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(cake_compensation_mode, CakeCompensationMode);
+
+int config_parse_cake_compensation_mode(
+ 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;
+ CakeCompensationMode mode;
+ 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) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+ return 0;
+ }
+
+ c = CAKE(qdisc);
+
+ if (isempty(rvalue)) {
+ c->compensation_mode = _CAKE_COMPENSATION_MODE_INVALID;
+ TAKE_PTR(qdisc);
+ return 0;
+ }
+
+ mode = cake_compensation_mode_from_string(rvalue);
+ if (mode < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, mode,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ c->compensation_mode = mode;
+ TAKE_PTR(qdisc);
+ return 0;
+}
+
+static const char * const cake_flow_isolation_mode_table[_CAKE_FLOW_ISOLATION_MODE_MAX] = {
+ [CAKE_FLOW_ISOLATION_MODE_NONE] = "none",
+ [CAKE_FLOW_ISOLATION_MODE_SRC_IP] = "src-host",
+ [CAKE_FLOW_ISOLATION_MODE_DST_IP] = "dst-host",
+ [CAKE_FLOW_ISOLATION_MODE_HOSTS] = "hosts",
+ [CAKE_FLOW_ISOLATION_MODE_FLOWS] = "flows",
+ [CAKE_FLOW_ISOLATION_MODE_DUAL_SRC] = "dual-src-host",
+ [CAKE_FLOW_ISOLATION_MODE_DUAL_DST] = "dual-dst-host",
+ [CAKE_FLOW_ISOLATION_MODE_TRIPLE] = "triple",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(cake_flow_isolation_mode, CakeFlowIsolationMode);
+
+int config_parse_cake_flow_isolation_mode(
+ 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;
+ CakeFlowIsolationMode mode;
+ 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) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+ return 0;
+ }
+
+ c = CAKE(qdisc);
+
+ if (isempty(rvalue)) {
+ c->flow_isolation_mode = _CAKE_FLOW_ISOLATION_MODE_INVALID;
+ TAKE_PTR(qdisc);
+ return 0;
+ }
+
+ mode = cake_flow_isolation_mode_from_string(rvalue);
+ if (mode < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, mode,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ c->flow_isolation_mode = mode;
+ TAKE_PTR(qdisc);
+ return 0;
+}
+
+static const char * const cake_priority_queueing_preset_table[_CAKE_PRESET_MAX] = {
+ [CAKE_PRESET_DIFFSERV3] = "diffserv3",
+ [CAKE_PRESET_DIFFSERV4] = "diffserv4",
+ [CAKE_PRESET_DIFFSERV8] = "diffserv8",
+ [CAKE_PRESET_BESTEFFORT] = "besteffort",
+ [CAKE_PRESET_PRECEDENCE] = "precedence",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(cake_priority_queueing_preset, CakePriorityQueueingPreset);
+
+int config_parse_cake_priority_queueing_preset(
+ 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;
+ CakePriorityQueueingPreset preset;
+ Network *network = data;
+ 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) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+ return 0;
+ }
+
+ c = CAKE(qdisc);
+
+ if (isempty(rvalue)) {
+ c->preset = _CAKE_PRESET_INVALID;
+ TAKE_PTR(qdisc);
+ return 0;
+ }
+
+ preset = cake_priority_queueing_preset_from_string(rvalue);
+ if (preset < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, preset,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ c->preset = preset;
+ TAKE_PTR(qdisc);
+ return 0;
+}
+
+int config_parse_cake_fwmark(
+ 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;
+ uint32_t fwmark;
+ 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) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+ return 0;
+ }
+
+ c = CAKE(qdisc);
+
+ if (isempty(rvalue)) {
+ c->fwmark = 0;
+ TAKE_PTR(qdisc);
+ return 0;
+ }
+
+ r = safe_atou32(rvalue, &fwmark);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+ if (fwmark <= 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ c->fwmark = fwmark;
TAKE_PTR(qdisc);
return 0;
}
@@ -159,5 +616,6 @@ int config_parse_cake_overhead(
const QDiscVTable cake_vtable = {
.object_size = sizeof(CommonApplicationsKeptEnhanced),
.tca_kind = "cake",
+ .init = cake_init,
.fill_message = cake_fill_message,
};
diff --git a/src/network/tc/cake.h b/src/network/tc/cake.h
index 1da28b7d20..ff68cedabf 100644
--- a/src/network/tc/cake.h
+++ b/src/network/tc/cake.h
@@ -2,15 +2,68 @@
* Copyright © 2020 VMware, Inc. */
#pragma once
+#include
+
#include "conf-parser.h"
#include "qdisc.h"
+typedef enum CakeCompensationMode {
+ CAKE_COMPENSATION_MODE_NONE = CAKE_ATM_NONE,
+ CAKE_COMPENSATION_MODE_ATM = CAKE_ATM_ATM,
+ CAKE_COMPENSATION_MODE_PTM = CAKE_ATM_PTM,
+ _CAKE_COMPENSATION_MODE_MAX,
+ _CAKE_COMPENSATION_MODE_INVALID = -EINVAL,
+} CakeCompensationMode;
+
+typedef enum CakeFlowIsolationMode {
+ CAKE_FLOW_ISOLATION_MODE_NONE = CAKE_FLOW_NONE,
+ CAKE_FLOW_ISOLATION_MODE_SRC_IP = CAKE_FLOW_SRC_IP,
+ CAKE_FLOW_ISOLATION_MODE_DST_IP = CAKE_FLOW_DST_IP,
+ CAKE_FLOW_ISOLATION_MODE_HOSTS = CAKE_FLOW_HOSTS,
+ CAKE_FLOW_ISOLATION_MODE_FLOWS = CAKE_FLOW_FLOWS,
+ CAKE_FLOW_ISOLATION_MODE_DUAL_SRC = CAKE_FLOW_DUAL_SRC,
+ CAKE_FLOW_ISOLATION_MODE_DUAL_DST = CAKE_FLOW_DUAL_DST,
+ CAKE_FLOW_ISOLATION_MODE_TRIPLE = CAKE_FLOW_TRIPLE,
+ _CAKE_FLOW_ISOLATION_MODE_MAX,
+ _CAKE_FLOW_ISOLATION_MODE_INVALID = -EINVAL,
+} CakeFlowIsolationMode;
+
+typedef enum CakePriorityQueueingPreset {
+ CAKE_PRESET_DIFFSERV3 = CAKE_DIFFSERV_DIFFSERV3,
+ CAKE_PRESET_DIFFSERV4 = CAKE_DIFFSERV_DIFFSERV4,
+ CAKE_PRESET_DIFFSERV8 = CAKE_DIFFSERV_DIFFSERV8,
+ CAKE_PRESET_BESTEFFORT = CAKE_DIFFSERV_BESTEFFORT,
+ CAKE_PRESET_PRECEDENCE = CAKE_DIFFSERV_PRECEDENCE,
+ _CAKE_PRESET_MAX,
+ _CAKE_PRESET_INVALID = -EINVAL,
+} CakePriorityQueueingPreset;
+
typedef struct CommonApplicationsKeptEnhanced {
QDisc meta;
- int overhead;
+ /* Shaper parameters */
+ int autorate;
uint64_t bandwidth;
+ /* Overhead compensation parameters */
+ bool overhead_set;
+ int overhead;
+ uint32_t mpu;
+ CakeCompensationMode compensation_mode;
+ int raw;
+
+ /* Flow isolation parameters */
+ CakeFlowIsolationMode flow_isolation_mode;
+ int nat;
+
+ /* Priority queue parameters */
+ CakePriorityQueueingPreset preset;
+ uint32_t fwmark;
+
+ /* Other parameters */
+ int wash;
+ int split_gso;
+
} CommonApplicationsKeptEnhanced;
DEFINE_QDISC_CAST(CAKE, CommonApplicationsKeptEnhanced);
@@ -18,3 +71,9 @@ extern const QDiscVTable cake_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_cake_bandwidth);
CONFIG_PARSER_PROTOTYPE(config_parse_cake_overhead);
+CONFIG_PARSER_PROTOTYPE(config_parse_cake_mpu);
+CONFIG_PARSER_PROTOTYPE(config_parse_cake_tristate);
+CONFIG_PARSER_PROTOTYPE(config_parse_cake_compensation_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_cake_flow_isolation_mode);
+CONFIG_PARSER_PROTOTYPE(config_parse_cake_priority_queueing_preset);
+CONFIG_PARSER_PROTOTYPE(config_parse_cake_fwmark);
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index 66038a2378..26ab3931e0 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -470,7 +470,17 @@ ECN=
Parent=
Handle=
Bandwidth=
+AutoRateIngress=
OverheadBytes=
+MPUBytes=
+CompensationMode=
+UseRawPacketSize=
+FlowIsolationMode=
+NAT=
+PriorityQueueingPreset=
+FirewallMark=
+Wash=
+SplitGSO=
[TrafficControlQueueingDiscipline]
Parent=
NetworkEmulatorDelaySec=
diff --git a/test/test-network/conf/25-qdisc-cake.network b/test/test-network/conf/25-qdisc-cake.network
index 9220a20bf5..b13720c6dd 100644
--- a/test/test-network/conf/25-qdisc-cake.network
+++ b/test/test-network/conf/25-qdisc-cake.network
@@ -9,5 +9,15 @@ Address=10.1.2.3/16
[CAKE]
Parent=root
Handle=3a
-OverheadBytes=128
Bandwidth=500M
+AutoRateIngress=yes
+OverheadBytes=128
+MPUBytes=20
+CompensationMode=atm
+UseRawPacketSize=yes
+FlowIsolationMode=dual-dst-host
+NAT=yes
+PriorityQueueingPreset=diffserv8
+FirewallMark=0xff00
+Wash=yes
+SplitGSO=yes
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 9d12d6a609..a68055086c 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -3262,9 +3262,19 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
output = check_output('tc qdisc show dev dummy98')
print(output)
- self.assertRegex(output, 'qdisc cake 3a: root')
- self.assertRegex(output, 'bandwidth 500Mbit')
- self.assertRegex(output, 'overhead 128')
+ self.assertIn('qdisc cake 3a: root', output)
+ self.assertIn('bandwidth 500Mbit', output)
+ self.assertIn('autorate-ingress', output)
+ self.assertIn('diffserv8', output)
+ self.assertIn('dual-dsthost', output)
+ self.assertIn(' nat', output)
+ self.assertIn(' wash', output)
+ self.assertIn(' split-gso', output)
+ self.assertIn(' raw', output)
+ self.assertIn(' atm', output)
+ self.assertIn('overhead 128', output)
+ self.assertIn('mpu 20', output)
+ self.assertIn('fwmark 0xff00', output)
@expectedFailureIfPIEIsNotAvailable()
def test_qdisc_pie(self):