]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/tc/fq.c
Update version and finalize NEWS for 256~rc4
[thirdparty/systemd.git] / src / network / tc / fq.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later
2 * Copyright © 2019 VMware, Inc. */
3
4 #include <linux/pkt_sched.h>
5
6 #include "alloc-util.h"
7 #include "conf-parser.h"
8 #include "fq.h"
9 #include "logarithm.h"
10 #include "netlink-util.h"
11 #include "parse-util.h"
12 #include "string-util.h"
13 #include "strv.h"
14
15 static int fair_queueing_init(QDisc *qdisc) {
16 FairQueueing *fq;
17
18 assert(qdisc);
19
20 fq = FQ(qdisc);
21
22 fq->pacing = -1;
23 fq->ce_threshold_usec = USEC_INFINITY;
24
25 return 0;
26 }
27
28 static int fair_queueing_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
29 FairQueueing *fq;
30 int r;
31
32 assert(link);
33 assert(qdisc);
34 assert(req);
35
36 assert_se(fq = FQ(qdisc));
37
38 r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "fq");
39 if (r < 0)
40 return r;
41
42 if (fq->packet_limit > 0) {
43 r = sd_netlink_message_append_u32(req, TCA_FQ_PLIMIT, fq->packet_limit);
44 if (r < 0)
45 return r;
46 }
47
48 if (fq->flow_limit > 0) {
49 r = sd_netlink_message_append_u32(req, TCA_FQ_FLOW_PLIMIT, fq->flow_limit);
50 if (r < 0)
51 return r;
52 }
53
54 if (fq->quantum > 0) {
55 r = sd_netlink_message_append_u32(req, TCA_FQ_QUANTUM, fq->quantum);
56 if (r < 0)
57 return r;
58 }
59
60 if (fq->initial_quantum > 0) {
61 r = sd_netlink_message_append_u32(req, TCA_FQ_INITIAL_QUANTUM, fq->initial_quantum);
62 if (r < 0)
63 return r;
64 }
65
66 if (fq->pacing >= 0) {
67 r = sd_netlink_message_append_u32(req, TCA_FQ_RATE_ENABLE, fq->pacing);
68 if (r < 0)
69 return r;
70 }
71
72 if (fq->max_rate > 0) {
73 r = sd_netlink_message_append_u32(req, TCA_FQ_FLOW_MAX_RATE, fq->max_rate);
74 if (r < 0)
75 return r;
76 }
77
78 if (fq->buckets > 0) {
79 uint32_t l;
80
81 l = log2u(fq->buckets);
82 r = sd_netlink_message_append_u32(req, TCA_FQ_BUCKETS_LOG, l);
83 if (r < 0)
84 return r;
85 }
86
87 if (fq->orphan_mask > 0) {
88 r = sd_netlink_message_append_u32(req, TCA_FQ_ORPHAN_MASK, fq->orphan_mask);
89 if (r < 0)
90 return r;
91 }
92
93 if (fq->ce_threshold_usec != USEC_INFINITY) {
94 r = sd_netlink_message_append_u32(req, TCA_FQ_CE_THRESHOLD, fq->ce_threshold_usec);
95 if (r < 0)
96 return r;
97 }
98
99 r = sd_netlink_message_close_container(req);
100 if (r < 0)
101 return r;
102
103 return 0;
104 }
105
106 int config_parse_fair_queueing_u32(
107 const char *unit,
108 const char *filename,
109 unsigned line,
110 const char *section,
111 unsigned section_line,
112 const char *lvalue,
113 int ltype,
114 const char *rvalue,
115 void *data,
116 void *userdata) {
117
118 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
119 FairQueueing *fq;
120 Network *network = ASSERT_PTR(data);
121 uint32_t *p;
122 int r;
123
124 assert(filename);
125 assert(lvalue);
126 assert(rvalue);
127
128 r = qdisc_new_static(QDISC_KIND_FQ, network, filename, section_line, &qdisc);
129 if (r == -ENOMEM)
130 return log_oom();
131 if (r < 0) {
132 log_syntax(unit, LOG_WARNING, filename, line, r,
133 "More than one kind of queueing discipline, ignoring assignment: %m");
134 return 0;
135 }
136
137 fq = FQ(qdisc);
138
139 if (streq(lvalue, "PacketLimit"))
140 p = &fq->packet_limit;
141 else if (streq(lvalue, "FlowLimit"))
142 p = &fq->flow_limit;
143 else if (streq(lvalue, "Buckets"))
144 p = &fq->buckets;
145 else if (streq(lvalue, "OrphanMask"))
146 p = &fq->orphan_mask;
147 else
148 assert_not_reached();
149
150 if (isempty(rvalue)) {
151 *p = 0;
152
153 qdisc = NULL;
154 return 0;
155 }
156
157 r = safe_atou32(rvalue, p);
158 if (r < 0) {
159 log_syntax(unit, LOG_WARNING, filename, line, r,
160 "Failed to parse '%s=', ignoring assignment: %s",
161 lvalue, rvalue);
162 return 0;
163 }
164
165 qdisc = NULL;
166
167 return 0;
168 }
169
170 int config_parse_fair_queueing_size(
171 const char *unit,
172 const char *filename,
173 unsigned line,
174 const char *section,
175 unsigned section_line,
176 const char *lvalue,
177 int ltype,
178 const char *rvalue,
179 void *data,
180 void *userdata) {
181
182 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
183 FairQueueing *fq;
184 Network *network = ASSERT_PTR(data);
185 uint64_t sz;
186 uint32_t *p;
187 int r;
188
189 assert(filename);
190 assert(lvalue);
191 assert(rvalue);
192
193 r = qdisc_new_static(QDISC_KIND_FQ, network, filename, section_line, &qdisc);
194 if (r == -ENOMEM)
195 return log_oom();
196 if (r < 0) {
197 log_syntax(unit, LOG_WARNING, filename, line, r,
198 "More than one kind of queueing discipline, ignoring assignment: %m");
199 return 0;
200 }
201
202 fq = FQ(qdisc);
203
204 if (STR_IN_SET(lvalue, "QuantumBytes", "Quantum"))
205 p = &fq->quantum;
206 else if (STR_IN_SET(lvalue, "InitialQuantumBytes", "InitialQuantum"))
207 p = &fq->initial_quantum;
208 else
209 assert_not_reached();
210
211 if (isempty(rvalue)) {
212 *p = 0;
213
214 qdisc = NULL;
215 return 0;
216 }
217
218 r = parse_size(rvalue, 1024, &sz);
219 if (r < 0) {
220 log_syntax(unit, LOG_WARNING, filename, line, r,
221 "Failed to parse '%s=', ignoring assignment: %s",
222 lvalue, rvalue);
223 return 0;
224 }
225 if (sz > UINT32_MAX) {
226 log_syntax(unit, LOG_WARNING, filename, line, 0,
227 "Specified '%s=' is too large, ignoring assignment: %s",
228 lvalue, rvalue);
229 return 0;
230 }
231
232 *p = sz;
233 qdisc = NULL;
234
235 return 0;
236 }
237
238 int config_parse_fair_queueing_bool(
239 const char *unit,
240 const char *filename,
241 unsigned line,
242 const char *section,
243 unsigned section_line,
244 const char *lvalue,
245 int ltype,
246 const char *rvalue,
247 void *data,
248 void *userdata) {
249
250 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
251 FairQueueing *fq;
252 Network *network = ASSERT_PTR(data);
253 int r;
254
255 assert(filename);
256 assert(lvalue);
257 assert(rvalue);
258
259 r = qdisc_new_static(QDISC_KIND_FQ, network, filename, section_line, &qdisc);
260 if (r == -ENOMEM)
261 return log_oom();
262 if (r < 0) {
263 log_syntax(unit, LOG_WARNING, filename, line, r,
264 "More than one kind of queueing discipline, ignoring assignment: %m");
265 return 0;
266 }
267
268 fq = FQ(qdisc);
269
270 r = parse_tristate(rvalue, &fq->pacing);
271 if (r < 0) {
272 log_syntax(unit, LOG_WARNING, filename, line, r,
273 "Failed to parse '%s=', ignoring assignment: %s",
274 lvalue, rvalue);
275 return 0;
276 }
277
278 fq->pacing = r;
279 TAKE_PTR(qdisc);
280
281 return 0;
282 }
283
284 int config_parse_fair_queueing_usec(
285 const char *unit,
286 const char *filename,
287 unsigned line,
288 const char *section,
289 unsigned section_line,
290 const char *lvalue,
291 int ltype,
292 const char *rvalue,
293 void *data,
294 void *userdata) {
295
296 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
297 FairQueueing *fq;
298 Network *network = ASSERT_PTR(data);
299 usec_t sec;
300 int r;
301
302 assert(filename);
303 assert(lvalue);
304 assert(rvalue);
305
306 r = qdisc_new_static(QDISC_KIND_FQ, network, filename, section_line, &qdisc);
307 if (r == -ENOMEM)
308 return log_oom();
309 if (r < 0) {
310 log_syntax(unit, LOG_WARNING, filename, line, r,
311 "More than one kind of queueing discipline, ignoring assignment: %m");
312 return 0;
313 }
314
315 fq = FQ(qdisc);
316
317 if (isempty(rvalue)) {
318 fq->ce_threshold_usec = USEC_INFINITY;
319
320 qdisc = NULL;
321 return 0;
322 }
323
324 r = parse_sec(rvalue, &sec);
325 if (r < 0) {
326 log_syntax(unit, LOG_WARNING, filename, line, r,
327 "Failed to parse '%s=', ignoring assignment: %s",
328 lvalue, rvalue);
329 return 0;
330 }
331 if (sec > UINT32_MAX) {
332 log_syntax(unit, LOG_WARNING, filename, line, 0,
333 "Specified '%s=' is too large, ignoring assignment: %s",
334 lvalue, rvalue);
335 return 0;
336 }
337
338 fq->ce_threshold_usec = sec;
339 qdisc = NULL;
340
341 return 0;
342 }
343
344 int config_parse_fair_queueing_max_rate(
345 const char *unit,
346 const char *filename,
347 unsigned line,
348 const char *section,
349 unsigned section_line,
350 const char *lvalue,
351 int ltype,
352 const char *rvalue,
353 void *data,
354 void *userdata) {
355
356 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
357 FairQueueing *fq;
358 Network *network = ASSERT_PTR(data);
359 uint64_t sz;
360 int r;
361
362 assert(filename);
363 assert(lvalue);
364 assert(rvalue);
365
366 r = qdisc_new_static(QDISC_KIND_FQ, network, filename, section_line, &qdisc);
367 if (r == -ENOMEM)
368 return log_oom();
369 if (r < 0) {
370 log_syntax(unit, LOG_WARNING, filename, line, r,
371 "More than one kind of queueing discipline, ignoring assignment: %m");
372 return 0;
373 }
374
375 fq = FQ(qdisc);
376
377 if (isempty(rvalue)) {
378 fq->max_rate = 0;
379
380 qdisc = NULL;
381 return 0;
382 }
383
384 r = parse_size(rvalue, 1000, &sz);
385 if (r < 0) {
386 log_syntax(unit, LOG_WARNING, filename, line, r,
387 "Failed to parse '%s=', ignoring assignment: %s",
388 lvalue, rvalue);
389 return 0;
390 }
391 if (sz / 8 > UINT32_MAX) {
392 log_syntax(unit, LOG_WARNING, filename, line, 0,
393 "Specified '%s=' is too large, ignoring assignment: %s",
394 lvalue, rvalue);
395 return 0;
396 }
397
398 fq->max_rate = sz / 8;
399 qdisc = NULL;
400
401 return 0;
402 }
403
404 const QDiscVTable fq_vtable = {
405 .init = fair_queueing_init,
406 .object_size = sizeof(FairQueueing),
407 .tca_kind = "fq",
408 .fill_message = fair_queueing_fill_message,
409 };