xref: /aosp_15_r20/external/libnl/lib/route/qdisc/fq_codel.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
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