]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkd tc: introduce tbf
authorSusant Sahani <ssahani@vmware.com>
Sun, 17 Nov 2019 06:30:03 +0000 (07:30 +0100)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 4 Dec 2019 11:55:48 +0000 (20:55 +0900)
See https://linux.die.net/man/8/tc-tbf

man/systemd.network.xml
src/libsystemd/sd-netlink/netlink-message.c
src/network/meson.build
src/network/networkd-network-gperf.gperf
src/network/tc/qdisc.c
src/network/tc/qdisc.h
src/network/tc/tbf.c [new file with mode: 0644]
src/network/tc/tbf.h [new file with mode: 0644]
test/fuzz/fuzz-network-parser/directives.network

index a26e08c99cc40966ddbdfbcff5fb8a8163ff6154..20723bfbfa8d3523b72df0a347339caeae4f3ff6 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>TokenBufferFilterLatencySec=</varname></term>
+        <listitem>
+          <para>Specifies the latency parameter, which specifies the maximum amount of time a
+          packet can sit in the Token Buffer Filter (TBF). Defaults to unset.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>TokenBufferFilterBurst=</varname></term>
+        <listitem>
+          <para>Specifies the size of the bucket. This is the maximum amount of bytes that tokens
+          can be available for instantaneous transfer. When the size is suffixed with K, M, or G, it is
+          parsed as Kilobytes, Megabytes, or Gigabytes, respectively, to the base of 1000. Defaults to
+          unset.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>TokenBufferFilterRate=</varname></term>
+        <listitem>
+          <para>Specifies the device specific bandwidth. When suffixed with K, M, or G, the specified
+          bandwidth is parsed as Kilobytes, Megabytes, or Gigabytes, respectively, to the base of 1000.
+          Defaults to unset.</para>
+        </listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
 
index 34b66e6fa605defff13d192ca5ad7e43fe26a523..1569f34cc41ac5eb22091a730b275168b7d40a9d 100644 (file)
@@ -532,7 +532,6 @@ int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
 
         assert_return(m, -EINVAL);
         assert_return(!m->sealed, -EPERM);
-        assert_return(m->n_containers > 0, -EINVAL);
 
         r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
         if (r < 0)
index d502279151cfc855918fc46cfde50bdc17aeacaf..3633694577097b60691dafc874029eb922614c2a 100644 (file)
@@ -109,6 +109,8 @@ sources = files('''
         tc/netem.h
         tc/qdisc.c
         tc/qdisc.h
+        tc/tbf.c
+        tc/tbf.h
         tc/tc-util.c
         tc/tc-util.h
 '''.split())
index f314b1ec16ef09d34b9a9b7ade7faa5d2a4a1b10..32c6afc49e9c931940157a5be84e55c3c73d7a4a 100644 (file)
@@ -250,6 +250,9 @@ TrafficControlQueueingDiscipline.NetworkEmulatorDelayJitterSec,      config_pars
 TrafficControlQueueingDiscipline.NetworkEmulatorLossRate,            config_parse_tc_network_emulator_rate,             0,                             0
 TrafficControlQueueingDiscipline.NetworkEmulatorDuplicateRate,       config_parse_tc_network_emulator_rate,             0,                             0
 TrafficControlQueueingDiscipline.NetworkEmulatorPacketLimit,         config_parse_tc_network_emulator_packet_limit,     0,                             0
+TrafficControlQueueingDiscipline.TokenBufferFilterRate,              config_parse_tc_token_buffer_filter_size,          0,                             0
+TrafficControlQueueingDiscipline.TokenBufferFilterBurst,             config_parse_tc_token_buffer_filter_size,          0,                             0
+TrafficControlQueueingDiscipline.TokenBufferFilterLatencySec,        config_parse_tc_token_buffer_filter_latency,       0,                             0
 /* backwards compatibility: do not add new entries to this section */
 Network.IPv4LL,                         config_parse_ipv4ll,                             0,                             offsetof(Network, link_local)
 DHCP.ClientIdentifier,                  config_parse_dhcp_client_identifier,             0,                             offsetof(Network, dhcp_client_identifier)
index ed9bd9167ae614efab098e49f41b37d234898b68..9baf7234619f9415c3fd36774967be6fd4bc16c0 100644 (file)
@@ -152,6 +152,16 @@ int qdisc_configure(Link *link, QDiscs *qdisc) {
                         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 (tca_kind) {
                 r = sd_netlink_message_append_string(req, TCA_KIND, tca_kind);
                 if (r < 0)
index 95ff829b9e34045676a76a18d7da242cdd585fee..0453c85c9d1eb0e97a14b826556789088a293915 100644 (file)
@@ -7,6 +7,7 @@
 #include "networkd-link.h"
 #include "networkd-network.h"
 #include "networkd-util.h"
+#include "tbf.h"
 
 typedef struct QDiscs {
         NetworkConfigSection *section;
@@ -20,8 +21,10 @@ typedef struct QDiscs {
         uint32_t parent;
 
         bool has_network_emulator:1;
+        bool has_token_buffer_filter:1;
 
         NetworkEmulator ne;
+        TokenBufferFilter tbf;
 } QDiscs;
 
 void qdisc_free(QDiscs *qdisc);
diff --git a/src/network/tc/tbf.c b/src/network/tc/tbf.c
new file mode 100644 (file)
index 0000000..47c999e
--- /dev/null
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: LGPL-2.1+
+ * Copyright © 2019 VMware, Inc. */
+
+#include <linux/pkt_sched.h>
+#include <math.h>
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "netem.h"
+#include "netlink-util.h"
+#include "networkd-manager.h"
+#include "parse-util.h"
+#include "qdisc.h"
+#include "string-util.h"
+#include "util.h"
+
+int token_buffer_filter_new(TokenBufferFilter **ret) {
+        TokenBufferFilter *ne = NULL;
+
+        ne = new0(TokenBufferFilter, 1);
+        if (!ne)
+                return -ENOMEM;
+
+        *ret = TAKE_PTR(ne);
+
+        return 0;
+}
+
+int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, sd_netlink_message *req) {
+        struct tc_tbf_qopt opt = {};
+        int r;
+
+        assert(link);
+        assert(tbf);
+        assert(req);
+
+        opt.rate.rate = tbf->rate >= (1ULL << 32) ? ~0U : tbf->rate;
+        opt.limit = tbf->rate * (double) tbf->latency / USEC_PER_SEC + tbf->burst;
+
+        r = sd_netlink_message_open_array(req, TCA_OPTIONS);
+        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_TBF_PARMS, &opt, sizeof(struct tc_tbf_qopt));
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append TCA_TBF_PARMS attribute: %m");
+
+        r = sd_netlink_message_append_data(req, TCA_TBF_BURST, &tbf->burst, sizeof(tbf->burst));
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append TCA_TBF_BURST attribute: %m");
+
+        if (tbf->rate >= (1ULL << 32)) {
+                r = sd_netlink_message_append_data(req, TCA_TBF_RATE64, &tbf->rate, sizeof(tbf->rate));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append TCA_TBF_RATE64 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_tc_token_buffer_filter_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) QDiscs *qdisc = NULL;
+        Network *network = data;
+        uint64_t k;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = qdisc_new_static(network, filename, section_line, &qdisc);
+        if (r < 0)
+                return r;
+
+        if (isempty(rvalue)) {
+                if (streq(lvalue, "TokenBufferFilterRate"))
+                        qdisc->tbf.rate = 0;
+                else if (streq(lvalue, "TokenBufferFilterBurst"))
+                        qdisc->tbf.burst = 0;
+
+                qdisc = NULL;
+                return 0;
+        }
+
+        r = parse_size(rvalue, 1000, &k);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to parse '%s=', ignoring assignment: %s",
+                           lvalue, rvalue);
+                return 0;
+        }
+
+        if (streq(lvalue, "TokenBufferFilterRate"))
+                qdisc->tbf.rate = k / 8;
+        else if (streq(lvalue, "TokenBufferFilterBurst"))
+                qdisc->tbf.burst = k;
+
+        qdisc->has_token_buffer_filter = true;
+        qdisc = NULL;
+
+        return 0;
+}
+
+int config_parse_tc_token_buffer_filter_latency(
+                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) QDiscs *qdisc = NULL;
+        Network *network = data;
+        usec_t u;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = qdisc_new_static(network, filename, section_line, &qdisc);
+        if (r < 0)
+                return r;
+
+        if (isempty(rvalue)) {
+                qdisc->tbf.latency = 0;
+
+                qdisc = NULL;
+                return 0;
+        }
+
+        r = parse_sec(rvalue, &u);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to parse '%s=', ignoring assignment: %s",
+                           lvalue, rvalue);
+                return 0;
+        }
+
+        qdisc->tbf.latency = u;
+
+        qdisc->has_token_buffer_filter = true;
+        qdisc = NULL;
+
+        return 0;
+}
diff --git a/src/network/tc/tbf.h b/src/network/tc/tbf.h
new file mode 100644 (file)
index 0000000..c8ae6d0
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: LGPL-2.1+
+ * Copyright © 2019 VMware, Inc. */
+#pragma once
+
+#include "sd-netlink.h"
+
+#include "conf-parser.h"
+#include "networkd-link.h"
+
+typedef struct TokenBufferFilter {
+        uint64_t rate;
+
+        uint32_t burst;
+        uint32_t latency;
+} TokenBufferFilter;
+
+int token_buffer_filter_new(TokenBufferFilter **ret);
+int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, sd_netlink_message *req);
+
+CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_latency);
+CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_size);
index cb10ca306a478d47d5ad91093c25fde6a84f6b61..1cdbc07a242654f8e81f038122719c31ed82d964 100644 (file)
@@ -270,3 +270,6 @@ NetworkEmulatorDelayJitterSec=
 NetworkEmulatorLossRate=
 NetworkEmulatorDuplicateRate=
 NetworkEmulatorPacketLimit=
+TokenBufferFilterRate=
+TokenBufferFilterBurst=
+TokenBufferFilterLatencySec=