1 /* SPDX-License-Identifier: LGPL-2.1+
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 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
133 "More than one kind of queueing discipline, ignoring assignment: %m");
137 if (streq(lvalue
, "PacketLimit"))
138 p
= &fq
->packet_limit
;
139 else if (streq(lvalue
, "FlowLimit"))
141 else if (streq(lvalue
, "Buckets"))
143 else if (streq(lvalue
, "OrphanMask"))
144 p
= &fq
->orphan_mask
;
146 assert_not_reached("Invalid lvalue");
148 if (isempty(rvalue
)) {
155 r
= safe_atou32(rvalue
, p
);
157 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
158 "Failed to parse '%s=', ignoring assignment: %s",
168 int config_parse_fair_queueing_size(
170 const char *filename
,
173 unsigned section_line
,
180 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
182 Network
*network
= data
;
192 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
196 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
197 "More than one kind of queueing discipline, ignoring assignment: %m");
201 if (STR_IN_SET(lvalue
, "QuantumBytes", "Quantum"))
203 else if (STR_IN_SET(lvalue
, "InitialQuantumBytes", "InitialQuantum"))
204 p
= &fq
->initial_quantum
;
206 assert_not_reached("Invalid lvalue");
208 if (isempty(rvalue
)) {
215 r
= parse_size(rvalue
, 1024, &sz
);
217 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
218 "Failed to parse '%s=', ignoring assignment: %s",
222 if (sz
> UINT32_MAX
) {
223 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
224 "Specified '%s=' is too large, ignoring assignment: %s",
235 int config_parse_fair_queueing_bool(
237 const char *filename
,
240 unsigned section_line
,
247 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
249 Network
*network
= data
;
257 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
261 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
262 "More than one kind of queueing discipline, ignoring assignment: %m");
266 if (isempty(rvalue
)) {
273 r
= parse_boolean(rvalue
);
275 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
276 "Failed to parse '%s=', ignoring assignment: %s",
287 int config_parse_fair_queueing_usec(
289 const char *filename
,
292 unsigned section_line
,
299 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
301 Network
*network
= data
;
310 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
314 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
315 "More than one kind of queueing discipline, ignoring assignment: %m");
319 if (isempty(rvalue
)) {
320 fq
->ce_threshold_usec
= USEC_INFINITY
;
326 r
= parse_sec(rvalue
, &sec
);
328 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
329 "Failed to parse '%s=', ignoring assignment: %s",
333 if (sec
> UINT32_MAX
) {
334 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
335 "Specified '%s=' is too large, ignoring assignment: %s",
340 fq
->ce_threshold_usec
= sec
;
346 int config_parse_fair_queueing_max_rate(
348 const char *filename
,
351 unsigned section_line
,
358 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
360 Network
*network
= data
;
369 r
= qdisc_new_static(QDISC_KIND_FQ
, network
, filename
, section_line
, &qdisc
);
373 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
374 "More than one kind of queueing discipline, ignoring assignment: %m");
378 if (isempty(rvalue
)) {
385 r
= parse_size(rvalue
, 1000, &sz
);
387 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
388 "Failed to parse '%s=', ignoring assignment: %s",
392 if (sz
/ 8 > UINT32_MAX
) {
393 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
394 "Specified '%s=' is too large, ignoring assignment: %s",
399 fq
->max_rate
= sz
/ 8;
405 const QDiscVTable fq_vtable
= {
406 .init
= fair_queueing_init
,
407 .object_size
= sizeof(FairQueueing
),
409 .fill_message
= fair_queueing_fill_message
,