libnl  3.2.24-rc1
fq_codel.c
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 
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 
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
367 static void __init fq_codel_init(void)
368 {
369  rtnl_tc_register(&fq_codel_ops);
370 }
371 
372 static void __exit fq_codel_exit(void)
373 {
374  rtnl_tc_unregister(&fq_codel_ops);
375 }
376 
377 /** @} */