Skip to content

Commit 19f86a6

Browse files
committed
network: tc: support HTB class
1 parent 4666f63 commit 19f86a6

File tree

8 files changed

+269
-1
lines changed

8 files changed

+269
-1
lines changed

man/systemd.network.xml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2832,6 +2832,60 @@
28322832
</variablelist>
28332833
</refsect1>
28342834

2835+
<refsect1>
2836+
<title>[HierarchyTokenBucketClass] Section Options</title>
2837+
<para>The <literal>[HierarchyTokenBucketClass]</literal> section manages the traffic control class of
2838+
hierarchy token bucket (htb).</para>
2839+
2840+
<variablelist class='network-directives'>
2841+
<varlistentry>
2842+
<term><varname>Parent=</varname></term>
2843+
<listitem>
2844+
<para>Specifies the parent Queueing Discipline (qdisc). Takes one of <literal>root</literal>,
2845+
or a qdisc id. The qdisc id takes the major and minor number in hexadecimal ranges 1 to ffff
2846+
separated with a colon (<literal>major:minor</literal>). Defaults to <literal>root</literal>.
2847+
</para>
2848+
</listitem>
2849+
</varlistentry>
2850+
2851+
<varlistentry>
2852+
<term><varname>ClassId=</varname></term>
2853+
<listitem>
2854+
<para>Specifies the major and minur number of unique identifier of the class, known as the
2855+
class ID. Each number is in hexadecimal ranges 1 to ffff. Defaults to unset.</para>
2856+
</listitem>
2857+
</varlistentry>
2858+
2859+
<varlistentry>
2860+
<term><varname>Priority=</varname></term>
2861+
<listitem>
2862+
<para>Specifies the priority of the class. In the round-robin process, classes with the lowest
2863+
priority field are tried for packets first. This setting is mandatory.</para>
2864+
</listitem>
2865+
</varlistentry>
2866+
2867+
<varlistentry>
2868+
<term><varname>Rate=</varname></term>
2869+
<listitem>
2870+
<para>Specifies the maximum rate this class and all its children are guaranteed. When suffixed
2871+
with K, M, or G, the specified size is parsed as Kilobits, Megabits, or Gigabits, respectively,
2872+
to the base of 1000. This setting is mandatory.</para>
2873+
</listitem>
2874+
</varlistentry>
2875+
2876+
<varlistentry>
2877+
<term><varname>CeilRate=</varname></term>
2878+
<listitem>
2879+
<para>Specifies the maximum rate at which a class can send, if its parent has bandwidth to spare.
2880+
When suffixed with K, M, or G, the specified size is parsed as Kilobits, Megabits, or Gigabits,
2881+
respectively, to the base of 1000. When unset, the value specified with <varname>Rate=</varname>
2882+
is used.</para>
2883+
</listitem>
2884+
</varlistentry>
2885+
2886+
</variablelist>
2887+
</refsect1>
2888+
28352889
<refsect1>
28362890
<title>[BridgeVLAN] Section Options</title>
28372891
<para>The <literal>[BridgeVLAN]</literal> section manages the VLAN ID configuration of a bridge port and accepts

src/libsystemd/sd-netlink/netlink-types.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,12 @@ static const NLType rtnl_tca_option_data_fq_codel_types[] = {
781781
};
782782

783783
static const NLType rtnl_tca_option_data_htb_types[] = {
784-
[TCA_HTB_INIT] = { .size = sizeof(struct tc_htb_glob) },
784+
[TCA_HTB_PARMS] = { .size = sizeof(struct tc_htb_opt) },
785+
[TCA_HTB_INIT] = { .size = sizeof(struct tc_htb_glob) },
786+
[TCA_HTB_CTAB] = { .size = TC_RTAB_SIZE },
787+
[TCA_HTB_RTAB] = { .size = TC_RTAB_SIZE },
788+
[TCA_HTB_RATE64] = { .type = NETLINK_TYPE_U64 },
789+
[TCA_HTB_CEIL64] = { .type = NETLINK_TYPE_U64 },
785790
};
786791

787792
static const NLType rtnl_tca_option_data_tbf_types[] = {

src/network/networkd-network-gperf.gperf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,11 @@ FairQueueingControlledDelay.ECN, config_parse_fair_queueing_controll
285285
HierarchyTokenBucket.Parent, config_parse_qdisc_parent, QDISC_KIND_HTB, 0
286286
HierarchyTokenBucket.Handle, config_parse_qdisc_handle, QDISC_KIND_HTB, 0
287287
HierarchyTokenBucket.DefaultClass, config_parse_hierarchy_token_bucket_default_class, QDISC_KIND_HTB, 0
288+
HierarchyTokenBucketClass.Parent, config_parse_tclass_parent, TCLASS_KIND_HTB, 0
289+
HierarchyTokenBucketClass.ClassId, config_parse_tclass_classid, TCLASS_KIND_HTB, 0
290+
HierarchyTokenBucketClass.Priority, config_parse_hierarchy_token_bucket_u32, TCLASS_KIND_HTB, 0
291+
HierarchyTokenBucketClass.Rate, config_parse_hierarchy_token_bucket_rate, TCLASS_KIND_HTB, 0
292+
HierarchyTokenBucketClass.CeilRate, config_parse_hierarchy_token_bucket_rate, TCLASS_KIND_HTB, 0
288293
NetworkEmulator.Parent, config_parse_qdisc_parent, QDISC_KIND_NETEM, 0
289294
NetworkEmulator.Handle, config_parse_qdisc_handle, QDISC_KIND_NETEM, 0
290295
NetworkEmulator.DelaySec, config_parse_network_emulator_delay, QDISC_KIND_NETEM, 0

src/network/networkd-network.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
488488
"FairQueueing\0"
489489
"FairQueueingControlledDelay\0"
490490
"HierarchyTokenBucket\0"
491+
"HierarchyTokenBucketClass\0"
491492
"NetworkEmulator\0"
492493
"StochasticFairnessQueueing\0"
493494
"TokenBucketFilter\0"

src/network/tc/htb.c

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "qdisc.h"
1010
#include "htb.h"
1111
#include "string-util.h"
12+
#include "tc-util.h"
1213

1314
static int hierarchy_token_bucket_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
1415
HierarchyTokenBucket *htb;
@@ -96,3 +97,183 @@ const QDiscVTable htb_vtable = {
9697
.tca_kind = "htb",
9798
.fill_message = hierarchy_token_bucket_fill_message,
9899
};
100+
101+
static int hierarchy_token_bucket_class_fill_message(Link *link, TClass *tclass, sd_netlink_message *req) {
102+
HierarchyTokenBucketClass *htb;
103+
struct tc_htb_opt opt = {};
104+
uint32_t rtab[256], ctab[256], mtu = 1600; /* Ethernet packet length */
105+
int r;
106+
107+
assert(link);
108+
assert(tclass);
109+
assert(req);
110+
111+
htb = TCLASS_TO_HTB(tclass);
112+
113+
if (htb->ceil_rate == 0)
114+
htb->ceil_rate = htb->rate;
115+
116+
opt.prio = htb->priority;
117+
opt.rate.rate = (htb->rate >= (1ULL << 32)) ? ~0U : htb->rate;
118+
opt.ceil.rate = (htb->ceil_rate >= (1ULL << 32)) ? ~0U : htb->ceil_rate;
119+
r = tc_transmit_time(htb->rate, mtu, &opt.buffer);
120+
if (r < 0)
121+
return log_link_error_errno(link, r, "Failed to calculate buffer size: %m");
122+
123+
r = tc_transmit_time(htb->ceil_rate, mtu, &opt.cbuffer);
124+
if (r < 0)
125+
return log_link_error_errno(link, r, "Failed to calculate ceil buffer size: %m");
126+
127+
r = tc_fill_ratespec_and_table(&opt.rate, rtab, mtu);
128+
if (r < 0)
129+
return log_link_error_errno(link, r, "Failed to calculate rate table: %m");
130+
131+
r = tc_fill_ratespec_and_table(&opt.ceil, ctab, mtu);
132+
if (r < 0)
133+
return log_link_error_errno(link, r, "Failed to calculate ceil rate table: %m");
134+
135+
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "htb");
136+
if (r < 0)
137+
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
138+
139+
r = sd_netlink_message_append_data(req, TCA_HTB_PARMS, &opt, sizeof(opt));
140+
if (r < 0)
141+
return log_link_error_errno(link, r, "Could not append TCA_HTB_PARMS attribute: %m");
142+
143+
if (htb->rate >= (1ULL << 32)) {
144+
r = sd_netlink_message_append_u64(req, TCA_HTB_RATE64, htb->rate);
145+
if (r < 0)
146+
return log_link_error_errno(link, r, "Could not append TCA_HTB_RATE64 attribute: %m");
147+
}
148+
149+
if (htb->ceil_rate >= (1ULL << 32)) {
150+
r = sd_netlink_message_append_u64(req, TCA_HTB_CEIL64, htb->ceil_rate);
151+
if (r < 0)
152+
return log_link_error_errno(link, r, "Could not append TCA_HTB_CEIL64 attribute: %m");
153+
}
154+
155+
r = sd_netlink_message_append_data(req, TCA_HTB_RTAB, rtab, sizeof(rtab));
156+
if (r < 0)
157+
return log_link_error_errno(link, r, "Could not append TCA_HTB_RTAB attribute: %m");
158+
159+
r = sd_netlink_message_append_data(req, TCA_HTB_CTAB, ctab, sizeof(ctab));
160+
if (r < 0)
161+
return log_link_error_errno(link, r, "Could not append TCA_HTB_CTAB attribute: %m");
162+
163+
r = sd_netlink_message_close_container(req);
164+
if (r < 0)
165+
return log_link_error_errno(link, r, "Could not close container TCA_OPTIONS: %m");
166+
return 0;
167+
}
168+
169+
int config_parse_hierarchy_token_bucket_u32(
170+
const char *unit,
171+
const char *filename,
172+
unsigned line,
173+
const char *section,
174+
unsigned section_line,
175+
const char *lvalue,
176+
int ltype,
177+
const char *rvalue,
178+
void *data,
179+
void *userdata) {
180+
181+
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
182+
HierarchyTokenBucketClass *htb;
183+
Network *network = data;
184+
int r;
185+
186+
assert(filename);
187+
assert(lvalue);
188+
assert(rvalue);
189+
assert(data);
190+
191+
r = tclass_new_static(TCLASS_KIND_HTB, network, filename, section_line, &tclass);
192+
if (r < 0)
193+
return log_syntax(unit, LOG_ERR, filename, line, r,
194+
"Failed to create traffic control class, ignoring assignment: %m");
195+
196+
htb = TCLASS_TO_HTB(tclass);
197+
198+
if (isempty(rvalue)) {
199+
htb->priority = 0;
200+
201+
tclass = NULL;
202+
return 0;
203+
}
204+
205+
r = safe_atou32(rvalue, &htb->priority);
206+
if (r < 0) {
207+
log_syntax(unit, LOG_ERR, filename, line, r,
208+
"Failed to parse '%s=', ignoring assignment: %s",
209+
lvalue, rvalue);
210+
return 0;
211+
}
212+
213+
tclass = NULL;
214+
215+
return 0;
216+
}
217+
218+
int config_parse_hierarchy_token_bucket_rate(
219+
const char *unit,
220+
const char *filename,
221+
unsigned line,
222+
const char *section,
223+
unsigned section_line,
224+
const char *lvalue,
225+
int ltype,
226+
const char *rvalue,
227+
void *data,
228+
void *userdata) {
229+
230+
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
231+
HierarchyTokenBucketClass *htb;
232+
Network *network = data;
233+
uint64_t *v;
234+
int r;
235+
236+
assert(filename);
237+
assert(lvalue);
238+
assert(rvalue);
239+
assert(data);
240+
241+
r = tclass_new_static(TCLASS_KIND_HTB, network, filename, section_line, &tclass);
242+
if (r < 0)
243+
return log_syntax(unit, LOG_ERR, filename, line, r,
244+
"Failed to create traffic control class, ignoring assignment: %m");
245+
246+
htb = TCLASS_TO_HTB(tclass);
247+
if (streq(lvalue, "Rate"))
248+
v = &htb->rate;
249+
else if (streq(lvalue, "CeilRate"))
250+
v = &htb->ceil_rate;
251+
else
252+
assert_not_reached("Invalid lvalue");
253+
254+
if (isempty(rvalue)) {
255+
*v = 0;
256+
257+
tclass = NULL;
258+
return 0;
259+
}
260+
261+
r = parse_size(rvalue, 1000, v);
262+
if (r < 0) {
263+
log_syntax(unit, LOG_ERR, filename, line, r,
264+
"Failed to parse '%s=', ignoring assignment: %s",
265+
lvalue, rvalue);
266+
return 0;
267+
}
268+
269+
*v /= 8;
270+
tclass = NULL;
271+
272+
return 0;
273+
}
274+
275+
const TClassVTable htb_tclass_vtable = {
276+
.object_size = sizeof(HierarchyTokenBucketClass),
277+
.tca_kind = "htb",
278+
.fill_message = hierarchy_token_bucket_class_fill_message,
279+
};

src/network/tc/htb.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "conf-parser.h"
55
#include "qdisc.h"
6+
#include "tclass.h"
67

78
typedef struct HierarchyTokenBucket {
89
QDisc meta;
@@ -14,3 +15,17 @@ DEFINE_QDISC_CAST(HTB, HierarchyTokenBucket);
1415
extern const QDiscVTable htb_vtable;
1516

1617
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_default_class);
18+
19+
typedef struct HierarchyTokenBucketClass {
20+
TClass meta;
21+
22+
uint32_t priority;
23+
uint64_t rate;
24+
uint64_t ceil_rate;
25+
} HierarchyTokenBucketClass;
26+
27+
DEFINE_TCLASS_CAST(HTB, HierarchyTokenBucketClass);
28+
extern const TClassVTable htb_tclass_vtable;
29+
30+
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_u32);
31+
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_rate);

src/network/tc/tclass.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "tclass.h"
1717

1818
const TClassVTable * const tclass_vtable[_TCLASS_KIND_MAX] = {
19+
[TCLASS_KIND_HTB] = &htb_tclass_vtable,
1920
};
2021

2122
static int tclass_new(TClassKind kind, TClass **ret) {

test/fuzz/fuzz-network-parser/directives.network

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,9 @@ Id=
341341
Parent=
342342
Handle=
343343
DefaultClass=
344+
[HierarchyTokenBucketClass]
345+
Parent=
346+
ClassId=
347+
Priority=
348+
Rate=
349+
CeilRate=

0 commit comments

Comments
 (0)