Tizen 2.1 base
[platform/upstream/libnl2.git] / lib / route / sch / 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-2008 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 -NLE_INVAL;
65
66         sfq = sfq_alloc(qdisc);
67         if (!sfq)
68                 return -NLE_NOMEM;
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 void sfq_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
91 {
92         struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
93
94         if (sfq)
95                 nl_dump(p, " quantum %u perturb %us", sfq->qs_quantum,
96                         nl_ticks2us(sfq->qs_perturb * nl_get_hz()));
97 }
98
99 static void sfq_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
100 {
101         struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
102
103         if (sfq)
104                 nl_dump(p, "limit %u divisor %u",
105                         sfq->qs_limit, sfq->qs_divisor);
106 }
107
108 static struct nl_msg *sfq_get_opts(struct rtnl_qdisc *qdisc)
109 {
110         struct rtnl_sfq *sfq;
111         struct tc_sfq_qopt opts;
112         struct nl_msg *msg;
113
114         sfq = sfq_qdisc(qdisc);
115         if (!sfq)
116                 return NULL;
117
118         msg = nlmsg_alloc();
119         if (!msg)
120                 goto errout;
121
122         memset(&opts, 0, sizeof(opts));
123         opts.quantum = sfq->qs_quantum;
124         opts.perturb_period = sfq->qs_perturb;
125         opts.limit = sfq->qs_limit;
126
127         if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
128                 goto errout;
129
130         return msg;
131 errout:
132         nlmsg_free(msg);
133         return NULL;
134 }
135
136 /**
137  * @name Attribute Access
138  * @{
139  */
140
141 /**
142  * Set quantum of SFQ qdisc.
143  * @arg qdisc           SFQ qdisc to be modified.
144  * @arg quantum         New quantum in bytes.
145  * @return 0 on success or a negative error code.
146  */
147 int rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum)
148 {
149         struct rtnl_sfq *sfq;
150         
151         sfq = sfq_alloc(qdisc);
152         if (!sfq)
153                 return -NLE_NOMEM;
154
155         sfq->qs_quantum = quantum;
156         sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM;
157
158         return 0;
159 }
160
161 /**
162  * Get quantum of SFQ qdisc.
163  * @arg qdisc           SFQ qdisc.
164  * @return Quantum in bytes or a negative error code.
165  */
166 int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc)
167 {
168         struct rtnl_sfq *sfq;
169
170         sfq = sfq_qdisc(qdisc);
171         if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM)
172                 return sfq->qs_quantum;
173         else
174                 return -NLE_NOATTR;
175 }
176
177 /**
178  * Set limit of SFQ qdisc.
179  * @arg qdisc           SFQ qdisc to be modified.
180  * @arg limit           New limit in number of packets.
181  * @return 0 on success or a negative error code.
182  */
183 int rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit)
184 {
185         struct rtnl_sfq *sfq;
186
187         sfq = sfq_alloc(qdisc);
188         if (!sfq)
189                 return -NLE_NOMEM;
190
191         sfq->qs_limit = limit;
192         sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT;
193
194         return 0;
195 }
196
197 /**
198  * Get limit of SFQ qdisc.
199  * @arg qdisc           SFQ qdisc.
200  * @return Limit or a negative error code.
201  */
202 int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc)
203 {
204         struct rtnl_sfq *sfq;
205
206         sfq = sfq_qdisc(qdisc);
207         if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_LIMIT)
208                 return sfq->qs_limit;
209         else
210                 return -NLE_NOATTR;
211 }
212
213 /**
214  * Set perturbation interval of SFQ qdisc.
215  * @arg qdisc           SFQ qdisc to be modified.
216  * @arg perturb         New perturbation interval in seconds.
217  * @note A value of 0 disables perturbation altogether.
218  * @return 0 on success or a negative error code.
219  */
220 int rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb)
221 {
222         struct rtnl_sfq *sfq;
223
224         sfq = sfq_alloc(qdisc);
225         if (!sfq)
226                 return -NLE_NOMEM;
227
228         sfq->qs_perturb = perturb;
229         sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB;
230
231         return 0;
232 }
233
234 /**
235  * Get perturbation interval of SFQ qdisc.
236  * @arg qdisc           SFQ qdisc.
237  * @return Perturbation interval in seconds or a negative error code.
238  */
239 int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc)
240 {
241         struct rtnl_sfq *sfq;
242
243         sfq = sfq_qdisc(qdisc);
244         if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_PERTURB)
245                 return sfq->qs_perturb;
246         else
247                 return -NLE_NOATTR;
248 }
249
250 /**
251  * Get divisor of SFQ qdisc.
252  * @arg qdisc           SFQ qdisc.
253  * @return Divisor in number of entries or a negative error code.
254  */
255 int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc)
256 {
257         struct rtnl_sfq *sfq;
258
259         sfq = sfq_qdisc(qdisc);
260         if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR)
261                 return sfq->qs_divisor;
262         else
263                 return -NLE_NOATTR;
264 }
265
266 /** @} */
267
268 static struct rtnl_qdisc_ops sfq_ops = {
269         .qo_kind                = "sfq",
270         .qo_msg_parser          = sfq_msg_parser,
271         .qo_free_data           = sfq_free_data,
272         .qo_dump = {
273             [NL_DUMP_LINE]      = sfq_dump_line,
274             [NL_DUMP_DETAILS]   = sfq_dump_details,
275         },
276         .qo_get_opts            = sfq_get_opts,
277 };
278
279 static void __init sfq_init(void)
280 {
281         rtnl_qdisc_register(&sfq_ops);
282 }
283
284 static void __exit sfq_exit(void)
285 {
286         rtnl_qdisc_unregister(&sfq_ops);
287 }
288
289 /** @} */