]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/tc/fq.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / network / tc / fq.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 "alloc-util.h"
7 #include "conf-parser.h"
8 #include "fq.h"
9 #include "netlink-util.h"
10 #include "parse-util.h"
11 #include "string-util.h"
12 #include "strv.h"
13
14 static int fair_queueing_init(QDisc *qdisc) {
15 FairQueueing *fq;
16
17 assert(qdisc);
18
19 fq = FQ(qdisc);
20
21 fq->pacing = -1;
22 fq->ce_threshold_usec = USEC_INFINITY;
23
24 return 0;
25 }
26
27 static int fair_queueing_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
28 FairQueueing *fq;
29 int r;
30
31 assert(link);
32 assert(qdisc);
33 assert(req);
34
35 assert_se(fq = FQ(qdisc));
36
37 r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "fq");
38 if (r < 0)
39 return r;
40
41 if (fq->packet_limit > 0) {
42 r = sd_netlink_message_append_u32(req, TCA_FQ_PLIMIT, fq->packet_limit);
43 if (r < 0)
44 return r;
45 }
46
47 if (fq->flow_limit > 0) {
48 r = sd_netlink_message_append_u32(req, TCA_FQ_FLOW_PLIMIT, fq->flow_limit);
49 if (r < 0)
50 return r;
51 }
52
53 if (fq->quantum > 0) {
54 r = sd_netlink_message_append_u32(req, TCA_FQ_QUANTUM, fq->quantum);
55 if (r < 0)
56 return r;
57 }
58
59 if (fq->initial_quantum > 0) {
60 r = sd_netlink_message_append_u32(req, TCA_FQ_INITIAL_QUANTUM, fq->initial_quantum);
61 if (r < 0)
62 return r;
63 }
64
65 if (fq->pacing >= 0) {
66 r = sd_netlink_message_append_u32(req, TCA_FQ_RATE_ENABLE, fq->pacing);
67 if (r < 0)
68 return r;
69 }
70
71 if (fq->max_rate > 0) {
72 r = sd_netlink_message_append_u32(req, TCA_FQ_FLOW_MAX_RATE, fq->max_rate);
73 if (r < 0)
74 return r;
75 }
76
77 if (fq->buckets > 0) {
78 uint32_t l;
79
80 l = log2u(fq->buckets);
81 r = sd_netlink_message_append_u32(req, TCA_FQ_BUCKETS_LOG, l);
82 if (r < 0)
83 return r;
84 }
85
86 if (fq->orphan_mask > 0) {
87 r = sd_netlink_message_append_u32(req, TCA_FQ_ORPHAN_MASK, fq->orphan_mask);
88 if (r < 0)
89 return r;
90 }
91
92 if (fq->ce_threshold_usec != USEC_INFINITY) {
93 r = sd_netlink_message_append_u32(req, TCA_FQ_CE_THRESHOLD, fq->ce_threshold_usec);
94 if (r < 0)
95 return r;
96 }
97
98 r = sd_netlink_message_close_container(req);
99 if (r < 0)
100 return r;
101
102 return 0;
103 }
104
105 int config_parse_fair_queueing_u32(
106 const char *unit,
107 const char *filename,
108 unsigned line,
109 const char *section,
110 unsigned section_line,
111 const char *lvalue,
112 int ltype,
113 const char *rvalue,
114 void *data,
115 void *userdata) {
116
117 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
118 FairQueueing *fq;
119 Network *network = ASSERT_PTR(data);
120 uint32_t *p;
121 int r;
122
123 assert(filename);
124 assert(lvalue);
125 assert(rvalue);
126
127 r = qdisc_new_static(QDISC_KIND_FQ, network, filename, section_line, &qdisc);
128 if (r == -ENOMEM)
129 return log_oom();
130 if (r < 0) {
131 log_syntax(unit, LOG_WARNING, filename, line, r,
132 "More than one kind of queueing discipline, ignoring assignment: %m");
133 return 0;
134 }
135
136 fq = FQ(qdisc);
137
138 if (streq(lvalue, "PacketLimit"))
139 p = &fq->packet_limit;
140 else if (streq(lvalue, "FlowLimit"))
141 p = &fq->flow_limit;
142 else if (streq(lvalue, "Buckets"))
143 p = &fq->buckets;
144 else if (streq(lvalue, "OrphanMask"))
145 p = &fq->orphan_mask;
146 else
147 assert_not_reached();
148
149 if (isempty(rvalue)) {
150 *p = 0;
151
152 qdisc = NULL;
153 return 0;
154 }
155
156 r = safe_atou32(rvalue, p);
157 if (r < 0) {
158 log_syntax(unit, LOG_WARNING, filename, line, r,
159 "Failed to parse '%s=', ignoring assignment: %s",
160 lvalue, rvalue);
161 return 0;
162 }
163
164 qdisc = NULL;
165
166 return 0;
167 }
168
169 int config_parse_fair_queueing_size(
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_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
182 FairQueueing *fq;
183 Network *network = ASSERT_PTR(data);
184 uint64_t sz;
185 uint32_t *p;
186 int r;
187
188 assert(filename);
189 assert(lvalue);
190 assert(rvalue);
191
192 r = qdisc_new_static(QDISC_KIND_FQ, network, filename, section_line, &qdisc);
193 if (r == -ENOMEM)
194 return log_oom();
195 if (r < 0) {
196 log_syntax(unit, LOG_WARNING, filename, line, r,
197 "More than one kind of queueing discipline, ignoring assignment: %m");
198 return 0;
199 }
200
201 fq = FQ(qdisc);
202
203 if (STR_IN_SET(lvalue, "QuantumBytes", "Quantum"))
204 p = &fq->quantum;
205 else if (STR_IN_SET(lvalue, "InitialQuantumBytes", "InitialQuantum"))
206 p = &fq->initial_quantum;
207 else
208 assert_not_reached();
209
210 if (isempty(rvalue)) {
211 *p = 0;
212
213 qdisc = NULL;
214 return 0;
215 }
216
217 r = parse_size(rvalue, 1024, &sz);
218 if (r < 0) {
219 log_syntax(unit, LOG_WARNING, filename, line, r,
220 "Failed to parse '%s=', ignoring assignment: %s",
221 lvalue, rvalue);
222 return 0;
223 }
224 if (sz > UINT32_MAX) {
225 log_syntax(unit, LOG_WARNING, filename, line, 0,
226 "Specified '%s=' is too large, ignoring assignment: %s",
227 lvalue, rvalue);
228 return 0;
229 }
230
231 *p = sz;
232 qdisc = NULL;
233
234 return 0;
235 }
236
237 int config_parse_fair_queueing_bool(
238 const char *unit,
239 const char *filename,
240 unsigned line,
241 const char *section,
242 unsigned section_line,
243 const char *lvalue,
244 int ltype,
245 const char *rvalue,
246 void *data,
247 void *userdata) {
248
249 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
250 FairQueueing *fq;
251 Network *network = ASSERT_PTR(data);
252 int r;
253
254 assert(filename);
255 assert(lvalue);
256 assert(rvalue);
257
258 r = qdisc_new_static(QDISC_KIND_FQ, network, filename, section_line, &qdisc);
259 if (r == -ENOMEM)
260 return log_oom();
261 if (r < 0) {
262 log_syntax(unit, LOG_WARNING, filename, line, r,
263 "More than one kind of queueing discipline, ignoring assignment: %m");
264 return 0;
265 }
266
267 fq = FQ(qdisc);
268
269 if (isempty(rvalue)) {
270 fq->pacing = -1;
271
272 qdisc = NULL;
273 return 0;
274 }
275
276 r = parse_boolean(rvalue);
277 if (r < 0) {
278 log_syntax(unit, LOG_WARNING, filename, line, r,
279 "Failed to parse '%s=', ignoring assignment: %s",
280 lvalue, rvalue);
281 return 0;
282 }
283
284 fq->pacing = r;
285 qdisc = NULL;
286
287 return 0;
288 }
289
290 int config_parse_fair_queueing_usec(
291 const char *unit,
292 const char *filename,
293 unsigned line,
294 const char *section,
295 unsigned section_line,
296 const char *lvalue,
297 int ltype,
298 const char *rvalue,
299 void *data,
300 void *userdata) {
301
302 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
303 FairQueueing *fq;
304 Network *network = ASSERT_PTR(data);
305 usec_t sec;
306 int r;
307
308 assert(filename);
309 assert(lvalue);
310 assert(rvalue);
311
312 r = qdisc_new_static(QDISC_KIND_FQ, network, filename, section_line, &qdisc);
313 if (r == -ENOMEM)
314 return log_oom();
315 if (r < 0) {
316 log_syntax(unit, LOG_WARNING, filename, line, r,
317 "More than one kind of queueing discipline, ignoring assignment: %m");
318 return 0;
319 }
320
321 fq = FQ(qdisc);
322
323 if (isempty(rvalue)) {
324 fq->ce_threshold_usec = USEC_INFINITY;
325
326 qdisc = NULL;
327 return 0;
328 }
329
330 r = parse_sec(rvalue, &sec);
331 if (r < 0) {
332 log_syntax(unit, LOG_WARNING, filename, line, r,
333 "Failed to parse '%s=', ignoring assignment: %s",
334 lvalue, rvalue);
335 return 0;
336 }
337 if (sec > UINT32_MAX) {
338 log_syntax(unit, LOG_WARNING, filename, line, 0,
339 "Specified '%s=' is too large, ignoring assignment: %s",
340 lvalue, rvalue);
341 return 0;
342 }
343
344 fq->ce_threshold_usec = sec;
345 qdisc = NULL;
346
347 return 0;
348 }
349
350 int config_parse_fair_queueing_max_rate(
351 const char *unit,
352 const char *filename,
353 unsigned line,
354 const char *section,
355 unsigned section_line,
356 const char *lvalue,
357 int ltype,
358 const char *rvalue,
359 void *data,
360 void *userdata) {
361
362 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
363 FairQueueing *fq;
364 Network *network = ASSERT_PTR(data);
365 uint64_t sz;
366 int r;
367
368 assert(filename);
369 assert(lvalue);
370 assert(rvalue);
371
372 r = qdisc_new_static(QDISC_KIND_FQ, network, filename, section_line, &qdisc);
373 if (r == -ENOMEM)
374 return log_oom();
375 if (r < 0) {
376 log_syntax(unit, LOG_WARNING, filename, line, r,
377 "More than one kind of queueing discipline, ignoring assignment: %m");
378 return 0;
379 }
380
381 fq = FQ(qdisc);
382
383 if (isempty(rvalue)) {
384 fq->max_rate = 0;
385
386 qdisc = NULL;
387 return 0;
388 }
389
390 r = parse_size(rvalue, 1000, &sz);
391 if (r < 0) {
392 log_syntax(unit, LOG_WARNING, filename, line, r,
393 "Failed to parse '%s=', ignoring assignment: %s",
394 lvalue, rvalue);
395 return 0;
396 }
397 if (sz / 8 > UINT32_MAX) {
398 log_syntax(unit, LOG_WARNING, filename, line, 0,
399 "Specified '%s=' is too large, ignoring assignment: %s",
400 lvalue, rvalue);
401 return 0;
402 }
403
404 fq->max_rate = sz / 8;
405 qdisc = NULL;
406
407 return 0;
408 }
409
410 const QDiscVTable fq_vtable = {
411 .init = fair_queueing_init,
412 .object_size = sizeof(FairQueueing),
413 .tca_kind = "fq",
414 .fill_message = fair_queueing_fill_message,
415 };