]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/tc/fq-codel.c
88b88e99ef447185c8f1d0aa27e8a5bf852b420e
[thirdparty/systemd.git] / src / network / tc / fq-codel.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later
2 * Copyright © 2019 VMware, Inc. */
3
4 #include <linux/pkt_sched.h>
5
6 #include "sd-netlink.h"
7
8 #include "fq-codel.h"
9 #include "log.h"
10 #include "parse-util.h"
11 #include "string-util.h"
12 #include "strv.h"
13
14 static int fair_queueing_controlled_delay_init(QDisc *qdisc) {
15 FairQueueingControlledDelay *fqcd;
16
17 assert(qdisc);
18
19 fqcd = FQ_CODEL(qdisc);
20
21 fqcd->memory_limit = UINT32_MAX;
22 fqcd->ce_threshold_usec = USEC_INFINITY;
23 fqcd->ecn = -1;
24
25 return 0;
26 }
27
28 static int fair_queueing_controlled_delay_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
29 FairQueueingControlledDelay *fqcd;
30 int r;
31
32 assert(link);
33 assert(qdisc);
34 assert(req);
35
36 assert_se(fqcd = FQ_CODEL(qdisc));
37
38 r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "fq_codel");
39 if (r < 0)
40 return r;
41
42 if (fqcd->packet_limit > 0) {
43 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_LIMIT, fqcd->packet_limit);
44 if (r < 0)
45 return r;
46 }
47
48 if (fqcd->flows > 0) {
49 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_FLOWS, fqcd->flows);
50 if (r < 0)
51 return r;
52 }
53
54 if (fqcd->quantum > 0) {
55 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_QUANTUM, fqcd->quantum);
56 if (r < 0)
57 return r;
58 }
59
60 if (fqcd->interval_usec > 0) {
61 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_INTERVAL, fqcd->interval_usec);
62 if (r < 0)
63 return r;
64 }
65
66 if (fqcd->target_usec > 0) {
67 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_TARGET, fqcd->target_usec);
68 if (r < 0)
69 return r;
70 }
71
72 if (fqcd->ecn >= 0) {
73 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_ECN, fqcd->ecn);
74 if (r < 0)
75 return r;
76 }
77
78 if (fqcd->ce_threshold_usec != USEC_INFINITY) {
79 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_CE_THRESHOLD, fqcd->ce_threshold_usec);
80 if (r < 0)
81 return r;
82 }
83
84 if (fqcd->memory_limit != UINT32_MAX) {
85 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_MEMORY_LIMIT, fqcd->memory_limit);
86 if (r < 0)
87 return r;
88 }
89
90 r = sd_netlink_message_close_container(req);
91 if (r < 0)
92 return r;
93
94 return 0;
95 }
96
97 int config_parse_fair_queueing_controlled_delay_u32(
98 const char *unit,
99 const char *filename,
100 unsigned line,
101 const char *section,
102 unsigned section_line,
103 const char *lvalue,
104 int ltype,
105 const char *rvalue,
106 void *data,
107 void *userdata) {
108
109 _cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
110 FairQueueingControlledDelay *fqcd;
111 Network *network = ASSERT_PTR(data);
112 uint32_t *p;
113 int r;
114
115 assert(filename);
116 assert(lvalue);
117 assert(rvalue);
118
119 r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
120 if (r == -ENOMEM)
121 return log_oom();
122 if (r < 0) {
123 log_syntax(unit, LOG_WARNING, filename, line, r,
124 "More than one kind of queueing discipline, ignoring assignment: %m");
125 return 0;
126 }
127
128 fqcd = FQ_CODEL(qdisc);
129
130 if (streq(lvalue, "PacketLimit"))
131 p = &fqcd->packet_limit;
132 else if (streq(lvalue, "Flows"))
133 p = &fqcd->flows;
134 else
135 assert_not_reached();
136
137 if (isempty(rvalue)) {
138 *p = 0;
139
140 TAKE_PTR(qdisc);
141 return 0;
142 }
143
144 r = safe_atou32(rvalue, p);
145 if (r < 0) {
146 log_syntax(unit, LOG_WARNING, filename, line, r,
147 "Failed to parse '%s=', ignoring assignment: %s",
148 lvalue, rvalue);
149 return 0;
150 }
151
152 TAKE_PTR(qdisc);
153
154 return 0;
155 }
156
157 int config_parse_fair_queueing_controlled_delay_usec(
158 const char *unit,
159 const char *filename,
160 unsigned line,
161 const char *section,
162 unsigned section_line,
163 const char *lvalue,
164 int ltype,
165 const char *rvalue,
166 void *data,
167 void *userdata) {
168
169 _cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
170 FairQueueingControlledDelay *fqcd;
171 Network *network = ASSERT_PTR(data);
172 usec_t *p;
173 int r;
174
175 assert(filename);
176 assert(lvalue);
177 assert(rvalue);
178
179 r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
180 if (r == -ENOMEM)
181 return log_oom();
182 if (r < 0) {
183 log_syntax(unit, LOG_WARNING, filename, line, r,
184 "More than one kind of queueing discipline, ignoring assignment: %m");
185 return 0;
186 }
187
188 fqcd = FQ_CODEL(qdisc);
189
190 if (streq(lvalue, "TargetSec"))
191 p = &fqcd->target_usec;
192 else if (streq(lvalue, "IntervalSec"))
193 p = &fqcd->interval_usec;
194 else if (streq(lvalue, "CEThresholdSec"))
195 p = &fqcd->ce_threshold_usec;
196 else
197 assert_not_reached();
198
199 if (isempty(rvalue)) {
200 if (streq(lvalue, "CEThresholdSec"))
201 *p = USEC_INFINITY;
202 else
203 *p = 0;
204
205 TAKE_PTR(qdisc);
206 return 0;
207 }
208
209 r = parse_sec(rvalue, p);
210 if (r < 0) {
211 log_syntax(unit, LOG_WARNING, filename, line, r,
212 "Failed to parse '%s=', ignoring assignment: %s",
213 lvalue, rvalue);
214 return 0;
215 }
216
217 TAKE_PTR(qdisc);
218
219 return 0;
220 }
221
222 int config_parse_fair_queueing_controlled_delay_bool(
223 const char *unit,
224 const char *filename,
225 unsigned line,
226 const char *section,
227 unsigned section_line,
228 const char *lvalue,
229 int ltype,
230 const char *rvalue,
231 void *data,
232 void *userdata) {
233
234 _cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
235 FairQueueingControlledDelay *fqcd;
236 Network *network = ASSERT_PTR(data);
237 int r;
238
239 assert(filename);
240 assert(lvalue);
241 assert(rvalue);
242
243 r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
244 if (r == -ENOMEM)
245 return log_oom();
246 if (r < 0) {
247 log_syntax(unit, LOG_WARNING, filename, line, r,
248 "More than one kind of queueing discipline, ignoring assignment: %m");
249 return 0;
250 }
251
252 fqcd = FQ_CODEL(qdisc);
253
254 r = parse_tristate(rvalue, &fqcd->ecn);
255 if (r < 0) {
256 log_syntax(unit, LOG_WARNING, filename, line, r,
257 "Failed to parse '%s=', ignoring assignment: %s",
258 lvalue, rvalue);
259 return 0;
260 }
261
262 TAKE_PTR(qdisc);
263
264 return 0;
265 }
266
267 int config_parse_fair_queueing_controlled_delay_size(
268 const char *unit,
269 const char *filename,
270 unsigned line,
271 const char *section,
272 unsigned section_line,
273 const char *lvalue,
274 int ltype,
275 const char *rvalue,
276 void *data,
277 void *userdata) {
278
279 _cleanup_(qdisc_unref_or_set_invalidp) QDisc *qdisc = NULL;
280 FairQueueingControlledDelay *fqcd;
281 Network *network = ASSERT_PTR(data);
282 uint64_t sz;
283 uint32_t *p;
284 int r;
285
286 assert(filename);
287 assert(lvalue);
288 assert(rvalue);
289
290 r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
291 if (r == -ENOMEM)
292 return log_oom();
293 if (r < 0) {
294 log_syntax(unit, LOG_WARNING, filename, line, r,
295 "More than one kind of queueing discipline, ignoring assignment: %m");
296 return 0;
297 }
298
299 fqcd = FQ_CODEL(qdisc);
300
301 if (STR_IN_SET(lvalue, "MemoryLimitBytes", "MemoryLimit"))
302 p = &fqcd->memory_limit;
303 else if (STR_IN_SET(lvalue, "QuantumBytes", "Quantum"))
304 p = &fqcd->quantum;
305 else
306 assert_not_reached();
307
308 if (isempty(rvalue)) {
309 if (STR_IN_SET(lvalue, "MemoryLimitBytes", "MemoryLimit"))
310 *p = UINT32_MAX;
311 else
312 *p = 0;
313
314 TAKE_PTR(qdisc);
315 return 0;
316 }
317
318 r = parse_size(rvalue, 1024, &sz);
319 if (r < 0) {
320 log_syntax(unit, LOG_WARNING, filename, line, r,
321 "Failed to parse '%s=', ignoring assignment: %s",
322 lvalue, rvalue);
323 return 0;
324 }
325 if (sz >= UINT32_MAX) {
326 log_syntax(unit, LOG_WARNING, filename, line, 0,
327 "Specified '%s=' is too large, ignoring assignment: %s",
328 lvalue, rvalue);
329 return 0;
330 }
331
332 *p = sz;
333 TAKE_PTR(qdisc);
334
335 return 0;
336 }
337
338 const QDiscVTable fq_codel_vtable = {
339 .object_size = sizeof(FairQueueingControlledDelay),
340 .tca_kind = "fq_codel",
341 .init = fair_queueing_controlled_delay_init,
342 .fill_message = fair_queueing_controlled_delay_fill_message,
343 };