1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2013 Cong Wang <[email protected]>
4 */
5
6 /**
7 * @ingroup qdisc
8 * @defgroup qdisc_fq_codel Fair Queue CoDel
9 * @brief
10 *
11 * @{
12 */
13
14 #include "nl-default.h"
15
16 #include <netlink/netlink.h>
17 #include <netlink/route/qdisc.h>
18 #include <netlink/route/qdisc/fq_codel.h>
19 #include <netlink/utils.h>
20
21 #include "tc-api.h"
22
23 /** @cond SKIP */
24 struct rtnl_fq_codel {
25 int fq_limit;
26 uint32_t fq_target;
27 uint32_t fq_interval;
28 int fq_flows;
29 uint32_t fq_quantum;
30 int fq_ecn;
31 uint32_t fq_mask;
32 };
33
34 #define SCH_FQ_CODEL_ATTR_TARGET 0x1
35 #define SCH_FQ_CODEL_ATTR_LIMIT 0x2
36 #define SCH_FQ_CODEL_ATTR_INTERVAL 0x4
37 #define SCH_FQ_CODEL_ATTR_FLOWS 0x8
38 #define SCH_FQ_CODEL_ATTR_QUANTUM 0x10
39 #define SCH_FQ_CODEL_ATTR_ECN 0x20
40 /** @endcond */
41
42 static struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = {
43 [TCA_FQ_CODEL_TARGET] = { .type = NLA_U32 },
44 [TCA_FQ_CODEL_LIMIT] = { .type = NLA_U32 },
45 [TCA_FQ_CODEL_INTERVAL] = { .type = NLA_U32 },
46 [TCA_FQ_CODEL_ECN] = { .type = NLA_U32 },
47 [TCA_FQ_CODEL_FLOWS] = { .type = NLA_U32 },
48 [TCA_FQ_CODEL_QUANTUM] = { .type = NLA_U32 },
49 };
50
fq_codel_msg_parser(struct rtnl_tc * tc,void * data)51 static int fq_codel_msg_parser(struct rtnl_tc *tc, void *data)
52 {
53 struct rtnl_fq_codel *fq_codel = data;
54 struct nlattr *tb[TCA_FQ_CODEL_MAX + 1];
55 int err;
56
57 err = tca_parse(tb, TCA_FQ_CODEL_MAX, tc, fq_codel_policy);
58 if (err < 0)
59 return err;
60
61 if (tb[TCA_FQ_CODEL_TARGET]) {
62 fq_codel->fq_target = nla_get_u32(tb[TCA_FQ_CODEL_TARGET]);
63 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_TARGET;
64 }
65
66 if (tb[TCA_FQ_CODEL_INTERVAL]) {
67 fq_codel->fq_interval = nla_get_u32(tb[TCA_FQ_CODEL_INTERVAL]);
68 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_INTERVAL;
69 }
70
71 if (tb[TCA_FQ_CODEL_LIMIT]) {
72 fq_codel->fq_limit = nla_get_u32(tb[TCA_FQ_CODEL_LIMIT]);
73 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_LIMIT;
74 }
75
76 if (tb[TCA_FQ_CODEL_QUANTUM]) {
77 fq_codel->fq_quantum = nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM]);
78 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_QUANTUM;
79 }
80
81 if (tb[TCA_FQ_CODEL_FLOWS]) {
82 fq_codel->fq_flows = nla_get_u32(tb[TCA_FQ_CODEL_FLOWS]);
83 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_FLOWS;
84 }
85
86 if (tb[TCA_FQ_CODEL_ECN]) {
87 fq_codel->fq_ecn = nla_get_u32(tb[TCA_FQ_CODEL_ECN]);
88 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_ECN;
89 }
90
91 return 0;
92 }
93
fq_codel_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)94 static void fq_codel_dump_line(struct rtnl_tc *tc, void *data,
95 struct nl_dump_params *p)
96 {
97 struct rtnl_fq_codel *fq_codel = data;
98
99 if (!fq_codel)
100 return;
101
102 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_LIMIT)
103 nl_dump(p, " limit %u packets", fq_codel->fq_limit);
104 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_TARGET)
105 nl_dump(p, " target %u", fq_codel->fq_target);
106 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_INTERVAL)
107 nl_dump(p, " interval %u", fq_codel->fq_interval);
108 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_ECN)
109 nl_dump(p, " ecn %u", fq_codel->fq_ecn);
110 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_FLOWS)
111 nl_dump(p, " flows %u", fq_codel->fq_flows);
112 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_QUANTUM)
113 nl_dump(p, " quantum %u", fq_codel->fq_quantum);
114 }
115
fq_codel_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)116 static int fq_codel_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
117 {
118 struct rtnl_fq_codel *fq_codel = data;
119
120 if (!fq_codel)
121 return -NLE_INVAL;
122
123 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_LIMIT)
124 NLA_PUT_U32(msg, TCA_FQ_CODEL_LIMIT, fq_codel->fq_limit);
125 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_INTERVAL)
126 NLA_PUT_U32(msg, TCA_FQ_CODEL_INTERVAL, fq_codel->fq_interval);
127 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_TARGET)
128 NLA_PUT_U32(msg, TCA_FQ_CODEL_TARGET, fq_codel->fq_target);
129 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_QUANTUM)
130 NLA_PUT_U32(msg, TCA_FQ_CODEL_QUANTUM, fq_codel->fq_quantum);
131 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_FLOWS)
132 NLA_PUT_U32(msg, TCA_FQ_CODEL_FLOWS, fq_codel->fq_flows);
133 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_ECN)
134 NLA_PUT_U32(msg, TCA_FQ_CODEL_ECN, fq_codel->fq_ecn);
135 return 0;
136
137 nla_put_failure:
138 return -NLE_MSGSIZE;
139
140 }
141
142 /**
143 * @name Attribute Modification
144 * @{
145 */
146
147 /**
148 * Set limit of fq_codel qdisc.
149 * @arg qdisc fq_codel qdisc to be modified.
150 * @arg limit New limit.
151 * @return 0 on success or a negative error code.
152 */
rtnl_qdisc_fq_codel_set_limit(struct rtnl_qdisc * qdisc,int limit)153 int rtnl_qdisc_fq_codel_set_limit(struct rtnl_qdisc *qdisc, int limit)
154 {
155 struct rtnl_fq_codel *fq_codel;
156
157 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
158 return -NLE_NOMEM;
159
160 fq_codel->fq_limit = limit;
161 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_LIMIT;
162
163 return 0;
164 }
165
166 /**
167 * Get limit of a fq_codel qdisc.
168 * @arg qdisc fq_codel qdisc.
169 * @return Numeric limit or a negative error code.
170 */
rtnl_qdisc_fq_codel_get_limit(struct rtnl_qdisc * qdisc)171 int rtnl_qdisc_fq_codel_get_limit(struct rtnl_qdisc *qdisc)
172 {
173 struct rtnl_fq_codel *fq_codel;
174
175 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
176 return -NLE_NOMEM;
177
178 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_LIMIT)
179 return fq_codel->fq_limit;
180 else
181 return -NLE_NOATTR;
182 }
183
184 /**
185 * Set target of fq_codel qdisc.
186 * @arg qdisc fq_codel qdisc to be modified.
187 * @arg target New target.
188 * @return 0 on success or a negative error code.
189 */
rtnl_qdisc_fq_codel_set_target(struct rtnl_qdisc * qdisc,uint32_t target)190 int rtnl_qdisc_fq_codel_set_target(struct rtnl_qdisc *qdisc, uint32_t target)
191 {
192 struct rtnl_fq_codel *fq_codel;
193
194 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
195 return -NLE_NOMEM;
196
197 fq_codel->fq_target = target;
198 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_TARGET;
199
200 return 0;
201 }
202
203 /**
204 * Get target of a fq_codel qdisc.
205 * @arg qdisc fq_codel qdisc.
206 * @return Numeric target or zero.
207 */
rtnl_qdisc_fq_codel_get_target(struct rtnl_qdisc * qdisc)208 uint32_t rtnl_qdisc_fq_codel_get_target(struct rtnl_qdisc *qdisc)
209 {
210 struct rtnl_fq_codel *fq_codel;
211
212 if ((fq_codel = rtnl_tc_data(TC_CAST(qdisc))) &&
213 fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_TARGET)
214 return fq_codel->fq_target;
215 else
216 return 0;
217 }
218
219 /**
220 * Set interval of fq_codel qdisc.
221 * @arg qdisc fq_codel qdisc to be modified.
222 * @arg interval New interval.
223 * @return 0 on success or a negative error code.
224 */
rtnl_qdisc_fq_codel_set_interval(struct rtnl_qdisc * qdisc,uint32_t interval)225 int rtnl_qdisc_fq_codel_set_interval(struct rtnl_qdisc *qdisc, uint32_t interval)
226 {
227 struct rtnl_fq_codel *fq_codel;
228
229 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
230 return -NLE_NOMEM;
231
232 fq_codel->fq_interval = interval;
233 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_INTERVAL;
234
235 return 0;
236 }
237
238 /**
239 * Get target of a fq_codel qdisc.
240 * @arg qdisc fq_codel qdisc.
241 * @return Numeric interval or zero.
242 */
rtnl_qdisc_fq_codel_get_interval(struct rtnl_qdisc * qdisc)243 uint32_t rtnl_qdisc_fq_codel_get_interval(struct rtnl_qdisc *qdisc)
244 {
245 struct rtnl_fq_codel *fq_codel;
246
247 if ((fq_codel = rtnl_tc_data(TC_CAST(qdisc))) &&
248 fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_INTERVAL)
249 return fq_codel->fq_interval;
250 else
251 return 0;
252 }
253
254 /**
255 * Set quantum of fq_codel qdisc.
256 * @arg qdisc fq_codel qdisc to be modified.
257 * @arg quantum New quantum.
258 * @return 0 on success or a negative error code.
259 */
rtnl_qdisc_fq_codel_set_quantum(struct rtnl_qdisc * qdisc,uint32_t quantum)260 int rtnl_qdisc_fq_codel_set_quantum(struct rtnl_qdisc *qdisc, uint32_t quantum)
261 {
262 struct rtnl_fq_codel *fq_codel;
263
264 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
265 return -NLE_NOMEM;
266
267 fq_codel->fq_quantum = quantum;
268 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_QUANTUM;
269
270 return 0;
271 }
272
273 /**
274 * Get quantum of a fq_codel qdisc.
275 * @arg qdisc fq_codel qdisc.
276 * @return Numeric quantum or zero.
277 */
rtnl_qdisc_fq_codel_get_quantum(struct rtnl_qdisc * qdisc)278 uint32_t rtnl_qdisc_fq_codel_get_quantum(struct rtnl_qdisc *qdisc)
279 {
280 struct rtnl_fq_codel *fq_codel;
281
282 if ((fq_codel = rtnl_tc_data(TC_CAST(qdisc))) &&
283 (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_QUANTUM))
284 return fq_codel->fq_quantum;
285 else
286 return 0;
287 }
288
289 /**
290 * Set flows of fq_codel qdisc.
291 * @arg qdisc fq_codel qdisc to be modified.
292 * @arg flows New flows value.
293 * @return 0 on success or a negative error code.
294 */
rtnl_qdisc_fq_codel_set_flows(struct rtnl_qdisc * qdisc,int flows)295 int rtnl_qdisc_fq_codel_set_flows(struct rtnl_qdisc *qdisc, int flows)
296 {
297 struct rtnl_fq_codel *fq_codel;
298
299 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
300 return -NLE_NOMEM;
301
302 fq_codel->fq_flows = flows;
303 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_FLOWS;
304
305 return 0;
306 }
307
308 /**
309 * Get flows of a fq_codel qdisc.
310 * @arg qdisc fq_codel qdisc.
311 * @return Numeric flows or a negative error code.
312 */
rtnl_qdisc_fq_codel_get_flows(struct rtnl_qdisc * qdisc)313 int rtnl_qdisc_fq_codel_get_flows(struct rtnl_qdisc *qdisc)
314 {
315 struct rtnl_fq_codel *fq_codel;
316
317 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
318 return -NLE_NOMEM;
319
320 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_FLOWS)
321 return fq_codel->fq_flows;
322 else
323 return -NLE_NOATTR;
324 }
325 /**
326 * Set ecn of fq_codel qdisc.
327 * @arg qdisc fq_codel qdisc to be modified.
328 * @arg ecn New ecn value.
329 * @return 0 on success or a negative error code.
330 */
rtnl_qdisc_fq_codel_set_ecn(struct rtnl_qdisc * qdisc,int ecn)331 int rtnl_qdisc_fq_codel_set_ecn(struct rtnl_qdisc *qdisc, int ecn)
332 {
333 struct rtnl_fq_codel *fq_codel;
334
335 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
336 return -NLE_NOMEM;
337
338 fq_codel->fq_ecn = ecn;
339 fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_ECN;
340
341 return 0;
342 }
343
344 /**
345 * Get ecn of a fq_codel qdisc.
346 * @arg qdisc fq_codel qdisc.
347 * @return Numeric ecn or a negative error code.
348 */
rtnl_qdisc_fq_codel_get_ecn(struct rtnl_qdisc * qdisc)349 int rtnl_qdisc_fq_codel_get_ecn(struct rtnl_qdisc *qdisc)
350 {
351 struct rtnl_fq_codel *fq_codel;
352
353 if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
354 return -NLE_NOMEM;
355
356 if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_ECN)
357 return fq_codel->fq_ecn;
358 else
359 return -NLE_NOATTR;
360 }
361 /** @} */
362
363 static struct rtnl_tc_ops fq_codel_ops = {
364 .to_kind = "fq_codel",
365 .to_type = RTNL_TC_TYPE_QDISC,
366 .to_size = sizeof(struct rtnl_fq_codel),
367 .to_msg_parser = fq_codel_msg_parser,
368 .to_dump[NL_DUMP_LINE] = fq_codel_dump_line,
369 .to_msg_fill = fq_codel_msg_fill,
370 };
371
fq_codel_init(void)372 static void _nl_init fq_codel_init(void)
373 {
374 rtnl_tc_register(&fq_codel_ops);
375 }
376
fq_codel_exit(void)377 static void _nl_exit fq_codel_exit(void)
378 {
379 rtnl_tc_unregister(&fq_codel_ops);
380 }
381
382 /** @} */
383