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