diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index da48dd04f4..f1625dfde4 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -2500,6 +2500,38 @@
+
+ [PIE] Section Options
+ The [PIE] section manages the queueing discipline
+ (qdisc) of Proportional Integral controller-Enhanced (PIE).
+
+
+
+ Parent=
+
+ Specifies the parent Queueing Discipline (qdisc). Takes one of root,
+ clsact or ingress. 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.
+
+
+
+
+ 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 ranges 1 to 4294967294. Defaults to unset and kernel's default is used.
+
+
+
+
+
[StochasticFairBlue] Section Options
The [StochasticFairBlue] section manages the queueing discipline
@@ -2565,6 +2597,40 @@
+
+ [BFIFO] Section Options
+ The [BFIFO] section manages the queueing discipline (qdisc) of
+ Byte limited Packet First In First Out (bfifo).
+
+
+
+ Parent=
+
+ Specifies the parent Queueing Discipline (qdisc). Takes one of root,
+ clsact or ingress. 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.
+
+
+
+
+ LimitSize=
+
+ Specifies the hard limit on the FIFO size in bytes. The size limit (a buffer size) to prevent it
+ from overflowing in case it is unable to dequeue packets as quickly as it receives them. When this limit
+ is reached, incoming packets are dropped. When suffixed with K, M, or G, the specified size is parsed as
+ Kilobytes, Megabytes, or Gigabytes, respectively, to the base of 1024. Defaults to unset and kernel's default is used.
+
+
+
+
+
[PFIFO] Section Options
The [PFIFO] section manages the queueing discipline (qdisc) of
@@ -2598,6 +2664,54 @@
+
+ [PFIFOHeadDrop] Section Options
+ The [PFIFOHeadDrop] section manages the queueing discipline (qdisc) of
+ Packet First In First Out Head Drop (pfifo_head_drop).
+
+
+
+ Parent=
+
+ As in [PFIFO] section.
+
+
+
+ Handle=
+
+ As in [PFIFO] section..
+
+
+
+
+ PacketLimit=
+
+ As in [PFIFO] section.
+
+
+
+
+
+ [PFIFOFast] Section Options
+ The [PFIFOFast] section manages the queueing discipline (qdisc) of
+ Packet First In First Out Fast (pfifo_fast).
+
+
+
+ Parent=
+
+ As in [PFIFO] section.
+
+
+
+ Handle=
+
+ As in [PFIFO] section..
+
+
+
+
+
[CAKE] Section Options
The [CAKE] section manages the queueing discipline (qdisc) of
@@ -2707,6 +2821,68 @@
+
+ [DeficitRoundRobinScheduler] Section Options
+ The [DeficitRoundRobinScheduler] section manages the queueing discipline (qdisc) of
+ Deficit Round Robin Scheduler (DRR).
+
+
+
+ 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.
+
+
+
+
+
+
+ [DeficitRoundRobinSchedulerClass] Section Options
+ The [DeficitRoundRobinSchedulerClass] section manages the traffic control class of
+ Deficit Round Robin Scheduler (DRR).
+
+
+
+ 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.
+
+
+
+
+ ClassId=
+
+ Specifies the major and minur number of unique identifier of the class, known as the
+ class ID. Each number is in hexadecimal ranges 1 to ffff. Defaults to unset.
+
+
+
+
+ Quantum=
+
+ Specifies the amount of bytes a flow is allowed to dequeue before the
+ scheduler moves to the next class. An unsigned integer ranges 1 to 4294967294.
+ Defaults to the MTU of the interface.
+
+
+
+
+
+
[GenericRandomEarlyDetection] Section Options
The [GenericRandomEarlyDetection] section manages the queueing discipline
@@ -3070,7 +3246,38 @@
is used.
+
+
+
+ [HeavyHitterFilter] Section Options
+ The [HeavyHitterFilter] section manages the queueing discipline
+ (qdisc) of Heavy Hitter Filter (hhf).
+
+
+
+ Parent=
+
+ Specifies the parent Queueing Discipline (qdisc). Takes one of root,
+ clsact or ingress. 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.
+
+
+
+
+ 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 ranges 0 to 4294967294. 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 102cec49a1..720e48e227 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -760,6 +760,10 @@ static const NLType rtnl_tca_option_data_codel_types[] = {
[TCA_CODEL_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 },
};
+static const NLType rtnl_tca_option_data_drr_types[] = {
+ [TCA_DRR_QUANTUM] = { .type = NETLINK_TYPE_U32 },
+};
+
static const NLType rtnl_tca_option_data_fq_types[] = {
[TCA_FQ_PLIMIT] = { .type = NETLINK_TYPE_U32 },
[TCA_FQ_FLOW_PLIMIT] = { .type = NETLINK_TYPE_U32 },
@@ -791,6 +795,10 @@ static const NLType rtnl_tca_option_data_gred_types[] = {
[TCA_GRED_DPS] = { .size = sizeof(struct tc_gred_sopt) },
};
+static const NLType rtnl_tca_option_data_hhf_types[] = {
+ [TCA_HHF_BACKLOG_LIMIT] = { .type = NETLINK_TYPE_U32 },
+};
+
static const NLType rtnl_tca_option_data_htb_types[] = {
[TCA_HTB_PARMS] = { .size = sizeof(struct tc_htb_opt) },
[TCA_HTB_INIT] = { .size = sizeof(struct tc_htb_glob) },
@@ -800,6 +808,10 @@ static const NLType rtnl_tca_option_data_htb_types[] = {
[TCA_HTB_CEIL64] = { .type = NETLINK_TYPE_U64 },
};
+static const NLType rtnl_tca_option_data_pie_types[] = {
+ [TCA_PIE_LIMIT] = { .type = NETLINK_TYPE_U32 },
+};
+
static const NLType rtnl_tca_option_data_sfb_types[] = {
[TCA_SFB_PARMS] = { .size = sizeof(struct tc_sfb_qopt) },
};
@@ -817,10 +829,13 @@ 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_DRR] = "drr",
[NL_UNION_TCA_OPTION_DATA_FQ] = "fq",
[NL_UNION_TCA_OPTION_DATA_FQ_CODEL] = "fq_codel",
[NL_UNION_TCA_OPTION_DATA_GRED] = "gred",
+ [NL_UNION_TCA_OPTION_DATA_HHF] = "hhf",
[NL_UNION_TCA_OPTION_DATA_HTB] = "htb",
+ [NL_UNION_TCA_OPTION_DATA_PIE] = "pie",
[NL_UNION_TCA_OPTION_DATA_SFB] = "sfb",
[NL_UNION_TCA_OPTION_DATA_TBF] = "tbf",
};
@@ -832,14 +847,20 @@ static const NLTypeSystem rtnl_tca_option_data_type_systems[] = {
.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_DRR] = { .count = ELEMENTSOF(rtnl_tca_option_data_drr_types),
+ .types = rtnl_tca_option_data_drr_types },
[NL_UNION_TCA_OPTION_DATA_FQ] = { .count = ELEMENTSOF(rtnl_tca_option_data_fq_types),
.types = rtnl_tca_option_data_fq_types },
[NL_UNION_TCA_OPTION_DATA_FQ_CODEL] = { .count = ELEMENTSOF(rtnl_tca_option_data_fq_codel_types),
.types = rtnl_tca_option_data_fq_codel_types },
[NL_UNION_TCA_OPTION_DATA_GRED] = { .count = ELEMENTSOF(rtnl_tca_option_data_gred_types),
.types = rtnl_tca_option_data_gred_types },
+ [NL_UNION_TCA_OPTION_DATA_HHF] = { .count = ELEMENTSOF(rtnl_tca_option_data_hhf_types),
+ .types = rtnl_tca_option_data_hhf_types },
[NL_UNION_TCA_OPTION_DATA_HTB] = { .count = ELEMENTSOF(rtnl_tca_option_data_htb_types),
.types = rtnl_tca_option_data_htb_types },
+ [NL_UNION_TCA_OPTION_DATA_PIE] = { .count = ELEMENTSOF(rtnl_tca_option_data_pie_types),
+ .types = rtnl_tca_option_data_pie_types },
[NL_UNION_TCA_OPTION_DATA_SFB] = { .count = ELEMENTSOF(rtnl_tca_option_data_sfb_types),
.types = rtnl_tca_option_data_sfb_types },
[NL_UNION_TCA_OPTION_DATA_TBF] = { .count = ELEMENTSOF(rtnl_tca_option_data_tbf_types),
diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h
index edc4a580b8..08b91c78c0 100644
--- a/src/libsystemd/sd-netlink/netlink-types.h
+++ b/src/libsystemd/sd-netlink/netlink-types.h
@@ -98,10 +98,13 @@ 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_DRR,
NL_UNION_TCA_OPTION_DATA_FQ,
NL_UNION_TCA_OPTION_DATA_FQ_CODEL,
NL_UNION_TCA_OPTION_DATA_GRED,
+ NL_UNION_TCA_OPTION_DATA_HHF,
NL_UNION_TCA_OPTION_DATA_HTB,
+ NL_UNION_TCA_OPTION_DATA_PIE,
NL_UNION_TCA_OPTION_DATA_SFB,
NL_UNION_TCA_OPTION_DATA_TBF,
_NL_UNION_TCA_OPTION_DATA_MAX,
diff --git a/src/network/meson.build b/src/network/meson.build
index 57d3772c3e..35b35a76a6 100644
--- a/src/network/meson.build
+++ b/src/network/meson.build
@@ -111,6 +111,8 @@ sources = files('''
tc/cake.h
tc/codel.c
tc/codel.h
+ tc/drr.c
+ tc/drr.h
tc/fifo.c
tc/fifo.h
tc/fq.c
@@ -119,10 +121,14 @@ sources = files('''
tc/fq-codel.h
tc/gred.c
tc/gred.h
+ tc/hhf.c
+ tc/hhf.h
tc/htb.c
tc/htb.h
tc/netem.c
tc/netem.h
+ tc/pie.c
+ tc/pie.h
tc/qdisc.c
tc/qdisc.h
tc/sfb.c
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 8bf80afddd..e1b9b5687a 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -258,6 +258,9 @@ CAN.TripleSampling, config_parse_tristate,
CAN.Termination, config_parse_tristate, 0, offsetof(Network, can_termination)
QDisc.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0
QDisc.Handle, config_parse_qdisc_handle, _QDISC_KIND_INVALID, 0
+BFIFO.Parent, config_parse_qdisc_parent, QDISC_KIND_BFIFO, 0
+BFIFO.Handle, config_parse_qdisc_handle, QDISC_KIND_BFIFO, 0
+BFIFO.LimitSize, config_parse_bfifo_size, QDISC_KIND_BFIFO, 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
@@ -269,9 +272,19 @@ ControlledDelay.TargetSec, config_parse_controlled_delay_usec,
ControlledDelay.IntervalSec, config_parse_controlled_delay_usec, QDISC_KIND_CODEL, 0
ControlledDelay.CEThresholdSec, config_parse_controlled_delay_usec, QDISC_KIND_CODEL, 0
ControlledDelay.ECN, config_parse_controlled_delay_bool, QDISC_KIND_CODEL, 0
+DeficitRoundRobinScheduler.Parent, config_parse_qdisc_parent, QDISC_KIND_DRR, 0
+DeficitRoundRobinScheduler.Handle, config_parse_qdisc_handle, QDISC_KIND_DRR, 0
+DeficitRoundRobinSchedulerClass.Parent, config_parse_tclass_parent, TCLASS_KIND_DRR, 0
+DeficitRoundRobinSchedulerClass.ClassId, config_parse_tclass_classid, TCLASS_KIND_DRR, 0
+DeficitRoundRobinSchedulerClass.Quantum, config_parse_drr_size, TCLASS_KIND_DRR, 0
PFIFO.Parent, config_parse_qdisc_parent, QDISC_KIND_PFIFO, 0
PFIFO.Handle, config_parse_qdisc_handle, QDISC_KIND_PFIFO, 0
-PFIFO.PacketLimit, config_parse_fifo_size, QDISC_KIND_PFIFO, 0
+PFIFO.PacketLimit, config_parse_pfifo_size, QDISC_KIND_PFIFO, 0
+PFIFOFast.Parent, config_parse_qdisc_parent, QDISC_KIND_PFIFO_FAST, 0
+PFIFOFast.Handle, config_parse_qdisc_handle, QDISC_KIND_PFIFO_FAST, 0
+PFIFOHeadDrop.Parent, config_parse_qdisc_parent, QDISC_KIND_PFIFO_HEAD_DROP, 0
+PFIFOHeadDrop.Handle, config_parse_qdisc_handle, QDISC_KIND_PFIFO_HEAD_DROP, 0
+PFIFOHeadDrop.PacketLimit, config_parse_pfifo_size, QDISC_KIND_PFIFO_HEAD_DROP, 0
FairQueueing.Parent, config_parse_qdisc_parent, QDISC_KIND_FQ, 0
FairQueueing.Handle, config_parse_qdisc_handle, QDISC_KIND_FQ, 0
FairQueueing.PacketLimit, config_parse_fair_queueing_u32, QDISC_KIND_FQ, 0
@@ -298,6 +311,9 @@ GenericRandomEarlyDetection.Handle, config_parse_qdisc_handle,
GenericRandomEarlyDetection.VirtualQueues, config_parse_generic_random_early_detection_u32, QDISC_KIND_GRED, 0
GenericRandomEarlyDetection.DefaultVirtualQueue, config_parse_generic_random_early_detection_u32, QDISC_KIND_GRED, 0
GenericRandomEarlyDetection.GenericRIO, config_parse_generic_random_early_detection_bool, QDISC_KIND_GRED, 0
+HeavyHitterFilter.Parent, config_parse_qdisc_parent, QDISC_KIND_HHF, 0
+HeavyHitterFilter.Handle, config_parse_qdisc_handle, QDISC_KIND_HHF, 0
+HeavyHitterFilter.PacketLimit, config_parse_heavy_hitter_filter_packet_limit, QDISC_KIND_HHF, 0
HierarchyTokenBucket.Parent, config_parse_qdisc_parent, QDISC_KIND_HTB, 0
HierarchyTokenBucket.Handle, config_parse_qdisc_handle, QDISC_KIND_HTB, 0
HierarchyTokenBucket.DefaultClass, config_parse_hierarchy_token_bucket_default_class, QDISC_KIND_HTB, 0
@@ -313,6 +329,9 @@ NetworkEmulator.DelayJitterSec, config_parse_network_emulator_delay
NetworkEmulator.LossRate, config_parse_network_emulator_rate, QDISC_KIND_NETEM, 0
NetworkEmulator.DuplicateRate, config_parse_network_emulator_rate, QDISC_KIND_NETEM, 0
NetworkEmulator.PacketLimit, config_parse_network_emulator_packet_limit, QDISC_KIND_NETEM, 0
+PIE.Parent, config_parse_qdisc_parent, QDISC_KIND_PIE, 0
+PIE.Handle, config_parse_qdisc_handle, QDISC_KIND_PIE, 0
+PIE.PacketLimit, config_parse_pie_packet_limit, QDISC_KIND_PIE, 0
StochasticFairBlue.Parent, config_parse_qdisc_parent, QDISC_KIND_SFB, 0
StochasticFairBlue.Handle, config_parse_qdisc_handle, QDISC_KIND_SFB, 0
StochasticFairBlue.PacketLimit, config_parse_stochastic_fair_blue_u32, QDISC_KIND_SFB, 0
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 40e4009bec..f99886d5f9 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -486,15 +486,22 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
"TrafficControlQueueingDiscipline\0"
"CAN\0"
"QDisc\0"
+ "BFIFO\0"
"CAKE\0"
"ControlledDelay\0"
+ "DeficitRoundRobinScheduler\0"
+ "DeficitRoundRobinSchedulerClass\0"
"PFIFO\0"
+ "PFIFOFast\0"
+ "PFIFOHeadDrop\0"
"FairQueueing\0"
"FairQueueingControlledDelay\0"
"GenericRandomEarlyDetection\0"
+ "HeavyHitterFilter\0"
"HierarchyTokenBucket\0"
"HierarchyTokenBucketClass\0"
"NetworkEmulator\0"
+ "PIE\0"
"StochasticFairBlue\0"
"StochasticFairnessQueueing\0"
"TokenBucketFilter\0"
diff --git a/src/network/tc/drr.c b/src/network/tc/drr.c
new file mode 100644
index 0000000000..ac64eb8b03
--- /dev/null
+++ b/src/network/tc/drr.c
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: LGPL-2.1+
+ * Copyright © 2020 VMware, Inc. */
+
+#include
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "drr.h"
+#include "netlink-util.h"
+#include "parse-util.h"
+#include "string-util.h"
+
+const QDiscVTable drr_vtable = {
+ .object_size = sizeof(DeficitRoundRobinScheduler),
+ .tca_kind = "drr",
+};
+
+static int drr_class_fill_message(Link *link, TClass *tclass, sd_netlink_message *req) {
+ DeficitRoundRobinSchedulerClass *drr;
+ int r;
+
+ assert(link);
+ assert(tclass);
+ assert(req);
+
+ drr = TCLASS_TO_DRR(tclass);
+
+ r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "drr");
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
+
+ if (drr->quantum > 0) {
+ r = sd_netlink_message_append_u32(req, TCA_DRR_QUANTUM, drr->quantum);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_DRR_QUANTUM, 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_drr_size(
+ 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_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
+ DeficitRoundRobinSchedulerClass *drr;
+ Network *network = data;
+ uint64_t u;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = tclass_new_static(TCLASS_KIND_DRR, network, filename, section_line, &tclass);
+ if (r < 0)
+ return log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to create traffic control class, ignoring assignment: %m");
+
+ drr = TCLASS_TO_DRR(tclass);
+
+ if (isempty(rvalue)) {
+ drr->quantum = 0;
+
+ tclass = NULL;
+ return 0;
+ }
+
+ r = parse_size(rvalue, 1000, &u);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+ if (u > UINT32_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ drr->quantum = (uint32_t) u;
+
+ tclass = NULL;
+ return 0;
+}
+
+const TClassVTable drr_tclass_vtable = {
+ .object_size = sizeof(DeficitRoundRobinSchedulerClass),
+ .tca_kind = "drr",
+ .fill_message = drr_class_fill_message,
+};
diff --git a/src/network/tc/drr.h b/src/network/tc/drr.h
new file mode 100644
index 0000000000..ff2b658acc
--- /dev/null
+++ b/src/network/tc/drr.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: LGPL-2.1+
+ * Copyright © 2020 VMware, Inc. */
+#pragma once
+
+#include "qdisc.h"
+
+typedef struct DeficitRoundRobinScheduler {
+ QDisc meta;
+} DeficitRoundRobinScheduler;
+
+DEFINE_QDISC_CAST(DRR, DeficitRoundRobinScheduler);
+extern const QDiscVTable drr_vtable;
+
+typedef struct DeficitRoundRobinSchedulerClass {
+ TClass meta;
+
+ uint32_t quantum;
+} DeficitRoundRobinSchedulerClass;
+
+DEFINE_TCLASS_CAST(DRR, DeficitRoundRobinSchedulerClass);
+extern const TClassVTable drr_tclass_vtable;
+
+CONFIG_PARSER_PROTOTYPE(config_parse_drr_size);
diff --git a/src/network/tc/fifo.c b/src/network/tc/fifo.c
index 2d2a863e3a..8ef6e513bb 100644
--- a/src/network/tc/fifo.c
+++ b/src/network/tc/fifo.c
@@ -19,7 +19,19 @@ static int fifo_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req)
assert(qdisc);
assert(req);
- fifo = PFIFO(qdisc);
+ switch(qdisc->kind) {
+ case QDISC_KIND_PFIFO:
+ fifo = PFIFO(qdisc);
+ break;
+ case QDISC_KIND_BFIFO:
+ fifo = BFIFO(qdisc);
+ break;
+ case QDISC_KIND_PFIFO_HEAD_DROP:
+ fifo = PFIFO_HEAD_DROP(qdisc);
+ break;
+ default:
+ assert_not_reached("Invalid QDisc kind.");
+ }
opt.limit = fifo->limit;
@@ -30,7 +42,7 @@ static int fifo_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req)
return 0;
}
-int config_parse_fifo_size(
+int config_parse_pfifo_size(
const char *unit,
const char *filename,
unsigned line,
@@ -52,14 +64,23 @@ int config_parse_fifo_size(
assert(rvalue);
assert(data);
- r = qdisc_new_static(QDISC_KIND_PFIFO, network, filename, section_line, &qdisc);
+ r = qdisc_new_static(ltype, 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");
- fifo = PFIFO(qdisc);
+ switch(qdisc->kind) {
+ case QDISC_KIND_PFIFO:
+ fifo = PFIFO(qdisc);
+ break;
+ case QDISC_KIND_PFIFO_HEAD_DROP:
+ fifo = PFIFO_HEAD_DROP(qdisc);
+ break;
+ default:
+ assert_not_reached("Invalid QDisc kind.");
+ }
if (isempty(rvalue)) {
fifo->limit = 0;
@@ -80,8 +101,83 @@ int config_parse_fifo_size(
return 0;
}
+int config_parse_bfifo_size(
+ 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;
+ FirstInFirstOut *fifo;
+ uint64_t u;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = qdisc_new_static(QDISC_KIND_BFIFO, 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");
+
+ fifo = BFIFO(qdisc);
+
+ if (isempty(rvalue)) {
+ fifo->limit = 0;
+
+ qdisc = NULL;
+ return 0;
+ }
+
+ r = parse_size(rvalue, 1000, &u);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+ if (u > UINT32_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ fifo->limit = (uint32_t) u;
+
+ qdisc = NULL;
+ return 0;
+}
+
const QDiscVTable pfifo_vtable = {
.object_size = sizeof(FirstInFirstOut),
.tca_kind = "pfifo",
.fill_message = fifo_fill_message,
};
+
+const QDiscVTable bfifo_vtable = {
+ .object_size = sizeof(FirstInFirstOut),
+ .tca_kind = "bfifo",
+ .fill_message = fifo_fill_message,
+};
+
+const QDiscVTable pfifo_head_drop_vtable = {
+ .object_size = sizeof(FirstInFirstOut),
+ .tca_kind = "pfifo_head_drop",
+ .fill_message = fifo_fill_message,
+};
+
+const QDiscVTable pfifo_fast_vtable = {
+ .object_size = sizeof(FirstInFirstOut),
+ .tca_kind = "pfifo_fast",
+};
diff --git a/src/network/tc/fifo.h b/src/network/tc/fifo.h
index 02976568dd..e4c976b942 100644
--- a/src/network/tc/fifo.h
+++ b/src/network/tc/fifo.h
@@ -12,6 +12,14 @@ typedef struct FirstInFirstOut {
} FirstInFirstOut;
DEFINE_QDISC_CAST(PFIFO, FirstInFirstOut);
-extern const QDiscVTable pfifo_vtable;
+DEFINE_QDISC_CAST(BFIFO, FirstInFirstOut);
+DEFINE_QDISC_CAST(PFIFO_HEAD_DROP, FirstInFirstOut);
+DEFINE_QDISC_CAST(PFIFO_FAST, FirstInFirstOut);
-CONFIG_PARSER_PROTOTYPE(config_parse_fifo_size);
+extern const QDiscVTable pfifo_vtable;
+extern const QDiscVTable bfifo_vtable;
+extern const QDiscVTable pfifo_head_drop_vtable;
+extern const QDiscVTable pfifo_fast_vtable;
+
+CONFIG_PARSER_PROTOTYPE(config_parse_pfifo_size);
+CONFIG_PARSER_PROTOTYPE(config_parse_bfifo_size);
diff --git a/src/network/tc/hhf.c b/src/network/tc/hhf.c
new file mode 100644
index 0000000000..a9d0bdad2f
--- /dev/null
+++ b/src/network/tc/hhf.c
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: LGPL-2.1+
+ * Copyright © 2020 VMware, Inc. */
+
+#include
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "hhf.h"
+#include "netlink-util.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "util.h"
+
+static int heavy_hitter_filter_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
+ HeavyHitterFilter *hhf;
+ int r;
+
+ assert(link);
+ assert(qdisc);
+ assert(req);
+
+ hhf = HHF(qdisc);
+
+ r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "hhf");
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
+
+ if (hhf->packet_limit > 0) {
+ r = sd_netlink_message_append_u32(req, TCA_HHF_BACKLOG_LIMIT, hhf->packet_limit);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_HHF_BACKLOG_LIMIT 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_heavy_hitter_filter_packet_limit(
+ 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;
+ HeavyHitterFilter *hhf;
+ Network *network = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = qdisc_new_static(QDISC_KIND_HHF, 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");
+
+ hhf = HHF(qdisc);
+
+ if (isempty(rvalue)) {
+ hhf->packet_limit = 0;
+
+ qdisc = NULL;
+ return 0;
+ }
+
+ r = safe_atou32(rvalue, &hhf->packet_limit);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ qdisc = NULL;
+
+ return 0;
+}
+
+const QDiscVTable hhf_vtable = {
+ .object_size = sizeof(HeavyHitterFilter),
+ .tca_kind = "hhf",
+ .fill_message = heavy_hitter_filter_fill_message,
+};
diff --git a/src/network/tc/hhf.h b/src/network/tc/hhf.h
new file mode 100644
index 0000000000..a555998eee
--- /dev/null
+++ b/src/network/tc/hhf.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: LGPL-2.1+
+ * Copyright © 2020 VMware, Inc. */
+#pragma once
+
+#include "conf-parser.h"
+#include "qdisc.h"
+
+typedef struct HeavyHitterFilter {
+ QDisc meta;
+
+ uint32_t packet_limit;
+} HeavyHitterFilter;
+
+DEFINE_QDISC_CAST(HHF, HeavyHitterFilter);
+extern const QDiscVTable hhf_vtable;
+
+CONFIG_PARSER_PROTOTYPE(config_parse_heavy_hitter_filter_packet_limit);
diff --git a/src/network/tc/pie.c b/src/network/tc/pie.c
new file mode 100644
index 0000000000..e92ced1343
--- /dev/null
+++ b/src/network/tc/pie.c
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: LGPL-2.1+
+ * Copyright © 2020 VMware, Inc. */
+
+#include
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "pie.h"
+#include "netlink-util.h"
+#include "parse-util.h"
+#include "string-util.h"
+
+static int pie_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
+ proportional_integral_controller_enhanced *pie;
+ int r;
+
+ assert(link);
+ assert(qdisc);
+ assert(req);
+
+ pie = PIE(qdisc);
+
+ r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "pie");
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
+
+ if (pie->packet_limit > 0) {
+ r = sd_netlink_message_append_u32(req, TCA_PIE_LIMIT, pie->packet_limit);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append TCA_PIE_PLIMIT 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_pie_packet_limit(
+ 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;
+ proportional_integral_controller_enhanced *pie;
+ Network *network = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = qdisc_new_static(QDISC_KIND_PIE, 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");
+
+ pie = PIE(qdisc);
+
+ if (isempty(rvalue)) {
+ pie->packet_limit = 0;
+
+ qdisc = NULL;
+ return 0;
+ }
+
+ r = safe_atou32(rvalue, &pie->packet_limit);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ qdisc = NULL;
+
+ return 0;
+}
+
+const QDiscVTable pie_vtable = {
+ .object_size = sizeof(proportional_integral_controller_enhanced),
+ .tca_kind = "pie",
+ .fill_message = pie_fill_message,
+};
diff --git a/src/network/tc/pie.h b/src/network/tc/pie.h
new file mode 100644
index 0000000000..44214f1ba1
--- /dev/null
+++ b/src/network/tc/pie.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: LGPL-2.1+
+ * Copyright © 2020 VMware, Inc. */
+#pragma once
+
+#include "conf-parser.h"
+#include "qdisc.h"
+
+typedef struct proportional_integral_controller_enhanced {
+ QDisc meta;
+
+ uint32_t packet_limit;
+} proportional_integral_controller_enhanced;
+
+DEFINE_QDISC_CAST(PIE, proportional_integral_controller_enhanced);
+extern const QDiscVTable pie_vtable;
+
+CONFIG_PARSER_PROTOTYPE(config_parse_pie_packet_limit);
diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c
index 31b6a716c4..543f71330f 100644
--- a/src/network/tc/qdisc.c
+++ b/src/network/tc/qdisc.c
@@ -16,14 +16,20 @@
#include "tc-util.h"
const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = {
+ [QDISC_KIND_BFIFO] = &bfifo_vtable,
[QDISC_KIND_CAKE] = &cake_vtable,
[QDISC_KIND_CODEL] = &codel_vtable,
+ [QDISC_KIND_DRR] = &drr_vtable,
[QDISC_KIND_FQ] = &fq_vtable,
[QDISC_KIND_FQ_CODEL] = &fq_codel_vtable,
[QDISC_KIND_GRED] = &gred_vtable,
+ [QDISC_KIND_HHF] = &hhf_vtable,
[QDISC_KIND_HTB] = &htb_vtable,
[QDISC_KIND_NETEM] = &netem_vtable,
+ [QDISC_KIND_PIE] = &pie_vtable,
[QDISC_KIND_PFIFO] = &pfifo_vtable,
+ [QDISC_KIND_PFIFO_FAST] = &pfifo_fast_vtable,
+ [QDISC_KIND_PFIFO_HEAD_DROP] = &pfifo_head_drop_vtable,
[QDISC_KIND_SFB] = &sfb_vtable,
[QDISC_KIND_SFQ] = &sfq_vtable,
[QDISC_KIND_TBF] = &tbf_vtable,
diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h
index 403d6a5b53..5c43d7a838 100644
--- a/src/network/tc/qdisc.h
+++ b/src/network/tc/qdisc.h
@@ -9,14 +9,20 @@
#include "tc.h"
typedef enum QDiscKind {
+ QDISC_KIND_BFIFO,
QDISC_KIND_CAKE,
QDISC_KIND_CODEL,
+ QDISC_KIND_DRR,
QDISC_KIND_FQ,
QDISC_KIND_FQ_CODEL,
QDISC_KIND_GRED,
+ QDISC_KIND_HHF,
QDISC_KIND_HTB,
QDISC_KIND_NETEM,
QDISC_KIND_PFIFO,
+ QDISC_KIND_PFIFO_FAST,
+ QDISC_KIND_PFIFO_HEAD_DROP,
+ QDISC_KIND_PIE,
QDISC_KIND_SFB,
QDISC_KIND_SFQ,
QDISC_KIND_TBF,
@@ -84,8 +90,11 @@ CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_handle);
#include "fq-codel.h"
#include "fq.h"
#include "gred.h"
+#include "hhf.h"
#include "htb.h"
+#include "pie.h"
#include "netem.h"
+#include "drr.h"
#include "sfb.h"
#include "sfq.h"
#include "tbf.h"
diff --git a/src/network/tc/tclass.c b/src/network/tc/tclass.c
index 87f5bcf704..219ffa2ea6 100644
--- a/src/network/tc/tclass.c
+++ b/src/network/tc/tclass.c
@@ -16,6 +16,7 @@
#include "tclass.h"
const TClassVTable * const tclass_vtable[_TCLASS_KIND_MAX] = {
+ [TCLASS_KIND_DRR] = &drr_tclass_vtable,
[TCLASS_KIND_HTB] = &htb_tclass_vtable,
};
diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h
index 9698e582fa..217dbfe001 100644
--- a/src/network/tc/tclass.h
+++ b/src/network/tc/tclass.h
@@ -9,6 +9,7 @@
#include "tc.h"
typedef enum TClassKind {
+ TCLASS_KIND_DRR,
TCLASS_KIND_HTB,
_TCLASS_KIND_MAX,
_TCLASS_KIND_INVALID = -1,
@@ -64,4 +65,5 @@ DEFINE_TC_CAST(TCLASS, TClass);
CONFIG_PARSER_PROTOTYPE(config_parse_tclass_parent);
CONFIG_PARSER_PROTOTYPE(config_parse_tclass_classid);
+#include "drr.h"
#include "htb.h"
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index b97daca959..a729adcc86 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -356,10 +356,21 @@ ClassId=
Priority=
Rate=
CeilRate=
+[BFIFO]
+Parent=
+Handle=
+LimitSize=
[PFIFO]
Parent=
Handle=
PacketLimit=
+[PFIFOHeadDrop]
+Parent=
+Handle=
+PacketLimit=
+[PFIFOFast]
+Parent=
+Handle=
[GenericRandomEarlyDetection]
Parent=
Handle=
@@ -370,3 +381,18 @@ GenericRIO=
Parent=
Handle=
PacketLimit=
+[PIE]
+Parent=
+Handle=
+PacketLimit=
+[DeficitRoundRobinScheduler]
+Parent=
+Handle=
+[DeficitRoundRobinSchedulerClass]
+Parent=
+ClassId=
+Quantum=
+[HeavyHitterFilter]
+Parent=
+Handle=
+PacketLimit=
diff --git a/test/test-network/conf/25-qdisc-clsact-and-htb.network b/test/test-network/conf/25-qdisc-clsact-and-htb.network
index 039a2ffa65..0d6815710c 100644
--- a/test/test-network/conf/25-qdisc-clsact-and-htb.network
+++ b/test/test-network/conf/25-qdisc-clsact-and-htb.network
@@ -160,3 +160,38 @@ CeilRate=0.5M
Parent=2:39
Handle=0039
PacketLimit=200000
+
+[HierarchyTokenBucketClass]
+Parent=root
+ClassId=0002:003a
+Priority=1
+Rate=1M
+CeilRate=0.5M
+
+[BFIFO]
+Parent=2:3a
+Handle=003a
+LimitSize=1M
+
+[HierarchyTokenBucketClass]
+Parent=root
+ClassId=0002:003b
+Priority=1
+Rate=1M
+CeilRate=0.5M
+
+[PFIFOHeadDrop]
+Parent=2:3b
+Handle=003b
+PacketLimit=1023
+
+[HierarchyTokenBucketClass]
+Parent=root
+ClassId=0002:003c
+Priority=1
+Rate=1M
+CeilRate=0.5M
+
+[PFIFOFast]
+Parent=2:3c
+Handle=003c
diff --git a/test/test-network/conf/25-qdisc-drr.network b/test/test-network/conf/25-qdisc-drr.network
new file mode 100644
index 0000000000..4632740061
--- /dev/null
+++ b/test/test-network/conf/25-qdisc-drr.network
@@ -0,0 +1,15 @@
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[DeficitRoundRobinScheduler]
+Parent=root
+Handle=0002
+
+[DeficitRoundRobinSchedulerClass]
+Parent=root
+ClassId=0002:0030
+Quantum=2000
diff --git a/test/test-network/conf/25-qdisc-hhf.network b/test/test-network/conf/25-qdisc-hhf.network
new file mode 100644
index 0000000000..950536259f
--- /dev/null
+++ b/test/test-network/conf/25-qdisc-hhf.network
@@ -0,0 +1,11 @@
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[HeavyHitterFilter]
+Parent=root
+Handle=3a
+PacketLimit=1022
diff --git a/test/test-network/conf/25-qdisc-pie.network b/test/test-network/conf/25-qdisc-pie.network
new file mode 100644
index 0000000000..d41ceba3ef
--- /dev/null
+++ b/test/test-network/conf/25-qdisc-pie.network
@@ -0,0 +1,11 @@
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[PIE]
+Parent=root
+Handle=3a
+PacketLimit=200000
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index fb0048b3e6..5df1fed985 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -169,6 +169,30 @@ def expectedFailureIfCAKEIsNotAvailable():
return f
+def expectedFailureIfPIEIsNotAvailable():
+ def f(func):
+ call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
+ rc = call('tc qdisc add dev dummy98 parent root pie', stderr=subprocess.DEVNULL)
+ call('ip link del dummy98', stderr=subprocess.DEVNULL)
+ if rc == 0:
+ return func
+ else:
+ return unittest.expectedFailure(func)
+
+ return f
+
+def expectedFailureIfHHFIsNotAvailable():
+ def f(func):
+ call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
+ rc = call('tc qdisc add dev dummy98 parent root hhf', stderr=subprocess.DEVNULL)
+ call('ip link del dummy98', stderr=subprocess.DEVNULL)
+ if rc == 0:
+ return func
+ else:
+ return unittest.expectedFailure(func)
+
+ return f
+
def setUpModule():
global running_units
@@ -1635,7 +1659,10 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
'25-nexthop.network',
'25-qdisc-cake.network',
'25-qdisc-clsact-and-htb.network',
+ '25-qdisc-drr.network',
+ '25-qdisc-hhf.network',
'25-qdisc-ingress-netem-compat.network',
+ '25-qdisc-pie.network',
'25-route-ipv6-src.network',
'25-route-static.network',
'25-route-vrf.network',
@@ -2316,6 +2343,14 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'qdisc sfb 39: parent 2:39')
self.assertRegex(output, 'limit 200000')
+ self.assertRegex(output, 'qdisc bfifo 3a: parent 2:3a')
+ self.assertRegex(output, 'limit 1000000')
+
+ self.assertRegex(output, 'qdisc pfifo_head_drop 3b: parent 2:3b')
+ self.assertRegex(output, 'limit 1023p')
+
+ self.assertRegex(output, 'qdisc pfifo_fast 3c: parent 2:3c')
+
output = check_output('tc class show dev dummy98')
print(output)
self.assertRegex(output, 'class htb 2:30 root leaf 30:')
@@ -2328,8 +2363,24 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'class htb 2:37 root leaf 37:')
self.assertRegex(output, 'class htb 2:38 root leaf 38:')
self.assertRegex(output, 'class htb 2:39 root leaf 39:')
+ self.assertRegex(output, 'class htb 2:3a root leaf 3a:')
+ self.assertRegex(output, 'class htb 2:3b root leaf 3b:')
+ self.assertRegex(output, 'class htb 2:3c root leaf 3c:')
self.assertRegex(output, 'prio 1 rate 1Mbit ceil 500Kbit')
+ def test_qdisc2(self):
+ copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev')
+ start_networkd()
+
+ self.wait_online(['dummy98:routable'])
+
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'qdisc drr 2: root')
+ output = check_output('tc class show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'class drr 2:30 root quantum 2000b')
+
@expectedFailureIfCAKEIsNotAvailable()
def test_qdisc_cake(self):
copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
@@ -2342,6 +2393,28 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'bandwidth 500Mbit')
self.assertRegex(output, 'overhead 128')
+ @expectedFailureIfPIEIsNotAvailable()
+ def test_qdisc_pie(self):
+ copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
+
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'qdisc pie 3a: root')
+ self.assertRegex(output, 'limit 200000')
+
+ @expectedFailureIfHHFIsNotAvailable()
+ def test_qdisc_hhf(self):
+ copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
+
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'qdisc hhf 3a: root')
+ self.assertRegex(output, 'limit 1022p')
+
class NetworkdStateFileTests(unittest.TestCase, Utilities):
links = [
'dummy98',