diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-12-08 21:46:45 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-09 13:46:15 -0500 |
commit | a73ed26bbae7327370c5bd298f07de78df9e3466 (patch) | |
tree | 3c7a04e638261cdd16c324ecd07e303e72fac3b9 /net | |
parent | 0221cd51543972782af558c527e4ac58b32049fa (diff) |
sch_red: generalize accurate MAX_P support to RED/GRED/CHOKE
Now RED uses a Q0.32 number to store max_p (max probability), allow
RED/GRED/CHOKE to use/report full resolution at config/dump time.
Old tc binaries are non aware of new attributes, and still set/get Plog.
New tc binary set/get both Plog and max_p for backward compatibility,
they display "probability value" if they get max_p from new kernels.
# tc -d qdisc show dev ...
...
qdisc red 10: parent 1:1 limit 360Kb min 30Kb max 90Kb ecn ewma 5
probability 0.09 Scell_log 15
Make sure we avoid potential divides by 0 in reciprocal_value(), if
(max_th - min_th) is big.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/sched/sch_choke.c | 8 | ||||
-rw-r--r-- | net/sched/sch_gred.c | 22 | ||||
-rw-r--r-- | net/sched/sch_red.c | 9 |
3 files changed, 32 insertions, 7 deletions
diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 205d369a217c..bef00acb8bd2 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c | |||
@@ -394,6 +394,7 @@ static void choke_reset(struct Qdisc *sch) | |||
394 | static const struct nla_policy choke_policy[TCA_CHOKE_MAX + 1] = { | 394 | static const struct nla_policy choke_policy[TCA_CHOKE_MAX + 1] = { |
395 | [TCA_CHOKE_PARMS] = { .len = sizeof(struct tc_red_qopt) }, | 395 | [TCA_CHOKE_PARMS] = { .len = sizeof(struct tc_red_qopt) }, |
396 | [TCA_CHOKE_STAB] = { .len = RED_STAB_SIZE }, | 396 | [TCA_CHOKE_STAB] = { .len = RED_STAB_SIZE }, |
397 | [TCA_CHOKE_MAX_P] = { .type = NLA_U32 }, | ||
397 | }; | 398 | }; |
398 | 399 | ||
399 | 400 | ||
@@ -415,6 +416,7 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt) | |||
415 | int err; | 416 | int err; |
416 | struct sk_buff **old = NULL; | 417 | struct sk_buff **old = NULL; |
417 | unsigned int mask; | 418 | unsigned int mask; |
419 | u32 max_P; | ||
418 | 420 | ||
419 | if (opt == NULL) | 421 | if (opt == NULL) |
420 | return -EINVAL; | 422 | return -EINVAL; |
@@ -427,6 +429,8 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt) | |||
427 | tb[TCA_CHOKE_STAB] == NULL) | 429 | tb[TCA_CHOKE_STAB] == NULL) |
428 | return -EINVAL; | 430 | return -EINVAL; |
429 | 431 | ||
432 | max_P = tb[TCA_CHOKE_MAX_P] ? nla_get_u32(tb[TCA_CHOKE_MAX_P]) : 0; | ||
433 | |||
430 | ctl = nla_data(tb[TCA_CHOKE_PARMS]); | 434 | ctl = nla_data(tb[TCA_CHOKE_PARMS]); |
431 | 435 | ||
432 | if (ctl->limit > CHOKE_MAX_QUEUE) | 436 | if (ctl->limit > CHOKE_MAX_QUEUE) |
@@ -476,7 +480,8 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt) | |||
476 | 480 | ||
477 | red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, | 481 | red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, |
478 | ctl->Plog, ctl->Scell_log, | 482 | ctl->Plog, ctl->Scell_log, |
479 | nla_data(tb[TCA_CHOKE_STAB])); | 483 | nla_data(tb[TCA_CHOKE_STAB]), |
484 | max_P); | ||
480 | 485 | ||
481 | if (q->head == q->tail) | 486 | if (q->head == q->tail) |
482 | red_end_of_idle_period(&q->parms); | 487 | red_end_of_idle_period(&q->parms); |
@@ -510,6 +515,7 @@ static int choke_dump(struct Qdisc *sch, struct sk_buff *skb) | |||
510 | goto nla_put_failure; | 515 | goto nla_put_failure; |
511 | 516 | ||
512 | NLA_PUT(skb, TCA_CHOKE_PARMS, sizeof(opt), &opt); | 517 | NLA_PUT(skb, TCA_CHOKE_PARMS, sizeof(opt), &opt); |
518 | NLA_PUT_U32(skb, TCA_CHOKE_MAX_P, q->parms.max_P); | ||
513 | return nla_nest_end(skb, opts); | 519 | return nla_nest_end(skb, opts); |
514 | 520 | ||
515 | nla_put_failure: | 521 | nla_put_failure: |
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index b9493a09a870..a1b7407ac2a4 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c | |||
@@ -34,7 +34,7 @@ struct gred_sched; | |||
34 | 34 | ||
35 | struct gred_sched_data { | 35 | struct gred_sched_data { |
36 | u32 limit; /* HARD maximal queue length */ | 36 | u32 limit; /* HARD maximal queue length */ |
37 | u32 DP; /* the drop pramaters */ | 37 | u32 DP; /* the drop parameters */ |
38 | u32 bytesin; /* bytes seen on virtualQ so far*/ | 38 | u32 bytesin; /* bytes seen on virtualQ so far*/ |
39 | u32 packetsin; /* packets seen on virtualQ so far*/ | 39 | u32 packetsin; /* packets seen on virtualQ so far*/ |
40 | u32 backlog; /* bytes on the virtualQ */ | 40 | u32 backlog; /* bytes on the virtualQ */ |
@@ -379,7 +379,8 @@ static inline int gred_change_table_def(struct Qdisc *sch, struct nlattr *dps) | |||
379 | } | 379 | } |
380 | 380 | ||
381 | static inline int gred_change_vq(struct Qdisc *sch, int dp, | 381 | static inline int gred_change_vq(struct Qdisc *sch, int dp, |
382 | struct tc_gred_qopt *ctl, int prio, u8 *stab) | 382 | struct tc_gred_qopt *ctl, int prio, |
383 | u8 *stab, u32 max_P) | ||
383 | { | 384 | { |
384 | struct gred_sched *table = qdisc_priv(sch); | 385 | struct gred_sched *table = qdisc_priv(sch); |
385 | struct gred_sched_data *q; | 386 | struct gred_sched_data *q; |
@@ -400,7 +401,7 @@ static inline int gred_change_vq(struct Qdisc *sch, int dp, | |||
400 | 401 | ||
401 | red_set_parms(&q->parms, | 402 | red_set_parms(&q->parms, |
402 | ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog, | 403 | ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog, |
403 | ctl->Scell_log, stab); | 404 | ctl->Scell_log, stab, max_P); |
404 | 405 | ||
405 | return 0; | 406 | return 0; |
406 | } | 407 | } |
@@ -409,6 +410,7 @@ static const struct nla_policy gred_policy[TCA_GRED_MAX + 1] = { | |||
409 | [TCA_GRED_PARMS] = { .len = sizeof(struct tc_gred_qopt) }, | 410 | [TCA_GRED_PARMS] = { .len = sizeof(struct tc_gred_qopt) }, |
410 | [TCA_GRED_STAB] = { .len = 256 }, | 411 | [TCA_GRED_STAB] = { .len = 256 }, |
411 | [TCA_GRED_DPS] = { .len = sizeof(struct tc_gred_sopt) }, | 412 | [TCA_GRED_DPS] = { .len = sizeof(struct tc_gred_sopt) }, |
413 | [TCA_GRED_MAX_P] = { .type = NLA_U32 }, | ||
412 | }; | 414 | }; |
413 | 415 | ||
414 | static int gred_change(struct Qdisc *sch, struct nlattr *opt) | 416 | static int gred_change(struct Qdisc *sch, struct nlattr *opt) |
@@ -418,6 +420,7 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt) | |||
418 | struct nlattr *tb[TCA_GRED_MAX + 1]; | 420 | struct nlattr *tb[TCA_GRED_MAX + 1]; |
419 | int err, prio = GRED_DEF_PRIO; | 421 | int err, prio = GRED_DEF_PRIO; |
420 | u8 *stab; | 422 | u8 *stab; |
423 | u32 max_P; | ||
421 | 424 | ||
422 | if (opt == NULL) | 425 | if (opt == NULL) |
423 | return -EINVAL; | 426 | return -EINVAL; |
@@ -433,6 +436,8 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt) | |||
433 | tb[TCA_GRED_STAB] == NULL) | 436 | tb[TCA_GRED_STAB] == NULL) |
434 | return -EINVAL; | 437 | return -EINVAL; |
435 | 438 | ||
439 | max_P = tb[TCA_GRED_MAX_P] ? nla_get_u32(tb[TCA_GRED_MAX_P]) : 0; | ||
440 | |||
436 | err = -EINVAL; | 441 | err = -EINVAL; |
437 | ctl = nla_data(tb[TCA_GRED_PARMS]); | 442 | ctl = nla_data(tb[TCA_GRED_PARMS]); |
438 | stab = nla_data(tb[TCA_GRED_STAB]); | 443 | stab = nla_data(tb[TCA_GRED_STAB]); |
@@ -457,7 +462,7 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt) | |||
457 | 462 | ||
458 | sch_tree_lock(sch); | 463 | sch_tree_lock(sch); |
459 | 464 | ||
460 | err = gred_change_vq(sch, ctl->DP, ctl, prio, stab); | 465 | err = gred_change_vq(sch, ctl->DP, ctl, prio, stab, max_P); |
461 | if (err < 0) | 466 | if (err < 0) |
462 | goto errout_locked; | 467 | goto errout_locked; |
463 | 468 | ||
@@ -498,6 +503,7 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) | |||
498 | struct gred_sched *table = qdisc_priv(sch); | 503 | struct gred_sched *table = qdisc_priv(sch); |
499 | struct nlattr *parms, *opts = NULL; | 504 | struct nlattr *parms, *opts = NULL; |
500 | int i; | 505 | int i; |
506 | u32 max_p[MAX_DPs]; | ||
501 | struct tc_gred_sopt sopt = { | 507 | struct tc_gred_sopt sopt = { |
502 | .DPs = table->DPs, | 508 | .DPs = table->DPs, |
503 | .def_DP = table->def, | 509 | .def_DP = table->def, |
@@ -509,6 +515,14 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) | |||
509 | if (opts == NULL) | 515 | if (opts == NULL) |
510 | goto nla_put_failure; | 516 | goto nla_put_failure; |
511 | NLA_PUT(skb, TCA_GRED_DPS, sizeof(sopt), &sopt); | 517 | NLA_PUT(skb, TCA_GRED_DPS, sizeof(sopt), &sopt); |
518 | |||
519 | for (i = 0; i < MAX_DPs; i++) { | ||
520 | struct gred_sched_data *q = table->tab[i]; | ||
521 | |||
522 | max_p[i] = q ? q->parms.max_P : 0; | ||
523 | } | ||
524 | NLA_PUT(skb, TCA_GRED_MAX_P, sizeof(max_p), max_p); | ||
525 | |||
512 | parms = nla_nest_start(skb, TCA_GRED_PARMS); | 526 | parms = nla_nest_start(skb, TCA_GRED_PARMS); |
513 | if (parms == NULL) | 527 | if (parms == NULL) |
514 | goto nla_put_failure; | 528 | goto nla_put_failure; |
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 8f5a85bf9d10..ce2256a17d7e 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c | |||
@@ -170,6 +170,7 @@ static void red_destroy(struct Qdisc *sch) | |||
170 | static const struct nla_policy red_policy[TCA_RED_MAX + 1] = { | 170 | static const struct nla_policy red_policy[TCA_RED_MAX + 1] = { |
171 | [TCA_RED_PARMS] = { .len = sizeof(struct tc_red_qopt) }, | 171 | [TCA_RED_PARMS] = { .len = sizeof(struct tc_red_qopt) }, |
172 | [TCA_RED_STAB] = { .len = RED_STAB_SIZE }, | 172 | [TCA_RED_STAB] = { .len = RED_STAB_SIZE }, |
173 | [TCA_RED_MAX_P] = { .type = NLA_U32 }, | ||
173 | }; | 174 | }; |
174 | 175 | ||
175 | static int red_change(struct Qdisc *sch, struct nlattr *opt) | 176 | static int red_change(struct Qdisc *sch, struct nlattr *opt) |
@@ -179,6 +180,7 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt) | |||
179 | struct tc_red_qopt *ctl; | 180 | struct tc_red_qopt *ctl; |
180 | struct Qdisc *child = NULL; | 181 | struct Qdisc *child = NULL; |
181 | int err; | 182 | int err; |
183 | u32 max_P; | ||
182 | 184 | ||
183 | if (opt == NULL) | 185 | if (opt == NULL) |
184 | return -EINVAL; | 186 | return -EINVAL; |
@@ -191,6 +193,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt) | |||
191 | tb[TCA_RED_STAB] == NULL) | 193 | tb[TCA_RED_STAB] == NULL) |
192 | return -EINVAL; | 194 | return -EINVAL; |
193 | 195 | ||
196 | max_P = tb[TCA_RED_MAX_P] ? nla_get_u32(tb[TCA_RED_MAX_P]) : 0; | ||
197 | |||
194 | ctl = nla_data(tb[TCA_RED_PARMS]); | 198 | ctl = nla_data(tb[TCA_RED_PARMS]); |
195 | 199 | ||
196 | if (ctl->limit > 0) { | 200 | if (ctl->limit > 0) { |
@@ -209,8 +213,9 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt) | |||
209 | } | 213 | } |
210 | 214 | ||
211 | red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, | 215 | red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, |
212 | ctl->Plog, ctl->Scell_log, | 216 | ctl->Plog, ctl->Scell_log, |
213 | nla_data(tb[TCA_RED_STAB])); | 217 | nla_data(tb[TCA_RED_STAB]), |
218 | max_P); | ||
214 | 219 | ||
215 | del_timer(&q->adapt_timer); | 220 | del_timer(&q->adapt_timer); |
216 | if (ctl->flags & TC_RED_ADAPTATIVE) | 221 | if (ctl->flags & TC_RED_ADAPTATIVE) |