aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/act_api.c26
-rw-r--r--net/sched/act_csum.c2
-rw-r--r--net/sched/act_gact.c2
-rw-r--r--net/sched/act_ipt.c4
-rw-r--r--net/sched/act_mirred.c2
-rw-r--r--net/sched/act_nat.c2
-rw-r--r--net/sched/act_pedit.c2
-rw-r--r--net/sched/act_police.c1
-rw-r--r--net/sched/act_simple.c1
-rw-r--r--net/sched/act_skbedit.c1
-rw-r--r--net/sched/sch_htb.c20
-rw-r--r--net/sched/sch_netem.c7
-rw-r--r--net/sched/sch_tbf.c139
13 files changed, 122 insertions, 87 deletions
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index fd7072827a40..69cb848e8345 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -270,6 +270,16 @@ int tcf_register_action(struct tc_action_ops *act)
270{ 270{
271 struct tc_action_ops *a, **ap; 271 struct tc_action_ops *a, **ap;
272 272
273 /* Must supply act, dump, cleanup and init */
274 if (!act->act || !act->dump || !act->cleanup || !act->init)
275 return -EINVAL;
276
277 /* Supply defaults */
278 if (!act->lookup)
279 act->lookup = tcf_hash_search;
280 if (!act->walk)
281 act->walk = tcf_generic_walker;
282
273 write_lock(&act_mod_lock); 283 write_lock(&act_mod_lock);
274 for (ap = &act_base; (a = *ap) != NULL; ap = &a->next) { 284 for (ap = &act_base; (a = *ap) != NULL; ap = &a->next) {
275 if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) { 285 if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) {
@@ -381,7 +391,7 @@ int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act,
381 } 391 }
382 while ((a = act) != NULL) { 392 while ((a = act) != NULL) {
383repeat: 393repeat:
384 if (a->ops && a->ops->act) { 394 if (a->ops) {
385 ret = a->ops->act(skb, a, res); 395 ret = a->ops->act(skb, a, res);
386 if (TC_MUNGED & skb->tc_verd) { 396 if (TC_MUNGED & skb->tc_verd) {
387 /* copied already, allow trampling */ 397 /* copied already, allow trampling */
@@ -405,7 +415,7 @@ void tcf_action_destroy(struct tc_action *act, int bind)
405 struct tc_action *a; 415 struct tc_action *a;
406 416
407 for (a = act; a; a = act) { 417 for (a = act; a; a = act) {
408 if (a->ops && a->ops->cleanup) { 418 if (a->ops) {
409 if (a->ops->cleanup(a, bind) == ACT_P_DELETED) 419 if (a->ops->cleanup(a, bind) == ACT_P_DELETED)
410 module_put(a->ops->owner); 420 module_put(a->ops->owner);
411 act = act->next; 421 act = act->next;
@@ -424,7 +434,7 @@ tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
424{ 434{
425 int err = -EINVAL; 435 int err = -EINVAL;
426 436
427 if (a->ops == NULL || a->ops->dump == NULL) 437 if (a->ops == NULL)
428 return err; 438 return err;
429 return a->ops->dump(skb, a, bind, ref); 439 return a->ops->dump(skb, a, bind, ref);
430} 440}
@@ -436,7 +446,7 @@ tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
436 unsigned char *b = skb_tail_pointer(skb); 446 unsigned char *b = skb_tail_pointer(skb);
437 struct nlattr *nest; 447 struct nlattr *nest;
438 448
439 if (a->ops == NULL || a->ops->dump == NULL) 449 if (a->ops == NULL)
440 return err; 450 return err;
441 451
442 if (nla_put_string(skb, TCA_KIND, a->ops->kind)) 452 if (nla_put_string(skb, TCA_KIND, a->ops->kind))
@@ -723,8 +733,6 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
723 a->ops = tc_lookup_action(tb[TCA_ACT_KIND]); 733 a->ops = tc_lookup_action(tb[TCA_ACT_KIND]);
724 if (a->ops == NULL) 734 if (a->ops == NULL)
725 goto err_free; 735 goto err_free;
726 if (a->ops->lookup == NULL)
727 goto err_mod;
728 err = -ENOENT; 736 err = -ENOENT;
729 if (a->ops->lookup(a, index) == 0) 737 if (a->ops->lookup(a, index) == 0)
730 goto err_mod; 738 goto err_mod;
@@ -1084,12 +1092,6 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
1084 memset(&a, 0, sizeof(struct tc_action)); 1092 memset(&a, 0, sizeof(struct tc_action));
1085 a.ops = a_o; 1093 a.ops = a_o;
1086 1094
1087 if (a_o->walk == NULL) {
1088 WARN(1, "tc_dump_action: %s !capable of dumping table\n",
1089 a_o->kind);
1090 goto out_module_put;
1091 }
1092
1093 nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 1095 nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
1094 cb->nlh->nlmsg_type, sizeof(*t), 0); 1096 cb->nlh->nlmsg_type, sizeof(*t), 0);
1095 if (!nlh) 1097 if (!nlh)
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index 3a4c0caa1f7d..5c5edf56adbd 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -585,9 +585,7 @@ static struct tc_action_ops act_csum_ops = {
585 .act = tcf_csum, 585 .act = tcf_csum,
586 .dump = tcf_csum_dump, 586 .dump = tcf_csum_dump,
587 .cleanup = tcf_csum_cleanup, 587 .cleanup = tcf_csum_cleanup,
588 .lookup = tcf_hash_search,
589 .init = tcf_csum_init, 588 .init = tcf_csum_init,
590 .walk = tcf_generic_walker
591}; 589};
592 590
593MODULE_DESCRIPTION("Checksum updating actions"); 591MODULE_DESCRIPTION("Checksum updating actions");
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index fd2b3cff5fa2..5645a4d32abd 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -206,9 +206,7 @@ static struct tc_action_ops act_gact_ops = {
206 .act = tcf_gact, 206 .act = tcf_gact,
207 .dump = tcf_gact_dump, 207 .dump = tcf_gact_dump,
208 .cleanup = tcf_gact_cleanup, 208 .cleanup = tcf_gact_cleanup,
209 .lookup = tcf_hash_search,
210 .init = tcf_gact_init, 209 .init = tcf_gact_init,
211 .walk = tcf_generic_walker
212}; 210};
213 211
214MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"); 212MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 60d88b6b9560..882a89762f77 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -298,9 +298,7 @@ static struct tc_action_ops act_ipt_ops = {
298 .act = tcf_ipt, 298 .act = tcf_ipt,
299 .dump = tcf_ipt_dump, 299 .dump = tcf_ipt_dump,
300 .cleanup = tcf_ipt_cleanup, 300 .cleanup = tcf_ipt_cleanup,
301 .lookup = tcf_hash_search,
302 .init = tcf_ipt_init, 301 .init = tcf_ipt_init,
303 .walk = tcf_generic_walker
304}; 302};
305 303
306static struct tc_action_ops act_xt_ops = { 304static struct tc_action_ops act_xt_ops = {
@@ -312,9 +310,7 @@ static struct tc_action_ops act_xt_ops = {
312 .act = tcf_ipt, 310 .act = tcf_ipt,
313 .dump = tcf_ipt_dump, 311 .dump = tcf_ipt_dump,
314 .cleanup = tcf_ipt_cleanup, 312 .cleanup = tcf_ipt_cleanup,
315 .lookup = tcf_hash_search,
316 .init = tcf_ipt_init, 313 .init = tcf_ipt_init,
317 .walk = tcf_generic_walker
318}; 314};
319 315
320MODULE_AUTHOR("Jamal Hadi Salim(2002-13)"); 316MODULE_AUTHOR("Jamal Hadi Salim(2002-13)");
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 977c10e0631b..252378121ce7 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -271,9 +271,7 @@ static struct tc_action_ops act_mirred_ops = {
271 .act = tcf_mirred, 271 .act = tcf_mirred,
272 .dump = tcf_mirred_dump, 272 .dump = tcf_mirred_dump,
273 .cleanup = tcf_mirred_cleanup, 273 .cleanup = tcf_mirred_cleanup,
274 .lookup = tcf_hash_search,
275 .init = tcf_mirred_init, 274 .init = tcf_mirred_init,
276 .walk = tcf_generic_walker
277}; 275};
278 276
279MODULE_AUTHOR("Jamal Hadi Salim(2002)"); 277MODULE_AUTHOR("Jamal Hadi Salim(2002)");
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index 876f0ef29694..6a15ace00241 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -308,9 +308,7 @@ static struct tc_action_ops act_nat_ops = {
308 .act = tcf_nat, 308 .act = tcf_nat,
309 .dump = tcf_nat_dump, 309 .dump = tcf_nat_dump,
310 .cleanup = tcf_nat_cleanup, 310 .cleanup = tcf_nat_cleanup,
311 .lookup = tcf_hash_search,
312 .init = tcf_nat_init, 311 .init = tcf_nat_init,
313 .walk = tcf_generic_walker
314}; 312};
315 313
316MODULE_DESCRIPTION("Stateless NAT actions"); 314MODULE_DESCRIPTION("Stateless NAT actions");
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 7ed78c9e505c..03b67674169c 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -243,9 +243,7 @@ static struct tc_action_ops act_pedit_ops = {
243 .act = tcf_pedit, 243 .act = tcf_pedit,
244 .dump = tcf_pedit_dump, 244 .dump = tcf_pedit_dump,
245 .cleanup = tcf_pedit_cleanup, 245 .cleanup = tcf_pedit_cleanup,
246 .lookup = tcf_hash_search,
247 .init = tcf_pedit_init, 246 .init = tcf_pedit_init,
248 .walk = tcf_generic_walker
249}; 247};
250 248
251MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"); 249MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 272d8e924cf6..16a62c36928a 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -407,7 +407,6 @@ static struct tc_action_ops act_police_ops = {
407 .act = tcf_act_police, 407 .act = tcf_act_police,
408 .dump = tcf_act_police_dump, 408 .dump = tcf_act_police_dump,
409 .cleanup = tcf_act_police_cleanup, 409 .cleanup = tcf_act_police_cleanup,
410 .lookup = tcf_hash_search,
411 .init = tcf_act_police_locate, 410 .init = tcf_act_police_locate,
412 .walk = tcf_act_police_walker 411 .walk = tcf_act_police_walker
413}; 412};
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index 7725eb4ab756..31157d3e729c 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -201,7 +201,6 @@ static struct tc_action_ops act_simp_ops = {
201 .dump = tcf_simp_dump, 201 .dump = tcf_simp_dump,
202 .cleanup = tcf_simp_cleanup, 202 .cleanup = tcf_simp_cleanup,
203 .init = tcf_simp_init, 203 .init = tcf_simp_init,
204 .walk = tcf_generic_walker,
205}; 204};
206 205
207MODULE_AUTHOR("Jamal Hadi Salim(2005)"); 206MODULE_AUTHOR("Jamal Hadi Salim(2005)");
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index cb4221171f93..35ea643b4325 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -203,7 +203,6 @@ static struct tc_action_ops act_skbedit_ops = {
203 .dump = tcf_skbedit_dump, 203 .dump = tcf_skbedit_dump,
204 .cleanup = tcf_skbedit_cleanup, 204 .cleanup = tcf_skbedit_cleanup,
205 .init = tcf_skbedit_init, 205 .init = tcf_skbedit_init,
206 .walk = tcf_generic_walker,
207}; 206};
208 207
209MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>"); 208MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>");
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 0e1e38b40025..717b2108f852 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1477,11 +1477,22 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
1477 sch_tree_lock(sch); 1477 sch_tree_lock(sch);
1478 } 1478 }
1479 1479
1480 rate64 = tb[TCA_HTB_RATE64] ? nla_get_u64(tb[TCA_HTB_RATE64]) : 0;
1481
1482 ceil64 = tb[TCA_HTB_CEIL64] ? nla_get_u64(tb[TCA_HTB_CEIL64]) : 0;
1483
1484 psched_ratecfg_precompute(&cl->rate, &hopt->rate, rate64);
1485 psched_ratecfg_precompute(&cl->ceil, &hopt->ceil, ceil64);
1486
1480 /* it used to be a nasty bug here, we have to check that node 1487 /* it used to be a nasty bug here, we have to check that node
1481 * is really leaf before changing cl->un.leaf ! 1488 * is really leaf before changing cl->un.leaf !
1482 */ 1489 */
1483 if (!cl->level) { 1490 if (!cl->level) {
1484 cl->quantum = hopt->rate.rate / q->rate2quantum; 1491 u64 quantum = cl->rate.rate_bytes_ps;
1492
1493 do_div(quantum, q->rate2quantum);
1494 cl->quantum = min_t(u64, quantum, INT_MAX);
1495
1485 if (!hopt->quantum && cl->quantum < 1000) { 1496 if (!hopt->quantum && cl->quantum < 1000) {
1486 pr_warning( 1497 pr_warning(
1487 "HTB: quantum of class %X is small. Consider r2q change.\n", 1498 "HTB: quantum of class %X is small. Consider r2q change.\n",
@@ -1500,13 +1511,6 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
1500 cl->prio = TC_HTB_NUMPRIO - 1; 1511 cl->prio = TC_HTB_NUMPRIO - 1;
1501 } 1512 }
1502 1513
1503 rate64 = tb[TCA_HTB_RATE64] ? nla_get_u64(tb[TCA_HTB_RATE64]) : 0;
1504
1505 ceil64 = tb[TCA_HTB_CEIL64] ? nla_get_u64(tb[TCA_HTB_CEIL64]) : 0;
1506
1507 psched_ratecfg_precompute(&cl->rate, &hopt->rate, rate64);
1508 psched_ratecfg_precompute(&cl->ceil, &hopt->ceil, ceil64);
1509
1510 cl->buffer = PSCHED_TICKS2NS(hopt->buffer); 1514 cl->buffer = PSCHED_TICKS2NS(hopt->buffer);
1511 cl->cbuffer = PSCHED_TICKS2NS(hopt->cbuffer); 1515 cl->cbuffer = PSCHED_TICKS2NS(hopt->cbuffer);
1512 1516
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 75c94e59a3bd..bccd52b36e97 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -215,10 +215,10 @@ static bool loss_4state(struct netem_sched_data *q)
215 if (rnd < clg->a4) { 215 if (rnd < clg->a4) {
216 clg->state = 4; 216 clg->state = 4;
217 return true; 217 return true;
218 } else if (clg->a4 < rnd && rnd < clg->a1) { 218 } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) {
219 clg->state = 3; 219 clg->state = 3;
220 return true; 220 return true;
221 } else if (clg->a1 < rnd) 221 } else if (clg->a1 + clg->a4 < rnd)
222 clg->state = 1; 222 clg->state = 1;
223 223
224 break; 224 break;
@@ -268,10 +268,11 @@ static bool loss_gilb_ell(struct netem_sched_data *q)
268 clg->state = 2; 268 clg->state = 2;
269 if (net_random() < clg->a4) 269 if (net_random() < clg->a4)
270 return true; 270 return true;
271 break;
271 case 2: 272 case 2:
272 if (net_random() < clg->a2) 273 if (net_random() < clg->a2)
273 clg->state = 1; 274 clg->state = 1;
274 if (clg->a3 > net_random()) 275 if (net_random() > clg->a3)
275 return true; 276 return true;
276 } 277 }
277 278
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 68f98595819c..887e672f9d7d 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -21,6 +21,7 @@
21#include <net/netlink.h> 21#include <net/netlink.h>
22#include <net/sch_generic.h> 22#include <net/sch_generic.h>
23#include <net/pkt_sched.h> 23#include <net/pkt_sched.h>
24#include <net/tcp.h>
24 25
25 26
26/* Simple Token Bucket Filter. 27/* Simple Token Bucket Filter.
@@ -117,6 +118,48 @@ struct tbf_sched_data {
117}; 118};
118 119
119 120
121/* Time to Length, convert time in ns to length in bytes
122 * to determinate how many bytes can be sent in given time.
123 */
124static u64 psched_ns_t2l(const struct psched_ratecfg *r,
125 u64 time_in_ns)
126{
127 /* The formula is :
128 * len = (time_in_ns * r->rate_bytes_ps) / NSEC_PER_SEC
129 */
130 u64 len = time_in_ns * r->rate_bytes_ps;
131
132 do_div(len, NSEC_PER_SEC);
133
134 if (unlikely(r->linklayer == TC_LINKLAYER_ATM)) {
135 do_div(len, 53);
136 len = len * 48;
137 }
138
139 if (len > r->overhead)
140 len -= r->overhead;
141 else
142 len = 0;
143
144 return len;
145}
146
147/*
148 * Return length of individual segments of a gso packet,
149 * including all headers (MAC, IP, TCP/UDP)
150 */
151static unsigned int skb_gso_seglen(const struct sk_buff *skb)
152{
153 unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
154 const struct skb_shared_info *shinfo = skb_shinfo(skb);
155
156 if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
157 hdr_len += tcp_hdrlen(skb);
158 else
159 hdr_len += sizeof(struct udphdr);
160 return hdr_len + shinfo->gso_size;
161}
162
120/* GSO packet is too big, segment it so that tbf can transmit 163/* GSO packet is too big, segment it so that tbf can transmit
121 * each segment in time 164 * each segment in time
122 */ 165 */
@@ -136,12 +179,8 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
136 while (segs) { 179 while (segs) {
137 nskb = segs->next; 180 nskb = segs->next;
138 segs->next = NULL; 181 segs->next = NULL;
139 if (likely(segs->len <= q->max_size)) { 182 qdisc_skb_cb(segs)->pkt_len = segs->len;
140 qdisc_skb_cb(segs)->pkt_len = segs->len; 183 ret = qdisc_enqueue(segs, q->qdisc);
141 ret = qdisc_enqueue(segs, q->qdisc);
142 } else {
143 ret = qdisc_reshape_fail(skb, sch);
144 }
145 if (ret != NET_XMIT_SUCCESS) { 184 if (ret != NET_XMIT_SUCCESS) {
146 if (net_xmit_drop_count(ret)) 185 if (net_xmit_drop_count(ret))
147 sch->qstats.drops++; 186 sch->qstats.drops++;
@@ -163,7 +202,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
163 int ret; 202 int ret;
164 203
165 if (qdisc_pkt_len(skb) > q->max_size) { 204 if (qdisc_pkt_len(skb) > q->max_size) {
166 if (skb_is_gso(skb)) 205 if (skb_is_gso(skb) && skb_gso_seglen(skb) <= q->max_size)
167 return tbf_segment(skb, sch); 206 return tbf_segment(skb, sch);
168 return qdisc_reshape_fail(skb, sch); 207 return qdisc_reshape_fail(skb, sch);
169 } 208 }
@@ -276,10 +315,11 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
276 struct tbf_sched_data *q = qdisc_priv(sch); 315 struct tbf_sched_data *q = qdisc_priv(sch);
277 struct nlattr *tb[TCA_TBF_MAX + 1]; 316 struct nlattr *tb[TCA_TBF_MAX + 1];
278 struct tc_tbf_qopt *qopt; 317 struct tc_tbf_qopt *qopt;
279 struct qdisc_rate_table *rtab = NULL;
280 struct qdisc_rate_table *ptab = NULL;
281 struct Qdisc *child = NULL; 318 struct Qdisc *child = NULL;
282 int max_size, n; 319 struct psched_ratecfg rate;
320 struct psched_ratecfg peak;
321 u64 max_size;
322 s64 buffer, mtu;
283 u64 rate64 = 0, prate64 = 0; 323 u64 rate64 = 0, prate64 = 0;
284 324
285 err = nla_parse_nested(tb, TCA_TBF_MAX, opt, tbf_policy); 325 err = nla_parse_nested(tb, TCA_TBF_MAX, opt, tbf_policy);
@@ -291,33 +331,13 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
291 goto done; 331 goto done;
292 332
293 qopt = nla_data(tb[TCA_TBF_PARMS]); 333 qopt = nla_data(tb[TCA_TBF_PARMS]);
294 rtab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB]); 334 if (qopt->rate.linklayer == TC_LINKLAYER_UNAWARE)
295 if (rtab == NULL) 335 qdisc_put_rtab(qdisc_get_rtab(&qopt->rate,
296 goto done; 336 tb[TCA_TBF_RTAB]));
297 337
298 if (qopt->peakrate.rate) { 338 if (qopt->peakrate.linklayer == TC_LINKLAYER_UNAWARE)
299 if (qopt->peakrate.rate > qopt->rate.rate) 339 qdisc_put_rtab(qdisc_get_rtab(&qopt->peakrate,
300 ptab = qdisc_get_rtab(&qopt->peakrate, tb[TCA_TBF_PTAB]); 340 tb[TCA_TBF_PTAB]));
301 if (ptab == NULL)
302 goto done;
303 }
304
305 for (n = 0; n < 256; n++)
306 if (rtab->data[n] > qopt->buffer)
307 break;
308 max_size = (n << qopt->rate.cell_log) - 1;
309 if (ptab) {
310 int size;
311
312 for (n = 0; n < 256; n++)
313 if (ptab->data[n] > qopt->mtu)
314 break;
315 size = (n << qopt->peakrate.cell_log) - 1;
316 if (size < max_size)
317 max_size = size;
318 }
319 if (max_size < 0)
320 goto done;
321 341
322 if (q->qdisc != &noop_qdisc) { 342 if (q->qdisc != &noop_qdisc) {
323 err = fifo_set_limit(q->qdisc, qopt->limit); 343 err = fifo_set_limit(q->qdisc, qopt->limit);
@@ -331,6 +351,39 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
331 } 351 }
332 } 352 }
333 353
354 buffer = min_t(u64, PSCHED_TICKS2NS(qopt->buffer), ~0U);
355 mtu = min_t(u64, PSCHED_TICKS2NS(qopt->mtu), ~0U);
356
357 if (tb[TCA_TBF_RATE64])
358 rate64 = nla_get_u64(tb[TCA_TBF_RATE64]);
359 psched_ratecfg_precompute(&rate, &qopt->rate, rate64);
360
361 max_size = min_t(u64, psched_ns_t2l(&rate, buffer), ~0U);
362
363 if (qopt->peakrate.rate) {
364 if (tb[TCA_TBF_PRATE64])
365 prate64 = nla_get_u64(tb[TCA_TBF_PRATE64]);
366 psched_ratecfg_precompute(&peak, &qopt->peakrate, prate64);
367 if (peak.rate_bytes_ps <= rate.rate_bytes_ps) {
368 pr_warn_ratelimited("sch_tbf: peakrate %llu is lower than or equals to rate %llu !\n",
369 peak.rate_bytes_ps, rate.rate_bytes_ps);
370 err = -EINVAL;
371 goto done;
372 }
373
374 max_size = min_t(u64, max_size, psched_ns_t2l(&peak, mtu));
375 }
376
377 if (max_size < psched_mtu(qdisc_dev(sch)))
378 pr_warn_ratelimited("sch_tbf: burst %llu is lower than device %s mtu (%u) !\n",
379 max_size, qdisc_dev(sch)->name,
380 psched_mtu(qdisc_dev(sch)));
381
382 if (!max_size) {
383 err = -EINVAL;
384 goto done;
385 }
386
334 sch_tree_lock(sch); 387 sch_tree_lock(sch);
335 if (child) { 388 if (child) {
336 qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); 389 qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
@@ -344,13 +397,9 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
344 q->tokens = q->buffer; 397 q->tokens = q->buffer;
345 q->ptokens = q->mtu; 398 q->ptokens = q->mtu;
346 399
347 if (tb[TCA_TBF_RATE64]) 400 memcpy(&q->rate, &rate, sizeof(struct psched_ratecfg));
348 rate64 = nla_get_u64(tb[TCA_TBF_RATE64]); 401 if (qopt->peakrate.rate) {
349 psched_ratecfg_precompute(&q->rate, &rtab->rate, rate64); 402 memcpy(&q->peak, &peak, sizeof(struct psched_ratecfg));
350 if (ptab) {
351 if (tb[TCA_TBF_PRATE64])
352 prate64 = nla_get_u64(tb[TCA_TBF_PRATE64]);
353 psched_ratecfg_precompute(&q->peak, &ptab->rate, prate64);
354 q->peak_present = true; 403 q->peak_present = true;
355 } else { 404 } else {
356 q->peak_present = false; 405 q->peak_present = false;
@@ -359,10 +408,6 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
359 sch_tree_unlock(sch); 408 sch_tree_unlock(sch);
360 err = 0; 409 err = 0;
361done: 410done:
362 if (rtab)
363 qdisc_put_rtab(rtab);
364 if (ptab)
365 qdisc_put_rtab(ptab);
366 return err; 411 return err;
367} 412}
368 413