]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/tc/cake.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / network / tc / cake.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later
ad8352f4
SS
2 * Copyright © 2020 VMware, Inc. */
3
4#include <linux/pkt_sched.h>
5
6#include "alloc-util.h"
7#include "cake.h"
8#include "conf-parser.h"
9#include "netlink-util.h"
10#include "parse-util.h"
11#include "qdisc.h"
b6eccfda 12#include "string-table.h"
ad8352f4
SS
13#include "string-util.h"
14
025cd94e
YW
15static int cake_init(QDisc *qdisc) {
16 CommonApplicationsKeptEnhanced *c;
17
18 assert(qdisc);
19
20 c = CAKE(qdisc);
21
22 c->autorate = -1;
b6eccfda 23 c->compensation_mode = _CAKE_COMPENSATION_MODE_INVALID;
1c7a81e6 24 c->raw = -1;
a049cf16 25 c->flow_isolation_mode = _CAKE_FLOW_ISOLATION_MODE_INVALID;
4bff8086 26 c->nat = -1;
fe8e156e 27 c->preset = _CAKE_PRESET_INVALID;
d05dce95 28 c->wash = -1;
35896db4 29 c->split_gso = -1;
025cd94e
YW
30
31 return 0;
32}
33
ad8352f4
SS
34static int cake_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
35 CommonApplicationsKeptEnhanced *c;
36 int r;
37
38 assert(link);
39 assert(qdisc);
40 assert(req);
41
16924f54 42 assert_se(c = CAKE(qdisc));
ad8352f4
SS
43
44 r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "cake");
45 if (r < 0)
16924f54 46 return r;
ad8352f4
SS
47
48 if (c->bandwidth > 0) {
49 r = sd_netlink_message_append_u64(req, TCA_CAKE_BASE_RATE64, c->bandwidth);
50 if (r < 0)
16924f54 51 return r;
ad8352f4
SS
52 }
53
025cd94e
YW
54 if (c->autorate >= 0) {
55 r = sd_netlink_message_append_u32(req, TCA_CAKE_AUTORATE, c->autorate);
56 if (r < 0)
16924f54 57 return r;
025cd94e
YW
58 }
59
3a86a31e
YW
60 if (c->overhead_set) {
61 r = sd_netlink_message_append_s32(req, TCA_CAKE_OVERHEAD, c->overhead);
62 if (r < 0)
16924f54 63 return r;
3a86a31e 64 }
ad8352f4 65
863542e1
YW
66 if (c->mpu > 0) {
67 r = sd_netlink_message_append_u32(req, TCA_CAKE_MPU, c->mpu);
68 if (r < 0)
16924f54 69 return r;
863542e1
YW
70 }
71
b6eccfda
YW
72 if (c->compensation_mode >= 0) {
73 r = sd_netlink_message_append_u32(req, TCA_CAKE_ATM, c->compensation_mode);
74 if (r < 0)
16924f54 75 return r;
b6eccfda
YW
76 }
77
1c7a81e6
YW
78 if (c->raw > 0) {
79 /* TCA_CAKE_RAW attribute is mostly a flag, not boolean. */
80 r = sd_netlink_message_append_u32(req, TCA_CAKE_RAW, 0);
81 if (r < 0)
16924f54 82 return r;
1c7a81e6
YW
83 }
84
a049cf16
YW
85 if (c->flow_isolation_mode >= 0) {
86 r = sd_netlink_message_append_u32(req, TCA_CAKE_FLOW_MODE, c->flow_isolation_mode);
87 if (r < 0)
16924f54 88 return r;
a049cf16
YW
89 }
90
4bff8086
YW
91 if (c->nat >= 0) {
92 r = sd_netlink_message_append_u32(req, TCA_CAKE_NAT, c->nat);
93 if (r < 0)
16924f54 94 return r;
4bff8086
YW
95 }
96
fe8e156e
YW
97 if (c->preset >= 0) {
98 r = sd_netlink_message_append_u32(req, TCA_CAKE_DIFFSERV_MODE, c->preset);
99 if (r < 0)
16924f54 100 return r;
fe8e156e
YW
101 }
102
049b66cc
YW
103 if (c->fwmark > 0) {
104 r = sd_netlink_message_append_u32(req, TCA_CAKE_FWMARK, c->fwmark);
105 if (r < 0)
16924f54 106 return r;
049b66cc
YW
107 }
108
d05dce95
YW
109 if (c->wash >= 0) {
110 r = sd_netlink_message_append_u32(req, TCA_CAKE_WASH, c->wash);
111 if (r < 0)
16924f54 112 return r;
d05dce95
YW
113 }
114
35896db4 115 if (c->split_gso >= 0) {
4883a5ec 116 r = sd_netlink_message_append_u32(req, TCA_CAKE_SPLIT_GSO, c->split_gso);
35896db4 117 if (r < 0)
16924f54 118 return r;
35896db4
YW
119 }
120
ad8352f4
SS
121 r = sd_netlink_message_close_container(req);
122 if (r < 0)
16924f54 123 return r;
ad8352f4
SS
124
125 return 0;
126}
127
128int config_parse_cake_bandwidth(
129 const char *unit,
130 const char *filename,
131 unsigned line,
132 const char *section,
133 unsigned section_line,
134 const char *lvalue,
135 int ltype,
136 const char *rvalue,
137 void *data,
138 void *userdata) {
139
140 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
141 CommonApplicationsKeptEnhanced *c;
99534007 142 Network *network = ASSERT_PTR(data);
ad8352f4
SS
143 uint64_t k;
144 int r;
145
146 assert(filename);
147 assert(lvalue);
148 assert(rvalue);
ad8352f4
SS
149
150 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
151 if (r == -ENOMEM)
152 return log_oom();
d96edb2c
YW
153 if (r < 0) {
154 log_syntax(unit, LOG_WARNING, filename, line, r,
155 "More than one kind of queueing discipline, ignoring assignment: %m");
156 return 0;
157 }
ad8352f4
SS
158
159 c = CAKE(qdisc);
160
161 if (isempty(rvalue)) {
162 c->bandwidth = 0;
163
0132453c 164 TAKE_PTR(qdisc);
ad8352f4
SS
165 return 0;
166 }
167
168 r = parse_size(rvalue, 1000, &k);
169 if (r < 0) {
d96edb2c 170 log_syntax(unit, LOG_WARNING, filename, line, r,
ad8352f4
SS
171 "Failed to parse '%s=', ignoring assignment: %s",
172 lvalue, rvalue);
173 return 0;
174 }
175
176 c->bandwidth = k/8;
0132453c 177 TAKE_PTR(qdisc);
ad8352f4
SS
178
179 return 0;
180}
181
182int config_parse_cake_overhead(
183 const char *unit,
184 const char *filename,
185 unsigned line,
186 const char *section,
187 unsigned section_line,
188 const char *lvalue,
189 int ltype,
190 const char *rvalue,
191 void *data,
192 void *userdata) {
193
194 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
195 CommonApplicationsKeptEnhanced *c;
99534007 196 Network *network = ASSERT_PTR(data);
ad8352f4
SS
197 int32_t v;
198 int r;
199
200 assert(filename);
201 assert(lvalue);
202 assert(rvalue);
ad8352f4
SS
203
204 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
205 if (r == -ENOMEM)
206 return log_oom();
d96edb2c
YW
207 if (r < 0) {
208 log_syntax(unit, LOG_WARNING, filename, line, r,
209 "More than one kind of queueing discipline, ignoring assignment: %m");
210 return 0;
211 }
ad8352f4
SS
212
213 c = CAKE(qdisc);
214
215 if (isempty(rvalue)) {
3a86a31e 216 c->overhead_set = false;
0132453c 217 TAKE_PTR(qdisc);
ad8352f4
SS
218 return 0;
219 }
220
221 r = safe_atoi32(rvalue, &v);
222 if (r < 0) {
d96edb2c 223 log_syntax(unit, LOG_WARNING, filename, line, r,
c03ef420
YW
224 "Failed to parse '%s=', ignoring assignment: %s",
225 lvalue, rvalue);
ad8352f4
SS
226 return 0;
227 }
228 if (v < -64 || v > 256) {
d96edb2c 229 log_syntax(unit, LOG_WARNING, filename, line, 0,
c03ef420
YW
230 "Invalid '%s=', ignoring assignment: %s",
231 lvalue, rvalue);
ad8352f4
SS
232 return 0;
233 }
234
235 c->overhead = v;
3a86a31e 236 c->overhead_set = true;
0132453c 237 TAKE_PTR(qdisc);
ad8352f4
SS
238 return 0;
239}
240
863542e1
YW
241int config_parse_cake_mpu(
242 const char *unit,
243 const char *filename,
244 unsigned line,
245 const char *section,
246 unsigned section_line,
247 const char *lvalue,
248 int ltype,
249 const char *rvalue,
250 void *data,
251 void *userdata) {
252
253 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
254 CommonApplicationsKeptEnhanced *c;
99534007 255 Network *network = ASSERT_PTR(data);
863542e1
YW
256 uint32_t v;
257 int r;
258
259 assert(filename);
260 assert(lvalue);
261 assert(rvalue);
863542e1
YW
262
263 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
264 if (r == -ENOMEM)
265 return log_oom();
266 if (r < 0) {
267 log_syntax(unit, LOG_WARNING, filename, line, r,
268 "More than one kind of queueing discipline, ignoring assignment: %m");
269 return 0;
270 }
271
272 c = CAKE(qdisc);
273
274 if (isempty(rvalue)) {
275 c->mpu = 0;
276 TAKE_PTR(qdisc);
277 return 0;
278 }
279
280 r = safe_atou32(rvalue, &v);
281 if (r < 0) {
282 log_syntax(unit, LOG_WARNING, filename, line, r,
283 "Failed to parse '%s=', ignoring assignment: %s",
284 lvalue, rvalue);
285 return 0;
286 }
287 if (v <= 0 || v > 256) {
288 log_syntax(unit, LOG_WARNING, filename, line, 0,
289 "Invalid '%s=', ignoring assignment: %s",
290 lvalue, rvalue);
291 return 0;
292 }
293
294 c->mpu = v;
295 TAKE_PTR(qdisc);
296 return 0;
297}
298
025cd94e
YW
299int config_parse_cake_tristate(
300 const char *unit,
301 const char *filename,
302 unsigned line,
303 const char *section,
304 unsigned section_line,
305 const char *lvalue,
306 int ltype,
307 const char *rvalue,
308 void *data,
309 void *userdata) {
310
311 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
312 CommonApplicationsKeptEnhanced *c;
99534007 313 Network *network = ASSERT_PTR(data);
025cd94e
YW
314 int *dest, r;
315
316 assert(filename);
317 assert(lvalue);
318 assert(rvalue);
025cd94e
YW
319
320 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
321 if (r == -ENOMEM)
322 return log_oom();
323 if (r < 0) {
324 log_syntax(unit, LOG_WARNING, filename, line, r,
325 "More than one kind of queueing discipline, ignoring assignment: %m");
326 return 0;
327 }
328
329 c = CAKE(qdisc);
330
331 if (streq(lvalue, "AutoRateIngress"))
332 dest = &c->autorate;
1c7a81e6
YW
333 else if (streq(lvalue, "UseRawPacketSize"))
334 dest = &c->raw;
4bff8086
YW
335 else if (streq(lvalue, "NAT"))
336 dest = &c->nat;
d05dce95
YW
337 else if (streq(lvalue, "Wash"))
338 dest = &c->wash;
35896db4
YW
339 else if (streq(lvalue, "SplitGSO"))
340 dest = &c->split_gso;
025cd94e
YW
341 else
342 assert_not_reached();
343
344 if (isempty(rvalue)) {
345 *dest = -1;
346 TAKE_PTR(qdisc);
347 return 0;
348 }
349
350 r = parse_boolean(rvalue);
351 if (r < 0) {
352 log_syntax(unit, LOG_WARNING, filename, line, r,
353 "Failed to parse '%s=', ignoring assignment: %s",
354 lvalue, rvalue);
355 return 0;
356 }
357
358 *dest = r;
359 TAKE_PTR(qdisc);
360 return 0;
361}
362
b6eccfda
YW
363static const char * const cake_compensation_mode_table[_CAKE_COMPENSATION_MODE_MAX] = {
364 [CAKE_COMPENSATION_MODE_NONE] = "none",
365 [CAKE_COMPENSATION_MODE_ATM] = "atm",
366 [CAKE_COMPENSATION_MODE_PTM] = "ptm",
367};
368
369DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(cake_compensation_mode, CakeCompensationMode);
370
371int config_parse_cake_compensation_mode(
372 const char *unit,
373 const char *filename,
374 unsigned line,
375 const char *section,
376 unsigned section_line,
377 const char *lvalue,
378 int ltype,
379 const char *rvalue,
380 void *data,
381 void *userdata) {
382
383 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
384 CommonApplicationsKeptEnhanced *c;
99534007 385 Network *network = ASSERT_PTR(data);
b6eccfda
YW
386 CakeCompensationMode mode;
387 int r;
388
389 assert(filename);
390 assert(lvalue);
391 assert(rvalue);
b6eccfda
YW
392
393 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
394 if (r == -ENOMEM)
395 return log_oom();
396 if (r < 0) {
397 log_syntax(unit, LOG_WARNING, filename, line, r,
398 "More than one kind of queueing discipline, ignoring assignment: %m");
399 return 0;
400 }
401
402 c = CAKE(qdisc);
403
404 if (isempty(rvalue)) {
405 c->compensation_mode = _CAKE_COMPENSATION_MODE_INVALID;
406 TAKE_PTR(qdisc);
407 return 0;
408 }
409
410 mode = cake_compensation_mode_from_string(rvalue);
411 if (mode < 0) {
412 log_syntax(unit, LOG_WARNING, filename, line, mode,
413 "Failed to parse '%s=', ignoring assignment: %s",
414 lvalue, rvalue);
415 return 0;
416 }
417
418 c->compensation_mode = mode;
419 TAKE_PTR(qdisc);
420 return 0;
421}
422
a049cf16
YW
423static const char * const cake_flow_isolation_mode_table[_CAKE_FLOW_ISOLATION_MODE_MAX] = {
424 [CAKE_FLOW_ISOLATION_MODE_NONE] = "none",
425 [CAKE_FLOW_ISOLATION_MODE_SRC_IP] = "src-host",
426 [CAKE_FLOW_ISOLATION_MODE_DST_IP] = "dst-host",
427 [CAKE_FLOW_ISOLATION_MODE_HOSTS] = "hosts",
428 [CAKE_FLOW_ISOLATION_MODE_FLOWS] = "flows",
429 [CAKE_FLOW_ISOLATION_MODE_DUAL_SRC] = "dual-src-host",
430 [CAKE_FLOW_ISOLATION_MODE_DUAL_DST] = "dual-dst-host",
431 [CAKE_FLOW_ISOLATION_MODE_TRIPLE] = "triple",
432};
433
434DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(cake_flow_isolation_mode, CakeFlowIsolationMode);
435
436int config_parse_cake_flow_isolation_mode(
437 const char *unit,
438 const char *filename,
439 unsigned line,
440 const char *section,
441 unsigned section_line,
442 const char *lvalue,
443 int ltype,
444 const char *rvalue,
445 void *data,
446 void *userdata) {
447
448 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
449 CommonApplicationsKeptEnhanced *c;
99534007 450 Network *network = ASSERT_PTR(data);
a049cf16
YW
451 CakeFlowIsolationMode mode;
452 int r;
453
454 assert(filename);
455 assert(lvalue);
456 assert(rvalue);
a049cf16
YW
457
458 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
459 if (r == -ENOMEM)
460 return log_oom();
461 if (r < 0) {
462 log_syntax(unit, LOG_WARNING, filename, line, r,
463 "More than one kind of queueing discipline, ignoring assignment: %m");
464 return 0;
465 }
466
467 c = CAKE(qdisc);
468
469 if (isempty(rvalue)) {
470 c->flow_isolation_mode = _CAKE_FLOW_ISOLATION_MODE_INVALID;
471 TAKE_PTR(qdisc);
472 return 0;
473 }
474
475 mode = cake_flow_isolation_mode_from_string(rvalue);
476 if (mode < 0) {
477 log_syntax(unit, LOG_WARNING, filename, line, mode,
478 "Failed to parse '%s=', ignoring assignment: %s",
479 lvalue, rvalue);
480 return 0;
481 }
482
483 c->flow_isolation_mode = mode;
484 TAKE_PTR(qdisc);
485 return 0;
486}
487
fe8e156e
YW
488static const char * const cake_priority_queueing_preset_table[_CAKE_PRESET_MAX] = {
489 [CAKE_PRESET_DIFFSERV3] = "diffserv3",
490 [CAKE_PRESET_DIFFSERV4] = "diffserv4",
491 [CAKE_PRESET_DIFFSERV8] = "diffserv8",
492 [CAKE_PRESET_BESTEFFORT] = "besteffort",
493 [CAKE_PRESET_PRECEDENCE] = "precedence",
494};
495
496DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(cake_priority_queueing_preset, CakePriorityQueueingPreset);
497
498int config_parse_cake_priority_queueing_preset(
499 const char *unit,
500 const char *filename,
501 unsigned line,
502 const char *section,
503 unsigned section_line,
504 const char *lvalue,
505 int ltype,
506 const char *rvalue,
507 void *data,
508 void *userdata) {
509
510 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
511 CommonApplicationsKeptEnhanced *c;
512 CakePriorityQueueingPreset preset;
99534007 513 Network *network = ASSERT_PTR(data);
fe8e156e
YW
514 int r;
515
516 assert(filename);
517 assert(lvalue);
518 assert(rvalue);
fe8e156e
YW
519
520 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
521 if (r == -ENOMEM)
522 return log_oom();
523 if (r < 0) {
524 log_syntax(unit, LOG_WARNING, filename, line, r,
525 "More than one kind of queueing discipline, ignoring assignment: %m");
526 return 0;
527 }
528
529 c = CAKE(qdisc);
530
531 if (isempty(rvalue)) {
532 c->preset = _CAKE_PRESET_INVALID;
533 TAKE_PTR(qdisc);
534 return 0;
535 }
536
537 preset = cake_priority_queueing_preset_from_string(rvalue);
538 if (preset < 0) {
539 log_syntax(unit, LOG_WARNING, filename, line, preset,
540 "Failed to parse '%s=', ignoring assignment: %s",
541 lvalue, rvalue);
542 return 0;
543 }
544
545 c->preset = preset;
546 TAKE_PTR(qdisc);
547 return 0;
548}
549
049b66cc
YW
550int config_parse_cake_fwmark(
551 const char *unit,
552 const char *filename,
553 unsigned line,
554 const char *section,
555 unsigned section_line,
556 const char *lvalue,
557 int ltype,
558 const char *rvalue,
559 void *data,
560 void *userdata) {
561
562 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
563 CommonApplicationsKeptEnhanced *c;
99534007 564 Network *network = ASSERT_PTR(data);
049b66cc
YW
565 uint32_t fwmark;
566 int r;
567
568 assert(filename);
569 assert(lvalue);
570 assert(rvalue);
049b66cc
YW
571
572 r = qdisc_new_static(QDISC_KIND_CAKE, network, filename, section_line, &qdisc);
573 if (r == -ENOMEM)
574 return log_oom();
575 if (r < 0) {
576 log_syntax(unit, LOG_WARNING, filename, line, r,
577 "More than one kind of queueing discipline, ignoring assignment: %m");
578 return 0;
579 }
580
581 c = CAKE(qdisc);
582
583 if (isempty(rvalue)) {
584 c->fwmark = 0;
585 TAKE_PTR(qdisc);
586 return 0;
587 }
588
589 r = safe_atou32(rvalue, &fwmark);
590 if (r < 0) {
591 log_syntax(unit, LOG_WARNING, filename, line, r,
592 "Failed to parse '%s=', ignoring assignment: %s",
593 lvalue, rvalue);
594 return 0;
595 }
596 if (fwmark <= 0) {
597 log_syntax(unit, LOG_WARNING, filename, line, 0,
598 "Invalid '%s=', ignoring assignment: %s",
599 lvalue, rvalue);
600 return 0;
601 }
602
603 c->fwmark = fwmark;
604 TAKE_PTR(qdisc);
605 return 0;
606}
607
ad8352f4
SS
608const QDiscVTable cake_vtable = {
609 .object_size = sizeof(CommonApplicationsKeptEnhanced),
610 .tca_kind = "cake",
025cd94e 611 .init = cake_init,
ad8352f4
SS
612 .fill_message = cake_fill_message,
613};