1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <linux/pkt_sched.h>
5 #include "alloc-util.h"
6 #include "conf-parser.h"
8 #include "memory-util.h"
9 #include "netlink-util.h"
10 #include "parse-util.h"
12 #include "string-util.h"
15 static int enhanced_transmission_selection_fill_message(Link
*link
, QDisc
*qdisc
, sd_netlink_message
*req
) {
16 EnhancedTransmissionSelection
*ets
;
25 r
= sd_netlink_message_open_container_union(req
, TCA_OPTIONS
, "ets");
27 return log_link_error_errno(link
, r
, "Could not open container TCA_OPTIONS: %m");
29 r
= sd_netlink_message_append_u8(req
, TCA_ETS_NBANDS
, ets
->n_bands
);
31 return log_link_error_errno(link
, r
, "Could not append TCA_ETS_NBANDS attribute: %m");
33 if (ets
->n_strict
> 0) {
34 r
= sd_netlink_message_append_u8(req
, TCA_ETS_NSTRICT
, ets
->n_strict
);
36 return log_link_error_errno(link
, r
, "Could not append TCA_ETS_NSTRICT attribute: %m");
39 if (ets
->n_quanta
> 0) {
40 r
= sd_netlink_message_open_container(req
, TCA_ETS_QUANTA
);
42 return log_link_error_errno(link
, r
, "Could not open container TCA_ETS_QUANTA: %m");
44 for (unsigned i
= 0; i
< ets
->n_quanta
; i
++) {
45 r
= sd_netlink_message_append_u32(req
, TCA_ETS_QUANTA_BAND
, ets
->quanta
[i
]);
47 return log_link_error_errno(link
, r
, "Could not append TCA_ETS_QUANTA_BAND attribute: %m");
50 r
= sd_netlink_message_close_container(req
);
52 return log_link_error_errno(link
, r
, "Could not close container TCA_ETS_QUANTA: %m");
55 if (ets
->n_prio
> 0) {
56 r
= sd_netlink_message_open_container(req
, TCA_ETS_PRIOMAP
);
58 return log_link_error_errno(link
, r
, "Could not open container TCA_ETS_PRIOMAP: %m");
60 for (unsigned i
= 0; i
< ets
->n_prio
; i
++) {
61 r
= sd_netlink_message_append_u8(req
, TCA_ETS_PRIOMAP_BAND
, ets
->prio
[i
]);
63 return log_link_error_errno(link
, r
, "Could not append TCA_ETS_PRIOMAP_BAND attribute: %m");
66 r
= sd_netlink_message_close_container(req
);
68 return log_link_error_errno(link
, r
, "Could not close container TCA_ETS_PRIOMAP: %m");
71 r
= sd_netlink_message_close_container(req
);
73 return log_link_error_errno(link
, r
, "Could not close container TCA_OPTIONS: %m");
78 int config_parse_ets_u8(
83 unsigned section_line
,
90 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
91 EnhancedTransmissionSelection
*ets
;
92 Network
*network
= data
;
101 r
= qdisc_new_static(QDISC_KIND_ETS
, network
, filename
, section_line
, &qdisc
);
105 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
106 "More than one kind of queueing discipline, ignoring assignment: %m");
109 if (streq(lvalue
, "Bands"))
111 else if (streq(lvalue
, "StrictBands"))
114 assert_not_reached("Invalid lvalue.");
116 if (isempty(rvalue
)) {
123 r
= safe_atou8(rvalue
, &v
);
125 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
126 "Failed to parse '%s=', ignoring assignment: %s",
130 if (v
> TCQ_ETS_MAX_BANDS
) {
131 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
132 "Invalid '%s='. The value must be <= %d, ignoring assignment: %s",
133 lvalue
, TCQ_ETS_MAX_BANDS
, rvalue
);
143 int config_parse_ets_quanta(
145 const char *filename
,
148 unsigned section_line
,
155 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
156 EnhancedTransmissionSelection
*ets
;
157 Network
*network
= data
;
165 r
= qdisc_new_static(QDISC_KIND_ETS
, network
, filename
, section_line
, &qdisc
);
169 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
170 "More than one kind of queueing discipline, ignoring assignment: %m");
174 if (isempty(rvalue
)) {
175 memzero(ets
->quanta
, sizeof(uint32_t) * TCQ_ETS_MAX_BANDS
);
182 for (const char *p
= rvalue
;;) {
183 _cleanup_free_
char *word
= NULL
;
186 r
= extract_first_word(&p
, &word
, NULL
, 0);
190 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
191 "Failed to extract next value, ignoring: %m");
197 r
= parse_size(word
, 1024, &v
);
199 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
200 "Failed to parse '%s=', ignoring assignment: %s",
204 if (v
== 0 || v
> UINT32_MAX
) {
205 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
206 "Invalid '%s=', ignoring assignment: %s",
210 if (ets
->n_quanta
>= TCQ_ETS_MAX_BANDS
) {
211 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
212 "Too many quanta in '%s=', ignoring assignment: %s",
217 ets
->quanta
[ets
->n_quanta
++] = v
;
225 int config_parse_ets_prio(
227 const char *filename
,
230 unsigned section_line
,
237 _cleanup_(qdisc_free_or_set_invalidp
) QDisc
*qdisc
= NULL
;
238 EnhancedTransmissionSelection
*ets
;
239 Network
*network
= data
;
247 r
= qdisc_new_static(QDISC_KIND_ETS
, network
, filename
, section_line
, &qdisc
);
251 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
252 "More than one kind of queueing discipline, ignoring assignment: %m");
256 if (isempty(rvalue
)) {
257 memzero(ets
->prio
, sizeof(uint8_t) * (TC_PRIO_MAX
+ 1));
264 for (const char *p
= rvalue
;;) {
265 _cleanup_free_
char *word
= NULL
;
268 r
= extract_first_word(&p
, &word
, NULL
, 0);
272 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
273 "Failed to extract next value, ignoring: %m");
279 r
= safe_atou8(word
, &v
);
281 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
282 "Failed to parse '%s=', ignoring assignment: %s",
286 if (ets
->n_quanta
> TC_PRIO_MAX
) {
287 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
288 "Too many priomap in '%s=', ignoring assignment: %s",
293 ets
->prio
[ets
->n_prio
++] = v
;
301 static int enhanced_transmission_selection_verify(QDisc
*qdisc
) {
302 EnhancedTransmissionSelection
*ets
;
308 if (ets
->n_bands
== 0)
309 ets
->n_bands
= ets
->n_strict
+ ets
->n_quanta
;
311 if (ets
->n_bands
== 0)
312 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
313 "%s: At least one of Band=, Strict=, or Quanta= must be specified. "
314 "Ignoring [EnhancedTransmissionSelection] section from line %u.",
315 qdisc
->section
->filename
, qdisc
->section
->line
);
317 if (ets
->n_bands
< ets
->n_strict
+ ets
->n_quanta
)
318 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
319 "%s: Not enough total bands to cover all the strict bands and quanta. "
320 "Ignoring [EnhancedTransmissionSelection] section from line %u.",
321 qdisc
->section
->filename
, qdisc
->section
->line
);
323 for (unsigned i
= 0; i
< ets
->n_prio
; i
++)
324 if (ets
->prio
[i
] >= ets
->n_bands
)
325 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
326 "%s: PriorityMap= element is out of bands. "
327 "Ignoring [EnhancedTransmissionSelection] section from line %u.",
328 qdisc
->section
->filename
, qdisc
->section
->line
);
333 const QDiscVTable ets_vtable
= {
334 .object_size
= sizeof(EnhancedTransmissionSelection
),
336 .fill_message
= enhanced_transmission_selection_fill_message
,
337 .verify
= enhanced_transmission_selection_verify
,