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