summaryrefslogtreecommitdiffstats
path: root/src/network/tc/cake.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:49:52 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:49:52 +0000
commit55944e5e40b1be2afc4855d8d2baf4b73d1876b5 (patch)
tree33f869f55a1b149e9b7c2b7e201867ca5dd52992 /src/network/tc/cake.c
parentInitial commit. (diff)
downloadsystemd-55944e5e40b1be2afc4855d8d2baf4b73d1876b5.tar.xz
systemd-55944e5e40b1be2afc4855d8d2baf4b73d1876b5.zip
Adding upstream version 255.4.upstream/255.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/network/tc/cake.c')
-rw-r--r--src/network/tc/cake.c737
1 files changed, 737 insertions, 0 deletions
diff --git a/src/network/tc/cake.c b/src/network/tc/cake.c
new file mode 100644
index 0000000..c495faf
--- /dev/null
+++ b/src/network/tc/cake.c
@@ -0,0 +1,737 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright © 2020 VMware, Inc. */
+
+#include <linux/pkt_sched.h>
+
+#include "alloc-util.h"
+#include "cake.h"
+#include "conf-parser.h"
+#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;
+ c->ack_filter = _CAKE_ACK_FILTER_INVALID;
+
+ return 0;
+}
+
+static int cake_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
+ CommonApplicationsKeptEnhanced *c;
+ int r;
+
+ assert(link);
+ assert(qdisc);
+ assert(req);
+
+ assert_se(c = CAKE(qdisc));
+
+ r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "cake");
+ if (r < 0)
+ return r;
+
+ if (c->bandwidth > 0) {
+ r = sd_netlink_message_append_u64(req, TCA_CAKE_BASE_RATE64, c->bandwidth);
+ if (r < 0)
+ return r;
+ }
+
+ if (c->autorate >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_AUTORATE, c->autorate);
+ if (r < 0)
+ return r;
+ }
+
+ if (c->overhead_set) {
+ r = sd_netlink_message_append_s32(req, TCA_CAKE_OVERHEAD, c->overhead);
+ if (r < 0)
+ return r;
+ }
+
+ if (c->mpu > 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_MPU, c->mpu);
+ if (r < 0)
+ return r;
+ }
+
+ if (c->compensation_mode >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_ATM, c->compensation_mode);
+ if (r < 0)
+ return r;
+ }
+
+ 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 r;
+ }
+
+ 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 r;
+ }
+
+ if (c->nat >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_NAT, c->nat);
+ if (r < 0)
+ return r;
+ }
+
+ if (c->preset >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_DIFFSERV_MODE, c->preset);
+ if (r < 0)
+ return r;
+ }
+
+ if (c->fwmark > 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_FWMARK, c->fwmark);
+ if (r < 0)
+ return r;
+ }
+
+ if (c->wash >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_WASH, c->wash);
+ if (r < 0)
+ return r;
+ }
+
+ if (c->split_gso >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_SPLIT_GSO, c->split_gso);
+ if (r < 0)
+ return r;
+ }
+
+ if (c->rtt > 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_RTT, c->rtt);
+ if (r < 0)
+ return r;
+ }
+
+ if (c->ack_filter >= 0) {
+ r = sd_netlink_message_append_u32(req, TCA_CAKE_ACK_FILTER, c->ack_filter);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_netlink_message_close_container(req);
+ if (r < 0)
+ return r;
+
+ 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 = ASSERT_PTR(data);
+ uint64_t k;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ 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->bandwidth = 0;
+
+ TAKE_PTR(qdisc);
+ return 0;
+ }
+
+ r = parse_size(rvalue, 1000, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ c->bandwidth = k/8;
+ TAKE_PTR(qdisc);
+
+ 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 = ASSERT_PTR(data);
+ int32_t v;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ 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->overhead_set = false;
+ TAKE_PTR(qdisc);
+ return 0;
+ }
+
+ r = safe_atoi32(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 < -64 || v > 256) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ 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 = ASSERT_PTR(data);
+ uint32_t v;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ 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 = ASSERT_PTR(data);
+ int *dest, r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ 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();
+
+ r = parse_tristate(rvalue, dest);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ 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 = ASSERT_PTR(data);
+ CakeCompensationMode mode;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ 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 = ASSERT_PTR(data);
+ CakeFlowIsolationMode mode;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ 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 = ASSERT_PTR(data);
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ 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 = ASSERT_PTR(data);
+ uint32_t fwmark;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ 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;
+}
+
+int config_parse_cake_rtt(
+ 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 = ASSERT_PTR(data);
+ usec_t t;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ 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->rtt = 0;
+ TAKE_PTR(qdisc);
+ return 0;
+ }
+
+ r = parse_sec(rvalue, &t);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+ if (t <= 0 || t > UINT32_MAX) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ c->rtt = t;
+ TAKE_PTR(qdisc);
+ return 0;
+}
+
+static const char * const cake_ack_filter_table[_CAKE_ACK_FILTER_MAX] = {
+ [CAKE_ACK_FILTER_NO] = "no",
+ [CAKE_ACK_FILTER_YES] = "yes",
+ [CAKE_ACK_FILTER_AGGRESSIVE] = "aggressive",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(cake_ack_filter, CakeAckFilter, CAKE_ACK_FILTER_YES);
+
+int config_parse_cake_ack_filter(
+ 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;
+ CakeAckFilter ack_filter;
+ Network *network = ASSERT_PTR(data);
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ 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->ack_filter = _CAKE_ACK_FILTER_INVALID;
+ TAKE_PTR(qdisc);
+ return 0;
+ }
+
+ ack_filter = cake_ack_filter_from_string(rvalue);
+ if (ack_filter < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, ack_filter,
+ "Failed to parse '%s=', ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ c->ack_filter = ack_filter;
+ TAKE_PTR(qdisc);
+ return 0;
+}
+
+const QDiscVTable cake_vtable = {
+ .object_size = sizeof(CommonApplicationsKeptEnhanced),
+ .tca_kind = "cake",
+ .init = cake_init,
+ .fill_message = cake_fill_message,
+};