summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2019-12-11 12:10:29 +0100
committerYu Watanabe <watanabe.yu+github@gmail.com>2019-12-11 16:17:18 +0100
commite8c17dc078ee60b6810c8f1e9070b35e67353334 (patch)
tree49864e1d75f828337a468734fb352074776875c8
parentnetwork: tc: drop unused element (diff)
downloadsystemd-e8c17dc078ee60b6810c8f1e9070b35e67353334.tar.xz
systemd-e8c17dc078ee60b6810c8f1e9070b35e67353334.zip
network: tc: introduce QDiscVTable for future extendability
-rw-r--r--src/network/tc/fq-codel.c28
-rw-r--r--src/network/tc/fq-codel.h8
-rw-r--r--src/network/tc/netem.c65
-rw-r--r--src/network/tc/netem.h9
-rw-r--r--src/network/tc/qdisc.c148
-rw-r--r--src/network/tc/qdisc.h55
-rw-r--r--src/network/tc/sfq.c28
-rw-r--r--src/network/tc/sfq.h10
-rw-r--r--src/network/tc/tbf.c78
-rw-r--r--src/network/tc/tbf.h13
10 files changed, 266 insertions, 176 deletions
diff --git a/src/network/tc/fq-codel.c b/src/network/tc/fq-codel.c
index 6a0cc21cd6..4ae2ca913b 100644
--- a/src/network/tc/fq-codel.c
+++ b/src/network/tc/fq-codel.c
@@ -10,13 +10,16 @@
#include "qdisc.h"
#include "string-util.h"
-int fair_queuing_controlled_delay_fill_message(Link *link, const FairQueuingControlledDelay *fqcd, sd_netlink_message *req) {
+static int fair_queuing_controlled_delay_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
+ FairQueuingControlledDelay *fqcd;
int r;
assert(link);
- assert(fqcd);
+ assert(qdisc);
assert(req);
+ fqcd = FQ_CODEL(qdisc);
+
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "fq_codel");
if (r < 0)
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
@@ -45,6 +48,7 @@ int config_parse_tc_fair_queuing_controlled_delay_limit(
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
+ FairQueuingControlledDelay *fqcd;
Network *network = data;
int r;
@@ -53,18 +57,23 @@ int config_parse_tc_fair_queuing_controlled_delay_limit(
assert(rvalue);
assert(data);
- r = qdisc_new_static(network, filename, section_line, &qdisc);
+ r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0)
- return r;
+ return log_syntax(unit, LOG_ERR, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+
+ fqcd = FQ_CODEL(qdisc);
if (isempty(rvalue)) {
- qdisc->fq_codel.limit = 0;
+ fqcd->limit = 0;
qdisc = NULL;
return 0;
}
- r = safe_atou32(rvalue, &qdisc->fq_codel.limit);
+ r = safe_atou32(rvalue, &fqcd->limit);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse '%s=', ignoring assignment: %s",
@@ -72,8 +81,13 @@ int config_parse_tc_fair_queuing_controlled_delay_limit(
return 0;
}
- qdisc->has_fair_queuing_controlled_delay = true;
qdisc = NULL;
return 0;
}
+
+const QDiscVTable fq_codel_vtable = {
+ .object_size = sizeof(FairQueuingControlledDelay),
+ .tca_kind = "fq_codel",
+ .fill_message = fair_queuing_controlled_delay_fill_message,
+};
diff --git a/src/network/tc/fq-codel.h b/src/network/tc/fq-codel.h
index c83a835653..47c3cb5b8e 100644
--- a/src/network/tc/fq-codel.h
+++ b/src/network/tc/fq-codel.h
@@ -2,15 +2,15 @@
* Copyright © 2019 VMware, Inc. */
#pragma once
-#include "sd-netlink.h"
-
#include "conf-parser.h"
-#include "networkd-link.h"
+#include "qdisc.h"
typedef struct FairQueuingControlledDelay {
+ QDisc meta;
uint32_t limit;
} FairQueuingControlledDelay;
-int fair_queuing_controlled_delay_fill_message(Link *link, const FairQueuingControlledDelay *sfq, sd_netlink_message *req);
+DEFINE_QDISC_CAST(FQ_CODEL, FairQueuingControlledDelay);
+extern const QDiscVTable fq_codel_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_tc_fair_queuing_controlled_delay_limit);
diff --git a/src/network/tc/netem.c b/src/network/tc/netem.c
index 4e094b6d10..f74be288e1 100644
--- a/src/network/tc/netem.c
+++ b/src/network/tc/netem.c
@@ -13,16 +13,19 @@
#include "string-util.h"
#include "tc-util.h"
-int network_emulator_fill_message(Link *link, const NetworkEmulator *ne, sd_netlink_message *req) {
+static int network_emulator_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
struct tc_netem_qopt opt = {
.limit = 1000,
};
+ NetworkEmulator *ne;
int r;
assert(link);
- assert(ne);
+ assert(qdisc);
assert(req);
+ ne = NETEM(qdisc);
+
if (ne->limit > 0)
opt.limit = ne->limit;
@@ -65,6 +68,7 @@ int config_parse_tc_network_emulator_delay(
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
+ NetworkEmulator *ne;
usec_t u;
int r;
@@ -73,15 +77,20 @@ int config_parse_tc_network_emulator_delay(
assert(rvalue);
assert(data);
- r = qdisc_new_static(network, filename, section_line, &qdisc);
+ r = qdisc_new_static(QDISC_KIND_NETEM, network, filename, section_line, &qdisc);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0)
- return r;
+ return log_syntax(unit, LOG_ERR, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+
+ ne = NETEM(qdisc);
if (isempty(rvalue)) {
if (streq(lvalue, "NetworkEmulatorDelaySec"))
- qdisc->ne.delay = USEC_INFINITY;
+ ne->delay = USEC_INFINITY;
else if (streq(lvalue, "NetworkEmulatorDelayJitterSec"))
- qdisc->ne.jitter = USEC_INFINITY;
+ ne->jitter = USEC_INFINITY;
qdisc = NULL;
return 0;
@@ -96,11 +105,10 @@ int config_parse_tc_network_emulator_delay(
}
if (streq(lvalue, "NetworkEmulatorDelaySec"))
- qdisc->ne.delay = u;
+ ne->delay = u;
else if (streq(lvalue, "NetworkEmulatorDelayJitterSec"))
- qdisc->ne.jitter = u;
+ ne->jitter = u;
- qdisc->has_network_emulator = true;
qdisc = NULL;
return 0;
@@ -120,6 +128,7 @@ int config_parse_tc_network_emulator_rate(
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
+ NetworkEmulator *ne;
uint32_t rate;
int r;
@@ -128,12 +137,20 @@ int config_parse_tc_network_emulator_rate(
assert(rvalue);
assert(data);
- r = qdisc_new_static(network, filename, section_line, &qdisc);
+ r = qdisc_new_static(QDISC_KIND_NETEM, network, filename, section_line, &qdisc);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0)
- return r;
+ return log_syntax(unit, LOG_ERR, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+
+ ne = NETEM(qdisc);
if (isempty(rvalue)) {
- qdisc->ne.loss = 0;
+ if (streq(lvalue, "NetworkEmulatorLossRate"))
+ ne->loss = 0;
+ else if (streq(lvalue, "NetworkEmulatorDuplicateRate"))
+ ne->duplicate = 0;
qdisc = NULL;
return 0;
@@ -148,9 +165,9 @@ int config_parse_tc_network_emulator_rate(
}
if (streq(lvalue, "NetworkEmulatorLossRate"))
- qdisc->ne.loss = rate;
+ ne->loss = rate;
else if (streq(lvalue, "NetworkEmulatorDuplicateRate"))
- qdisc->ne.duplicate = rate;
+ ne->duplicate = rate;
qdisc = NULL;
return 0;
@@ -170,6 +187,7 @@ int config_parse_tc_network_emulator_packet_limit(
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
+ NetworkEmulator *ne;
int r;
assert(filename);
@@ -177,18 +195,23 @@ int config_parse_tc_network_emulator_packet_limit(
assert(rvalue);
assert(data);
- r = qdisc_new_static(network, filename, section_line, &qdisc);
+ r = qdisc_new_static(QDISC_KIND_NETEM, network, filename, section_line, &qdisc);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0)
- return r;
+ return log_syntax(unit, LOG_ERR, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+
+ ne = NETEM(qdisc);
if (isempty(rvalue)) {
- qdisc->ne.limit = 0;
+ ne->limit = 0;
qdisc = NULL;
return 0;
}
- r = safe_atou(rvalue, &qdisc->ne.limit);
+ r = safe_atou(rvalue, &ne->limit);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse 'NetworkEmulatorPacketLimit=', ignoring assignment: %s",
@@ -199,3 +222,9 @@ int config_parse_tc_network_emulator_packet_limit(
qdisc = NULL;
return 0;
}
+
+const QDiscVTable netem_vtable = {
+ .object_size = sizeof(NetworkEmulator),
+ .tca_kind = "netem",
+ .fill_message = network_emulator_fill_message,
+};
diff --git a/src/network/tc/netem.h b/src/network/tc/netem.h
index 94da2670e6..7bf27e34fd 100644
--- a/src/network/tc/netem.h
+++ b/src/network/tc/netem.h
@@ -2,13 +2,13 @@
* Copyright © 2019 VMware, Inc. */
#pragma once
-#include "sd-netlink.h"
-
#include "conf-parser.h"
-#include "networkd-link.h"
+#include "qdisc.h"
#include "time-util.h"
typedef struct NetworkEmulator {
+ QDisc meta;
+
usec_t delay;
usec_t jitter;
@@ -17,7 +17,8 @@ typedef struct NetworkEmulator {
uint32_t duplicate;
} NetworkEmulator;
-int network_emulator_fill_message(Link *link, const NetworkEmulator *ne, sd_netlink_message *req);
+DEFINE_QDISC_CAST(NETEM, NetworkEmulator);
+extern const QDiscVTable netem_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_delay);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_rate);
diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c
index d066e0713f..ee5aafe5e9 100644
--- a/src/network/tc/qdisc.c
+++ b/src/network/tc/qdisc.c
@@ -13,65 +13,94 @@
#include "set.h"
#include "string-util.h"
-static int qdisc_new(QDisc **ret) {
+const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = {
+ [QDISC_KIND_FQ_CODEL] = &fq_codel_vtable,
+ [QDISC_KIND_NETEM] = &netem_vtable,
+ [QDISC_KIND_SFQ] = &sfq_vtable,
+ [QDISC_KIND_TBF] = &tbf_vtable,
+};
+
+static int qdisc_new(QDiscKind kind, QDisc **ret) {
QDisc *qdisc;
- qdisc = new(QDisc, 1);
- if (!qdisc)
- return -ENOMEM;
+ if (kind == _QDISC_KIND_INVALID) {
+ qdisc = new(QDisc, 1);
+ if (!qdisc)
+ return -ENOMEM;
- *qdisc = (QDisc) {
- .family = AF_UNSPEC,
- .parent = TC_H_ROOT,
- };
+ *qdisc = (QDisc) {
+ .family = AF_UNSPEC,
+ .parent = TC_H_ROOT,
+ .kind = kind,
+ };
+ } else {
+ qdisc = malloc0(qdisc_vtable[kind]->object_size);
+ if (!qdisc)
+ return -ENOMEM;
+
+ qdisc->family = AF_UNSPEC;
+ qdisc->parent = TC_H_ROOT;
+ qdisc->kind = kind;
+ }
*ret = TAKE_PTR(qdisc);
return 0;
}
-int qdisc_new_static(Network *network, const char *filename, unsigned section_line, QDisc **ret) {
+int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret) {
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
_cleanup_(qdisc_freep) QDisc *qdisc = NULL;
+ QDisc *existing;
int r;
assert(network);
assert(ret);
- assert(!!filename == (section_line > 0));
+ assert(filename);
+ assert(section_line > 0);
- if (filename) {
- r = network_config_section_new(filename, section_line, &n);
- if (r < 0)
- return r;
+ r = network_config_section_new(filename, section_line, &n);
+ if (r < 0)
+ return r;
- qdisc = ordered_hashmap_get(network->qdiscs_by_section, n);
- if (qdisc) {
- *ret = TAKE_PTR(qdisc);
+ existing = ordered_hashmap_get(network->qdiscs_by_section, n);
+ if (existing) {
+ if (existing->kind != _QDISC_KIND_INVALID &&
+ kind != _QDISC_KIND_INVALID &&
+ existing->kind != kind)
+ return -EINVAL;
+ if (existing->kind == kind || kind == _QDISC_KIND_INVALID) {
+ *ret = existing;
return 0;
}
}
- r = qdisc_new(&qdisc);
+ r = qdisc_new(kind, &qdisc);
if (r < 0)
return r;
- qdisc->network = network;
+ if (existing) {
+ qdisc->family = existing->family;
+ qdisc->handle = existing->handle;
+ qdisc->parent = existing->parent;
+ qdisc->tca_kind = TAKE_PTR(existing->tca_kind);
- if (filename) {
- qdisc->section = TAKE_PTR(n);
+ qdisc_free(ordered_hashmap_remove(network->qdiscs_by_section, n));
+ }
- r = ordered_hashmap_ensure_allocated(&network->qdiscs_by_section, &network_config_hash_ops);
- if (r < 0)
- return r;
+ qdisc->network = network;
+ qdisc->section = TAKE_PTR(n);
- r = ordered_hashmap_put(network->qdiscs_by_section, qdisc->section, qdisc);
- if (r < 0)
- return r;
- }
+ r = ordered_hashmap_ensure_allocated(&network->qdiscs_by_section, &network_config_hash_ops);
+ if (r < 0)
+ return r;
- *ret = TAKE_PTR(qdisc);
+ r = ordered_hashmap_put(network->qdiscs_by_section, qdisc->section, qdisc);
+ if (r < 0)
+ return r;
+ *ret = TAKE_PTR(qdisc);
return 0;
}
@@ -116,8 +145,6 @@ static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int qdisc_configure(Link *link, QDisc *qdisc) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
- _cleanup_free_ char *tca_kind = NULL;
- char *p;
int r;
assert(link);
@@ -139,49 +166,16 @@ int qdisc_configure(Link *link, QDisc *qdisc) {
return log_link_error_errno(link, r, "Could not set tcm_handle message: %m");
}
- if (qdisc->has_network_emulator) {
- r = free_and_strdup(&tca_kind, "netem");
+ if (QDISC_VTABLE(qdisc)) {
+ r = sd_netlink_message_append_string(req, TCA_KIND, QDISC_VTABLE(qdisc)->tca_kind);
if (r < 0)
- return log_oom();
-
- r = network_emulator_fill_message(link, &qdisc->ne, req);
- if (r < 0)
- return r;
- }
-
- if (qdisc->has_token_buffer_filter) {
- r = free_and_strdup(&tca_kind, "tbf");
- if (r < 0)
- return log_oom();
-
- r = token_buffer_filter_fill_message(link, &qdisc->tbf, req);
- if (r < 0)
- return r;
- }
-
- if (qdisc->has_stochastic_fairness_queueing) {
- r = free_and_strdup(&tca_kind, "sfq");
- if (r < 0)
- return log_oom();
-
- r = stochastic_fairness_queueing_fill_message(link, &qdisc->sfq, req);
- if (r < 0)
- return r;
- }
-
- if (qdisc->has_fair_queuing_controlled_delay) {
- r = free_and_strdup(&tca_kind, "fq_codel");
- if (r < 0)
- return log_oom();
+ return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m");
- r = fair_queuing_controlled_delay_fill_message(link, &qdisc->fq_codel, req);
+ r = QDISC_VTABLE(qdisc)->fill_message(link, qdisc, req);
if (r < 0)
return r;
- }
-
- p = tca_kind ?:qdisc->tca_kind;
- if (p) {
- r = sd_netlink_message_append_string(req, TCA_KIND, p);
+ } else {
+ r = sd_netlink_message_append_string(req, TCA_KIND, qdisc->tca_kind);
if (r < 0)
return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m");
}
@@ -197,7 +191,6 @@ int qdisc_configure(Link *link, QDisc *qdisc) {
}
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) {
- unsigned i;
int r;
assert(qdisc);
@@ -207,15 +200,8 @@ int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) {
if (section_is_invalid(qdisc->section))
return -EINVAL;
- i = qdisc->has_network_emulator + qdisc->has_token_buffer_filter + qdisc->has_stochastic_fairness_queueing;
- if (i > 1)
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: TrafficControlQueueingDiscipline section has more than one type of discipline. "
- "Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
- qdisc->section->filename, qdisc->section->line);
-
- if (qdisc->has_token_buffer_filter) {
- r = token_buffer_filter_section_verify(&qdisc->tbf, qdisc->section);
+ if (QDISC_VTABLE(qdisc) && QDISC_VTABLE(qdisc)->verify) {
+ r = QDISC_VTABLE(qdisc)->verify(qdisc);
if (r < 0)
return r;
}
@@ -260,7 +246,7 @@ int config_parse_tc_qdiscs_parent(
assert(rvalue);
assert(data);
- r = qdisc_new_static(network, filename, section_line, &qdisc);
+ r = qdisc_new_static(_QDISC_KIND_INVALID, network, filename, section_line, &qdisc);
if (r < 0)
return r;
diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h
index 56f4f8492c..8e0ae28855 100644
--- a/src/network/tc/qdisc.h
+++ b/src/network/tc/qdisc.h
@@ -3,42 +3,65 @@
#pragma once
#include "conf-parser.h"
-#include "fq-codel.h"
-#include "netem.h"
#include "networkd-link.h"
#include "networkd-network.h"
#include "networkd-util.h"
-#include "sfq.h"
-#include "tbf.h"
+
+typedef enum QDiscKind {
+ QDISC_KIND_FQ_CODEL,
+ QDISC_KIND_NETEM,
+ QDISC_KIND_SFQ,
+ QDISC_KIND_TBF,
+ _QDISC_KIND_MAX,
+ _QDISC_KIND_INVALID = -1,
+} QDiscKind;
typedef struct QDisc {
NetworkConfigSection *section;
Network *network;
int family;
-
uint32_t handle;
uint32_t parent;
char *tca_kind;
- bool has_network_emulator:1;
- bool has_token_buffer_filter:1;
- bool has_stochastic_fairness_queueing:1;
- bool has_fair_queuing_controlled_delay:1;
-
- NetworkEmulator ne;
- TokenBufferFilter tbf;
- StochasticFairnessQueueing sfq;
- FairQueuingControlledDelay fq_codel;
+ QDiscKind kind;
} QDisc;
+typedef struct QDiscVTable {
+ size_t object_size;
+ const char *tca_kind;
+ int (*fill_message)(Link *link, QDisc *qdisc, sd_netlink_message *m);
+ int (*verify)(QDisc *qdisc);
+} QDiscVTable;
+
+extern const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX];
+
+#define QDISC_VTABLE(q) ((q)->kind != _QDISC_KIND_INVALID ? qdisc_vtable[(q)->kind] : NULL)
+
+/* For casting a qdisc into the various qdisc kinds */
+#define DEFINE_QDISC_CAST(UPPERCASE, MixedCase) \
+ static inline MixedCase* UPPERCASE(QDisc *q) { \
+ if (_unlikely_(!q || q->kind != QDISC_KIND_##UPPERCASE)) \
+ return NULL; \
+ \
+ return (MixedCase*) q; \
+ }
+
+/* For casting the various qdisc kinds into a qdisc */
+#define QDISC(q) (&(q)->meta)
+
void qdisc_free(QDisc *qdisc);
-int qdisc_new_static(Network *network, const char *filename, unsigned section_line, QDisc **ret);
+int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret);
int qdisc_configure(Link *link, QDisc *qdisc);
-
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact);
DEFINE_NETWORK_SECTION_FUNCTIONS(QDisc, qdisc_free);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_qdiscs_parent);
+
+#include "fq-codel.h"
+#include "netem.h"
+#include "sfq.h"
+#include "tbf.h"
diff --git a/src/network/tc/sfq.c b/src/network/tc/sfq.c
index 607b9a83a8..fc0c9bfc27 100644
--- a/src/network/tc/sfq.c
+++ b/src/network/tc/sfq.c
@@ -11,14 +11,17 @@
#include "sfq.h"
#include "string-util.h"
-int stochastic_fairness_queueing_fill_message(Link *link, const StochasticFairnessQueueing *sfq, sd_netlink_message *req) {
+static int stochastic_fairness_queueing_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
+ StochasticFairnessQueueing *sfq;
struct tc_sfq_qopt_v1 opt = {};
int r;
assert(link);
- assert(sfq);
+ assert(qdisc);
assert(req);
+ sfq = SFQ(qdisc);
+
opt.v0.perturb_period = sfq->perturb_period / USEC_PER_SEC;
r = sd_netlink_message_append_data(req, TCA_OPTIONS, &opt, sizeof(struct tc_sfq_qopt_v1));
@@ -41,6 +44,7 @@ int config_parse_tc_stochastic_fairness_queueing_perturb_period(
void *userdata) {
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
+ StochasticFairnessQueueing *sfq;
Network *network = data;
int r;
@@ -49,18 +53,23 @@ int config_parse_tc_stochastic_fairness_queueing_perturb_period(
assert(rvalue);
assert(data);
- r = qdisc_new_static(network, filename, section_line, &qdisc);
+ r = qdisc_new_static(QDISC_KIND_SFQ, network, filename, section_line, &qdisc);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0)
- return r;
+ return log_syntax(unit, LOG_ERR, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+
+ sfq = SFQ(qdisc);
if (isempty(rvalue)) {
- qdisc->sfq.perturb_period = 0;
+ sfq->perturb_period = 0;
qdisc = NULL;
return 0;
}
- r = parse_sec(rvalue, &qdisc->sfq.perturb_period);
+ r = parse_sec(rvalue, &sfq->perturb_period);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse '%s=', ignoring assignment: %s",
@@ -68,8 +77,13 @@ int config_parse_tc_stochastic_fairness_queueing_perturb_period(
return 0;
}
- qdisc->has_stochastic_fairness_queueing = true;
qdisc = NULL;
return 0;
}
+
+const QDiscVTable sfq_vtable = {
+ .object_size = sizeof(StochasticFairnessQueueing),
+ .tca_kind = "sfq",
+ .fill_message = stochastic_fairness_queueing_fill_message,
+};
diff --git a/src/network/tc/sfq.h b/src/network/tc/sfq.h
index 529d9e9680..d29bcc2e93 100644
--- a/src/network/tc/sfq.h
+++ b/src/network/tc/sfq.h
@@ -2,15 +2,17 @@
* Copyright © 2019 VMware, Inc. */
#pragma once
-#include "sd-netlink.h"
-
#include "conf-parser.h"
-#include "networkd-link.h"
+#include "qdisc.h"
+#include "time-util.h"
typedef struct StochasticFairnessQueueing {
+ QDisc meta;
+
usec_t perturb_period;
} StochasticFairnessQueueing;
-int stochastic_fairness_queueing_fill_message(Link *link, const StochasticFairnessQueueing *sfq, sd_netlink_message *req);
+DEFINE_QDISC_CAST(SFQ, StochasticFairnessQueueing);
+extern const QDiscVTable sfq_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_tc_stochastic_fairness_queueing_perturb_period);
diff --git a/src/network/tc/tbf.c b/src/network/tc/tbf.c
index a2d234be9a..7dfc565111 100644
--- a/src/network/tc/tbf.c
+++ b/src/network/tc/tbf.c
@@ -15,15 +15,18 @@
#include "tc-util.h"
#include "util.h"
-int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, sd_netlink_message *req) {
+static int token_buffer_filter_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
uint32_t rtab[256], ptab[256];
struct tc_tbf_qopt opt = {};
+ TokenBufferFilter *tbf;
int r;
assert(link);
- assert(tbf);
+ assert(qdisc);
assert(req);
+ tbf = TBF(qdisc);
+
opt.rate.rate = tbf->rate >= (1ULL << 32) ? ~0U : tbf->rate;
opt.peakrate.rate = tbf->peak_rate >= (1ULL << 32) ? ~0U : tbf->peak_rate;
@@ -121,6 +124,7 @@ int config_parse_tc_token_buffer_filter_size(
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
+ TokenBufferFilter *tbf;
uint64_t k;
int r;
@@ -129,23 +133,28 @@ int config_parse_tc_token_buffer_filter_size(
assert(rvalue);
assert(data);
- r = qdisc_new_static(network, filename, section_line, &qdisc);
+ r = qdisc_new_static(QDISC_KIND_TBF, network, filename, section_line, &qdisc);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0)
- return r;
+ return log_syntax(unit, LOG_ERR, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+
+ tbf = TBF(qdisc);
if (isempty(rvalue)) {
if (streq(lvalue, "TokenBufferFilterRate"))
- qdisc->tbf.rate = 0;
+ tbf->rate = 0;
else if (streq(lvalue, "TokenBufferFilterBurst"))
- qdisc->tbf.burst = 0;
+ tbf->burst = 0;
else if (streq(lvalue, "TokenBufferFilterLimitSize"))
- qdisc->tbf.limit = 0;
+ tbf->limit = 0;
else if (streq(lvalue, "TokenBufferFilterMTUBytes"))
- qdisc->tbf.mtu = 0;
+ tbf->mtu = 0;
else if (streq(lvalue, "TokenBufferFilterMPUBytes"))
- qdisc->tbf.mpu = 0;
+ tbf->mpu = 0;
else if (streq(lvalue, "TokenBufferFilterPeakRate"))
- qdisc->tbf.peak_rate = 0;
+ tbf->peak_rate = 0;
qdisc = NULL;
return 0;
@@ -160,19 +169,18 @@ int config_parse_tc_token_buffer_filter_size(
}
if (streq(lvalue, "TokenBufferFilterRate"))
- qdisc->tbf.rate = k / 8;
+ tbf->rate = k / 8;
else if (streq(lvalue, "TokenBufferFilterBurst"))
- qdisc->tbf.burst = k;
+ tbf->burst = k;
else if (streq(lvalue, "TokenBufferFilterLimitSize"))
- qdisc->tbf.limit = k;
+ tbf->limit = k;
else if (streq(lvalue, "TokenBufferFilterMPUBytes"))
- qdisc->tbf.mpu = k;
+ tbf->mpu = k;
else if (streq(lvalue, "TokenBufferFilterMTUBytes"))
- qdisc->tbf.mtu = k;
+ tbf->mtu = k;
else if (streq(lvalue, "TokenBufferFilterPeakRate"))
- qdisc->tbf.peak_rate = k / 8;
+ tbf->peak_rate = k / 8;
- qdisc->has_token_buffer_filter = true;
qdisc = NULL;
return 0;
@@ -192,6 +200,7 @@ int config_parse_tc_token_buffer_filter_latency(
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
Network *network = data;
+ TokenBufferFilter *tbf;
usec_t u;
int r;
@@ -200,12 +209,17 @@ int config_parse_tc_token_buffer_filter_latency(
assert(rvalue);
assert(data);
- r = qdisc_new_static(network, filename, section_line, &qdisc);
+ r = qdisc_new_static(QDISC_KIND_TBF, network, filename, section_line, &qdisc);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0)
- return r;
+ return log_syntax(unit, LOG_ERR, filename, line, r,
+ "More than one kind of queueing discipline, ignoring assignment: %m");
+
+ tbf = TBF(qdisc);
if (isempty(rvalue)) {
- qdisc->tbf.latency = 0;
+ tbf->latency = 0;
qdisc = NULL;
return 0;
@@ -219,44 +233,52 @@ int config_parse_tc_token_buffer_filter_latency(
return 0;
}
- qdisc->tbf.latency = u;
+ tbf->latency = u;
- qdisc->has_token_buffer_filter = true;
qdisc = NULL;
return 0;
}
-int token_buffer_filter_section_verify(const TokenBufferFilter *tbf, const NetworkConfigSection *section) {
+static int token_buffer_filter_verify(QDisc *qdisc) {
+ TokenBufferFilter *tbf = TBF(qdisc);
+
if (tbf->limit > 0 && tbf->latency > 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Specifying both TokenBufferFilterLimitSize= and TokenBufferFilterLatencySec= is not allowed. "
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
- section->filename, section->line);
+ qdisc->section->filename, qdisc->section->line);
if (tbf->limit == 0 && tbf->latency == 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Either TokenBufferFilterLimitSize= or TokenBufferFilterLatencySec= is required. "
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
- section->filename, section->line);
+ qdisc->section->filename, qdisc->section->line);
if (tbf->rate == 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: TokenBufferFilterRate= is mandatory. "
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
- section->filename, section->line);
+ qdisc->section->filename, qdisc->section->line);
if (tbf->burst == 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: TokenBufferFilterBurst= is mandatory. "
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
- section->filename, section->line);
+ qdisc->section->filename, qdisc->section->line);
if (tbf->peak_rate > 0 && tbf->mtu == 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: TokenBufferFilterMTUBytes= is mandatory when TokenBufferFilterPeakRate= is specified. "
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
- section->filename, section->line);
+ qdisc->section->filename, qdisc->section->line);
return 0;
}
+
+const QDiscVTable tbf_vtable = {
+ .object_size = sizeof(TokenBufferFilter),
+ .tca_kind = "tbf",
+ .fill_message = token_buffer_filter_fill_message,
+ .verify = token_buffer_filter_verify
+};
diff --git a/src/network/tc/tbf.h b/src/network/tc/tbf.h
index 166350a133..317dc03107 100644
--- a/src/network/tc/tbf.h
+++ b/src/network/tc/tbf.h
@@ -2,14 +2,13 @@
* Copyright © 2019 VMware, Inc. */
#pragma once
-#include "sd-netlink.h"
-
#include "conf-parser.h"
-#include "networkd-link.h"
-#include "networkd-util.h"
-#include "tc-util.h"
+#include "qdisc.h"
+#include "time-util.h"
typedef struct TokenBufferFilter {
+ QDisc meta;
+
uint64_t rate;
uint64_t peak_rate;
uint32_t burst;
@@ -19,8 +18,8 @@ typedef struct TokenBufferFilter {
size_t mpu;
} TokenBufferFilter;
-int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, sd_netlink_message *req);
-int token_buffer_filter_section_verify(const TokenBufferFilter *tbf, const NetworkConfigSection *section);
+DEFINE_QDISC_CAST(TBF, TokenBufferFilter);
+extern const QDiscVTable tbf_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_latency);
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_size);