1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/string.h>
19#include <linux/errno.h>
20#include <linux/skbuff.h>
21#include <net/netlink.h>
22#include <net/pkt_sched.h>
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100struct tbf_sched_data
101{
102
103 u32 limit;
104 u32 buffer;
105 u32 mtu;
106 u32 max_size;
107 struct qdisc_rate_table *R_tab;
108 struct qdisc_rate_table *P_tab;
109
110
111 long tokens;
112 long ptokens;
113 psched_time_t t_c;
114 struct Qdisc *qdisc;
115 struct qdisc_watchdog watchdog;
116};
117
118#define L2T(q,L) qdisc_l2t((q)->R_tab,L)
119#define L2T_P(q,L) qdisc_l2t((q)->P_tab,L)
120
121static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
122{
123 struct tbf_sched_data *q = qdisc_priv(sch);
124 int ret;
125
126 if (qdisc_pkt_len(skb) > q->max_size)
127 return qdisc_reshape_fail(skb, sch);
128
129 ret = qdisc_enqueue(skb, q->qdisc);
130 if (ret != 0) {
131 if (net_xmit_drop_count(ret))
132 sch->qstats.drops++;
133 return ret;
134 }
135
136 sch->q.qlen++;
137 sch->bstats.bytes += qdisc_pkt_len(skb);
138 sch->bstats.packets++;
139 return 0;
140}
141
142static unsigned int tbf_drop(struct Qdisc* sch)
143{
144 struct tbf_sched_data *q = qdisc_priv(sch);
145 unsigned int len = 0;
146
147 if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) {
148 sch->q.qlen--;
149 sch->qstats.drops++;
150 }
151 return len;
152}
153
154static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
155{
156 struct tbf_sched_data *q = qdisc_priv(sch);
157 struct sk_buff *skb;
158
159 skb = q->qdisc->ops->peek(q->qdisc);
160
161 if (skb) {
162 psched_time_t now;
163 long toks;
164 long ptoks = 0;
165 unsigned int len = qdisc_pkt_len(skb);
166
167 now = psched_get_time();
168 toks = psched_tdiff_bounded(now, q->t_c, q->buffer);
169
170 if (q->P_tab) {
171 ptoks = toks + q->ptokens;
172 if (ptoks > (long)q->mtu)
173 ptoks = q->mtu;
174 ptoks -= L2T_P(q, len);
175 }
176 toks += q->tokens;
177 if (toks > (long)q->buffer)
178 toks = q->buffer;
179 toks -= L2T(q, len);
180
181 if ((toks|ptoks) >= 0) {
182 skb = qdisc_dequeue_peeked(q->qdisc);
183 if (unlikely(!skb))
184 return NULL;
185
186 q->t_c = now;
187 q->tokens = toks;
188 q->ptokens = ptoks;
189 sch->q.qlen--;
190 sch->flags &= ~TCQ_F_THROTTLED;
191 return skb;
192 }
193
194 qdisc_watchdog_schedule(&q->watchdog,
195 now + max_t(long, -toks, -ptoks));
196
197
198
199
200
201
202
203
204
205
206
207
208 sch->qstats.overlimits++;
209 }
210 return NULL;
211}
212
213static void tbf_reset(struct Qdisc* sch)
214{
215 struct tbf_sched_data *q = qdisc_priv(sch);
216
217 qdisc_reset(q->qdisc);
218 sch->q.qlen = 0;
219 q->t_c = psched_get_time();
220 q->tokens = q->buffer;
221 q->ptokens = q->mtu;
222 qdisc_watchdog_cancel(&q->watchdog);
223}
224
225static const struct nla_policy tbf_policy[TCA_TBF_MAX + 1] = {
226 [TCA_TBF_PARMS] = { .len = sizeof(struct tc_tbf_qopt) },
227 [TCA_TBF_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
228 [TCA_TBF_PTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
229};
230
231static int tbf_change(struct Qdisc* sch, struct nlattr *opt)
232{
233 int err;
234 struct tbf_sched_data *q = qdisc_priv(sch);
235 struct nlattr *tb[TCA_TBF_PTAB + 1];
236 struct tc_tbf_qopt *qopt;
237 struct qdisc_rate_table *rtab = NULL;
238 struct qdisc_rate_table *ptab = NULL;
239 struct Qdisc *child = NULL;
240 int max_size,n;
241
242 err = nla_parse_nested(tb, TCA_TBF_PTAB, opt, tbf_policy);
243 if (err < 0)
244 return err;
245
246 err = -EINVAL;
247 if (tb[TCA_TBF_PARMS] == NULL)
248 goto done;
249
250 qopt = nla_data(tb[TCA_TBF_PARMS]);
251 rtab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB]);
252 if (rtab == NULL)
253 goto done;
254
255 if (qopt->peakrate.rate) {
256 if (qopt->peakrate.rate > qopt->rate.rate)
257 ptab = qdisc_get_rtab(&qopt->peakrate, tb[TCA_TBF_PTAB]);
258 if (ptab == NULL)
259 goto done;
260 }
261
262 for (n = 0; n < 256; n++)
263 if (rtab->data[n] > qopt->buffer) break;
264 max_size = (n << qopt->rate.cell_log)-1;
265 if (ptab) {
266 int size;
267
268 for (n = 0; n < 256; n++)
269 if (ptab->data[n] > qopt->mtu) break;
270 size = (n << qopt->peakrate.cell_log)-1;
271 if (size < max_size) max_size = size;
272 }
273 if (max_size < 0)
274 goto done;
275
276 if (qopt->limit > 0) {
277 child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
278 if (IS_ERR(child)) {
279 err = PTR_ERR(child);
280 goto done;
281 }
282 }
283
284 sch_tree_lock(sch);
285 if (child) {
286 qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
287 qdisc_destroy(q->qdisc);
288 q->qdisc = child;
289 }
290 q->limit = qopt->limit;
291 q->mtu = qopt->mtu;
292 q->max_size = max_size;
293 q->buffer = qopt->buffer;
294 q->tokens = q->buffer;
295 q->ptokens = q->mtu;
296
297 swap(q->R_tab, rtab);
298 swap(q->P_tab, ptab);
299
300 sch_tree_unlock(sch);
301 err = 0;
302done:
303 if (rtab)
304 qdisc_put_rtab(rtab);
305 if (ptab)
306 qdisc_put_rtab(ptab);
307 return err;
308}
309
310static int tbf_init(struct Qdisc* sch, struct nlattr *opt)
311{
312 struct tbf_sched_data *q = qdisc_priv(sch);
313
314 if (opt == NULL)
315 return -EINVAL;
316
317 q->t_c = psched_get_time();
318 qdisc_watchdog_init(&q->watchdog, sch);
319 q->qdisc = &noop_qdisc;
320
321 return tbf_change(sch, opt);
322}
323
324static void tbf_destroy(struct Qdisc *sch)
325{
326 struct tbf_sched_data *q = qdisc_priv(sch);
327
328 qdisc_watchdog_cancel(&q->watchdog);
329
330 if (q->P_tab)
331 qdisc_put_rtab(q->P_tab);
332 if (q->R_tab)
333 qdisc_put_rtab(q->R_tab);
334
335 qdisc_destroy(q->qdisc);
336}
337
338static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
339{
340 struct tbf_sched_data *q = qdisc_priv(sch);
341 struct nlattr *nest;
342 struct tc_tbf_qopt opt;
343
344 nest = nla_nest_start(skb, TCA_OPTIONS);
345 if (nest == NULL)
346 goto nla_put_failure;
347
348 opt.limit = q->limit;
349 opt.rate = q->R_tab->rate;
350 if (q->P_tab)
351 opt.peakrate = q->P_tab->rate;
352 else
353 memset(&opt.peakrate, 0, sizeof(opt.peakrate));
354 opt.mtu = q->mtu;
355 opt.buffer = q->buffer;
356 NLA_PUT(skb, TCA_TBF_PARMS, sizeof(opt), &opt);
357
358 nla_nest_end(skb, nest);
359 return skb->len;
360
361nla_put_failure:
362 nla_nest_cancel(skb, nest);
363 return -1;
364}
365
366static int tbf_dump_class(struct Qdisc *sch, unsigned long cl,
367 struct sk_buff *skb, struct tcmsg *tcm)
368{
369 struct tbf_sched_data *q = qdisc_priv(sch);
370
371 if (cl != 1)
372 return -ENOENT;
373
374 tcm->tcm_handle |= TC_H_MIN(1);
375 tcm->tcm_info = q->qdisc->handle;
376
377 return 0;
378}
379
380static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
381 struct Qdisc **old)
382{
383 struct tbf_sched_data *q = qdisc_priv(sch);
384
385 if (new == NULL)
386 new = &noop_qdisc;
387
388 sch_tree_lock(sch);
389 *old = q->qdisc;
390 q->qdisc = new;
391 qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
392 qdisc_reset(*old);
393 sch_tree_unlock(sch);
394
395 return 0;
396}
397
398static struct Qdisc *tbf_leaf(struct Qdisc *sch, unsigned long arg)
399{
400 struct tbf_sched_data *q = qdisc_priv(sch);
401 return q->qdisc;
402}
403
404static unsigned long tbf_get(struct Qdisc *sch, u32 classid)
405{
406 return 1;
407}
408
409static void tbf_put(struct Qdisc *sch, unsigned long arg)
410{
411}
412
413static int tbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
414 struct nlattr **tca, unsigned long *arg)
415{
416 return -ENOSYS;
417}
418
419static int tbf_delete(struct Qdisc *sch, unsigned long arg)
420{
421 return -ENOSYS;
422}
423
424static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker)
425{
426 if (!walker->stop) {
427 if (walker->count >= walker->skip)
428 if (walker->fn(sch, 1, walker) < 0) {
429 walker->stop = 1;
430 return;
431 }
432 walker->count++;
433 }
434}
435
436static struct tcf_proto **tbf_find_tcf(struct Qdisc *sch, unsigned long cl)
437{
438 return NULL;
439}
440
441static const struct Qdisc_class_ops tbf_class_ops =
442{
443 .graft = tbf_graft,
444 .leaf = tbf_leaf,
445 .get = tbf_get,
446 .put = tbf_put,
447 .change = tbf_change_class,
448 .delete = tbf_delete,
449 .walk = tbf_walk,
450 .tcf_chain = tbf_find_tcf,
451 .dump = tbf_dump_class,
452};
453
454static struct Qdisc_ops tbf_qdisc_ops __read_mostly = {
455 .next = NULL,
456 .cl_ops = &tbf_class_ops,
457 .id = "tbf",
458 .priv_size = sizeof(struct tbf_sched_data),
459 .enqueue = tbf_enqueue,
460 .dequeue = tbf_dequeue,
461 .peek = qdisc_peek_dequeued,
462 .drop = tbf_drop,
463 .init = tbf_init,
464 .reset = tbf_reset,
465 .destroy = tbf_destroy,
466 .change = tbf_change,
467 .dump = tbf_dump,
468 .owner = THIS_MODULE,
469};
470
471static int __init tbf_module_init(void)
472{
473 return register_qdisc(&tbf_qdisc_ops);
474}
475
476static void __exit tbf_module_exit(void)
477{
478 unregister_qdisc(&tbf_qdisc_ops);
479}
480module_init(tbf_module_init)
481module_exit(tbf_module_exit)
482MODULE_LICENSE("GPL");
483