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
) {
37 r
= sd_netlink_message_open_container_union(req
, TCA_OPTIONS
, "fq");
39 return log_link_error_errno(link
, r
, "Could not open container TCA_OPTIONS: %m");
41 if (fq
->packet_limit
> 0) {
42 r
= sd_netlink_message_append_u32(req
, TCA_FQ_PLIMIT
, fq
->packet_limit
);
44 return log_link_error_errno(link
, r
, "Could not append TCA_FQ_PLIMIT attribute: %m");
47 if (fq
->flow_limit
> 0) {
48 r
= sd_netlink_message_append_u32(req
, TCA_FQ_FLOW_PLIMIT
, fq
->flow_limit
);
50 return log_link_error_errno(link
, r
, "Could not append TCA_FQ_FLOW_PLIMIT attribute: %m");
53 if (fq
->quantum
> 0) {
54 r
= sd_netlink_message_append_u32(req
, TCA_FQ_QUANTUM
, fq
->quantum
);
56 return log_link_error_errno(link
, r
, "Could not append TCA_FQ_QUANTUM attribute: %m");
59 if (fq
->initial_quantum
> 0) {
60 r
= sd_netlink_message_append_u32(req
, TCA_FQ_INITIAL_QUANTUM
, fq
->initial_quantum
);
62 return log_link_error_errno(link
, r
, "Could not append TCA_FQ_INITIAL_QUANTUM attribute: %m");
65 if (fq
->pacing
>= 0) {
66 r
= sd_netlink_message_append_u32(req
, TCA_FQ_RATE_ENABLE
, fq
->pacing
);
68 return log_link_error_errno(link
, r
, "Could not append TCA_FQ_RATE_ENABLE attribute: %m");
71 if (fq
->max_rate
> 0) {
72 r
= sd_netlink_message_append_u32(req
, TCA_FQ_FLOW_MAX_RATE
, fq
->max_rate
);
74 return log_link_error_errno(link
, r
, "Could not append TCA_FQ_FLOW_MAX_RATE attribute: %m");
77 if (fq
->buckets
> 0) {
80 l
= log2u(fq
->buckets
);
81 r
= sd_netlink_message_append_u32(req
, TCA_FQ_BUCKETS_LOG
, l
);
83 return log_link_error_errno(link
, r
, "Could not append TCA_FQ_BUCKETS_LOG attribute: %m");
86 if (fq
->orphan_mask
> 0) {
87 r
= sd_netlink_message_append_u32(req
, TCA_FQ_ORPHAN_MASK
, fq
->orphan_mask
);
89 return log_link_error_errno(link
, r
, "Could not append TCA_FQ_ORPHAN_MASK attribute: %m");
92 if (fq
->ce_threshold_usec
!= USEC_INFINITY
) {
93 r
= sd_netlink_message_append_u32(req
, TCA_FQ_CE_THRESHOLD
, fq
->ce_threshold_usec
);
95 return log_link_error_errno(link
, r
, "Could not append TCA_FQ_CE_THRESHOLD attribute: %m");
98 r
= sd_netlink_message_close_container(req
);
100 return log_link_error_errno(link
, r
, "Could not close container TCA_OPTIONS: %m");
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
= 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("Invalid lvalue");
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
= data
;
194 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
198 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
199 "More than one kind of queueing discipline, ignoring assignment: %m");
205 if (STR_IN_SET(lvalue
, "QuantumBytes", "Quantum"))
207 else if (STR_IN_SET(lvalue
, "InitialQuantumBytes", "InitialQuantum"))
208 p
= &fq
->initial_quantum
;
210 assert_not_reached("Invalid lvalue");
212 if (isempty(rvalue
)) {
219 r
= parse_size(rvalue
, 1024, &sz
);
221 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
222 "Failed to parse '%s=', ignoring assignment: %s",
226 if (sz
> UINT32_MAX
) {
227 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
228 "Specified '%s=' is too large, ignoring assignment: %s",
239 int config_parse_fair_queueing_bool(
241 const char *filename
,
244 unsigned section_line
,
251 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
253 Network
*network
= data
;
261 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
265 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
266 "More than one kind of queueing discipline, ignoring assignment: %m");
272 if (isempty(rvalue
)) {
279 r
= parse_boolean(rvalue
);
281 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
282 "Failed to parse '%s=', ignoring assignment: %s",
293 int config_parse_fair_queueing_usec(
295 const char *filename
,
298 unsigned section_line
,
305 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
307 Network
*network
= data
;
316 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
320 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
321 "More than one kind of queueing discipline, ignoring assignment: %m");
327 if (isempty(rvalue
)) {
328 fq
->ce_threshold_usec
= USEC_INFINITY
;
334 r
= parse_sec(rvalue
, &sec
);
336 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
337 "Failed to parse '%s=', ignoring assignment: %s",
341 if (sec
> UINT32_MAX
) {
342 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
343 "Specified '%s=' is too large, ignoring assignment: %s",
348 fq
->ce_threshold_usec
= sec
;
354 int config_parse_fair_queueing_max_rate(
356 const char *filename
,
359 unsigned section_line
,
366 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
368 Network
*network
= data
;
377 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
381 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
382 "More than one kind of queueing discipline, ignoring assignment: %m");
388 if (isempty(rvalue
)) {
395 r
= parse_size(rvalue
, 1000, &sz
);
397 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
398 "Failed to parse '%s=', ignoring assignment: %s",
402 if (sz
/ 8 > UINT32_MAX
) {
403 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
404 "Specified '%s=' is too large, ignoring assignment: %s",
409 fq
->max_rate
= sz
/ 8;
415 const QDiscVTable fq_vtable
= {
416 .init
= fair_queueing_init
,
417 .object_size
= sizeof(FairQueueing
),
419 .fill_message
= fair_queueing_fill_message
,