diff options
Diffstat (limited to 'net/sched/cls_u32.c')
-rw-r--r-- | net/sched/cls_u32.c | 103 |
1 files changed, 53 insertions, 50 deletions
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index c39008209164..e8a775689123 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c | |||
@@ -460,10 +460,20 @@ static u32 gen_new_kid(struct tc_u_hnode *ht, u32 handle) | |||
460 | return handle|(i>0xFFF ? 0xFFF : i); | 460 | return handle|(i>0xFFF ? 0xFFF : i); |
461 | } | 461 | } |
462 | 462 | ||
463 | static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = { | ||
464 | [TCA_U32_CLASSID] = { .type = NLA_U32 }, | ||
465 | [TCA_U32_HASH] = { .type = NLA_U32 }, | ||
466 | [TCA_U32_LINK] = { .type = NLA_U32 }, | ||
467 | [TCA_U32_DIVISOR] = { .type = NLA_U32 }, | ||
468 | [TCA_U32_SEL] = { .len = sizeof(struct tc_u32_sel) }, | ||
469 | [TCA_U32_INDEV] = { .type = NLA_STRING, .len = IFNAMSIZ }, | ||
470 | [TCA_U32_MARK] = { .len = sizeof(struct tc_u32_mark) }, | ||
471 | }; | ||
472 | |||
463 | static int u32_set_parms(struct tcf_proto *tp, unsigned long base, | 473 | static int u32_set_parms(struct tcf_proto *tp, unsigned long base, |
464 | struct tc_u_hnode *ht, | 474 | struct tc_u_hnode *ht, |
465 | struct tc_u_knode *n, struct rtattr **tb, | 475 | struct tc_u_knode *n, struct nlattr **tb, |
466 | struct rtattr *est) | 476 | struct nlattr *est) |
467 | { | 477 | { |
468 | int err; | 478 | int err; |
469 | struct tcf_exts e; | 479 | struct tcf_exts e; |
@@ -473,8 +483,8 @@ static int u32_set_parms(struct tcf_proto *tp, unsigned long base, | |||
473 | return err; | 483 | return err; |
474 | 484 | ||
475 | err = -EINVAL; | 485 | err = -EINVAL; |
476 | if (tb[TCA_U32_LINK-1]) { | 486 | if (tb[TCA_U32_LINK]) { |
477 | u32 handle = *(u32*)RTA_DATA(tb[TCA_U32_LINK-1]); | 487 | u32 handle = nla_get_u32(tb[TCA_U32_LINK]); |
478 | struct tc_u_hnode *ht_down = NULL; | 488 | struct tc_u_hnode *ht_down = NULL; |
479 | 489 | ||
480 | if (TC_U32_KEY(handle)) | 490 | if (TC_U32_KEY(handle)) |
@@ -495,14 +505,14 @@ static int u32_set_parms(struct tcf_proto *tp, unsigned long base, | |||
495 | if (ht_down) | 505 | if (ht_down) |
496 | ht_down->refcnt--; | 506 | ht_down->refcnt--; |
497 | } | 507 | } |
498 | if (tb[TCA_U32_CLASSID-1]) { | 508 | if (tb[TCA_U32_CLASSID]) { |
499 | n->res.classid = *(u32*)RTA_DATA(tb[TCA_U32_CLASSID-1]); | 509 | n->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]); |
500 | tcf_bind_filter(tp, &n->res, base); | 510 | tcf_bind_filter(tp, &n->res, base); |
501 | } | 511 | } |
502 | 512 | ||
503 | #ifdef CONFIG_NET_CLS_IND | 513 | #ifdef CONFIG_NET_CLS_IND |
504 | if (tb[TCA_U32_INDEV-1]) { | 514 | if (tb[TCA_U32_INDEV]) { |
505 | err = tcf_change_indev(tp, n->indev, tb[TCA_U32_INDEV-1]); | 515 | err = tcf_change_indev(tp, n->indev, tb[TCA_U32_INDEV]); |
506 | if (err < 0) | 516 | if (err < 0) |
507 | goto errout; | 517 | goto errout; |
508 | } | 518 | } |
@@ -516,33 +526,34 @@ errout: | |||
516 | } | 526 | } |
517 | 527 | ||
518 | static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, | 528 | static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, |
519 | struct rtattr **tca, | 529 | struct nlattr **tca, |
520 | unsigned long *arg) | 530 | unsigned long *arg) |
521 | { | 531 | { |
522 | struct tc_u_common *tp_c = tp->data; | 532 | struct tc_u_common *tp_c = tp->data; |
523 | struct tc_u_hnode *ht; | 533 | struct tc_u_hnode *ht; |
524 | struct tc_u_knode *n; | 534 | struct tc_u_knode *n; |
525 | struct tc_u32_sel *s; | 535 | struct tc_u32_sel *s; |
526 | struct rtattr *opt = tca[TCA_OPTIONS-1]; | 536 | struct nlattr *opt = tca[TCA_OPTIONS]; |
527 | struct rtattr *tb[TCA_U32_MAX]; | 537 | struct nlattr *tb[TCA_U32_MAX + 1]; |
528 | u32 htid; | 538 | u32 htid; |
529 | int err; | 539 | int err; |
530 | 540 | ||
531 | if (opt == NULL) | 541 | if (opt == NULL) |
532 | return handle ? -EINVAL : 0; | 542 | return handle ? -EINVAL : 0; |
533 | 543 | ||
534 | if (rtattr_parse_nested(tb, TCA_U32_MAX, opt) < 0) | 544 | err = nla_parse_nested(tb, TCA_U32_MAX, opt, u32_policy); |
535 | return -EINVAL; | 545 | if (err < 0) |
546 | return err; | ||
536 | 547 | ||
537 | if ((n = (struct tc_u_knode*)*arg) != NULL) { | 548 | if ((n = (struct tc_u_knode*)*arg) != NULL) { |
538 | if (TC_U32_KEY(n->handle) == 0) | 549 | if (TC_U32_KEY(n->handle) == 0) |
539 | return -EINVAL; | 550 | return -EINVAL; |
540 | 551 | ||
541 | return u32_set_parms(tp, base, n->ht_up, n, tb, tca[TCA_RATE-1]); | 552 | return u32_set_parms(tp, base, n->ht_up, n, tb, tca[TCA_RATE]); |
542 | } | 553 | } |
543 | 554 | ||
544 | if (tb[TCA_U32_DIVISOR-1]) { | 555 | if (tb[TCA_U32_DIVISOR]) { |
545 | unsigned divisor = *(unsigned*)RTA_DATA(tb[TCA_U32_DIVISOR-1]); | 556 | unsigned divisor = nla_get_u32(tb[TCA_U32_DIVISOR]); |
546 | 557 | ||
547 | if (--divisor > 0x100) | 558 | if (--divisor > 0x100) |
548 | return -EINVAL; | 559 | return -EINVAL; |
@@ -567,8 +578,8 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, | |||
567 | return 0; | 578 | return 0; |
568 | } | 579 | } |
569 | 580 | ||
570 | if (tb[TCA_U32_HASH-1]) { | 581 | if (tb[TCA_U32_HASH]) { |
571 | htid = *(unsigned*)RTA_DATA(tb[TCA_U32_HASH-1]); | 582 | htid = nla_get_u32(tb[TCA_U32_HASH]); |
572 | if (TC_U32_HTID(htid) == TC_U32_ROOT) { | 583 | if (TC_U32_HTID(htid) == TC_U32_ROOT) { |
573 | ht = tp->root; | 584 | ht = tp->root; |
574 | htid = ht->handle; | 585 | htid = ht->handle; |
@@ -592,11 +603,10 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, | |||
592 | } else | 603 | } else |
593 | handle = gen_new_kid(ht, htid); | 604 | handle = gen_new_kid(ht, htid); |
594 | 605 | ||
595 | if (tb[TCA_U32_SEL-1] == NULL || | 606 | if (tb[TCA_U32_SEL] == NULL) |
596 | RTA_PAYLOAD(tb[TCA_U32_SEL-1]) < sizeof(struct tc_u32_sel)) | ||
597 | return -EINVAL; | 607 | return -EINVAL; |
598 | 608 | ||
599 | s = RTA_DATA(tb[TCA_U32_SEL-1]); | 609 | s = nla_data(tb[TCA_U32_SEL]); |
600 | 610 | ||
601 | n = kzalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key), GFP_KERNEL); | 611 | n = kzalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key), GFP_KERNEL); |
602 | if (n == NULL) | 612 | if (n == NULL) |
@@ -616,23 +626,16 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, | |||
616 | n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; | 626 | n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; |
617 | 627 | ||
618 | #ifdef CONFIG_CLS_U32_MARK | 628 | #ifdef CONFIG_CLS_U32_MARK |
619 | if (tb[TCA_U32_MARK-1]) { | 629 | if (tb[TCA_U32_MARK]) { |
620 | struct tc_u32_mark *mark; | 630 | struct tc_u32_mark *mark; |
621 | 631 | ||
622 | if (RTA_PAYLOAD(tb[TCA_U32_MARK-1]) < sizeof(struct tc_u32_mark)) { | 632 | mark = nla_data(tb[TCA_U32_MARK]); |
623 | #ifdef CONFIG_CLS_U32_PERF | ||
624 | kfree(n->pf); | ||
625 | #endif | ||
626 | kfree(n); | ||
627 | return -EINVAL; | ||
628 | } | ||
629 | mark = RTA_DATA(tb[TCA_U32_MARK-1]); | ||
630 | memcpy(&n->mark, mark, sizeof(struct tc_u32_mark)); | 633 | memcpy(&n->mark, mark, sizeof(struct tc_u32_mark)); |
631 | n->mark.success = 0; | 634 | n->mark.success = 0; |
632 | } | 635 | } |
633 | #endif | 636 | #endif |
634 | 637 | ||
635 | err = u32_set_parms(tp, base, ht, n, tb, tca[TCA_RATE-1]); | 638 | err = u32_set_parms(tp, base, ht, n, tb, tca[TCA_RATE]); |
636 | if (err == 0) { | 639 | if (err == 0) { |
637 | struct tc_u_knode **ins; | 640 | struct tc_u_knode **ins; |
638 | for (ins = &ht->ht[TC_U32_HASH(handle)]; *ins; ins = &(*ins)->next) | 641 | for (ins = &ht->ht[TC_U32_HASH(handle)]; *ins; ins = &(*ins)->next) |
@@ -693,66 +696,66 @@ static int u32_dump(struct tcf_proto *tp, unsigned long fh, | |||
693 | struct sk_buff *skb, struct tcmsg *t) | 696 | struct sk_buff *skb, struct tcmsg *t) |
694 | { | 697 | { |
695 | struct tc_u_knode *n = (struct tc_u_knode*)fh; | 698 | struct tc_u_knode *n = (struct tc_u_knode*)fh; |
696 | unsigned char *b = skb_tail_pointer(skb); | 699 | struct nlattr *nest; |
697 | struct rtattr *rta; | ||
698 | 700 | ||
699 | if (n == NULL) | 701 | if (n == NULL) |
700 | return skb->len; | 702 | return skb->len; |
701 | 703 | ||
702 | t->tcm_handle = n->handle; | 704 | t->tcm_handle = n->handle; |
703 | 705 | ||
704 | rta = (struct rtattr*)b; | 706 | nest = nla_nest_start(skb, TCA_OPTIONS); |
705 | RTA_PUT(skb, TCA_OPTIONS, 0, NULL); | 707 | if (nest == NULL) |
708 | goto nla_put_failure; | ||
706 | 709 | ||
707 | if (TC_U32_KEY(n->handle) == 0) { | 710 | if (TC_U32_KEY(n->handle) == 0) { |
708 | struct tc_u_hnode *ht = (struct tc_u_hnode*)fh; | 711 | struct tc_u_hnode *ht = (struct tc_u_hnode*)fh; |
709 | u32 divisor = ht->divisor+1; | 712 | u32 divisor = ht->divisor+1; |
710 | RTA_PUT(skb, TCA_U32_DIVISOR, 4, &divisor); | 713 | NLA_PUT_U32(skb, TCA_U32_DIVISOR, divisor); |
711 | } else { | 714 | } else { |
712 | RTA_PUT(skb, TCA_U32_SEL, | 715 | NLA_PUT(skb, TCA_U32_SEL, |
713 | sizeof(n->sel) + n->sel.nkeys*sizeof(struct tc_u32_key), | 716 | sizeof(n->sel) + n->sel.nkeys*sizeof(struct tc_u32_key), |
714 | &n->sel); | 717 | &n->sel); |
715 | if (n->ht_up) { | 718 | if (n->ht_up) { |
716 | u32 htid = n->handle & 0xFFFFF000; | 719 | u32 htid = n->handle & 0xFFFFF000; |
717 | RTA_PUT(skb, TCA_U32_HASH, 4, &htid); | 720 | NLA_PUT_U32(skb, TCA_U32_HASH, htid); |
718 | } | 721 | } |
719 | if (n->res.classid) | 722 | if (n->res.classid) |
720 | RTA_PUT(skb, TCA_U32_CLASSID, 4, &n->res.classid); | 723 | NLA_PUT_U32(skb, TCA_U32_CLASSID, n->res.classid); |
721 | if (n->ht_down) | 724 | if (n->ht_down) |
722 | RTA_PUT(skb, TCA_U32_LINK, 4, &n->ht_down->handle); | 725 | NLA_PUT_U32(skb, TCA_U32_LINK, n->ht_down->handle); |
723 | 726 | ||
724 | #ifdef CONFIG_CLS_U32_MARK | 727 | #ifdef CONFIG_CLS_U32_MARK |
725 | if (n->mark.val || n->mark.mask) | 728 | if (n->mark.val || n->mark.mask) |
726 | RTA_PUT(skb, TCA_U32_MARK, sizeof(n->mark), &n->mark); | 729 | NLA_PUT(skb, TCA_U32_MARK, sizeof(n->mark), &n->mark); |
727 | #endif | 730 | #endif |
728 | 731 | ||
729 | if (tcf_exts_dump(skb, &n->exts, &u32_ext_map) < 0) | 732 | if (tcf_exts_dump(skb, &n->exts, &u32_ext_map) < 0) |
730 | goto rtattr_failure; | 733 | goto nla_put_failure; |
731 | 734 | ||
732 | #ifdef CONFIG_NET_CLS_IND | 735 | #ifdef CONFIG_NET_CLS_IND |
733 | if(strlen(n->indev)) | 736 | if(strlen(n->indev)) |
734 | RTA_PUT(skb, TCA_U32_INDEV, IFNAMSIZ, n->indev); | 737 | NLA_PUT_STRING(skb, TCA_U32_INDEV, n->indev); |
735 | #endif | 738 | #endif |
736 | #ifdef CONFIG_CLS_U32_PERF | 739 | #ifdef CONFIG_CLS_U32_PERF |
737 | RTA_PUT(skb, TCA_U32_PCNT, | 740 | NLA_PUT(skb, TCA_U32_PCNT, |
738 | sizeof(struct tc_u32_pcnt) + n->sel.nkeys*sizeof(u64), | 741 | sizeof(struct tc_u32_pcnt) + n->sel.nkeys*sizeof(u64), |
739 | n->pf); | 742 | n->pf); |
740 | #endif | 743 | #endif |
741 | } | 744 | } |
742 | 745 | ||
743 | rta->rta_len = skb_tail_pointer(skb) - b; | 746 | nla_nest_end(skb, nest); |
747 | |||
744 | if (TC_U32_KEY(n->handle)) | 748 | if (TC_U32_KEY(n->handle)) |
745 | if (tcf_exts_dump_stats(skb, &n->exts, &u32_ext_map) < 0) | 749 | if (tcf_exts_dump_stats(skb, &n->exts, &u32_ext_map) < 0) |
746 | goto rtattr_failure; | 750 | goto nla_put_failure; |
747 | return skb->len; | 751 | return skb->len; |
748 | 752 | ||
749 | rtattr_failure: | 753 | nla_put_failure: |
750 | nlmsg_trim(skb, b); | 754 | nla_nest_cancel(skb, nest); |
751 | return -1; | 755 | return -1; |
752 | } | 756 | } |
753 | 757 | ||
754 | static struct tcf_proto_ops cls_u32_ops = { | 758 | static struct tcf_proto_ops cls_u32_ops __read_mostly = { |
755 | .next = NULL, | ||
756 | .kind = "u32", | 759 | .kind = "u32", |
757 | .classify = u32_classify, | 760 | .classify = u32_classify, |
758 | .init = u32_init, | 761 | .init = u32_init, |