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=