diff options
author | Davide Caratti <dcaratti@redhat.com> | 2018-01-22 12:14:32 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-23 19:51:46 -0500 |
commit | 9c5f69bbd75a7db80578782b037629c5f1e59dce (patch) | |
tree | d2c862565b212a36ce9629f328958a4fbbbc956c | |
parent | f6052cf2fc51772ea51e54c795b9ea234834ad9a (diff) |
net/sched: act_csum: don't use spinlock in the fast path
use RCU instead of spin_{,unlock}_bh() to protect concurrent read/write on
act_csum configuration, to reduce the effects of contention in the data
path when multiple readers are present.
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/tc_act/tc_csum.h | 16 | ||||
-rw-r--r-- | net/sched/act_csum.c | 58 |
2 files changed, 59 insertions, 15 deletions
diff --git a/include/net/tc_act/tc_csum.h b/include/net/tc_act/tc_csum.h index 781f3433a0be..9470fd7e4350 100644 --- a/include/net/tc_act/tc_csum.h +++ b/include/net/tc_act/tc_csum.h | |||
@@ -6,10 +6,16 @@ | |||
6 | #include <net/act_api.h> | 6 | #include <net/act_api.h> |
7 | #include <linux/tc_act/tc_csum.h> | 7 | #include <linux/tc_act/tc_csum.h> |
8 | 8 | ||
9 | struct tcf_csum_params { | ||
10 | int action; | ||
11 | u32 update_flags; | ||
12 | struct rcu_head rcu; | ||
13 | }; | ||
14 | |||
9 | struct tcf_csum { | 15 | struct tcf_csum { |
10 | struct tc_action common; | 16 | struct tc_action common; |
11 | 17 | ||
12 | u32 update_flags; | 18 | struct tcf_csum_params __rcu *params; |
13 | }; | 19 | }; |
14 | #define to_tcf_csum(a) ((struct tcf_csum *)a) | 20 | #define to_tcf_csum(a) ((struct tcf_csum *)a) |
15 | 21 | ||
@@ -24,7 +30,13 @@ static inline bool is_tcf_csum(const struct tc_action *a) | |||
24 | 30 | ||
25 | static inline u32 tcf_csum_update_flags(const struct tc_action *a) | 31 | static inline u32 tcf_csum_update_flags(const struct tc_action *a) |
26 | { | 32 | { |
27 | return to_tcf_csum(a)->update_flags; | 33 | u32 update_flags; |
34 | |||
35 | rcu_read_lock(); | ||
36 | update_flags = rcu_dereference(to_tcf_csum(a)->params)->update_flags; | ||
37 | rcu_read_unlock(); | ||
38 | |||
39 | return update_flags; | ||
28 | } | 40 | } |
29 | 41 | ||
30 | #endif /* __NET_TC_CSUM_H */ | 42 | #endif /* __NET_TC_CSUM_H */ |
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index df22da365cd9..b7ba9b06b147 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c | |||
@@ -49,6 +49,7 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla, | |||
49 | int bind) | 49 | int bind) |
50 | { | 50 | { |
51 | struct tc_action_net *tn = net_generic(net, csum_net_id); | 51 | struct tc_action_net *tn = net_generic(net, csum_net_id); |
52 | struct tcf_csum_params *params_old, *params_new; | ||
52 | struct nlattr *tb[TCA_CSUM_MAX + 1]; | 53 | struct nlattr *tb[TCA_CSUM_MAX + 1]; |
53 | struct tc_csum *parm; | 54 | struct tc_csum *parm; |
54 | struct tcf_csum *p; | 55 | struct tcf_csum *p; |
@@ -80,10 +81,21 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla, | |||
80 | } | 81 | } |
81 | 82 | ||
82 | p = to_tcf_csum(*a); | 83 | p = to_tcf_csum(*a); |
83 | spin_lock_bh(&p->tcf_lock); | 84 | ASSERT_RTNL(); |
84 | p->tcf_action = parm->action; | 85 | |
85 | p->update_flags = parm->update_flags; | 86 | params_new = kzalloc(sizeof(*params_new), GFP_KERNEL); |
86 | spin_unlock_bh(&p->tcf_lock); | 87 | if (unlikely(!params_new)) { |
88 | if (ret == ACT_P_CREATED) | ||
89 | tcf_idr_release(*a, bind); | ||
90 | return -ENOMEM; | ||
91 | } | ||
92 | params_old = rtnl_dereference(p->params); | ||
93 | |||
94 | params_new->action = parm->action; | ||
95 | params_new->update_flags = parm->update_flags; | ||
96 | rcu_assign_pointer(p->params, params_new); | ||
97 | if (params_old) | ||
98 | kfree_rcu(params_old, rcu); | ||
87 | 99 | ||
88 | if (ret == ACT_P_CREATED) | 100 | if (ret == ACT_P_CREATED) |
89 | tcf_idr_insert(tn, *a); | 101 | tcf_idr_insert(tn, *a); |
@@ -539,19 +551,21 @@ static int tcf_csum(struct sk_buff *skb, const struct tc_action *a, | |||
539 | struct tcf_result *res) | 551 | struct tcf_result *res) |
540 | { | 552 | { |
541 | struct tcf_csum *p = to_tcf_csum(a); | 553 | struct tcf_csum *p = to_tcf_csum(a); |
542 | int action; | 554 | struct tcf_csum_params *params; |
543 | u32 update_flags; | 555 | u32 update_flags; |
556 | int action; | ||
557 | |||
558 | rcu_read_lock(); | ||
559 | params = rcu_dereference(p->params); | ||
544 | 560 | ||
545 | tcf_lastuse_update(&p->tcf_tm); | 561 | tcf_lastuse_update(&p->tcf_tm); |
546 | bstats_cpu_update(this_cpu_ptr(p->common.cpu_bstats), skb); | 562 | bstats_cpu_update(this_cpu_ptr(p->common.cpu_bstats), skb); |
547 | spin_lock(&p->tcf_lock); | ||
548 | action = p->tcf_action; | ||
549 | update_flags = p->update_flags; | ||
550 | spin_unlock(&p->tcf_lock); | ||
551 | 563 | ||
564 | action = params->action; | ||
552 | if (unlikely(action == TC_ACT_SHOT)) | 565 | if (unlikely(action == TC_ACT_SHOT)) |
553 | goto drop; | 566 | goto drop_stats; |
554 | 567 | ||
568 | update_flags = params->update_flags; | ||
555 | switch (tc_skb_protocol(skb)) { | 569 | switch (tc_skb_protocol(skb)) { |
556 | case cpu_to_be16(ETH_P_IP): | 570 | case cpu_to_be16(ETH_P_IP): |
557 | if (!tcf_csum_ipv4(skb, update_flags)) | 571 | if (!tcf_csum_ipv4(skb, update_flags)) |
@@ -563,11 +577,16 @@ static int tcf_csum(struct sk_buff *skb, const struct tc_action *a, | |||
563 | break; | 577 | break; |
564 | } | 578 | } |
565 | 579 | ||
580 | unlock: | ||
581 | rcu_read_unlock(); | ||
566 | return action; | 582 | return action; |
567 | 583 | ||
568 | drop: | 584 | drop: |
585 | action = TC_ACT_SHOT; | ||
586 | |||
587 | drop_stats: | ||
569 | qstats_drop_inc(this_cpu_ptr(p->common.cpu_qstats)); | 588 | qstats_drop_inc(this_cpu_ptr(p->common.cpu_qstats)); |
570 | return TC_ACT_SHOT; | 589 | goto unlock; |
571 | } | 590 | } |
572 | 591 | ||
573 | static int tcf_csum_dump(struct sk_buff *skb, struct tc_action *a, int bind, | 592 | static int tcf_csum_dump(struct sk_buff *skb, struct tc_action *a, int bind, |
@@ -575,15 +594,18 @@ static int tcf_csum_dump(struct sk_buff *skb, struct tc_action *a, int bind, | |||
575 | { | 594 | { |
576 | unsigned char *b = skb_tail_pointer(skb); | 595 | unsigned char *b = skb_tail_pointer(skb); |
577 | struct tcf_csum *p = to_tcf_csum(a); | 596 | struct tcf_csum *p = to_tcf_csum(a); |
597 | struct tcf_csum_params *params; | ||
578 | struct tc_csum opt = { | 598 | struct tc_csum opt = { |
579 | .update_flags = p->update_flags, | ||
580 | .index = p->tcf_index, | 599 | .index = p->tcf_index, |
581 | .action = p->tcf_action, | ||
582 | .refcnt = p->tcf_refcnt - ref, | 600 | .refcnt = p->tcf_refcnt - ref, |
583 | .bindcnt = p->tcf_bindcnt - bind, | 601 | .bindcnt = p->tcf_bindcnt - bind, |
584 | }; | 602 | }; |
585 | struct tcf_t t; | 603 | struct tcf_t t; |
586 | 604 | ||
605 | params = rtnl_dereference(p->params); | ||
606 | opt.action = params->action; | ||
607 | opt.update_flags = params->update_flags; | ||
608 | |||
587 | if (nla_put(skb, TCA_CSUM_PARMS, sizeof(opt), &opt)) | 609 | if (nla_put(skb, TCA_CSUM_PARMS, sizeof(opt), &opt)) |
588 | goto nla_put_failure; | 610 | goto nla_put_failure; |
589 | 611 | ||
@@ -598,6 +620,15 @@ nla_put_failure: | |||
598 | return -1; | 620 | return -1; |
599 | } | 621 | } |
600 | 622 | ||
623 | static void tcf_csum_cleanup(struct tc_action *a) | ||
624 | { | ||
625 | struct tcf_csum *p = to_tcf_csum(a); | ||
626 | struct tcf_csum_params *params; | ||
627 | |||
628 | params = rcu_dereference_protected(p->params, 1); | ||
629 | kfree_rcu(params, rcu); | ||
630 | } | ||
631 | |||
601 | static int tcf_csum_walker(struct net *net, struct sk_buff *skb, | 632 | static int tcf_csum_walker(struct net *net, struct sk_buff *skb, |
602 | struct netlink_callback *cb, int type, | 633 | struct netlink_callback *cb, int type, |
603 | const struct tc_action_ops *ops) | 634 | const struct tc_action_ops *ops) |
@@ -621,6 +652,7 @@ static struct tc_action_ops act_csum_ops = { | |||
621 | .act = tcf_csum, | 652 | .act = tcf_csum, |
622 | .dump = tcf_csum_dump, | 653 | .dump = tcf_csum_dump, |
623 | .init = tcf_csum_init, | 654 | .init = tcf_csum_init, |
655 | .cleanup = tcf_csum_cleanup, | ||
624 | .walk = tcf_csum_walker, | 656 | .walk = tcf_csum_walker, |
625 | .lookup = tcf_csum_search, | 657 | .lookup = tcf_csum_search, |
626 | .size = sizeof(struct tcf_csum), | 658 | .size = sizeof(struct tcf_csum), |