[PATCH iproute2-next 2/2] tc/htb: enable use of 64 bit burst

Ioana Lazea
2026-03-23T09:31:45Z

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