* [PATCH iproute2-next 0/2] tc/tbf and tc/htb: Allow 64 bit burst
@ 2026-03-23 9:29 Ioana Lazea
2026-03-23 9:29 ` [PATCH iproute2-next 1/2] tc/tbf: enable use of " Ioana Lazea
2026-03-23 9:29 ` [PATCH iproute2-next 2/2] tc/htb: " Ioana Lazea
0 siblings, 2 replies; 3+ messages in thread
From: Ioana Lazea @ 2026-03-23 9:29 UTC (permalink / raw)
To: netdev; +Cc: jhs, stephen, dsahern, jay.vosburgh
This patchset updates the TBF and HTB queuing discipline
configurations to support burst sizes beyond the legacy 32-bit limits.
As network interface speeds increase, the kernel’s internal
representation of burst (calculated as time at a specific rate) can
easily exceed the 4 GB threshold. These changes enable userspace to
accommodate these larger values where the kernel API allows.
Additionally, if the burst exceeds the upper limit supported by
the kernel API, it is now reported as an error in userspace before
attempting the Netlink transition. Previously, such values would
silently overflow, causing corrupted values to be passed to the kernel.
The implementation follows the approach used for tc police burst
handling introduced in commit 3b26e8abf404 ("tc/police: enable use of 64
bit burst parameter"). The reasoning behind the patches proposed here is
largely based on the rationale described in the aforementioned change.
Similarly to the case of the tc police burst option, as
implemented now the TBF and HTB burst option limit the sizes of the
burst up to 4 GB (UINT_MAX for a 32 bit unsigned int) due to the
constraints in the user space tooling. Historically, TBF and HTB burst
options were capped at 32 bits, which was a sufficient limit for the
lower line rates common when they were initially developed. However,
since the underlying kernel logic treats the burst as a time-based
value, it is already capable of handling larger sizes at high rates
without requiring internal modifications. This patchset bridges that gap
in the user space tools.
The detailed technical explanation for this change was
previously detailed by Jay Vosburgh:
Link: https://lore.kernel.org/netdev/20250916215731.3431465-1-jay.vosburgh@canonical.com/
To summarize the details at the link, the burst size is limited
by the kernel to approximately 274 seconds at the specified rate, and
has no inherent 4 GB limit.
Below is a short description of the main changes made to the TBF
and HTB queuing disciplines.
In both TBF and HTB, the primary modification replaces the
unsigned integer burst variable with an unsigned 64 bit integer variable
(buffer64) so that burst sizes larger than 4 GB can be represented and
passed correctly through the kernel API.
For the TBF qdisc specifically, the following logic was added:
if (buffer64 < (1ULL << 32)) {
__u32 buffer32 = (__u32)buffer64;
addattr_l(n, 2124, TCA_TBF_BURST, &buffer32, sizeof(buffer32));
}
Increasing the burst size representation to 64 bits introduces
an issue with TCA_TBF_BURST. The kernel expects this attribute as
NLA_U32 (a 32-bit unsigned value), while the updated implementation may
produce burst values exceeding this range. Passing such values would
cause the tbf_policy validation in the kernel to fail. To avoid this,
TCA_TBF_BURST is only included when the value fits within 32 bits. When
the attribute is omitted (for example, when buffer64 exceeds the 32-bit
limit), the kernel falls back to using the value stored in qopt->buffer,
which already supports larger burst sizes.
As seen in commit 2e04ad424b03 ("sch_tbf: add
TBF_BURST/TBF_PBURST attribute"), TCA_TBF_BURST was originally
introduced to handle issues with very small burst values. Omitting the
attribute for large bursts therefore preserves the intended behavior
while avoiding incompatibilities with the kernel attribute policy.
Additionally, the burst value is explicitly cast to 32 bits where
required, ensuring that 64-bit values are not passed to kernel
interfaces expecting 32-bit fields.
These modifications bring the user space tools in line with the
kernel's internal 64-bit handling. The logic effectively avoids Netlink
attribute validation failures while preserving the original intent of
the burst mechanism for small values.
I look forward to your feedback on this approach.
Ioana Lazea (2):
tc/tbf: enable use of 64 bit burst parameter
tc/htb: enable use of 64 bit burst parameter
tc/q_htb.c | 16 ++++++++++------
tc/q_tbf.c | 24 ++++++++++++++++--------
2 files changed, 26 insertions(+), 14 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH iproute2-next 1/2] tc/tbf: enable use of 64 bit burst
2026-03-23 9:29 [PATCH iproute2-next 0/2] tc/tbf and tc/htb: Allow 64 bit burst Ioana Lazea
@ 2026-03-23 9:29 ` Ioana Lazea
2026-03-23 9:29 ` [PATCH iproute2-next 2/2] tc/htb: " Ioana Lazea
1 sibling, 0 replies; 3+ messages in thread
From: Ioana Lazea @ 2026-03-23 9:29 UTC (permalink / raw)
To: netdev; +Cc: jhs, stephen, dsahern, jay.vosburgh
Modify the TBF queueing discipline configuration to allow burst sizes up
to the limits supported by the kernel API, which may exceed 4 GB at
higher rates.
In the current implementation, the burst option is effectively limited
to 4 GB because it is stored in a 32-bit field. However, the kernel
internally represents the burst in psched ticks (64 nsec each). At
sufficiently high rates, this representation can correspond to burst
sizes larger than 4 GB without requiring kernel changes.
Overflows (burst values that exceed UINT_MAX psched ticks) are now
correctly detected, and flagged as an error, rather than passing
arbitrary psched tick values to the kernel.
The change to increase the burst size to 64-bit introduced an issue with
TCA_TBF_BURST. The kernel expects this attribute as NLA_U32 (a 32-bit
unsigned value), but the updated implementation may produce a 64-bit
value, causing the tbf_policy check in the kernel to fail. However, when
TCA_TBF_BURST is omitted (which occurs when buffer64 >= UINT_MAX), the
kernel falls back to using the value assigned to qopt->buffer, which
correctly supports large burst sizes. Omitting TCA_TBF_BURST for large
bursts preserves backward compatibility and aligns with existing kernel
behavior. This change therefore ensures correct handling of large burst
sizes while remaining compatible with kernel and iproute2 expectations.
Signed-off-by: Ioana Lazea <ioana.lazea@canonical.com>
---
tc/q_tbf.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/tc/q_tbf.c b/tc/q_tbf.c
index 9356dfd2..cbe11025 100644
--- a/tc/q_tbf.c
+++ b/tc/q_tbf.c
@@ -37,12 +37,12 @@ static int tbf_parse_opt(const struct qdisc_util *qu, int argc, char **argv,
struct tc_tbf_qopt opt = {};
__u32 rtab[256];
__u32 ptab[256];
- unsigned buffer = 0, mtu = 0, mpu = 0, latency = 0;
+ unsigned mtu = 0, mpu = 0, latency = 0;
int Rcell_log = -1, Pcell_log = -1;
unsigned short overhead = 0;
unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
struct rtattr *tail;
- __u64 rate64 = 0, prate64 = 0;
+ __u64 rate64 = 0, prate64 = 0, buffer64 = 0;
while (argc > 0) {
if (matches(*argv, "limit") == 0) {
@@ -79,11 +79,11 @@ static int tbf_parse_opt(const struct qdisc_util *qu, int argc, char **argv,
const char *parm_name = *argv;
NEXT_ARG();
- if (buffer) {
+ if (buffer64) {
fprintf(stderr, "tbf: duplicate \"buffer/burst/maxburst\" specification\n");
return -1;
}
- if (get_size_and_cell(&buffer, &Rcell_log, *argv) < 0) {
+ if (get_size64_and_cell(&buffer64, &Rcell_log, *argv) < 0) {
explain1(parm_name, *argv);
return -1;
}
@@ -175,7 +175,7 @@ static int tbf_parse_opt(const struct qdisc_util *qu, int argc, char **argv,
fprintf(stderr, "tbf: the \"rate\" parameter is mandatory.\n");
verdict = -1;
}
- if (!buffer) {
+ if (!buffer64) {
fprintf(stderr, "tbf: the \"burst\" parameter is mandatory.\n");
verdict = -1;
}
@@ -200,7 +200,7 @@ static int tbf_parse_opt(const struct qdisc_util *qu, int argc, char **argv,
opt.peakrate.rate = (prate64 >= (1ULL << 32)) ? ~0U : prate64;
if (opt.limit == 0) {
- double lim = rate64*(double)latency/TIME_UNITS_PER_SEC + buffer;
+ double lim = rate64*(double)latency/TIME_UNITS_PER_SEC + buffer64;
if (prate64) {
double lim2 = prate64*(double)latency/TIME_UNITS_PER_SEC + mtu;
@@ -217,7 +217,11 @@ static int tbf_parse_opt(const struct qdisc_util *qu, int argc, char **argv,
fprintf(stderr, "tbf: failed to calculate rate table.\n");
return -1;
}
- opt.buffer = tc_calc_xmittime(opt.rate.rate, buffer);
+ opt.buffer = tc_calc_xmittime(opt.rate.rate, buffer64);
+ if (opt.buffer == UINT_MAX) {
+ fprintf(stderr, "tbf: burst out of range\n");
+ return -1;
+ }
if (opt.peakrate.rate) {
opt.peakrate.mpu = mpu;
@@ -231,7 +235,11 @@ static int tbf_parse_opt(const struct qdisc_util *qu, int argc, char **argv,
tail = addattr_nest(n, 1024, TCA_OPTIONS);
addattr_l(n, 2024, TCA_TBF_PARMS, &opt, sizeof(opt));
- addattr_l(n, 2124, TCA_TBF_BURST, &buffer, sizeof(buffer));
+ if (buffer64 < (1ULL << 32)) {
+ __u32 buffer32 = (__u32)buffer64;
+
+ addattr_l(n, 2124, TCA_TBF_BURST, &buffer32, sizeof(buffer32));
+ }
if (rate64 >= (1ULL << 32))
addattr_l(n, 2124, TCA_TBF_RATE64, &rate64, sizeof(rate64));
addattr_l(n, 3024, TCA_TBF_RTAB, rtab, 1024);
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH iproute2-next 2/2] tc/htb: enable use of 64 bit burst
2026-03-23 9:29 [PATCH iproute2-next 0/2] tc/tbf and tc/htb: Allow 64 bit burst Ioana Lazea
2026-03-23 9:29 ` [PATCH iproute2-next 1/2] tc/tbf: enable use of " Ioana Lazea
@ 2026-03-23 9:29 ` Ioana Lazea
1 sibling, 0 replies; 3+ messages in thread
From: Ioana Lazea @ 2026-03-23 9:29 UTC (permalink / raw)
To: netdev; +Cc: jhs, stephen, dsahern, jay.vosburgh
Modify the HTB queueing discipline to allow burst sizes up to the
limits supported by the kernel API, which may exceed 4 GB at higher rates.
In the current implementation, the burst option is effectively limited
to 4 GB due to the use of a 32-bit field while parsing the burst size.
However, the kernel internally represents the burst in terms of time
derived from the configured rate. As a result, at sufficiently high
rates this time-based representation can correspond to burst sizes
larger than 4 GB, making such bursts feasible without requiring changes
to the kernel.
This change removes the artificial 4 GB limit and allows larger burst
sizes where supported by the kernel API.
Signed-off-by: Ioana Lazea <ioana.lazea@canonical.com>
---
tc/q_htb.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/tc/q_htb.c b/tc/q_htb.c
index 545152ff..a3ad4215 100644
--- a/tc/q_htb.c
+++ b/tc/q_htb.c
@@ -112,14 +112,14 @@ static int htb_parse_class_opt(const struct qdisc_util *qu, int argc, char **arg
{
struct tc_htb_opt opt = {};
__u32 rtab[256], ctab[256];
- unsigned buffer = 0, cbuffer = 0;
+ unsigned cbuffer = 0;
int cell_log = -1, ccell_log = -1;
unsigned int mtu = 1600; /* eth packet len */
unsigned short mpu = 0;
unsigned short overhead = 0;
unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
struct rtattr *tail;
- __u64 ceil64 = 0, rate64 = 0;
+ __u64 ceil64 = 0, rate64 = 0, buffer64 = 0;
char *param;
while (argc > 0) {
@@ -158,7 +158,7 @@ static int htb_parse_class_opt(const struct qdisc_util *qu, int argc, char **arg
strcmp(*argv, "maxburst") == 0) {
param = *argv;
NEXT_ARG();
- if (get_size_and_cell(&buffer, &cell_log, *argv) < 0) {
+ if (get_size64_and_cell(&buffer64, &cell_log, *argv) < 0) {
explain1(param);
return -1;
}
@@ -225,8 +225,8 @@ static int htb_parse_class_opt(const struct qdisc_util *qu, int argc, char **arg
/* compute minimal allowed burst from rate; mtu is added here to make
sure that buffer is larger than mtu and to have some safeguard space */
- if (!buffer)
- buffer = rate64 / get_hz() + mtu;
+ if (!buffer64)
+ buffer64 = rate64 / get_hz() + mtu;
if (!cbuffer)
cbuffer = ceil64 / get_hz() + mtu;
@@ -240,7 +240,11 @@ static int htb_parse_class_opt(const struct qdisc_util *qu, int argc, char **arg
fprintf(stderr, "htb: failed to calculate rate table.\n");
return -1;
}
- opt.buffer = tc_calc_xmittime(rate64, buffer);
+ opt.buffer = tc_calc_xmittime(rate64, buffer64);
+ if (opt.buffer == UINT_MAX) {
+ fprintf(stderr, "htb: burst out of range\n");
+ return -1;
+ }
if (tc_calc_rtable(&opt.ceil, ctab, ccell_log, mtu, linklayer) < 0) {
fprintf(stderr, "htb: failed to calculate ceil rate table.\n");
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-03-23 9:31 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-23 9:29 [PATCH iproute2-next 0/2] tc/tbf and tc/htb: Allow 64 bit burst Ioana Lazea
2026-03-23 9:29 ` [PATCH iproute2-next 1/2] tc/tbf: enable use of " Ioana Lazea
2026-03-23 9:29 ` [PATCH iproute2-next 2/2] tc/htb: " Ioana Lazea
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox