blob: a6090051c5dbe3d0a9aee6a2921b91397dbdc363 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * net/sched/sch_tbf.c Token Bucket Filter queue.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 * Dmitry Torokhov <dtor@mail.ru> - allow attaching inner qdiscs -
11 * original idea by Martin Devera
12 *
13 */
14
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/types.h>
17#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/skbuff.h>
Patrick McHardy0ba48052007-07-02 22:49:07 -070021#include <net/netlink.h>
Jiri Pirkob757c932013-02-12 00:12:05 +000022#include <net/sch_generic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <net/pkt_sched.h>
Eric Dumazet4d0820c2013-11-23 12:59:20 -080024#include <net/tcp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26
27/* Simple Token Bucket Filter.
28 =======================================
29
30 SOURCE.
31 -------
32
33 None.
34
35 Description.
36 ------------
37
38 A data flow obeys TBF with rate R and depth B, if for any
39 time interval t_i...t_f the number of transmitted bits
40 does not exceed B + R*(t_f-t_i).
41
42 Packetized version of this definition:
43 The sequence of packets of sizes s_i served at moments t_i
44 obeys TBF, if for any i<=k:
45
46 s_i+....+s_k <= B + R*(t_k - t_i)
47
48 Algorithm.
49 ----------
50
51 Let N(t_i) be B/R initially and N(t) grow continuously with time as:
52
53 N(t+delta) = min{B/R, N(t) + delta}
54
55 If the first packet in queue has length S, it may be
56 transmitted only at the time t_* when S/R <= N(t_*),
57 and in this case N(t) jumps:
58
59 N(t_* + 0) = N(t_* - 0) - S/R.
60
61
62
63 Actually, QoS requires two TBF to be applied to a data stream.
64 One of them controls steady state burst size, another
65 one with rate P (peak rate) and depth M (equal to link MTU)
66 limits bursts at a smaller time scale.
67
68 It is easy to see that P>R, and B>M. If P is infinity, this double
69 TBF is equivalent to a single one.
70
71 When TBF works in reshaping mode, latency is estimated as:
72
73 lat = max ((L-B)/R, (L-M)/P)
74
75
76 NOTES.
77 ------
78
79 If TBF throttles, it starts a watchdog timer, which will wake it up
80 when it is ready to transmit.
81 Note that the minimal timer resolution is 1/HZ.
82 If no new packets arrive during this period,
83 or if the device is not awaken by EOI for some previous packet,
84 TBF can stop its activity for 1/HZ.
85
86
87 This means, that with depth B, the maximal rate is
88
89 R_crit = B*HZ
90
91 F.e. for 10Mbit ethernet and HZ=100 the minimal allowed B is ~10Kbytes.
92
93 Note that the peak rate TBF is much more tough: with MTU 1500
94 P_crit = 150Kbytes/sec. So, if you need greater peak
95 rates, use alpha with HZ=1000 :-)
96
97 With classful TBF, limit is just kept for backwards compatibility.
98 It is passed to the default bfifo qdisc - if the inner qdisc is
99 changed the limit is not effective anymore.
100*/
101
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000102struct tbf_sched_data {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103/* Parameters */
104 u32 limit; /* Maximal length of backlog: bytes */
Jiri Pirkob757c932013-02-12 00:12:05 +0000105 s64 buffer; /* Token bucket depth/rate: MUST BE >= MTU/B */
106 s64 mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 u32 max_size;
Jiri Pirkob757c932013-02-12 00:12:05 +0000108 struct psched_ratecfg rate;
109 struct psched_ratecfg peak;
110 bool peak_present;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112/* Variables */
Jiri Pirkob757c932013-02-12 00:12:05 +0000113 s64 tokens; /* Current number of B tokens */
114 s64 ptokens; /* Current number of P tokens */
115 s64 t_c; /* Time check-point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 struct Qdisc *qdisc; /* Inner qdisc, default - bfifo queue */
Patrick McHardyf7f593e2007-03-16 01:20:07 -0700117 struct qdisc_watchdog watchdog; /* Watchdog timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118};
119
Eric Dumazete43ac792013-05-21 08:16:46 +0000120
Eric Dumazet4d0820c2013-11-23 12:59:20 -0800121/*
122 * Return length of individual segments of a gso packet,
123 * including all headers (MAC, IP, TCP/UDP)
124 */
125static unsigned int skb_gso_seglen(const struct sk_buff *skb)
126{
127 unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
128 const struct skb_shared_info *shinfo = skb_shinfo(skb);
129
130 if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
131 hdr_len += tcp_hdrlen(skb);
132 else
133 hdr_len += sizeof(struct udphdr);
134 return hdr_len + shinfo->gso_size;
135}
136
Eric Dumazete43ac792013-05-21 08:16:46 +0000137/* GSO packet is too big, segment it so that tbf can transmit
138 * each segment in time
139 */
140static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
141{
142 struct tbf_sched_data *q = qdisc_priv(sch);
143 struct sk_buff *segs, *nskb;
144 netdev_features_t features = netif_skb_features(skb);
145 int ret, nb;
146
147 segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
148
149 if (IS_ERR_OR_NULL(segs))
150 return qdisc_reshape_fail(skb, sch);
151
152 nb = 0;
153 while (segs) {
154 nskb = segs->next;
155 segs->next = NULL;
Eric Dumazet4d0820c2013-11-23 12:59:20 -0800156 qdisc_skb_cb(segs)->pkt_len = segs->len;
157 ret = qdisc_enqueue(segs, q->qdisc);
Eric Dumazete43ac792013-05-21 08:16:46 +0000158 if (ret != NET_XMIT_SUCCESS) {
159 if (net_xmit_drop_count(ret))
160 sch->qstats.drops++;
161 } else {
162 nb++;
163 }
164 segs = nskb;
165 }
166 sch->q.qlen += nb;
167 if (nb > 1)
168 qdisc_tree_decrease_qlen(sch, 1 - nb);
169 consume_skb(skb);
170 return nb > 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP;
171}
172
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000173static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
175 struct tbf_sched_data *q = qdisc_priv(sch);
176 int ret;
177
Eric Dumazete43ac792013-05-21 08:16:46 +0000178 if (qdisc_pkt_len(skb) > q->max_size) {
Eric Dumazet4d0820c2013-11-23 12:59:20 -0800179 if (skb_is_gso(skb) && skb_gso_seglen(skb) <= q->max_size)
Eric Dumazete43ac792013-05-21 08:16:46 +0000180 return tbf_segment(skb, sch);
David S. Miller69747652008-08-17 23:55:36 -0700181 return qdisc_reshape_fail(skb, sch);
Eric Dumazete43ac792013-05-21 08:16:46 +0000182 }
Jussi Kivilinna5f861732008-07-20 00:08:04 -0700183 ret = qdisc_enqueue(skb, q->qdisc);
Ben Greear9871e502010-08-10 01:45:40 -0700184 if (ret != NET_XMIT_SUCCESS) {
Jarek Poplawski378a2f02008-08-04 22:31:03 -0700185 if (net_xmit_drop_count(ret))
186 sch->qstats.drops++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 return ret;
188 }
189
190 sch->q.qlen++;
Ben Greear9871e502010-08-10 01:45:40 -0700191 return NET_XMIT_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192}
193
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000194static unsigned int tbf_drop(struct Qdisc *sch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195{
196 struct tbf_sched_data *q = qdisc_priv(sch);
Patrick McHardy6d037a22006-03-20 19:00:49 -0800197 unsigned int len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Patrick McHardy6d037a22006-03-20 19:00:49 -0800199 if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 sch->q.qlen--;
201 sch->qstats.drops++;
202 }
203 return len;
204}
205
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000206static struct sk_buff *tbf_dequeue(struct Qdisc *sch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
208 struct tbf_sched_data *q = qdisc_priv(sch);
209 struct sk_buff *skb;
210
Jarek Poplawski03c05f02008-10-31 00:46:19 -0700211 skb = q->qdisc->ops->peek(q->qdisc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 if (skb) {
Jiri Pirkob757c932013-02-12 00:12:05 +0000214 s64 now;
215 s64 toks;
216 s64 ptoks = 0;
Jussi Kivilinna0abf77e2008-07-20 00:08:27 -0700217 unsigned int len = qdisc_pkt_len(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Jiri Pirkob757c932013-02-12 00:12:05 +0000219 now = ktime_to_ns(ktime_get());
220 toks = min_t(s64, now - q->t_c, q->buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
Jiri Pirkob757c932013-02-12 00:12:05 +0000222 if (q->peak_present) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 ptoks = toks + q->ptokens;
Jiri Pirkob757c932013-02-12 00:12:05 +0000224 if (ptoks > q->mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 ptoks = q->mtu;
Jiri Pirkob757c932013-02-12 00:12:05 +0000226 ptoks -= (s64) psched_l2t_ns(&q->peak, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 }
228 toks += q->tokens;
Jiri Pirkob757c932013-02-12 00:12:05 +0000229 if (toks > q->buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 toks = q->buffer;
Jiri Pirkob757c932013-02-12 00:12:05 +0000231 toks -= (s64) psched_l2t_ns(&q->rate, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 if ((toks|ptoks) >= 0) {
Jarek Poplawski77be1552008-10-31 00:47:01 -0700234 skb = qdisc_dequeue_peeked(q->qdisc);
Jarek Poplawski03c05f02008-10-31 00:46:19 -0700235 if (unlikely(!skb))
236 return NULL;
237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 q->t_c = now;
239 q->tokens = toks;
240 q->ptokens = ptoks;
241 sch->q.qlen--;
Eric Dumazetfd245a42011-01-20 05:27:16 +0000242 qdisc_unthrottled(sch);
Eric Dumazet9190b3b2011-01-20 23:31:33 -0800243 qdisc_bstats_update(sch, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 return skb;
245 }
246
Jiri Pirkob757c932013-02-12 00:12:05 +0000247 qdisc_watchdog_schedule_ns(&q->watchdog,
248 now + max_t(long, -toks, -ptoks));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 /* Maybe we have a shorter packet in the queue,
251 which can be sent now. It sounds cool,
252 but, however, this is wrong in principle.
253 We MUST NOT reorder packets under these circumstances.
254
255 Really, if we split the flow into independent
256 subflows, it would be a very good solution.
257 This is the main idea of all FQ algorithms
258 (cf. CSZ, HPFQ, HFSC)
259 */
260
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 sch->qstats.overlimits++;
262 }
263 return NULL;
264}
265
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000266static void tbf_reset(struct Qdisc *sch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{
268 struct tbf_sched_data *q = qdisc_priv(sch);
269
270 qdisc_reset(q->qdisc);
271 sch->q.qlen = 0;
Jiri Pirkob757c932013-02-12 00:12:05 +0000272 q->t_c = ktime_to_ns(ktime_get());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 q->tokens = q->buffer;
274 q->ptokens = q->mtu;
Patrick McHardyf7f593e2007-03-16 01:20:07 -0700275 qdisc_watchdog_cancel(&q->watchdog);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276}
277
Patrick McHardy27a34212008-01-23 20:35:39 -0800278static const struct nla_policy tbf_policy[TCA_TBF_MAX + 1] = {
279 [TCA_TBF_PARMS] = { .len = sizeof(struct tc_tbf_qopt) },
280 [TCA_TBF_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
281 [TCA_TBF_PTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
Yang Yinglianga33c4a22013-11-08 10:23:34 +0800282 [TCA_TBF_RATE64] = { .type = NLA_U64 },
283 [TCA_TBF_PRATE64] = { .type = NLA_U64 },
Patrick McHardy27a34212008-01-23 20:35:39 -0800284};
285
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000286static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
Patrick McHardycee63722008-01-23 20:33:32 -0800288 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 struct tbf_sched_data *q = qdisc_priv(sch);
Yang Yinglianga33c4a22013-11-08 10:23:34 +0800290 struct nlattr *tb[TCA_TBF_MAX + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 struct tc_tbf_qopt *qopt;
292 struct qdisc_rate_table *rtab = NULL;
293 struct qdisc_rate_table *ptab = NULL;
294 struct Qdisc *child = NULL;
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000295 int max_size, n;
Yang Yinglianga33c4a22013-11-08 10:23:34 +0800296 u64 rate64 = 0, prate64 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Yang Yinglianga33c4a22013-11-08 10:23:34 +0800298 err = nla_parse_nested(tb, TCA_TBF_MAX, opt, tbf_policy);
Patrick McHardycee63722008-01-23 20:33:32 -0800299 if (err < 0)
300 return err;
301
302 err = -EINVAL;
Patrick McHardy27a34212008-01-23 20:35:39 -0800303 if (tb[TCA_TBF_PARMS] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 goto done;
305
Patrick McHardy1e904742008-01-22 22:11:17 -0800306 qopt = nla_data(tb[TCA_TBF_PARMS]);
307 rtab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 if (rtab == NULL)
309 goto done;
310
311 if (qopt->peakrate.rate) {
312 if (qopt->peakrate.rate > qopt->rate.rate)
Patrick McHardy1e904742008-01-22 22:11:17 -0800313 ptab = qdisc_get_rtab(&qopt->peakrate, tb[TCA_TBF_PTAB]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 if (ptab == NULL)
315 goto done;
316 }
317
318 for (n = 0; n < 256; n++)
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000319 if (rtab->data[n] > qopt->buffer)
320 break;
321 max_size = (n << qopt->rate.cell_log) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 if (ptab) {
323 int size;
324
325 for (n = 0; n < 256; n++)
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000326 if (ptab->data[n] > qopt->mtu)
327 break;
328 size = (n << qopt->peakrate.cell_log) - 1;
329 if (size < max_size)
330 max_size = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 }
332 if (max_size < 0)
333 goto done;
334
Eric Dumazet4d0820c2013-11-23 12:59:20 -0800335 if (max_size < psched_mtu(qdisc_dev(sch)))
336 pr_warn_ratelimited("sch_tbf: burst %u is lower than device %s mtu (%u) !\n",
337 max_size, qdisc_dev(sch)->name,
338 psched_mtu(qdisc_dev(sch)));
339
stephen hemmingerf0cd1502010-05-14 14:38:59 +0000340 if (q->qdisc != &noop_qdisc) {
341 err = fifo_set_limit(q->qdisc, qopt->limit);
342 if (err)
343 goto done;
344 } else if (qopt->limit > 0) {
Patrick McHardyfb0305c2008-07-05 23:40:21 -0700345 child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
346 if (IS_ERR(child)) {
347 err = PTR_ERR(child);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 goto done;
Patrick McHardyfb0305c2008-07-05 23:40:21 -0700349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 }
351
352 sch_tree_lock(sch);
Patrick McHardy5e50da02006-11-29 17:36:20 -0800353 if (child) {
354 qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
Patrick McHardyb94c8af2008-11-20 04:11:36 -0800355 qdisc_destroy(q->qdisc);
356 q->qdisc = child;
Patrick McHardy5e50da02006-11-29 17:36:20 -0800357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 q->limit = qopt->limit;
Jiri Pirkob757c932013-02-12 00:12:05 +0000359 q->mtu = PSCHED_TICKS2NS(qopt->mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 q->max_size = max_size;
Jiri Pirkob757c932013-02-12 00:12:05 +0000361 q->buffer = PSCHED_TICKS2NS(qopt->buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 q->tokens = q->buffer;
363 q->ptokens = q->mtu;
Patrick McHardyb94c8af2008-11-20 04:11:36 -0800364
Yang Yinglianga33c4a22013-11-08 10:23:34 +0800365 if (tb[TCA_TBF_RATE64])
366 rate64 = nla_get_u64(tb[TCA_TBF_RATE64]);
367 psched_ratecfg_precompute(&q->rate, &rtab->rate, rate64);
Jiri Pirkob757c932013-02-12 00:12:05 +0000368 if (ptab) {
Yang Yinglianga33c4a22013-11-08 10:23:34 +0800369 if (tb[TCA_TBF_PRATE64])
370 prate64 = nla_get_u64(tb[TCA_TBF_PRATE64]);
371 psched_ratecfg_precompute(&q->peak, &ptab->rate, prate64);
Jiri Pirkob757c932013-02-12 00:12:05 +0000372 q->peak_present = true;
373 } else {
374 q->peak_present = false;
375 }
Patrick McHardyb94c8af2008-11-20 04:11:36 -0800376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 sch_tree_unlock(sch);
378 err = 0;
379done:
380 if (rtab)
381 qdisc_put_rtab(rtab);
382 if (ptab)
383 qdisc_put_rtab(ptab);
384 return err;
385}
386
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000387static int tbf_init(struct Qdisc *sch, struct nlattr *opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
389 struct tbf_sched_data *q = qdisc_priv(sch);
390
391 if (opt == NULL)
392 return -EINVAL;
393
Jiri Pirkob757c932013-02-12 00:12:05 +0000394 q->t_c = ktime_to_ns(ktime_get());
Patrick McHardyf7f593e2007-03-16 01:20:07 -0700395 qdisc_watchdog_init(&q->watchdog, sch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 q->qdisc = &noop_qdisc;
397
398 return tbf_change(sch, opt);
399}
400
401static void tbf_destroy(struct Qdisc *sch)
402{
403 struct tbf_sched_data *q = qdisc_priv(sch);
404
Patrick McHardyf7f593e2007-03-16 01:20:07 -0700405 qdisc_watchdog_cancel(&q->watchdog);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 qdisc_destroy(q->qdisc);
407}
408
409static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
410{
411 struct tbf_sched_data *q = qdisc_priv(sch);
Patrick McHardy4b3550ef2008-01-23 20:34:11 -0800412 struct nlattr *nest;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 struct tc_tbf_qopt opt;
414
Eric Dumazetb0460e42011-12-28 23:27:44 +0000415 sch->qstats.backlog = q->qdisc->qstats.backlog;
Patrick McHardy4b3550ef2008-01-23 20:34:11 -0800416 nest = nla_nest_start(skb, TCA_OPTIONS);
417 if (nest == NULL)
418 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
420 opt.limit = q->limit;
Eric Dumazet01cb71d2013-06-02 13:55:05 +0000421 psched_ratecfg_getrate(&opt.rate, &q->rate);
Jiri Pirkob757c932013-02-12 00:12:05 +0000422 if (q->peak_present)
Eric Dumazet01cb71d2013-06-02 13:55:05 +0000423 psched_ratecfg_getrate(&opt.peakrate, &q->peak);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 else
425 memset(&opt.peakrate, 0, sizeof(opt.peakrate));
Jiri Pirkob757c932013-02-12 00:12:05 +0000426 opt.mtu = PSCHED_NS2TICKS(q->mtu);
427 opt.buffer = PSCHED_NS2TICKS(q->buffer);
David S. Miller1b34ec42012-03-29 05:11:39 -0400428 if (nla_put(skb, TCA_TBF_PARMS, sizeof(opt), &opt))
429 goto nla_put_failure;
Yang Yinglianga33c4a22013-11-08 10:23:34 +0800430 if (q->rate.rate_bytes_ps >= (1ULL << 32) &&
431 nla_put_u64(skb, TCA_TBF_RATE64, q->rate.rate_bytes_ps))
432 goto nla_put_failure;
433 if (q->peak_present &&
434 q->peak.rate_bytes_ps >= (1ULL << 32) &&
435 nla_put_u64(skb, TCA_TBF_PRATE64, q->peak.rate_bytes_ps))
436 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Patrick McHardy4b3550ef2008-01-23 20:34:11 -0800438 nla_nest_end(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 return skb->len;
440
Patrick McHardy1e904742008-01-22 22:11:17 -0800441nla_put_failure:
Patrick McHardy4b3550ef2008-01-23 20:34:11 -0800442 nla_nest_cancel(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 return -1;
444}
445
446static int tbf_dump_class(struct Qdisc *sch, unsigned long cl,
447 struct sk_buff *skb, struct tcmsg *tcm)
448{
449 struct tbf_sched_data *q = qdisc_priv(sch);
450
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 tcm->tcm_handle |= TC_H_MIN(1);
452 tcm->tcm_info = q->qdisc->handle;
453
454 return 0;
455}
456
457static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
458 struct Qdisc **old)
459{
460 struct tbf_sched_data *q = qdisc_priv(sch);
461
462 if (new == NULL)
463 new = &noop_qdisc;
464
465 sch_tree_lock(sch);
Patrick McHardyb94c8af2008-11-20 04:11:36 -0800466 *old = q->qdisc;
467 q->qdisc = new;
Patrick McHardy5e50da02006-11-29 17:36:20 -0800468 qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 qdisc_reset(*old);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 sch_tree_unlock(sch);
471
472 return 0;
473}
474
475static struct Qdisc *tbf_leaf(struct Qdisc *sch, unsigned long arg)
476{
477 struct tbf_sched_data *q = qdisc_priv(sch);
478 return q->qdisc;
479}
480
481static unsigned long tbf_get(struct Qdisc *sch, u32 classid)
482{
483 return 1;
484}
485
486static void tbf_put(struct Qdisc *sch, unsigned long arg)
487{
488}
489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker)
491{
492 if (!walker->stop) {
493 if (walker->count >= walker->skip)
494 if (walker->fn(sch, 1, walker) < 0) {
495 walker->stop = 1;
496 return;
497 }
498 walker->count++;
499 }
500}
501
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000502static const struct Qdisc_class_ops tbf_class_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 .graft = tbf_graft,
504 .leaf = tbf_leaf,
505 .get = tbf_get,
506 .put = tbf_put,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 .walk = tbf_walk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 .dump = tbf_dump_class,
509};
510
Eric Dumazet20fea082007-11-14 01:44:41 -0800511static struct Qdisc_ops tbf_qdisc_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 .next = NULL,
513 .cl_ops = &tbf_class_ops,
514 .id = "tbf",
515 .priv_size = sizeof(struct tbf_sched_data),
516 .enqueue = tbf_enqueue,
517 .dequeue = tbf_dequeue,
Jarek Poplawski77be1552008-10-31 00:47:01 -0700518 .peek = qdisc_peek_dequeued,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 .drop = tbf_drop,
520 .init = tbf_init,
521 .reset = tbf_reset,
522 .destroy = tbf_destroy,
523 .change = tbf_change,
524 .dump = tbf_dump,
525 .owner = THIS_MODULE,
526};
527
528static int __init tbf_module_init(void)
529{
530 return register_qdisc(&tbf_qdisc_ops);
531}
532
533static void __exit tbf_module_exit(void)
534{
535 unregister_qdisc(&tbf_qdisc_ops);
536}
537module_init(tbf_module_init)
538module_exit(tbf_module_exit)
539MODULE_LICENSE("GPL");