This commit was generated by cvs2svn to compensate for changes in r786,
[libnl.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-2006 Thomas Graf <tgraf@suug.ch>
10  */
11
12 /**
13  * @ingroup qdisc
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->q_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_build_no_hdr();
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), 0) < 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 /** @} */