libnl  1.1.4
sfq.c
1 /*
2  * lib/route/sch/sfq.c SFQ Qdisc
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) 2003-2006 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup qdisc_api
14  * @defgroup sfq Stochastic Fairness Queueing (SFQ)
15  * @brief
16  *
17  * @par Parameter Description
18  * - \b Quantum: Number of bytes to send out per slot and round.
19  * - \b Perturbation: Timer period between changing the hash function.
20  * - \b Limit: Upper limit of queue in number of packets before SFQ starts
21  * dropping packets.
22  * - \b Divisor: Hash table divisor, i.e. size of hash table.
23  * @{
24  */
25 
26 #include <netlink-local.h>
27 #include <netlink-tc.h>
28 #include <netlink/netlink.h>
29 #include <netlink/utils.h>
30 #include <netlink/route/qdisc.h>
31 #include <netlink/route/qdisc-modules.h>
32 #include <netlink/route/sch/sfq.h>
33 
34 /** @cond SKIP */
35 #define SCH_SFQ_ATTR_QUANTUM 0x01
36 #define SCH_SFQ_ATTR_PERTURB 0x02
37 #define SCH_SFQ_ATTR_LIMIT 0x04
38 #define SCH_SFQ_ATTR_DIVISOR 0x08
39 #define SCH_SFQ_ATTR_FLOWS 0x10
40 /** @endcond */
41 
42 static inline struct rtnl_sfq *sfq_qdisc(struct rtnl_qdisc *qdisc)
43 {
44  return (struct rtnl_sfq *) qdisc->q_subdata;
45 }
46 
47 static inline struct rtnl_sfq *sfq_alloc(struct rtnl_qdisc *qdisc)
48 {
49  if (!qdisc->q_subdata)
50  qdisc->q_subdata = calloc(1, sizeof(struct rtnl_sfq));
51 
52  return sfq_qdisc(qdisc);
53 }
54 
55 static int sfq_msg_parser(struct rtnl_qdisc *qdisc)
56 {
57  struct rtnl_sfq *sfq;
58  struct tc_sfq_qopt *opts;
59 
60  if (!(qdisc->ce_mask & TCA_ATTR_OPTS))
61  return 0;
62 
63  if (qdisc->q_opts->d_size < sizeof(*opts))
64  return nl_error(EINVAL, "SFQ specific options size mismatch");
65 
66  sfq = sfq_alloc(qdisc);
67  if (!sfq)
68  return nl_errno(ENOMEM);
69 
70  opts = (struct tc_sfq_qopt *) qdisc->q_opts->d_data;
71 
72  sfq->qs_quantum = opts->quantum;
73  sfq->qs_perturb = opts->perturb_period;
74  sfq->qs_limit = opts->limit;
75  sfq->qs_divisor = opts->divisor;
76  sfq->qs_flows = opts->flows;
77 
78  sfq->qs_mask = (SCH_SFQ_ATTR_QUANTUM | SCH_SFQ_ATTR_PERTURB |
79  SCH_SFQ_ATTR_LIMIT | SCH_SFQ_ATTR_DIVISOR |
80  SCH_SFQ_ATTR_FLOWS);
81 
82  return 0;
83 }
84 
85 static void sfq_free_data(struct rtnl_qdisc *qdisc)
86 {
87  free(qdisc->q_subdata);
88 }
89 
90 static int sfq_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
91  int line)
92 {
93  struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
94 
95  if (sfq)
96  dp_dump(p, " quantum %u perturb %us",
97  sfq->qs_quantum,
98  nl_ticks2us(sfq->qs_perturb * nl_get_hz()));
99 
100  return line;
101 }
102 
103 static int sfq_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
104  int line)
105 {
106  struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
107 
108  if (sfq)
109  dp_dump(p, "limit %u divisor %u",
110  sfq->qs_limit, sfq->qs_divisor);
111 
112  return line;
113 }
114 
115 static struct nl_msg *sfq_get_opts(struct rtnl_qdisc *qdisc)
116 {
117  struct rtnl_sfq *sfq;
118  struct tc_sfq_qopt opts;
119  struct nl_msg *msg;
120 
121  sfq = sfq_qdisc(qdisc);
122  if (!sfq)
123  return NULL;
124 
125  msg = nlmsg_alloc();
126  if (!msg)
127  goto errout;
128 
129  memset(&opts, 0, sizeof(opts));
130  opts.quantum = sfq->qs_quantum;
131  opts.perturb_period = sfq->qs_perturb;
132  opts.limit = sfq->qs_limit;
133 
134  if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
135  goto errout;
136 
137  return msg;
138 errout:
139  nlmsg_free(msg);
140  return NULL;
141 }
142 
143 /**
144  * @name Attribute Access
145  * @{
146  */
147 
148 /**
149  * Set quantum of SFQ qdisc.
150  * @arg qdisc SFQ qdisc to be modified.
151  * @arg quantum New quantum in bytes.
152  * @return 0 on success or a negative error code.
153  */
154 int rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum)
155 {
156  struct rtnl_sfq *sfq;
157 
158  sfq = sfq_alloc(qdisc);
159  if (!sfq)
160  return nl_errno(ENOMEM);
161 
162  sfq->qs_quantum = quantum;
163  sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM;
164 
165  return 0;
166 }
167 
168 /**
169  * Get quantum of SFQ qdisc.
170  * @arg qdisc SFQ qdisc.
171  * @return Quantum in bytes or a negative error code.
172  */
173 int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc)
174 {
175  struct rtnl_sfq *sfq;
176 
177  sfq = sfq_qdisc(qdisc);
178  if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM)
179  return sfq->qs_quantum;
180  else
181  return nl_errno(ENOENT);
182 }
183 
184 /**
185  * Set limit of SFQ qdisc.
186  * @arg qdisc SFQ qdisc to be modified.
187  * @arg limit New limit in number of packets.
188  * @return 0 on success or a negative error code.
189  */
190 int rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit)
191 {
192  struct rtnl_sfq *sfq;
193 
194  sfq = sfq_alloc(qdisc);
195  if (!sfq)
196  return nl_errno(ENOMEM);
197 
198  sfq->qs_limit = limit;
199  sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT;
200 
201  return 0;
202 }
203 
204 /**
205  * Get limit of SFQ qdisc.
206  * @arg qdisc SFQ qdisc.
207  * @return Limit or a negative error code.
208  */
209 int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc)
210 {
211  struct rtnl_sfq *sfq;
212 
213  sfq = sfq_qdisc(qdisc);
214  if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_LIMIT)
215  return sfq->qs_limit;
216  else
217  return nl_errno(ENOENT);
218 }
219 
220 /**
221  * Set perturbation interval of SFQ qdisc.
222  * @arg qdisc SFQ qdisc to be modified.
223  * @arg perturb New perturbation interval in seconds.
224  * @note A value of 0 disables perturbation altogether.
225  * @return 0 on success or a negative error code.
226  */
227 int rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb)
228 {
229  struct rtnl_sfq *sfq;
230 
231  sfq = sfq_alloc(qdisc);
232  if (!sfq)
233  return nl_errno(ENOMEM);
234 
235  sfq->qs_perturb = perturb;
236  sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB;
237 
238  return 0;
239 }
240 
241 /**
242  * Get perturbation interval of SFQ qdisc.
243  * @arg qdisc SFQ qdisc.
244  * @return Perturbation interval in seconds or a negative error code.
245  */
246 int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc)
247 {
248  struct rtnl_sfq *sfq;
249 
250  sfq = sfq_qdisc(qdisc);
251  if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_PERTURB)
252  return sfq->qs_perturb;
253  else
254  return nl_errno(ENOENT);
255 }
256 
257 /**
258  * Get divisor of SFQ qdisc.
259  * @arg qdisc SFQ qdisc.
260  * @return Divisor in number of entries or a negative error code.
261  */
262 int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc)
263 {
264  struct rtnl_sfq *sfq;
265 
266  sfq = sfq_qdisc(qdisc);
267  if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR)
268  return sfq->qs_divisor;
269  else
270  return nl_errno(ENOENT);
271 }
272 
273 /** @} */
274 
275 static struct rtnl_qdisc_ops sfq_ops = {
276  .qo_kind = "sfq",
277  .qo_msg_parser = sfq_msg_parser,
278  .qo_free_data = sfq_free_data,
279  .qo_dump[NL_DUMP_BRIEF] = sfq_dump_brief,
280  .qo_dump[NL_DUMP_FULL] = sfq_dump_full,
281  .qo_get_opts = sfq_get_opts,
282 };
283 
284 static void __init sfq_init(void)
285 {
286  rtnl_qdisc_register(&sfq_ops);
287 }
288 
289 static void __exit sfq_exit(void)
290 {
291  rtnl_qdisc_unregister(&sfq_ops);
292 }
293 
294 /** @} */
Dump object in a brief one-liner.
Definition: types.h:22
char qo_kind[32]
Kind/Name of Qdisc.
Definition: qdisc-modules.h:30
int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc)
Get quantum of SFQ qdisc.
Definition: sfq.c:173
int rtnl_qdisc_unregister(struct rtnl_qdisc_ops *qops)
Unregister a qdisc module.
Definition: qdisc_api.c:61
struct nl_msg * nlmsg_alloc(void)
Allocate a new netlink message with the default maximum payload size.
Definition: msg.c:401
void nlmsg_free(struct nl_msg *n)
Free a netlink message.
Definition: msg.c:656
int rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit)
Set limit of SFQ qdisc.
Definition: sfq.c:190
int rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb)
Set perturbation interval of SFQ qdisc.
Definition: sfq.c:227
uint32_t nl_ticks2us(uint32_t ticks)
Convert ticks to micro seconds.
Definition: utils.c:450
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
Definition: msg.c:549
int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc)
Get divisor of SFQ qdisc.
Definition: sfq.c:262
int rtnl_qdisc_register(struct rtnl_qdisc_ops *qops)
Register a qdisc module.
Definition: qdisc_api.c:40
Dumping parameters.
Definition: types.h:36
int rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum)
Set quantum of SFQ qdisc.
Definition: sfq.c:154
int nl_get_hz(void)
Return the value of HZ.
Definition: utils.c:428
Dump all attributes but no statistics.
Definition: types.h:23
Qdisc Operations.
Definition: qdisc-modules.h:25
int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc)
Get perturbation interval of SFQ qdisc.
Definition: sfq.c:246
int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc)
Get limit of SFQ qdisc.
Definition: sfq.c:209