]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/tc/ets.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / network / tc / ets.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
d474aa51
YW
2
3#include <linux/pkt_sched.h>
4
5#include "alloc-util.h"
6#include "conf-parser.h"
7#include "ets.h"
3a67b8bb 8#include "extract-word.h"
d474aa51
YW
9#include "memory-util.h"
10#include "netlink-util.h"
11#include "parse-util.h"
12#include "qdisc.h"
13#include "string-util.h"
14#include "tc-util.h"
15
16static int enhanced_transmission_selection_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
17 EnhancedTransmissionSelection *ets;
18 int r;
19
20 assert(link);
21 assert(qdisc);
22 assert(req);
23
16924f54 24 assert_se(ets = ETS(qdisc));
d474aa51
YW
25
26 r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "ets");
27 if (r < 0)
16924f54 28 return r;
d474aa51
YW
29
30 r = sd_netlink_message_append_u8(req, TCA_ETS_NBANDS, ets->n_bands);
31 if (r < 0)
16924f54 32 return r;
d474aa51
YW
33
34 if (ets->n_strict > 0) {
35 r = sd_netlink_message_append_u8(req, TCA_ETS_NSTRICT, ets->n_strict);
36 if (r < 0)
16924f54 37 return r;
d474aa51
YW
38 }
39
40 if (ets->n_quanta > 0) {
41 r = sd_netlink_message_open_container(req, TCA_ETS_QUANTA);
42 if (r < 0)
16924f54 43 return r;
d474aa51
YW
44
45 for (unsigned i = 0; i < ets->n_quanta; i++) {
46 r = sd_netlink_message_append_u32(req, TCA_ETS_QUANTA_BAND, ets->quanta[i]);
47 if (r < 0)
16924f54 48 return r;
d474aa51
YW
49 }
50
51 r = sd_netlink_message_close_container(req);
52 if (r < 0)
16924f54 53 return r;
d474aa51
YW
54 }
55
56 if (ets->n_prio > 0) {
57 r = sd_netlink_message_open_container(req, TCA_ETS_PRIOMAP);
58 if (r < 0)
16924f54 59 return r;
d474aa51
YW
60
61 for (unsigned i = 0; i < ets->n_prio; i++) {
62 r = sd_netlink_message_append_u8(req, TCA_ETS_PRIOMAP_BAND, ets->prio[i]);
63 if (r < 0)
16924f54 64 return r;
d474aa51
YW
65 }
66
67 r = sd_netlink_message_close_container(req);
68 if (r < 0)
16924f54 69 return r;
d474aa51
YW
70 }
71
72 r = sd_netlink_message_close_container(req);
73 if (r < 0)
16924f54 74 return r;
d474aa51
YW
75
76 return 0;
77}
78
79int config_parse_ets_u8(
80 const char *unit,
81 const char *filename,
82 unsigned line,
83 const char *section,
84 unsigned section_line,
85 const char *lvalue,
86 int ltype,
87 const char *rvalue,
88 void *data,
89 void *userdata) {
90
91 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
92 EnhancedTransmissionSelection *ets;
99534007 93 Network *network = ASSERT_PTR(data);
d474aa51
YW
94 uint8_t v, *p;
95 int r;
96
97 assert(filename);
98 assert(lvalue);
99 assert(rvalue);
d474aa51
YW
100
101 r = qdisc_new_static(QDISC_KIND_ETS, network, filename, section_line, &qdisc);
102 if (r == -ENOMEM)
103 return log_oom();
d96edb2c
YW
104 if (r < 0) {
105 log_syntax(unit, LOG_WARNING, filename, line, r,
106 "More than one kind of queueing discipline, ignoring assignment: %m");
107 return 0;
108 }
d474aa51
YW
109
110 ets = ETS(qdisc);
111 if (streq(lvalue, "Bands"))
112 p = &ets->n_bands;
113 else if (streq(lvalue, "StrictBands"))
114 p = &ets->n_strict;
115 else
04499a70 116 assert_not_reached();
d474aa51
YW
117
118 if (isempty(rvalue)) {
119 *p = 0;
120
121 qdisc = NULL;
122 return 0;
123 }
124
125 r = safe_atou8(rvalue, &v);
126 if (r < 0) {
d96edb2c 127 log_syntax(unit, LOG_WARNING, filename, line, r,
d474aa51
YW
128 "Failed to parse '%s=', ignoring assignment: %s",
129 lvalue, rvalue);
130 return 0;
131 }
132 if (v > TCQ_ETS_MAX_BANDS) {
d96edb2c 133 log_syntax(unit, LOG_WARNING, filename, line, 0,
d474aa51
YW
134 "Invalid '%s='. The value must be <= %d, ignoring assignment: %s",
135 lvalue, TCQ_ETS_MAX_BANDS, rvalue);
136 return 0;
137 }
138
139 *p = v;
140 qdisc = NULL;
141
142 return 0;
143}
144
145int config_parse_ets_quanta(
146 const char *unit,
147 const char *filename,
148 unsigned line,
149 const char *section,
150 unsigned section_line,
151 const char *lvalue,
152 int ltype,
153 const char *rvalue,
154 void *data,
155 void *userdata) {
156
157 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
158 EnhancedTransmissionSelection *ets;
99534007 159 Network *network = ASSERT_PTR(data);
d474aa51
YW
160 int r;
161
162 assert(filename);
163 assert(lvalue);
164 assert(rvalue);
d474aa51
YW
165
166 r = qdisc_new_static(QDISC_KIND_ETS, network, filename, section_line, &qdisc);
167 if (r == -ENOMEM)
168 return log_oom();
d96edb2c
YW
169 if (r < 0) {
170 log_syntax(unit, LOG_WARNING, filename, line, r,
171 "More than one kind of queueing discipline, ignoring assignment: %m");
172 return 0;
173 }
d474aa51
YW
174
175 ets = ETS(qdisc);
176
177 if (isempty(rvalue)) {
178 memzero(ets->quanta, sizeof(uint32_t) * TCQ_ETS_MAX_BANDS);
179 ets->n_quanta = 0;
180
181 qdisc = NULL;
182 return 0;
183 }
184
185 for (const char *p = rvalue;;) {
186 _cleanup_free_ char *word = NULL;
187 uint64_t v;
188
189 r = extract_first_word(&p, &word, NULL, 0);
190 if (r == -ENOMEM)
191 return log_oom();
192 if (r < 0) {
d96edb2c 193 log_syntax(unit, LOG_WARNING, filename, line, r,
d474aa51 194 "Failed to extract next value, ignoring: %m");
d96edb2c 195 break;
d474aa51
YW
196 }
197 if (r == 0)
198 break;
199
200 r = parse_size(word, 1024, &v);
201 if (r < 0) {
d96edb2c 202 log_syntax(unit, LOG_WARNING, filename, line, r,
d474aa51
YW
203 "Failed to parse '%s=', ignoring assignment: %s",
204 lvalue, word);
205 continue;
206 }
207 if (v == 0 || v > UINT32_MAX) {
d96edb2c 208 log_syntax(unit, LOG_WARNING, filename, line, 0,
d474aa51
YW
209 "Invalid '%s=', ignoring assignment: %s",
210 lvalue, word);
211 continue;
212 }
213 if (ets->n_quanta >= TCQ_ETS_MAX_BANDS) {
d96edb2c 214 log_syntax(unit, LOG_WARNING, filename, line, 0,
d474aa51
YW
215 "Too many quanta in '%s=', ignoring assignment: %s",
216 lvalue, word);
217 continue;
218 }
219
220 ets->quanta[ets->n_quanta++] = v;
221 }
222
223 qdisc = NULL;
224
225 return 0;
226}
227
228int config_parse_ets_prio(
229 const char *unit,
230 const char *filename,
231 unsigned line,
232 const char *section,
233 unsigned section_line,
234 const char *lvalue,
235 int ltype,
236 const char *rvalue,
237 void *data,
238 void *userdata) {
239
240 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
241 EnhancedTransmissionSelection *ets;
99534007 242 Network *network = ASSERT_PTR(data);
d474aa51
YW
243 int r;
244
245 assert(filename);
246 assert(lvalue);
247 assert(rvalue);
d474aa51
YW
248
249 r = qdisc_new_static(QDISC_KIND_ETS, network, filename, section_line, &qdisc);
250 if (r == -ENOMEM)
251 return log_oom();
d96edb2c
YW
252 if (r < 0) {
253 log_syntax(unit, LOG_WARNING, filename, line, r,
254 "More than one kind of queueing discipline, ignoring assignment: %m");
255 return 0;
256 }
d474aa51
YW
257
258 ets = ETS(qdisc);
259
260 if (isempty(rvalue)) {
261 memzero(ets->prio, sizeof(uint8_t) * (TC_PRIO_MAX + 1));
262 ets->n_prio = 0;
263
264 qdisc = NULL;
265 return 0;
266 }
267
268 for (const char *p = rvalue;;) {
269 _cleanup_free_ char *word = NULL;
270 uint8_t v;
271
272 r = extract_first_word(&p, &word, NULL, 0);
273 if (r == -ENOMEM)
274 return log_oom();
275 if (r < 0) {
d96edb2c 276 log_syntax(unit, LOG_WARNING, filename, line, r,
d474aa51 277 "Failed to extract next value, ignoring: %m");
d96edb2c 278 break;
d474aa51
YW
279 }
280 if (r == 0)
281 break;
282
283 r = safe_atou8(word, &v);
284 if (r < 0) {
d96edb2c 285 log_syntax(unit, LOG_WARNING, filename, line, r,
d474aa51
YW
286 "Failed to parse '%s=', ignoring assignment: %s",
287 lvalue, word);
288 continue;
289 }
e26538dd 290 if (ets->n_prio > TC_PRIO_MAX) {
d96edb2c 291 log_syntax(unit, LOG_WARNING, filename, line, 0,
d474aa51
YW
292 "Too many priomap in '%s=', ignoring assignment: %s",
293 lvalue, word);
294 continue;
295 }
296
297 ets->prio[ets->n_prio++] = v;
298 }
299
300 qdisc = NULL;
301
302 return 0;
303}
304
305static int enhanced_transmission_selection_verify(QDisc *qdisc) {
306 EnhancedTransmissionSelection *ets;
307
308 assert(qdisc);
309
310 ets = ETS(qdisc);
311
312 if (ets->n_bands == 0)
313 ets->n_bands = ets->n_strict + ets->n_quanta;
314
315 if (ets->n_bands == 0)
316 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
317 "%s: At least one of Band=, Strict=, or Quanta= must be specified. "
318 "Ignoring [EnhancedTransmissionSelection] section from line %u.",
319 qdisc->section->filename, qdisc->section->line);
320
321 if (ets->n_bands < ets->n_strict + ets->n_quanta)
322 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
323 "%s: Not enough total bands to cover all the strict bands and quanta. "
324 "Ignoring [EnhancedTransmissionSelection] section from line %u.",
325 qdisc->section->filename, qdisc->section->line);
326
327 for (unsigned i = 0; i < ets->n_prio; i++)
328 if (ets->prio[i] >= ets->n_bands)
329 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
330 "%s: PriorityMap= element is out of bands. "
331 "Ignoring [EnhancedTransmissionSelection] section from line %u.",
332 qdisc->section->filename, qdisc->section->line);
333
334 return 0;
335}
336
337const QDiscVTable ets_vtable = {
338 .object_size = sizeof(EnhancedTransmissionSelection),
339 .tca_kind = "ets",
340 .fill_message = enhanced_transmission_selection_fill_message,
341 .verify = enhanced_transmission_selection_verify,
342};