diff options
author | WANG Cong <xiyou.wangcong@gmail.com> | 2013-12-15 23:15:05 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-12-18 12:52:07 -0500 |
commit | 33be627159913b094bb578e83e9a7fdc66c10208 (patch) | |
tree | 387945e9391082d0b78890b176111a53b8897bf3 /net/sched/cls_api.c | |
parent | d84231d3a2b20bea26327d9b83c8bd8ba55dc68c (diff) |
net_sched: act: use standard struct list_head
Currently actions are chained by a singly linked list,
therefore it is a bit hard to add and remove a specific
entry. Convert it to struct list_head so that in the
latter patch we can remove an action without finding
its head.
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/cls_api.c')
-rw-r--r-- | net/sched/cls_api.c | 54 |
1 files changed, 26 insertions, 28 deletions
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 8e118af90973..3c056d73d394 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c | |||
@@ -500,10 +500,8 @@ out: | |||
500 | void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) | 500 | void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) |
501 | { | 501 | { |
502 | #ifdef CONFIG_NET_CLS_ACT | 502 | #ifdef CONFIG_NET_CLS_ACT |
503 | if (exts->action) { | 503 | tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND); |
504 | tcf_action_destroy(exts->action, TCA_ACT_UNBIND); | 504 | INIT_LIST_HEAD(&exts->actions); |
505 | exts->action = NULL; | ||
506 | } | ||
507 | #endif | 505 | #endif |
508 | } | 506 | } |
509 | EXPORT_SYMBOL(tcf_exts_destroy); | 507 | EXPORT_SYMBOL(tcf_exts_destroy); |
@@ -518,6 +516,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, | |||
518 | { | 516 | { |
519 | struct tc_action *act; | 517 | struct tc_action *act; |
520 | 518 | ||
519 | INIT_LIST_HEAD(&exts->actions); | ||
521 | if (map->police && tb[map->police]) { | 520 | if (map->police && tb[map->police]) { |
522 | act = tcf_action_init_1(net, tb[map->police], rate_tlv, | 521 | act = tcf_action_init_1(net, tb[map->police], rate_tlv, |
523 | "police", TCA_ACT_NOREPLACE, | 522 | "police", TCA_ACT_NOREPLACE, |
@@ -525,16 +524,15 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, | |||
525 | if (IS_ERR(act)) | 524 | if (IS_ERR(act)) |
526 | return PTR_ERR(act); | 525 | return PTR_ERR(act); |
527 | 526 | ||
528 | act->type = TCA_OLD_COMPAT; | 527 | act->type = exts->type = TCA_OLD_COMPAT; |
529 | exts->action = act; | 528 | list_add(&act->list, &exts->actions); |
530 | } else if (map->action && tb[map->action]) { | 529 | } else if (map->action && tb[map->action]) { |
531 | act = tcf_action_init(net, tb[map->action], rate_tlv, | 530 | int err; |
531 | err = tcf_action_init(net, tb[map->action], rate_tlv, | ||
532 | NULL, TCA_ACT_NOREPLACE, | 532 | NULL, TCA_ACT_NOREPLACE, |
533 | TCA_ACT_BIND); | 533 | TCA_ACT_BIND, &exts->actions); |
534 | if (IS_ERR(act)) | 534 | if (err) |
535 | return PTR_ERR(act); | 535 | return err; |
536 | |||
537 | exts->action = act; | ||
538 | } | 536 | } |
539 | } | 537 | } |
540 | #else | 538 | #else |
@@ -551,43 +549,45 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, | |||
551 | struct tcf_exts *src) | 549 | struct tcf_exts *src) |
552 | { | 550 | { |
553 | #ifdef CONFIG_NET_CLS_ACT | 551 | #ifdef CONFIG_NET_CLS_ACT |
554 | if (src->action) { | 552 | if (!list_empty(&src->actions)) { |
555 | struct tc_action *act; | 553 | LIST_HEAD(tmp); |
556 | tcf_tree_lock(tp); | 554 | tcf_tree_lock(tp); |
557 | act = dst->action; | 555 | list_splice_init(&dst->actions, &tmp); |
558 | dst->action = src->action; | 556 | list_splice(&src->actions, &dst->actions); |
559 | tcf_tree_unlock(tp); | 557 | tcf_tree_unlock(tp); |
560 | if (act) | 558 | tcf_action_destroy(&tmp, TCA_ACT_UNBIND); |
561 | tcf_action_destroy(act, TCA_ACT_UNBIND); | ||
562 | } | 559 | } |
563 | #endif | 560 | #endif |
564 | } | 561 | } |
565 | EXPORT_SYMBOL(tcf_exts_change); | 562 | EXPORT_SYMBOL(tcf_exts_change); |
566 | 563 | ||
564 | #define tcf_exts_first_act(ext) \ | ||
565 | list_first_entry(&(exts)->actions, struct tc_action, list) | ||
566 | |||
567 | int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts, | 567 | int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts, |
568 | const struct tcf_ext_map *map) | 568 | const struct tcf_ext_map *map) |
569 | { | 569 | { |
570 | #ifdef CONFIG_NET_CLS_ACT | 570 | #ifdef CONFIG_NET_CLS_ACT |
571 | if (map->action && exts->action) { | 571 | if (map->action && !list_empty(&exts->actions)) { |
572 | /* | 572 | /* |
573 | * again for backward compatible mode - we want | 573 | * again for backward compatible mode - we want |
574 | * to work with both old and new modes of entering | 574 | * to work with both old and new modes of entering |
575 | * tc data even if iproute2 was newer - jhs | 575 | * tc data even if iproute2 was newer - jhs |
576 | */ | 576 | */ |
577 | struct nlattr *nest; | 577 | struct nlattr *nest; |
578 | 578 | if (exts->type != TCA_OLD_COMPAT) { | |
579 | if (exts->action->type != TCA_OLD_COMPAT) { | ||
580 | nest = nla_nest_start(skb, map->action); | 579 | nest = nla_nest_start(skb, map->action); |
581 | if (nest == NULL) | 580 | if (nest == NULL) |
582 | goto nla_put_failure; | 581 | goto nla_put_failure; |
583 | if (tcf_action_dump(skb, exts->action, 0, 0) < 0) | 582 | if (tcf_action_dump(skb, &exts->actions, 0, 0) < 0) |
584 | goto nla_put_failure; | 583 | goto nla_put_failure; |
585 | nla_nest_end(skb, nest); | 584 | nla_nest_end(skb, nest); |
586 | } else if (map->police) { | 585 | } else if (map->police) { |
586 | struct tc_action *act = tcf_exts_first_act(exts); | ||
587 | nest = nla_nest_start(skb, map->police); | 587 | nest = nla_nest_start(skb, map->police); |
588 | if (nest == NULL) | 588 | if (nest == NULL) |
589 | goto nla_put_failure; | 589 | goto nla_put_failure; |
590 | if (tcf_action_dump_old(skb, exts->action, 0, 0) < 0) | 590 | if (tcf_action_dump_old(skb, act, 0, 0) < 0) |
591 | goto nla_put_failure; | 591 | goto nla_put_failure; |
592 | nla_nest_end(skb, nest); | 592 | nla_nest_end(skb, nest); |
593 | } | 593 | } |
@@ -604,13 +604,11 @@ int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts, | |||
604 | const struct tcf_ext_map *map) | 604 | const struct tcf_ext_map *map) |
605 | { | 605 | { |
606 | #ifdef CONFIG_NET_CLS_ACT | 606 | #ifdef CONFIG_NET_CLS_ACT |
607 | if (exts->action) | 607 | struct tc_action *a = tcf_exts_first_act(exts); |
608 | if (tcf_action_copy_stats(skb, exts->action, 1) < 0) | 608 | if (tcf_action_copy_stats(skb, a, 1) < 0) |
609 | goto nla_put_failure; | 609 | return -1; |
610 | #endif | 610 | #endif |
611 | return 0; | 611 | return 0; |
612 | nla_put_failure: __attribute__ ((unused)) | ||
613 | return -1; | ||
614 | } | 612 | } |
615 | EXPORT_SYMBOL(tcf_exts_dump_stats); | 613 | EXPORT_SYMBOL(tcf_exts_dump_stats); |
616 | 614 | ||