aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavide Caratti <dcaratti@redhat.com>2018-01-22 12:14:32 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-23 19:51:46 -0500
commit9c5f69bbd75a7db80578782b037629c5f1e59dce (patch)
treed2c862565b212a36ce9629f328958a4fbbbc956c
parentf6052cf2fc51772ea51e54c795b9ea234834ad9a (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.h16
-rw-r--r--net/sched/act_csum.c58
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
9struct tcf_csum_params {
10 int action;
11 u32 update_flags;
12 struct rcu_head rcu;
13};
14
9struct tcf_csum { 15struct 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
25static inline u32 tcf_csum_update_flags(const struct tc_action *a) 31static 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
580unlock:
581 rcu_read_unlock();
566 return action; 582 return action;
567 583
568drop: 584drop:
585 action = TC_ACT_SHOT;
586
587drop_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
573static int tcf_csum_dump(struct sk_buff *skb, struct tc_action *a, int bind, 592static 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
623static 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
601static int tcf_csum_walker(struct net *net, struct sk_buff *skb, 632static 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),