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"
9 #include "netlink-util.h"
10 #include "parse-util.h"
11 #include "string-util.h"
14 static int fair_queueing_init(QDisc
*qdisc
) {
22 fq
->ce_threshold_usec
= USEC_INFINITY
;
27 static int fair_queueing_fill_message(Link
*link
, QDisc
*qdisc
, sd_netlink_message
*req
) {
35 assert_se(fq
= FQ(qdisc
));
37 r
= sd_netlink_message_open_container_union(req
, TCA_OPTIONS
, "fq");
41 if (fq
->packet_limit
> 0) {
42 r
= sd_netlink_message_append_u32(req
, TCA_FQ_PLIMIT
, fq
->packet_limit
);
47 if (fq
->flow_limit
> 0) {
48 r
= sd_netlink_message_append_u32(req
, TCA_FQ_FLOW_PLIMIT
, fq
->flow_limit
);
53 if (fq
->quantum
> 0) {
54 r
= sd_netlink_message_append_u32(req
, TCA_FQ_QUANTUM
, fq
->quantum
);
59 if (fq
->initial_quantum
> 0) {
60 r
= sd_netlink_message_append_u32(req
, TCA_FQ_INITIAL_QUANTUM
, fq
->initial_quantum
);
65 if (fq
->pacing
>= 0) {
66 r
= sd_netlink_message_append_u32(req
, TCA_FQ_RATE_ENABLE
, fq
->pacing
);
71 if (fq
->max_rate
> 0) {
72 r
= sd_netlink_message_append_u32(req
, TCA_FQ_FLOW_MAX_RATE
, fq
->max_rate
);
77 if (fq
->buckets
> 0) {
80 l
= log2u(fq
->buckets
);
81 r
= sd_netlink_message_append_u32(req
, TCA_FQ_BUCKETS_LOG
, l
);
86 if (fq
->orphan_mask
> 0) {
87 r
= sd_netlink_message_append_u32(req
, TCA_FQ_ORPHAN_MASK
, fq
->orphan_mask
);
92 if (fq
->ce_threshold_usec
!= USEC_INFINITY
) {
93 r
= sd_netlink_message_append_u32(req
, TCA_FQ_CE_THRESHOLD
, fq
->ce_threshold_usec
);
98 r
= sd_netlink_message_close_container(req
);
105 int config_parse_fair_queueing_u32(
107 const char *filename
,
110 unsigned section_line
,
117 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
119 Network
*network
= ASSERT_PTR(data
);
127 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
131 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
132 "More than one kind of queueing discipline, ignoring assignment: %m");
138 if (streq(lvalue
, "PacketLimit"))
139 p
= &fq
->packet_limit
;
140 else if (streq(lvalue
, "FlowLimit"))
142 else if (streq(lvalue
, "Buckets"))
144 else if (streq(lvalue
, "OrphanMask"))
145 p
= &fq
->orphan_mask
;
147 assert_not_reached();
149 if (isempty(rvalue
)) {
156 r
= safe_atou32(rvalue
, p
);
158 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
159 "Failed to parse '%s=', ignoring assignment: %s",
169 int config_parse_fair_queueing_size(
171 const char *filename
,
174 unsigned section_line
,
181 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
183 Network
*network
= ASSERT_PTR(data
);
192 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
196 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
197 "More than one kind of queueing discipline, ignoring assignment: %m");
203 if (STR_IN_SET(lvalue
, "QuantumBytes", "Quantum"))
205 else if (STR_IN_SET(lvalue
, "InitialQuantumBytes", "InitialQuantum"))
206 p
= &fq
->initial_quantum
;
208 assert_not_reached();
210 if (isempty(rvalue
)) {
217 r
= parse_size(rvalue
, 1024, &sz
);
219 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
220 "Failed to parse '%s=', ignoring assignment: %s",
224 if (sz
> UINT32_MAX
) {
225 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
226 "Specified '%s=' is too large, ignoring assignment: %s",
237 int config_parse_fair_queueing_bool(
239 const char *filename
,
242 unsigned section_line
,
249 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
251 Network
*network
= ASSERT_PTR(data
);
258 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
262 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
263 "More than one kind of queueing discipline, ignoring assignment: %m");
269 if (isempty(rvalue
)) {
276 r
= parse_boolean(rvalue
);
278 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
279 "Failed to parse '%s=', ignoring assignment: %s",
290 int config_parse_fair_queueing_usec(
292 const char *filename
,
295 unsigned section_line
,
302 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
304 Network
*network
= ASSERT_PTR(data
);
312 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
316 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
317 "More than one kind of queueing discipline, ignoring assignment: %m");
323 if (isempty(rvalue
)) {
324 fq
->ce_threshold_usec
= USEC_INFINITY
;
330 r
= parse_sec(rvalue
, &sec
);
332 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
333 "Failed to parse '%s=', ignoring assignment: %s",
337 if (sec
> UINT32_MAX
) {
338 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
339 "Specified '%s=' is too large, ignoring assignment: %s",
344 fq
->ce_threshold_usec
= sec
;
350 int config_parse_fair_queueing_max_rate(
352 const char *filename
,
355 unsigned section_line
,
362 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
364 Network
*network
= ASSERT_PTR(data
);
372 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
376 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
377 "More than one kind of queueing discipline, ignoring assignment: %m");
383 if (isempty(rvalue
)) {
390 r
= parse_size(rvalue
, 1000, &sz
);
392 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
393 "Failed to parse '%s=', ignoring assignment: %s",
397 if (sz
/ 8 > UINT32_MAX
) {
398 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
399 "Specified '%s=' is too large, ignoring assignment: %s",
404 fq
->max_rate
= sz
/ 8;
410 const QDiscVTable fq_vtable
= {
411 .init
= fair_queueing_init
,
412 .object_size
= sizeof(FairQueueing
),
414 .fill_message
= fair_queueing_fill_message
,