]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: tc: support Hierarchy Token Bucket (HTB)
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 10 Feb 2020 10:41:12 +0000 (19:41 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 2 Mar 2020 06:46:28 +0000 (15:46 +0900)
12 files changed:
man/systemd.network.xml
src/basic/parse-util.h
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-types.h
src/network/meson.build
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/tc/htb.c [new file with mode: 0644]
src/network/tc/htb.h [new file with mode: 0644]
src/network/tc/qdisc.c
src/network/tc/qdisc.h
test/fuzz/fuzz-network-parser/directives.network

index c3608394c881afedb9623ef5a21738114e20d058..2e5ac9a28bc24ce0f073e3f62fab6c06061792ad 100644 (file)
     </variablelist>
   </refsect1>
 
+  <refsect1>
+    <title>[HierarchyTokenBucket] Section Options</title>
+    <para>The <literal>[HierarchyTokenBucket]</literal> section manages the queueing discipline (qdisc) of
+    hierarchy token bucket (htb).</para>
+
+    <variablelist class='network-directives'>
+      <varlistentry>
+        <term><varname>Parent=</varname></term>
+        <listitem>
+          <para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
+          <literal>clsact</literal>, <literal>ingress</literal> or a class id. The class id takes the
+          major and minor number in hexadecimal ranges 1 to ffff separated with a colon
+          (<literal>major:minor</literal>). Defaults to <literal>root</literal>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>Handle=</varname></term>
+        <listitem>
+          <para>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.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>DefaultClass=</varname></term>
+        <listitem>
+          <para>Takes the minor id in hexadecimal of the default class. Unclassified traffic gets sent
+          to the class. Defaults to unset.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
   <refsect1>
     <title>[BridgeVLAN] Section Options</title>
       <para>The <literal>[BridgeVLAN]</literal> section manages the VLAN ID configuration of a bridge port and accepts
index 6b30c727e3f98f1cb0e712a2983700caff6c5733..36d76ba57617b5f98bc9c4a371e2593881935655 100644 (file)
@@ -45,9 +45,13 @@ static inline int safe_atoux16(const char *s, uint16_t *ret) {
 
 int safe_atoi16(const char *s, int16_t *ret);
 
-static inline int safe_atou32(const char *s, uint32_t *ret_u) {
+static inline int safe_atou32_full(const char *s, unsigned base, uint32_t *ret_u) {
         assert_cc(sizeof(uint32_t) == sizeof(unsigned));
-        return safe_atou(s, (unsigned*) ret_u);
+        return safe_atou_full(s, base, (unsigned*) ret_u);
+}
+
+static inline int safe_atou32(const char *s, uint32_t *ret_u) {
+        return safe_atou32_full(s, 0, (unsigned*) ret_u);
 }
 
 static inline int safe_atoi32(const char *s, int32_t *ret_i) {
index e35127a4cd2ed97526cc3d1b5898dc722afa62dd..d4e9873bba3fd672c2784bc21b2c475921891aa1 100644 (file)
@@ -780,6 +780,10 @@ static const NLType rtnl_tca_option_data_fq_codel_types[] = {
         [TCA_FQ_CODEL_MEMORY_LIMIT]    = { .type = NETLINK_TYPE_U32 },
 };
 
+static const NLType rtnl_tca_option_data_htb_types[] = {
+        [TCA_HTB_INIT] = { .size = sizeof(struct tc_htb_glob) },
+};
+
 static const NLType rtnl_tca_option_data_tbf_types[] = {
         [TCA_TBF_PARMS]   = { .size = sizeof(struct tc_tbf_qopt) },
         [TCA_TBF_RTAB]    = { .size = TC_RTAB_SIZE },
@@ -794,6 +798,7 @@ static const char* const nl_union_tca_option_data_table[] = {
         [NL_UNION_TCA_OPTION_DATA_CODEL] = "codel",
         [NL_UNION_TCA_OPTION_DATA_FQ] = "fq",
         [NL_UNION_TCA_OPTION_DATA_FQ_CODEL] = "fq_codel",
+        [NL_UNION_TCA_OPTION_DATA_HTB] = "htb",
         [NL_UNION_TCA_OPTION_DATA_TBF] = "tbf",
 };
 
@@ -806,6 +811,8 @@ static const NLTypeSystem rtnl_tca_option_data_type_systems[] = {
                                                    .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_HTB] =         { .count = ELEMENTSOF(rtnl_tca_option_data_htb_types),
+                                                   .types = rtnl_tca_option_data_htb_types },
         [NL_UNION_TCA_OPTION_DATA_TBF] =         { .count = ELEMENTSOF(rtnl_tca_option_data_tbf_types),
                                                    .types = rtnl_tca_option_data_tbf_types },
 };
index b2fa8c96e64e770d0d1d1be878f5ce3a0b7d0456..a3dd4aa44739060feeba7a81dacf0d04b03a5f30 100644 (file)
@@ -95,6 +95,7 @@ typedef enum NLUnionTCAOptionData {
         NL_UNION_TCA_OPTION_DATA_CODEL,
         NL_UNION_TCA_OPTION_DATA_FQ,
         NL_UNION_TCA_OPTION_DATA_FQ_CODEL,
+        NL_UNION_TCA_OPTION_DATA_HTB,
         NL_UNION_TCA_OPTION_DATA_TBF,
         _NL_UNION_TCA_OPTION_DATA_MAX,
         _NL_UNION_TCA_OPTION_DATA_INVALID = -1,
index c1c02cfda162b06069e88747a13864c06e76a348..1f5175e053fce2371989a2e1b6b9e3eb0da4713d 100644 (file)
@@ -113,6 +113,8 @@ sources = files('''
         tc/fq.h
         tc/fq-codel.c
         tc/fq-codel.h
+        tc/htb.c
+        tc/htb.h
         tc/netem.c
         tc/netem.h
         tc/qdisc.c
index 134f1535d607ff87d45f807494740e569c473bee..4ebf285a6e67fcb4511d705e854e00926e4a598c 100644 (file)
@@ -281,6 +281,9 @@ FairQueueingControlledDelay.TargetSec,       config_parse_fair_queueing_controll
 FairQueueingControlledDelay.IntervalSec,     config_parse_fair_queueing_controlled_delay_usec,         QDISC_KIND_FQ_CODEL,           0
 FairQueueingControlledDelay.CEThresholdSec,  config_parse_fair_queueing_controlled_delay_usec,         QDISC_KIND_FQ_CODEL,           0
 FairQueueingControlledDelay.ECN,             config_parse_fair_queueing_controlled_delay_bool,         QDISC_KIND_FQ_CODEL,           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
 NetworkEmulator.Parent,                      config_parse_qdisc_parent,                                QDISC_KIND_NETEM,              0
 NetworkEmulator.Handle,                      config_parse_qdisc_handle,                                QDISC_KIND_NETEM,              0
 NetworkEmulator.DelaySec,                    config_parse_network_emulator_delay,                      QDISC_KIND_NETEM,              0
index b06ae75c058196d572689d69598fcd07aa0d2418..e6be07d9a194ac81c32ff4a0aa3476af83d6134c 100644 (file)
@@ -486,6 +486,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                               "ControlledDelay\0"
                               "FairQueueing\0"
                               "FairQueueingControlledDelay\0"
+                              "HierarchyTokenBucket\0"
                               "NetworkEmulator\0"
                               "StochasticFairnessQueueing\0"
                               "TokenBucketFilter\0"
diff --git a/src/network/tc/htb.c b/src/network/tc/htb.c
new file mode 100644 (file)
index 0000000..06dd5cb
--- /dev/null
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <linux/pkt_sched.h>
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "netlink-util.h"
+#include "parse-util.h"
+#include "qdisc.h"
+#include "htb.h"
+#include "string-util.h"
+
+static int hierarchy_token_bucket_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
+        HierarchyTokenBucket *htb;
+        struct tc_htb_glob opt = {
+                .rate2quantum = 10,
+                .version = 3,
+        };
+        int r;
+
+        assert(link);
+        assert(qdisc);
+        assert(req);
+
+        htb = HTB(qdisc);
+
+        opt.defcls = htb->default_class;
+
+        r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "htb");
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
+
+        r = sd_netlink_message_append_data(req, TCA_HTB_INIT, &opt, sizeof(opt));
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append TCA_HTB_INIT 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_hierarchy_token_bucket_default_class(
+                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;
+        HierarchyTokenBucket *htb;
+        Network *network = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = qdisc_new_static(QDISC_KIND_HTB, 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");
+
+        htb = HTB(qdisc);
+
+        if (isempty(rvalue)) {
+                htb->default_class = 0;
+
+                qdisc = NULL;
+                return 0;
+        }
+
+        r = safe_atou32_full(rvalue, 16, &htb->default_class);
+        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 htb_vtable = {
+        .object_size = sizeof(HierarchyTokenBucket),
+        .tca_kind = "htb",
+        .fill_message = hierarchy_token_bucket_fill_message,
+};
diff --git a/src/network/tc/htb.h b/src/network/tc/htb.h
new file mode 100644 (file)
index 0000000..6b5ef8c
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "conf-parser.h"
+#include "qdisc.h"
+
+typedef struct HierarchyTokenBucket {
+        QDisc meta;
+
+        uint32_t default_class;
+} HierarchyTokenBucket;
+
+DEFINE_QDISC_CAST(HTB, HierarchyTokenBucket);
+extern const QDiscVTable htb_vtable;
+
+CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_default_class);
index 988167f8b4d8934c2d6f2b5d2dbd61d5794c791d..9f60888aa5cbb8e7787f8481d8953b97bb0c9e44 100644 (file)
@@ -19,6 +19,7 @@ const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = {
         [QDISC_KIND_CODEL] = &codel_vtable,
         [QDISC_KIND_FQ] = &fq_vtable,
         [QDISC_KIND_FQ_CODEL] = &fq_codel_vtable,
+        [QDISC_KIND_HTB] = &htb_vtable,
         [QDISC_KIND_NETEM] = &netem_vtable,
         [QDISC_KIND_SFQ] = &sfq_vtable,
         [QDISC_KIND_TBF] = &tbf_vtable,
index 8e4a70de539f158105d32a69a859b83a38e995dc..7d9e0ddb06e614d899e2a33022bbfd785238038b 100644 (file)
@@ -11,6 +11,7 @@ typedef enum QDiscKind {
         QDISC_KIND_CODEL,
         QDISC_KIND_FQ,
         QDISC_KIND_FQ_CODEL,
+        QDISC_KIND_HTB,
         QDISC_KIND_NETEM,
         QDISC_KIND_SFQ,
         QDISC_KIND_TBF,
@@ -71,6 +72,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_qdisc_handle);
 #include "codel.h"
 #include "fq-codel.h"
 #include "fq.h"
+#include "htb.h"
 #include "netem.h"
 #include "sfq.h"
 #include "tbf.h"
index 2b41239b745817f49d6ce4b6e0aaf20861239d12..06e971110a8e9691d9c1655ff82968eae2ffd7f0 100644 (file)
@@ -337,3 +337,7 @@ NetworkEmulatorPacketLimit=
 Parent=
 Handle=
 Id=
+[HierarchyTokenBucket]
+Parent=
+Handle=
+DefaultClass=