Re: [PATCH net-next v4 3/3] net sched act_vlan: VLAN action rewrite to use RCU lock/unlock and update

2017-11-01 Thread Simon Horman
On Tue, Oct 31, 2017 at 02:17:00PM -0400, Manish Kurup wrote:
> Using a spinlock in the VLAN action causes performance issues when the VLAN
> action is used on multiple cores. Rewrote the VLAN action to use RCU read
> locking for reads and updates instead.
> 
> Acked-by: Jamal Hadi Salim 
> Acked-by: Jiri Pirko 
> Signed-off-by: Manish Kurup 
> ---
>  include/net/tc_act/tc_vlan.h | 46 +--
>  net/sched/act_vlan.c | 65 
> 
>  2 files changed, 78 insertions(+), 33 deletions(-)
> 
> diff --git a/include/net/tc_act/tc_vlan.h b/include/net/tc_act/tc_vlan.h
> index c2090df..22ae260 100644
> --- a/include/net/tc_act/tc_vlan.h
> +++ b/include/net/tc_act/tc_vlan.h
> @@ -13,12 +13,17 @@
>  #include 
>  #include 
>  
> +struct tcf_vlan_params {
> + int   tcfv_action;
> + u16   tcfv_push_vid;
> + __be16tcfv_push_proto;
> + u8tcfv_push_prio;
> + struct rcu_head   rcu;
> +};
> +
>  struct tcf_vlan {
>   struct tc_actioncommon;
> - int tcfv_action;
> - u16 tcfv_push_vid;
> - __be16  tcfv_push_proto;
> - u8  tcfv_push_prio;
> + struct tcf_vlan_params __rcu *vlan_p;
>  };
>  #define to_vlan(a) ((struct tcf_vlan *)a)
>  
> @@ -33,22 +38,45 @@ static inline bool is_tcf_vlan(const struct tc_action *a)
>  
>  static inline u32 tcf_vlan_action(const struct tc_action *a)
>  {
> - return to_vlan(a)->tcfv_action;
> + u32 tcfv_action;
> +
> + rcu_read_lock();
> + tcfv_action = rcu_dereference(to_vlan(a)->vlan_p)->tcfv_action;
> + rcu_read_unlock();
> +
> + return tcfv_action;
>  }
>  
>  static inline u16 tcf_vlan_push_vid(const struct tc_action *a)
>  {
> - return to_vlan(a)->tcfv_push_vid;
> + u16 tcfv_push_vid;
> +
> + rcu_read_lock();
> + tcfv_push_vid = rcu_dereference(to_vlan(a)->vlan_p)->tcfv_push_vid;
> + rcu_read_unlock();
> +
> + return tcfv_push_vid;
>  }
>  
>  static inline __be16 tcf_vlan_push_proto(const struct tc_action *a)
>  {
> - return to_vlan(a)->tcfv_push_proto;
> + __be16 tcfv_push_proto;
> +
> + rcu_read_lock();
> + tcfv_push_proto = rcu_dereference(to_vlan(a)->vlan_p)->tcfv_push_proto;
> + rcu_read_unlock();
> +
> + return tcfv_push_proto;
>  }
>  
>  static inline u8 tcf_vlan_push_prio(const struct tc_action *a)
>  {
> - return to_vlan(a)->tcfv_push_prio;
> -}
> + u8 tcfv_push_prio;
>  
> + rcu_read_lock();
> + tcfv_push_prio = rcu_dereference(to_vlan(a)->vlan_p)->tcfv_push_prio;
> + rcu_read_unlock();
> +
> + return tcfv_push_prio;
> +}
>  #endif /* __NET_TC_VLAN_H */
> diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
> index b093bad..7f461f9 100644
> --- a/net/sched/act_vlan.c
> +++ b/net/sched/act_vlan.c
> @@ -26,6 +26,7 @@ static int tcf_vlan(struct sk_buff *skb, const struct 
> tc_action *a,
>   struct tcf_result *res)
>  {
>   struct tcf_vlan *v = to_vlan(a);
> + struct tcf_vlan_params *p;
>   int action;
>   int err;
>   u16 tci;
> @@ -33,24 +34,27 @@ static int tcf_vlan(struct sk_buff *skb, const struct 
> tc_action *a,
>   tcf_lastuse_update(>tcf_tm);
>   bstats_cpu_update(this_cpu_ptr(v->common.cpu_bstats), skb);
>  
> - spin_lock(>tcf_lock);
> - action = v->tcf_action;
> -
>   /* Ensure 'data' points at mac_header prior calling vlan manipulating
>* functions.
>*/
>   if (skb_at_tc_ingress(skb))
>   skb_push_rcsum(skb, skb->mac_len);
>  
> - switch (v->tcfv_action) {
> + rcu_read_lock();
> +
> + action = READ_ONCE(v->tcf_action);
> +
> + p = rcu_dereference(v->vlan_p);
> +
> + switch (p->tcfv_action) {

Its not clear to me why v->tcfv_action is changed to p->tcfv_action here.

>   case TCA_VLAN_ACT_POP:
>   err = skb_vlan_pop(skb);
>   if (err)
>   goto drop;
>   break;
>   case TCA_VLAN_ACT_PUSH:
> - err = skb_vlan_push(skb, v->tcfv_push_proto, v->tcfv_push_vid |
> - (v->tcfv_push_prio << VLAN_PRIO_SHIFT));
> + err = skb_vlan_push(skb, p->tcfv_push_proto, p->tcfv_push_vid |
> + (p->tcfv_push_prio << VLAN_PRIO_SHIFT));
>   if (err)
>   goto drop;
>   break;
> @@ -69,14 +73,14 @@ static int tcf_vlan(struct sk_buff *skb, const struct 
> tc_action *a,
>   goto drop;
>   }
>   /* replace the vid */
> - tci = (tci & ~VLAN_VID_MASK) | v->tcfv_push_vid;
> + tci = (tci & ~VLAN_VID_MASK) | p->tcfv_push_vid;
>   /* replace prio bits, if tcfv_push_prio specified */
> - if (v->tcfv_push_prio) 

[PATCH net-next v4 3/3] net sched act_vlan: VLAN action rewrite to use RCU lock/unlock and update

2017-10-31 Thread Manish Kurup
Using a spinlock in the VLAN action causes performance issues when the VLAN
action is used on multiple cores. Rewrote the VLAN action to use RCU read
locking for reads and updates instead.

Acked-by: Jamal Hadi Salim 
Acked-by: Jiri Pirko 
Signed-off-by: Manish Kurup 
---
 include/net/tc_act/tc_vlan.h | 46 +--
 net/sched/act_vlan.c | 65 
 2 files changed, 78 insertions(+), 33 deletions(-)

diff --git a/include/net/tc_act/tc_vlan.h b/include/net/tc_act/tc_vlan.h
index c2090df..22ae260 100644
--- a/include/net/tc_act/tc_vlan.h
+++ b/include/net/tc_act/tc_vlan.h
@@ -13,12 +13,17 @@
 #include 
 #include 
 
+struct tcf_vlan_params {
+   int   tcfv_action;
+   u16   tcfv_push_vid;
+   __be16tcfv_push_proto;
+   u8tcfv_push_prio;
+   struct rcu_head   rcu;
+};
+
 struct tcf_vlan {
struct tc_actioncommon;
-   int tcfv_action;
-   u16 tcfv_push_vid;
-   __be16  tcfv_push_proto;
-   u8  tcfv_push_prio;
+   struct tcf_vlan_params __rcu *vlan_p;
 };
 #define to_vlan(a) ((struct tcf_vlan *)a)
 
@@ -33,22 +38,45 @@ static inline bool is_tcf_vlan(const struct tc_action *a)
 
 static inline u32 tcf_vlan_action(const struct tc_action *a)
 {
-   return to_vlan(a)->tcfv_action;
+   u32 tcfv_action;
+
+   rcu_read_lock();
+   tcfv_action = rcu_dereference(to_vlan(a)->vlan_p)->tcfv_action;
+   rcu_read_unlock();
+
+   return tcfv_action;
 }
 
 static inline u16 tcf_vlan_push_vid(const struct tc_action *a)
 {
-   return to_vlan(a)->tcfv_push_vid;
+   u16 tcfv_push_vid;
+
+   rcu_read_lock();
+   tcfv_push_vid = rcu_dereference(to_vlan(a)->vlan_p)->tcfv_push_vid;
+   rcu_read_unlock();
+
+   return tcfv_push_vid;
 }
 
 static inline __be16 tcf_vlan_push_proto(const struct tc_action *a)
 {
-   return to_vlan(a)->tcfv_push_proto;
+   __be16 tcfv_push_proto;
+
+   rcu_read_lock();
+   tcfv_push_proto = rcu_dereference(to_vlan(a)->vlan_p)->tcfv_push_proto;
+   rcu_read_unlock();
+
+   return tcfv_push_proto;
 }
 
 static inline u8 tcf_vlan_push_prio(const struct tc_action *a)
 {
-   return to_vlan(a)->tcfv_push_prio;
-}
+   u8 tcfv_push_prio;
 
+   rcu_read_lock();
+   tcfv_push_prio = rcu_dereference(to_vlan(a)->vlan_p)->tcfv_push_prio;
+   rcu_read_unlock();
+
+   return tcfv_push_prio;
+}
 #endif /* __NET_TC_VLAN_H */
diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
index b093bad..7f461f9 100644
--- a/net/sched/act_vlan.c
+++ b/net/sched/act_vlan.c
@@ -26,6 +26,7 @@ static int tcf_vlan(struct sk_buff *skb, const struct 
tc_action *a,
struct tcf_result *res)
 {
struct tcf_vlan *v = to_vlan(a);
+   struct tcf_vlan_params *p;
int action;
int err;
u16 tci;
@@ -33,24 +34,27 @@ static int tcf_vlan(struct sk_buff *skb, const struct 
tc_action *a,
tcf_lastuse_update(>tcf_tm);
bstats_cpu_update(this_cpu_ptr(v->common.cpu_bstats), skb);
 
-   spin_lock(>tcf_lock);
-   action = v->tcf_action;
-
/* Ensure 'data' points at mac_header prior calling vlan manipulating
 * functions.
 */
if (skb_at_tc_ingress(skb))
skb_push_rcsum(skb, skb->mac_len);
 
-   switch (v->tcfv_action) {
+   rcu_read_lock();
+
+   action = READ_ONCE(v->tcf_action);
+
+   p = rcu_dereference(v->vlan_p);
+
+   switch (p->tcfv_action) {
case TCA_VLAN_ACT_POP:
err = skb_vlan_pop(skb);
if (err)
goto drop;
break;
case TCA_VLAN_ACT_PUSH:
-   err = skb_vlan_push(skb, v->tcfv_push_proto, v->tcfv_push_vid |
-   (v->tcfv_push_prio << VLAN_PRIO_SHIFT));
+   err = skb_vlan_push(skb, p->tcfv_push_proto, p->tcfv_push_vid |
+   (p->tcfv_push_prio << VLAN_PRIO_SHIFT));
if (err)
goto drop;
break;
@@ -69,14 +73,14 @@ static int tcf_vlan(struct sk_buff *skb, const struct 
tc_action *a,
goto drop;
}
/* replace the vid */
-   tci = (tci & ~VLAN_VID_MASK) | v->tcfv_push_vid;
+   tci = (tci & ~VLAN_VID_MASK) | p->tcfv_push_vid;
/* replace prio bits, if tcfv_push_prio specified */
-   if (v->tcfv_push_prio) {
+   if (p->tcfv_push_prio) {
tci &= ~VLAN_PRIO_MASK;
-   tci |= v->tcfv_push_prio << VLAN_PRIO_SHIFT;
+   tci |= p->tcfv_push_prio << VLAN_PRIO_SHIFT;
}
/* put updated tci