From c853f594d4ed76b7cae9c76735513031bdb46734 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Tue, 10 Mar 2020 12:53:32 +0100 Subject: [PATCH] network: TC - introduce BFIFO bfifo - Byte limited First In, First Out queue --- man/systemd.network.xml | 34 ++++++++ src/network/networkd-network-gperf.gperf | 5 +- src/network/networkd-network.c | 1 + src/network/tc/fifo.c | 78 ++++++++++++++++++- src/network/tc/fifo.h | 8 +- src/network/tc/qdisc.c | 1 + src/network/tc/qdisc.h | 1 + .../fuzz-network-parser/directives.network | 4 + 8 files changed, 127 insertions(+), 5 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 516744c5f7..6d90c215ab 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2597,6 +2597,40 @@ + + [BFIFO] Section Options + The [BFIFO] section manages the queueing discipline (qdisc) of + Byte limited Packet First In First Out (bfifo). + + + + Parent= + + Specifies the parent Queueing Discipline (qdisc). Takes one of root, + clsact or ingress. Defaults to root. + + + + + Handle= + + 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. + + + + + LimitSize= + + Specifies the hard limit on the FIFO size in bytes. The size limit (a buffer size) to prevent it + from overflowing in case it is unable to dequeue packets as quickly as it receives them. When this limit + is reached, incoming packets are dropped. When suffixed with K, M, or G, the specified size is parsed as + Kilobytes, Megabytes, or Gigabytes, respectively, to the base of 1024. Defaults to unset and kernel's default is used. + + + + + [PFIFO] Section Options The [PFIFO] section manages the queueing discipline (qdisc) of diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 5d7150c58a..223d245a0f 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -258,6 +258,9 @@ CAN.TripleSampling, config_parse_tristate, CAN.Termination, config_parse_tristate, 0, offsetof(Network, can_termination) QDisc.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0 QDisc.Handle, config_parse_qdisc_handle, _QDISC_KIND_INVALID, 0 +BFIFO.Parent, config_parse_qdisc_parent, QDISC_KIND_BFIFO, 0 +BFIFO.Handle, config_parse_qdisc_handle, QDISC_KIND_BFIFO, 0 +BFIFO.LimitSize, config_parse_bfifo_size, QDISC_KIND_BFIFO, 0 CAKE.Parent, config_parse_qdisc_parent, QDISC_KIND_CAKE, 0 CAKE.Handle, config_parse_qdisc_handle, QDISC_KIND_CAKE, 0 CAKE.Bandwidth, config_parse_cake_bandwidth, QDISC_KIND_CAKE, 0 @@ -276,7 +279,7 @@ DeficitRoundRobinSchedulerClass.ClassId, config_parse_tclass_classid, DeficitRoundRobinSchedulerClass.Quantum, config_parse_drr_size, TCLASS_KIND_DRR, 0 PFIFO.Parent, config_parse_qdisc_parent, QDISC_KIND_PFIFO, 0 PFIFO.Handle, config_parse_qdisc_handle, QDISC_KIND_PFIFO, 0 -PFIFO.PacketLimit, config_parse_fifo_size, QDISC_KIND_PFIFO, 0 +PFIFO.PacketLimit, config_parse_pfifo_size, QDISC_KIND_PFIFO, 0 FairQueueing.Parent, config_parse_qdisc_parent, QDISC_KIND_FQ, 0 FairQueueing.Handle, config_parse_qdisc_handle, QDISC_KIND_FQ, 0 FairQueueing.PacketLimit, config_parse_fair_queueing_u32, QDISC_KIND_FQ, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index cf423e274a..6e4eb39f86 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -486,6 +486,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi "TrafficControlQueueingDiscipline\0" "CAN\0" "QDisc\0" + "BFIFO\0" "CAKE\0" "ControlledDelay\0" "DeficitRoundRobinScheduler\0" diff --git a/src/network/tc/fifo.c b/src/network/tc/fifo.c index 2d2a863e3a..7978f7b922 100644 --- a/src/network/tc/fifo.c +++ b/src/network/tc/fifo.c @@ -19,7 +19,16 @@ static int fifo_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) assert(qdisc); assert(req); - fifo = PFIFO(qdisc); + switch(qdisc->kind) { + case QDISC_KIND_PFIFO: + fifo = PFIFO(qdisc); + break; + case QDISC_KIND_BFIFO: + fifo = BFIFO(qdisc); + break; + default: + assert_not_reached("Invalid QDisc kind."); + } opt.limit = fifo->limit; @@ -30,7 +39,7 @@ static int fifo_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) return 0; } -int config_parse_fifo_size( +int config_parse_pfifo_size( const char *unit, const char *filename, unsigned line, @@ -80,8 +89,73 @@ int config_parse_fifo_size( return 0; } +int config_parse_bfifo_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) QDisc *qdisc = NULL; + Network *network = data; + FirstInFirstOut *fifo; + uint64_t u; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = qdisc_new_static(QDISC_KIND_BFIFO, 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"); + + fifo = BFIFO(qdisc); + + if (isempty(rvalue)) { + fifo->limit = 0; + + qdisc = NULL; + return 0; + } + + r = parse_size(rvalue, 1000, &u); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse '%s=', ignoring assignment: %s", + lvalue, rvalue); + return 0; + } + if (u > UINT32_MAX) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid '%s=', ignoring assignment: %s", + lvalue, rvalue); + return 0; + } + + fifo->limit = (uint32_t) u; + + qdisc = NULL; + return 0; +} + + const QDiscVTable pfifo_vtable = { .object_size = sizeof(FirstInFirstOut), .tca_kind = "pfifo", .fill_message = fifo_fill_message, }; + +const QDiscVTable bfifo_vtable = { + .object_size = sizeof(FirstInFirstOut), + .tca_kind = "bfifo", + .fill_message = fifo_fill_message, +}; diff --git a/src/network/tc/fifo.h b/src/network/tc/fifo.h index 02976568dd..7e6a94f16c 100644 --- a/src/network/tc/fifo.h +++ b/src/network/tc/fifo.h @@ -12,6 +12,10 @@ typedef struct FirstInFirstOut { } FirstInFirstOut; DEFINE_QDISC_CAST(PFIFO, FirstInFirstOut); -extern const QDiscVTable pfifo_vtable; +DEFINE_QDISC_CAST(BFIFO, FirstInFirstOut); -CONFIG_PARSER_PROTOTYPE(config_parse_fifo_size); +extern const QDiscVTable pfifo_vtable; +extern const QDiscVTable bfifo_vtable; + +CONFIG_PARSER_PROTOTYPE(config_parse_pfifo_size); +CONFIG_PARSER_PROTOTYPE(config_parse_bfifo_size); diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index 06204063eb..b6acc29f11 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -16,6 +16,7 @@ #include "tc-util.h" const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = { + [QDISC_KIND_BFIFO] = &bfifo_vtable, [QDISC_KIND_CAKE] = &cake_vtable, [QDISC_KIND_CODEL] = &codel_vtable, [QDISC_KIND_DRR] = &drr_vtable, diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index dea3847728..31a3ca3414 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -9,6 +9,7 @@ #include "tc.h" typedef enum QDiscKind { + QDISC_KIND_BFIFO, QDISC_KIND_CAKE, QDISC_KIND_CODEL, QDISC_KIND_DRR, diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 6ea18d7dc9..c4d13a73dc 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -356,6 +356,10 @@ ClassId= Priority= Rate= CeilRate= +[BFIFO] +Parent= +Handle= +LimitSize= [PFIFO] Parent= Handle=