diff options
author | Thomas Graf <tgraf@suug.ch> | 2005-11-05 15:14:13 -0500 |
---|---|---|
committer | Thomas Graf <tgr@axs.localdomain> | 2005-11-05 16:02:26 -0500 |
commit | 6639607ed9deaed9ab3a1cc588f0288891ece2ac (patch) | |
tree | 370e98cbb4143cf397d5b3cf2a3a8ddf66a13cf1 /net/sched | |
parent | e06368221c204d7b5f1ba37d047170f9a0dd359d (diff) |
[PKT_SCHED]: GRED: Use a central table definition change procedure
Introduces a function gred_change_table_def() acting as a central
point to change the table definition.
Adds missing validations for table definition: MAX_DPs > DPs > 0
and def_DP < DPs thus fixing possible invalid memory reference
oopses. Only root could do it but having a typo crashing the
machine is a bit hard.
Adds missing locking while changing the table definition, the
operation of changing the number of DPs and removing shadowed VQs
may not be interrupted by a dequeue.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_gred.c | 113 |
1 files changed, 61 insertions, 52 deletions
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index a1369550ce78..fdc20ced52ef 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c | |||
@@ -378,43 +378,72 @@ static void gred_reset(struct Qdisc* sch) | |||
378 | } | 378 | } |
379 | } | 379 | } |
380 | 380 | ||
381 | static int gred_change(struct Qdisc *sch, struct rtattr *opt) | 381 | static inline void gred_destroy_vq(struct gred_sched_data *q) |
382 | { | ||
383 | kfree(q); | ||
384 | } | ||
385 | |||
386 | static inline int gred_change_table_def(struct Qdisc *sch, struct rtattr *dps) | ||
382 | { | 387 | { |
383 | struct gred_sched *table = qdisc_priv(sch); | 388 | struct gred_sched *table = qdisc_priv(sch); |
384 | struct gred_sched_data *q; | ||
385 | struct tc_gred_qopt *ctl; | ||
386 | struct tc_gred_sopt *sopt; | 389 | struct tc_gred_sopt *sopt; |
387 | struct rtattr *tb[TCA_GRED_STAB]; | 390 | int i; |
388 | struct rtattr *tb2[TCA_GRED_DPS]; | ||
389 | 391 | ||
390 | if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, opt)) | 392 | if (dps == NULL || RTA_PAYLOAD(dps) < sizeof(*sopt)) |
391 | return -EINVAL; | 393 | return -EINVAL; |
392 | 394 | ||
393 | if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0) { | 395 | sopt = RTA_DATA(dps); |
394 | rtattr_parse_nested(tb2, TCA_GRED_DPS, opt); | ||
395 | 396 | ||
396 | if (tb2[TCA_GRED_DPS-1] == 0) | 397 | if (sopt->DPs > MAX_DPs || sopt->DPs == 0 || sopt->def_DP >= sopt->DPs) |
397 | return -EINVAL; | 398 | return -EINVAL; |
398 | 399 | ||
399 | sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); | 400 | sch_tree_lock(sch); |
400 | table->DPs=sopt->DPs; | 401 | table->DPs = sopt->DPs; |
401 | table->def=sopt->def_DP; | 402 | table->def = sopt->def_DP; |
402 | 403 | ||
403 | if (sopt->grio) { | 404 | /* |
404 | gred_enable_rio_mode(table); | 405 | * Every entry point to GRED is synchronized with the above code |
405 | gred_disable_wred_mode(table); | 406 | * and the DP is checked against DPs, i.e. shadowed VQs can no |
406 | if (gred_wred_mode_check(sch)) | 407 | * longer be found so we can unlock right here. |
407 | gred_enable_wred_mode(table); | 408 | */ |
408 | } else { | 409 | sch_tree_unlock(sch); |
409 | gred_disable_rio_mode(table); | ||
410 | gred_disable_wred_mode(table); | ||
411 | } | ||
412 | 410 | ||
413 | table->initd=0; | 411 | if (sopt->grio) { |
414 | /* probably need to clear all the table DP entries as well */ | 412 | gred_enable_rio_mode(table); |
415 | return 0; | 413 | gred_disable_wred_mode(table); |
416 | } | 414 | if (gred_wred_mode_check(sch)) |
415 | gred_enable_wred_mode(table); | ||
416 | } else { | ||
417 | gred_disable_rio_mode(table); | ||
418 | gred_disable_wred_mode(table); | ||
419 | } | ||
420 | |||
421 | for (i = table->DPs; i < MAX_DPs; i++) { | ||
422 | if (table->tab[i]) { | ||
423 | printk(KERN_WARNING "GRED: Warning: Destroying " | ||
424 | "shadowed VQ 0x%x\n", i); | ||
425 | gred_destroy_vq(table->tab[i]); | ||
426 | table->tab[i] = NULL; | ||
427 | } | ||
428 | } | ||
417 | 429 | ||
430 | table->initd = 0; | ||
431 | |||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static int gred_change(struct Qdisc *sch, struct rtattr *opt) | ||
436 | { | ||
437 | struct gred_sched *table = qdisc_priv(sch); | ||
438 | struct gred_sched_data *q; | ||
439 | struct tc_gred_qopt *ctl; | ||
440 | struct rtattr *tb[TCA_GRED_STAB]; | ||
441 | |||
442 | if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, opt)) | ||
443 | return -EINVAL; | ||
444 | |||
445 | if (tb[TCA_GRED_PARMS-1] == NULL && tb[TCA_GRED_STAB-1] == NULL) | ||
446 | return gred_change_table_def(sch, tb[TCA_GRED_DPS-1]); | ||
418 | 447 | ||
419 | if (!table->DPs || tb[TCA_GRED_PARMS-1] == 0 || tb[TCA_GRED_STAB-1] == 0 || | 448 | if (!table->DPs || tb[TCA_GRED_PARMS-1] == 0 || tb[TCA_GRED_STAB-1] == 0 || |
420 | RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) || | 449 | RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) || |
@@ -526,35 +555,15 @@ static int gred_change(struct Qdisc *sch, struct rtattr *opt) | |||
526 | 555 | ||
527 | static int gred_init(struct Qdisc *sch, struct rtattr *opt) | 556 | static int gred_init(struct Qdisc *sch, struct rtattr *opt) |
528 | { | 557 | { |
529 | struct gred_sched *table = qdisc_priv(sch); | 558 | struct rtattr *tb[TCA_GRED_MAX]; |
530 | struct tc_gred_sopt *sopt; | ||
531 | struct rtattr *tb[TCA_GRED_STAB]; | ||
532 | struct rtattr *tb2[TCA_GRED_DPS]; | ||
533 | 559 | ||
534 | if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, opt)) | 560 | if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_MAX, opt)) |
535 | return -EINVAL; | 561 | return -EINVAL; |
536 | 562 | ||
537 | if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0) { | 563 | if (tb[TCA_GRED_PARMS-1] || tb[TCA_GRED_STAB-1]) |
538 | rtattr_parse_nested(tb2, TCA_GRED_DPS, opt); | 564 | return -EINVAL; |
539 | |||
540 | if (tb2[TCA_GRED_DPS-1] == 0) | ||
541 | return -EINVAL; | ||
542 | |||
543 | sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); | ||
544 | table->DPs=sopt->DPs; | ||
545 | table->def=sopt->def_DP; | ||
546 | |||
547 | if (sopt->grio) | ||
548 | gred_enable_rio_mode(table); | ||
549 | else | ||
550 | gred_disable_rio_mode(table); | ||
551 | |||
552 | table->initd=0; | ||
553 | return 0; | ||
554 | } | ||
555 | 565 | ||
556 | DPRINTK("\n GRED_INIT error!\n"); | 566 | return gred_change_table_def(sch, tb[TCA_GRED_DPS-1]); |
557 | return -EINVAL; | ||
558 | } | 567 | } |
559 | 568 | ||
560 | static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) | 569 | static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) |
@@ -641,7 +650,7 @@ static void gred_destroy(struct Qdisc *sch) | |||
641 | 650 | ||
642 | for (i = 0;i < table->DPs; i++) { | 651 | for (i = 0;i < table->DPs; i++) { |
643 | if (table->tab[i]) | 652 | if (table->tab[i]) |
644 | kfree(table->tab[i]); | 653 | gred_destroy_vq(table->tab[i]); |
645 | } | 654 | } |
646 | } | 655 | } |
647 | 656 | ||