1 /* SPDX-License-Identifier: LGPL-2.1-or-later
2 * Copyright © 2019 VMware, Inc. */
4 #include <linux/pkt_sched.h>
6 #include "alloc-util.h"
7 #include "conf-parser.h"
10 #include "netlink-util.h"
11 #include "parse-util.h"
12 #include "string-util.h"
15 static int fair_queueing_init(QDisc
*qdisc
) {
23 fq
->ce_threshold_usec
= USEC_INFINITY
;
28 static int fair_queueing_fill_message(Link
*link
, QDisc
*qdisc
, sd_netlink_message
*req
) {
36 assert_se(fq
= FQ(qdisc
));
38 r
= sd_netlink_message_open_container_union(req
, TCA_OPTIONS
, "fq");
42 if (fq
->packet_limit
> 0) {
43 r
= sd_netlink_message_append_u32(req
, TCA_FQ_PLIMIT
, fq
->packet_limit
);
48 if (fq
->flow_limit
> 0) {
49 r
= sd_netlink_message_append_u32(req
, TCA_FQ_FLOW_PLIMIT
, fq
->flow_limit
);
54 if (fq
->quantum
> 0) {
55 r
= sd_netlink_message_append_u32(req
, TCA_FQ_QUANTUM
, fq
->quantum
);
60 if (fq
->initial_quantum
> 0) {
61 r
= sd_netlink_message_append_u32(req
, TCA_FQ_INITIAL_QUANTUM
, fq
->initial_quantum
);
66 if (fq
->pacing
>= 0) {
67 r
= sd_netlink_message_append_u32(req
, TCA_FQ_RATE_ENABLE
, fq
->pacing
);
72 if (fq
->max_rate
> 0) {
73 r
= sd_netlink_message_append_u32(req
, TCA_FQ_FLOW_MAX_RATE
, fq
->max_rate
);
78 if (fq
->buckets
> 0) {
81 l
= log2u(fq
->buckets
);
82 r
= sd_netlink_message_append_u32(req
, TCA_FQ_BUCKETS_LOG
, l
);
87 if (fq
->orphan_mask
> 0) {
88 r
= sd_netlink_message_append_u32(req
, TCA_FQ_ORPHAN_MASK
, fq
->orphan_mask
);
93 if (fq
->ce_threshold_usec
!= USEC_INFINITY
) {
94 r
= sd_netlink_message_append_u32(req
, TCA_FQ_CE_THRESHOLD
, fq
->ce_threshold_usec
);
99 r
= sd_netlink_message_close_container(req
);
106 int config_parse_fair_queueing_u32(
108 const char *filename
,
111 unsigned section_line
,
118 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
120 Network
*network
= ASSERT_PTR(data
);
128 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
132 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
133 "More than one kind of queueing discipline, ignoring assignment: %m");
139 if (streq(lvalue
, "PacketLimit"))
140 p
= &fq
->packet_limit
;
141 else if (streq(lvalue
, "FlowLimit"))
143 else if (streq(lvalue
, "Buckets"))
145 else if (streq(lvalue
, "OrphanMask"))
146 p
= &fq
->orphan_mask
;
148 assert_not_reached();
150 if (isempty(rvalue
)) {
157 r
= safe_atou32(rvalue
, p
);
159 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
160 "Failed to parse '%s=', ignoring assignment: %s",
170 int config_parse_fair_queueing_size(
172 const char *filename
,
175 unsigned section_line
,
182 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
184 Network
*network
= ASSERT_PTR(data
);
193 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
197 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
198 "More than one kind of queueing discipline, ignoring assignment: %m");
204 if (STR_IN_SET(lvalue
, "QuantumBytes", "Quantum"))
206 else if (STR_IN_SET(lvalue
, "InitialQuantumBytes", "InitialQuantum"))
207 p
= &fq
->initial_quantum
;
209 assert_not_reached();
211 if (isempty(rvalue
)) {
218 r
= parse_size(rvalue
, 1024, &sz
);
220 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
221 "Failed to parse '%s=', ignoring assignment: %s",
225 if (sz
> UINT32_MAX
) {
226 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
227 "Specified '%s=' is too large, ignoring assignment: %s",
238 int config_parse_fair_queueing_bool(
240 const char *filename
,
243 unsigned section_line
,
250 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
252 Network
*network
= ASSERT_PTR(data
);
259 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
263 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
264 "More than one kind of queueing discipline, ignoring assignment: %m");
270 r
= parse_tristate(rvalue
, &fq
->pacing
);
272 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
273 "Failed to parse '%s=', ignoring assignment: %s",
284 int config_parse_fair_queueing_usec(
286 const char *filename
,
289 unsigned section_line
,
296 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
298 Network
*network
= ASSERT_PTR(data
);
306 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
310 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
311 "More than one kind of queueing discipline, ignoring assignment: %m");
317 if (isempty(rvalue
)) {
318 fq
->ce_threshold_usec
= USEC_INFINITY
;
324 r
= parse_sec(rvalue
, &sec
);
326 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
327 "Failed to parse '%s=', ignoring assignment: %s",
331 if (sec
> UINT32_MAX
) {
332 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
333 "Specified '%s=' is too large, ignoring assignment: %s",
338 fq
->ce_threshold_usec
= sec
;
344 int config_parse_fair_queueing_max_rate(
346 const char *filename
,
349 unsigned section_line
,
356 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
358 Network
*network
= ASSERT_PTR(data
);
366 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
370 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
371 "More than one kind of queueing discipline, ignoring assignment: %m");
377 if (isempty(rvalue
)) {
384 r
= parse_size(rvalue
, 1000, &sz
);
386 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
387 "Failed to parse '%s=', ignoring assignment: %s",
391 if (sz
/ 8 > UINT32_MAX
) {
392 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
393 "Specified '%s=' is too large, ignoring assignment: %s",
398 fq
->max_rate
= sz
/ 8;
404 const QDiscVTable fq_vtable
= {
405 .init
= fair_queueing_init
,
406 .object_size
= sizeof(FairQueueing
),
408 .fill_message
= fair_queueing_fill_message
,