]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/tc/fq-codel.c
update-utmp: do not fail on EROFS
[thirdparty/systemd.git] / src / network / tc / fq-codel.c
1 /* SPDX-License-Identifier: LGPL-2.1+
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 "netlink-util.h"
9 #include "parse-util.h"
10 #include "qdisc.h"
11 #include "string-util.h"
12
13 static int fair_queueing_controlled_delay_init(QDisc *qdisc) {
14 FairQueueingControlledDelay *fqcd;
15
16 assert(qdisc);
17
18 fqcd = FQ_CODEL(qdisc);
19
20 fqcd->memory_limit = UINT32_MAX;
21 fqcd->ce_threshold_usec = USEC_INFINITY;
22 fqcd->ecn = -1;
23
24 return 0;
25 }
26
27 static int fair_queueing_controlled_delay_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
28 FairQueueingControlledDelay *fqcd;
29 int r;
30
31 assert(link);
32 assert(qdisc);
33 assert(req);
34
35 fqcd = FQ_CODEL(qdisc);
36
37 r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "fq_codel");
38 if (r < 0)
39 return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
40
41 if (fqcd->packet_limit > 0) {
42 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_LIMIT, fqcd->packet_limit);
43 if (r < 0)
44 return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_LIMIT attribute: %m");
45 }
46
47 if (fqcd->flows > 0) {
48 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_FLOWS, fqcd->flows);
49 if (r < 0)
50 return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_FLOWS attribute: %m");
51 }
52
53 if (fqcd->quantum > 0) {
54 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_QUANTUM, fqcd->quantum);
55 if (r < 0)
56 return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_QUANTUM attribute: %m");
57 }
58
59 if (fqcd->interval_usec > 0) {
60 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_INTERVAL, fqcd->interval_usec);
61 if (r < 0)
62 return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_INTERVAL attribute: %m");
63 }
64
65 if (fqcd->target_usec > 0) {
66 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_TARGET, fqcd->target_usec);
67 if (r < 0)
68 return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_TARGET attribute: %m");
69 }
70
71 if (fqcd->ecn >= 0) {
72 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_ECN, fqcd->ecn);
73 if (r < 0)
74 return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_ECN attribute: %m");
75 }
76
77 if (fqcd->ce_threshold_usec != USEC_INFINITY) {
78 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_CE_THRESHOLD, fqcd->ce_threshold_usec);
79 if (r < 0)
80 return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_CE_THRESHOLD attribute: %m");
81 }
82
83 if (fqcd->memory_limit != UINT32_MAX) {
84 r = sd_netlink_message_append_u32(req, TCA_FQ_CODEL_MEMORY_LIMIT, fqcd->memory_limit);
85 if (r < 0)
86 return log_link_error_errno(link, r, "Could not append TCA_FQ_CODEL_MEMORY_LIMIT attribute: %m");
87 }
88
89 r = sd_netlink_message_close_container(req);
90 if (r < 0)
91 return log_link_error_errno(link, r, "Could not close container TCA_OPTIONS: %m");
92
93 return 0;
94 }
95
96 int config_parse_fair_queueing_controlled_delay_u32(
97 const char *unit,
98 const char *filename,
99 unsigned line,
100 const char *section,
101 unsigned section_line,
102 const char *lvalue,
103 int ltype,
104 const char *rvalue,
105 void *data,
106 void *userdata) {
107
108 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
109 FairQueueingControlledDelay *fqcd;
110 Network *network = data;
111 uint32_t *p;
112 int r;
113
114 assert(filename);
115 assert(lvalue);
116 assert(rvalue);
117 assert(data);
118
119 r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
120 if (r == -ENOMEM)
121 return log_oom();
122 if (r < 0)
123 return log_syntax(unit, LOG_ERR, filename, line, r,
124 "More than one kind of queueing discipline, ignoring assignment: %m");
125
126 fqcd = FQ_CODEL(qdisc);
127
128 if (streq(lvalue, "PacketLimit"))
129 p = &fqcd->packet_limit;
130 else if (streq(lvalue, "Flows"))
131 p = &fqcd->flows;
132 else
133 assert_not_reached("Invalid lvalue.");
134
135 if (isempty(rvalue)) {
136 *p = 0;
137
138 qdisc = NULL;
139 return 0;
140 }
141
142 r = safe_atou32(rvalue, p);
143 if (r < 0) {
144 log_syntax(unit, LOG_ERR, filename, line, r,
145 "Failed to parse '%s=', ignoring assignment: %s",
146 lvalue, rvalue);
147 return 0;
148 }
149
150 qdisc = NULL;
151
152 return 0;
153 }
154
155 int config_parse_fair_queueing_controlled_delay_usec(
156 const char *unit,
157 const char *filename,
158 unsigned line,
159 const char *section,
160 unsigned section_line,
161 const char *lvalue,
162 int ltype,
163 const char *rvalue,
164 void *data,
165 void *userdata) {
166
167 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
168 FairQueueingControlledDelay *fqcd;
169 Network *network = data;
170 usec_t *p;
171 int r;
172
173 assert(filename);
174 assert(lvalue);
175 assert(rvalue);
176 assert(data);
177
178 r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
179 if (r == -ENOMEM)
180 return log_oom();
181 if (r < 0)
182 return log_syntax(unit, LOG_ERR, filename, line, r,
183 "More than one kind of queueing discipline, ignoring assignment: %m");
184
185 fqcd = FQ_CODEL(qdisc);
186
187 if (streq(lvalue, "TargetSec"))
188 p = &fqcd->target_usec;
189 else if (streq(lvalue, "IntervalSec"))
190 p = &fqcd->interval_usec;
191 else if (streq(lvalue, "CEThresholdSec"))
192 p = &fqcd->ce_threshold_usec;
193 else
194 assert_not_reached("Invalid lvalue.");
195
196 if (isempty(rvalue)) {
197 if (streq(lvalue, "CEThresholdSec"))
198 *p = USEC_INFINITY;
199 else
200 *p = 0;
201
202 qdisc = NULL;
203 return 0;
204 }
205
206 r = parse_sec(rvalue, p);
207 if (r < 0) {
208 log_syntax(unit, LOG_ERR, filename, line, r,
209 "Failed to parse '%s=', ignoring assignment: %s",
210 lvalue, rvalue);
211 return 0;
212 }
213
214 qdisc = NULL;
215
216 return 0;
217 }
218
219 int config_parse_fair_queueing_controlled_delay_bool(
220 const char *unit,
221 const char *filename,
222 unsigned line,
223 const char *section,
224 unsigned section_line,
225 const char *lvalue,
226 int ltype,
227 const char *rvalue,
228 void *data,
229 void *userdata) {
230
231 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
232 FairQueueingControlledDelay *fqcd;
233 Network *network = data;
234 int r;
235
236 assert(filename);
237 assert(lvalue);
238 assert(rvalue);
239 assert(data);
240
241 r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
242 if (r == -ENOMEM)
243 return log_oom();
244 if (r < 0)
245 return log_syntax(unit, LOG_ERR, filename, line, r,
246 "More than one kind of queueing discipline, ignoring assignment: %m");
247
248 fqcd = FQ_CODEL(qdisc);
249
250 if (isempty(rvalue)) {
251 fqcd->ecn = -1;
252
253 qdisc = NULL;
254 return 0;
255 }
256
257 r = parse_boolean(rvalue);
258 if (r < 0) {
259 log_syntax(unit, LOG_ERR, filename, line, r,
260 "Failed to parse '%s=', ignoring assignment: %s",
261 lvalue, rvalue);
262 return 0;
263 }
264
265 fqcd->ecn = r;
266 qdisc = NULL;
267
268 return 0;
269 }
270
271 int config_parse_fair_queueing_controlled_delay_size(
272 const char *unit,
273 const char *filename,
274 unsigned line,
275 const char *section,
276 unsigned section_line,
277 const char *lvalue,
278 int ltype,
279 const char *rvalue,
280 void *data,
281 void *userdata) {
282
283 _cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
284 FairQueueingControlledDelay *fqcd;
285 Network *network = data;
286 uint64_t sz;
287 uint32_t *p;
288 int r;
289
290 assert(filename);
291 assert(lvalue);
292 assert(rvalue);
293 assert(data);
294
295 r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
296 if (r == -ENOMEM)
297 return log_oom();
298 if (r < 0)
299 return log_syntax(unit, LOG_ERR, filename, line, r,
300 "More than one kind of queueing discipline, ignoring assignment: %m");
301
302 fqcd = FQ_CODEL(qdisc);
303
304 if (streq(lvalue, "MemoryLimit"))
305 p = &fqcd->memory_limit;
306 else if (streq(lvalue, "Quantum"))
307 p = &fqcd->quantum;
308 else
309 assert_not_reached("Invalid lvalue.");
310
311 if (isempty(rvalue)) {
312 if (streq(lvalue, "MemoryLimit"))
313 *p = UINT32_MAX;
314 else
315 *p = 0;
316
317 qdisc = NULL;
318 return 0;
319 }
320
321 r = parse_size(rvalue, 1024, &sz);
322 if (r < 0) {
323 log_syntax(unit, LOG_ERR, filename, line, r,
324 "Failed to parse '%s=', ignoring assignment: %s",
325 lvalue, rvalue);
326 return 0;
327 }
328 if (sz >= UINT32_MAX) {
329 log_syntax(unit, LOG_ERR, filename, line, r,
330 "Specified '%s=' is too large, ignoring assignment: %s",
331 lvalue, rvalue);
332 return 0;
333 }
334
335 *p = sz;
336 qdisc = NULL;
337
338 return 0;
339 }
340
341 const QDiscVTable fq_codel_vtable = {
342 .object_size = sizeof(FairQueueingControlledDelay),
343 .tca_kind = "fq_codel",
344 .init = fair_queueing_controlled_delay_init,
345 .fill_message = fair_queueing_controlled_delay_fill_message,
346 };