1 /* SPDX-License-Identifier: LGPL-2.1-or-later
2 * Copyright © 2020 VMware, Inc. */
4 #include <linux/pkt_sched.h>
6 #include "alloc-util.h"
8 #include "conf-parser.h"
9 #include "netlink-util.h"
10 #include "parse-util.h"
12 #include "string-table.h"
13 #include "string-util.h"
15 static int cake_init(QDisc
*qdisc
) {
16 CommonApplicationsKeptEnhanced
*c
;
23 c
->compensation_mode
= _CAKE_COMPENSATION_MODE_INVALID
;
25 c
->flow_isolation_mode
= _CAKE_FLOW_ISOLATION_MODE_INVALID
;
27 c
->preset
= _CAKE_PRESET_INVALID
;
34 static int cake_fill_message(Link
*link
, QDisc
*qdisc
, sd_netlink_message
*req
) {
35 CommonApplicationsKeptEnhanced
*c
;
42 assert_se(c
= CAKE(qdisc
));
44 r
= sd_netlink_message_open_container_union(req
, TCA_OPTIONS
, "cake");
48 if (c
->bandwidth
> 0) {
49 r
= sd_netlink_message_append_u64(req
, TCA_CAKE_BASE_RATE64
, c
->bandwidth
);
54 if (c
->autorate
>= 0) {
55 r
= sd_netlink_message_append_u32(req
, TCA_CAKE_AUTORATE
, c
->autorate
);
60 if (c
->overhead_set
) {
61 r
= sd_netlink_message_append_s32(req
, TCA_CAKE_OVERHEAD
, c
->overhead
);
67 r
= sd_netlink_message_append_u32(req
, TCA_CAKE_MPU
, c
->mpu
);
72 if (c
->compensation_mode
>= 0) {
73 r
= sd_netlink_message_append_u32(req
, TCA_CAKE_ATM
, c
->compensation_mode
);
79 /* TCA_CAKE_RAW attribute is mostly a flag, not boolean. */
80 r
= sd_netlink_message_append_u32(req
, TCA_CAKE_RAW
, 0);
85 if (c
->flow_isolation_mode
>= 0) {
86 r
= sd_netlink_message_append_u32(req
, TCA_CAKE_FLOW_MODE
, c
->flow_isolation_mode
);
92 r
= sd_netlink_message_append_u32(req
, TCA_CAKE_NAT
, c
->nat
);
98 r
= sd_netlink_message_append_u32(req
, TCA_CAKE_DIFFSERV_MODE
, c
->preset
);
104 r
= sd_netlink_message_append_u32(req
, TCA_CAKE_FWMARK
, c
->fwmark
);
110 r
= sd_netlink_message_append_u32(req
, TCA_CAKE_WASH
, c
->wash
);
115 if (c
->split_gso
>= 0) {
116 r
= sd_netlink_message_append_u32(req
, TCA_CAKE_SPLIT_GSO
, c
->split_gso
);
121 r
= sd_netlink_message_close_container(req
);
128 int config_parse_cake_bandwidth(
130 const char *filename
,
133 unsigned section_line
,
140 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
141 CommonApplicationsKeptEnhanced
*c
;
142 Network
*network
= ASSERT_PTR(data
);
150 r
= qdisc_new_static(QDISC_KIND_CAKE
, network
, filename
, section_line
, &qdisc
);
154 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
155 "More than one kind of queueing discipline, ignoring assignment: %m");
161 if (isempty(rvalue
)) {
168 r
= parse_size(rvalue
, 1000, &k
);
170 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
171 "Failed to parse '%s=', ignoring assignment: %s",
182 int config_parse_cake_overhead(
184 const char *filename
,
187 unsigned section_line
,
194 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
195 CommonApplicationsKeptEnhanced
*c
;
196 Network
*network
= ASSERT_PTR(data
);
204 r
= qdisc_new_static(QDISC_KIND_CAKE
, network
, filename
, section_line
, &qdisc
);
208 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
209 "More than one kind of queueing discipline, ignoring assignment: %m");
215 if (isempty(rvalue
)) {
216 c
->overhead_set
= false;
221 r
= safe_atoi32(rvalue
, &v
);
223 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
224 "Failed to parse '%s=', ignoring assignment: %s",
228 if (v
< -64 || v
> 256) {
229 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
230 "Invalid '%s=', ignoring assignment: %s",
236 c
->overhead_set
= true;
241 int config_parse_cake_mpu(
243 const char *filename
,
246 unsigned section_line
,
253 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
254 CommonApplicationsKeptEnhanced
*c
;
255 Network
*network
= ASSERT_PTR(data
);
263 r
= qdisc_new_static(QDISC_KIND_CAKE
, network
, filename
, section_line
, &qdisc
);
267 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
268 "More than one kind of queueing discipline, ignoring assignment: %m");
274 if (isempty(rvalue
)) {
280 r
= safe_atou32(rvalue
, &v
);
282 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
283 "Failed to parse '%s=', ignoring assignment: %s",
287 if (v
<= 0 || v
> 256) {
288 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
289 "Invalid '%s=', ignoring assignment: %s",
299 int config_parse_cake_tristate(
301 const char *filename
,
304 unsigned section_line
,
311 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
312 CommonApplicationsKeptEnhanced
*c
;
313 Network
*network
= ASSERT_PTR(data
);
320 r
= qdisc_new_static(QDISC_KIND_CAKE
, network
, filename
, section_line
, &qdisc
);
324 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
325 "More than one kind of queueing discipline, ignoring assignment: %m");
331 if (streq(lvalue
, "AutoRateIngress"))
333 else if (streq(lvalue
, "UseRawPacketSize"))
335 else if (streq(lvalue
, "NAT"))
337 else if (streq(lvalue
, "Wash"))
339 else if (streq(lvalue
, "SplitGSO"))
340 dest
= &c
->split_gso
;
342 assert_not_reached();
344 if (isempty(rvalue
)) {
350 r
= parse_boolean(rvalue
);
352 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
353 "Failed to parse '%s=', ignoring assignment: %s",
363 static 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",
369 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(cake_compensation_mode
, CakeCompensationMode
);
371 int config_parse_cake_compensation_mode(
373 const char *filename
,
376 unsigned section_line
,
383 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
384 CommonApplicationsKeptEnhanced
*c
;
385 Network
*network
= ASSERT_PTR(data
);
386 CakeCompensationMode mode
;
393 r
= qdisc_new_static(QDISC_KIND_CAKE
, network
, filename
, section_line
, &qdisc
);
397 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
398 "More than one kind of queueing discipline, ignoring assignment: %m");
404 if (isempty(rvalue
)) {
405 c
->compensation_mode
= _CAKE_COMPENSATION_MODE_INVALID
;
410 mode
= cake_compensation_mode_from_string(rvalue
);
412 log_syntax(unit
, LOG_WARNING
, filename
, line
, mode
,
413 "Failed to parse '%s=', ignoring assignment: %s",
418 c
->compensation_mode
= mode
;
423 static 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",
434 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(cake_flow_isolation_mode
, CakeFlowIsolationMode
);
436 int config_parse_cake_flow_isolation_mode(
438 const char *filename
,
441 unsigned section_line
,
448 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
449 CommonApplicationsKeptEnhanced
*c
;
450 Network
*network
= ASSERT_PTR(data
);
451 CakeFlowIsolationMode mode
;
458 r
= qdisc_new_static(QDISC_KIND_CAKE
, network
, filename
, section_line
, &qdisc
);
462 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
463 "More than one kind of queueing discipline, ignoring assignment: %m");
469 if (isempty(rvalue
)) {
470 c
->flow_isolation_mode
= _CAKE_FLOW_ISOLATION_MODE_INVALID
;
475 mode
= cake_flow_isolation_mode_from_string(rvalue
);
477 log_syntax(unit
, LOG_WARNING
, filename
, line
, mode
,
478 "Failed to parse '%s=', ignoring assignment: %s",
483 c
->flow_isolation_mode
= mode
;
488 static 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",
496 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(cake_priority_queueing_preset
, CakePriorityQueueingPreset
);
498 int config_parse_cake_priority_queueing_preset(
500 const char *filename
,
503 unsigned section_line
,
510 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
511 CommonApplicationsKeptEnhanced
*c
;
512 CakePriorityQueueingPreset preset
;
513 Network
*network
= ASSERT_PTR(data
);
520 r
= qdisc_new_static(QDISC_KIND_CAKE
, network
, filename
, section_line
, &qdisc
);
524 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
525 "More than one kind of queueing discipline, ignoring assignment: %m");
531 if (isempty(rvalue
)) {
532 c
->preset
= _CAKE_PRESET_INVALID
;
537 preset
= cake_priority_queueing_preset_from_string(rvalue
);
539 log_syntax(unit
, LOG_WARNING
, filename
, line
, preset
,
540 "Failed to parse '%s=', ignoring assignment: %s",
550 int config_parse_cake_fwmark(
552 const char *filename
,
555 unsigned section_line
,
562 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
563 CommonApplicationsKeptEnhanced
*c
;
564 Network
*network
= ASSERT_PTR(data
);
572 r
= qdisc_new_static(QDISC_KIND_CAKE
, network
, filename
, section_line
, &qdisc
);
576 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
577 "More than one kind of queueing discipline, ignoring assignment: %m");
583 if (isempty(rvalue
)) {
589 r
= safe_atou32(rvalue
, &fwmark
);
591 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
592 "Failed to parse '%s=', ignoring assignment: %s",
597 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
598 "Invalid '%s=', ignoring assignment: %s",
608 const QDiscVTable cake_vtable
= {
609 .object_size
= sizeof(CommonApplicationsKeptEnhanced
),
612 .fill_message
= cake_fill_message
,