]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: tc: introduce QDiscVTable for future extendability 14309/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 11 Dec 2019 11:10:29 +0000 (20:10 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 11 Dec 2019 15:17:18 +0000 (00:17 +0900)
src/network/tc/fq-codel.c
src/network/tc/fq-codel.h
src/network/tc/netem.c
src/network/tc/netem.h
src/network/tc/qdisc.c
src/network/tc/qdisc.h
src/network/tc/sfq.c
src/network/tc/sfq.h
src/network/tc/tbf.c
src/network/tc/tbf.h

index 6a0cc21cd663c2fcbf80acf5cd218ede4a523393..4ae2ca913b76372516748fee2ff4479467d22162 100644 (file)
 #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,
+};
index c83a83565365229d1c865b2c4057a6b79e4ce300..47c3cb5b8e58b7071733754c0c6fe62c3ab1f1f9 100644 (file)
@@ -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);
index 4e094b6d100f7596b8d35477cfbafea2a5142e08..f74be288e1b2020ab4974bef3f5cd760a1a1ab7c 100644 (file)
 #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,
+};
index 94da2670e61c18d346dcf09225e02c879e46ca47..7bf27e34fdba070d0fbd8c671b9c1a8b96c7310f 100644 (file)
@@ -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);
index d066e0713f95048510c5b7c1f64f1841b361bdc5..ee5aafe5e9fd381083a30244711433c899c1e9eb 100644 (file)
 #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;
 
index 56f4f8492cecf6db44e47dc211dc05e4a0800164..8e0ae28855fe5e1bb60900754a18b3742b14962a 100644 (file)
@@ -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"
index 607b9a83a81d8190b06d8e662846b7032c0e51de..fc0c9bfc27666ca56f8a3178cb2cc1bf3fe2082f 100644 (file)
 #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,
+};
index 529d9e9680e13b16221983a6da2ace8527aa26b5..d29bcc2e93c552a79249778f4cd0572e63c682ee 100644 (file)
@@ -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);
index a2d234be9ab7ce3c7d002e8b5c47a9418d16f16d..7dfc5651117e52b5ac93b09f274091683261a3b9 100644 (file)
 #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
+};
index 166350a133a1799115abc7e8a2ebd14b250ba1bd..317dc0310722acbb0932656fd98a67c51fe943a6 100644 (file)
@@ -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);