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