lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 11 Oct 2017 15:13:18 +0200
From:   Jiri Pirko <jiri@...nulli.us>
To:     Manish Kurup <kurup.manish@...il.com>
Cc:     jhs@...atatu.com, xiyou.wangcong@...il.com, davem@...emloft.net,
        netdev@...r.kernel.org, linux-kernel@...r.kernel.org,
        aring@...atatu.com, mrv@...atatu.com, manish.kurup@...izon.com
Subject: Re: [PATCH net-next 2/2] net sched act_vlan: VLAN action rewrite to
 use RCU lock/unlock and update

Wed, Oct 11, 2017 at 04:33:39AM CEST, kurup.manish@...il.com 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.
>
>Signed-off-by: Manish Kurup <manish.kurup@...izon.com>
>---
> include/net/tc_act/tc_vlan.h | 21 ++++++++-----
> net/sched/act_vlan.c         | 73 ++++++++++++++++++++++++++++++--------------
> 2 files changed, 63 insertions(+), 31 deletions(-)
>
>diff --git a/include/net/tc_act/tc_vlan.h b/include/net/tc_act/tc_vlan.h
>index c2090df..67fd355 100644
>--- a/include/net/tc_act/tc_vlan.h
>+++ b/include/net/tc_act/tc_vlan.h
>@@ -13,12 +13,17 @@
> #include <net/act_api.h>
> #include <linux/tc_act/tc_vlan.h>
> 
>+struct tcf_vlan_params {
>+	struct rcu_head   rcu;

Usually rcu_head is put at the very end of struct.


>+	int               tcfv_action;
>+	u16               tcfv_push_vid;
>+	__be16            tcfv_push_proto;
>+	u8                tcfv_push_prio;
>+};
>+
> struct tcf_vlan {
> 	struct tc_action	common;
>-	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,22 @@ 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;
>+	return to_vlan(a)->vlan_p->tcfv_action;
> }
> 
> static inline u16 tcf_vlan_push_vid(const struct tc_action *a)
> {
>-	return to_vlan(a)->tcfv_push_vid;
>+	return to_vlan(a)->vlan_p->tcfv_push_vid;
> }
> 
> static inline __be16 tcf_vlan_push_proto(const struct tc_action *a)
> {
>-	return to_vlan(a)->tcfv_push_proto;
>+	return to_vlan(a)->vlan_p->tcfv_push_proto;
> }
> 
> static inline u8 tcf_vlan_push_prio(const struct tc_action *a)
> {
>-	return to_vlan(a)->tcfv_push_prio;
>+	return to_vlan(a)->vlan_p->tcfv_push_prio;

All these helpers should use rtnl_dereference() as well


> }
> 
> #endif /* __NET_TC_VLAN_H */
>diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
>index 14c262c..9bb0236 100644
>--- a/net/sched/act_vlan.c
>+++ b/net/sched/act_vlan.c
>@@ -29,31 +29,37 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
> 	int action;
> 	int err;
> 	u16 tci;
>+	struct tcf_vlan_params *p;
> 
> 	tcf_lastuse_update(&v->tcf_tm);
> 	bstats_cpu_update(this_cpu_ptr(v->common.cpu_bstats), skb);
> 
>-	spin_lock(&v->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);
>+

Too many empty lines. At least remove the one above this ^


>+	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));

Again, indentation is odd. Please fix.



> 		if (err)
> 			goto drop;
> 		break;
>+

Avoid adding this unrelated empty line.


> 	case TCA_VLAN_ACT_MODIFY:
> 		/* No-op if no vlan tag (either hw-accel or in-payload) */
> 		if (!skb_vlan_tagged(skb))
>@@ -69,15 +75,16 @@ 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 as hwaccel tag */
>-		__vlan_hwaccel_put_tag(skb, v->tcfv_push_proto, tci);
>+		__vlan_hwaccel_put_tag(skb, p->tcfv_push_proto, tci);
> 		break;
>+

Again, avoid adding this unrelated empty line.


> 	default:
> 		BUG();
> 	}
>@@ -89,6 +96,7 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
> 	qstats_drop_inc(this_cpu_ptr(v->common.cpu_qstats));
> 
> unlock:
>+	rcu_read_unlock();
> 	if (skb_at_tc_ingress(skb))
> 		skb_pull_rcsum(skb, skb->mac_len);
> 
>@@ -111,6 +119,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
> 	struct nlattr *tb[TCA_VLAN_MAX + 1];
> 	struct tc_vlan *parm;
> 	struct tcf_vlan *v;
>+	struct tcf_vlan_params *p, *p_old;

The famous reverse-christmas-tree rule dictates this to be put right
above "struct tc_vlan *parm" :)


> 	int action;
> 	__be16 push_vid = 0;
> 	__be16 push_proto = 0;
>@@ -187,16 +196,33 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
> 
> 	v = to_vlan(*a);
> 
>-	spin_lock_bh(&v->tcf_lock);
>-
>-	v->tcfv_action = action;
>-	v->tcfv_push_vid = push_vid;
>-	v->tcfv_push_prio = push_prio;
>-	v->tcfv_push_proto = push_proto;
>+	ASSERT_RTNL();
>+	p = kzalloc(sizeof(*p), GFP_KERNEL);
>+	if (unlikely(!p)) {
>+		if (ovr)
>+			tcf_idr_release(*a, bind);
>+		return -ENOMEM;
>+	}
> 
> 	v->tcf_action = parm->action;
> 
>-	spin_unlock_bh(&v->tcf_lock);
>+	p_old = rtnl_dereference(v->vlan_p);
>+
>+	if (ovr)
>+		spin_lock_bh(&v->tcf_lock);
>+
>+	p->tcfv_action = action;
>+	p->tcfv_push_vid = push_vid;
>+	p->tcfv_push_prio = push_prio;
>+	p->tcfv_push_proto = push_proto;
>+
>+	rcu_assign_pointer(v->vlan_p, p);
>+
>+	if (ovr)
>+		spin_unlock_bh(&v->tcf_lock);
>+
>+	if (p_old)
>+		kfree_rcu(p_old, rcu);
> 
> 	if (ret == ACT_P_CREATED)
> 		tcf_idr_insert(tn, *a);
>@@ -208,25 +234,26 @@ static int tcf_vlan_dump(struct sk_buff *skb, struct tc_action *a,
> {
> 	unsigned char *b = skb_tail_pointer(skb);
> 	struct tcf_vlan *v = to_vlan(a);
>+	struct tcf_vlan_params *p = rtnl_dereference(v->vlan_p);
> 	struct tc_vlan opt = {
> 		.index    = v->tcf_index,
> 		.refcnt   = v->tcf_refcnt - ref,
> 		.bindcnt  = v->tcf_bindcnt - bind,
> 		.action   = v->tcf_action,
>-		.v_action = v->tcfv_action,
>+		.v_action = p->tcfv_action,
> 	};
> 	struct tcf_t t;
> 
> 	if (nla_put(skb, TCA_VLAN_PARMS, sizeof(opt), &opt))
> 		goto nla_put_failure;
> 
>-	if ((v->tcfv_action == TCA_VLAN_ACT_PUSH ||
>-	     v->tcfv_action == TCA_VLAN_ACT_MODIFY) &&
>-	    (nla_put_u16(skb, TCA_VLAN_PUSH_VLAN_ID, v->tcfv_push_vid) ||
>+	if ((p->tcfv_action == TCA_VLAN_ACT_PUSH ||
>+	     p->tcfv_action == TCA_VLAN_ACT_MODIFY) &&
>+	    (nla_put_u16(skb, TCA_VLAN_PUSH_VLAN_ID, p->tcfv_push_vid) ||
> 	     nla_put_be16(skb, TCA_VLAN_PUSH_VLAN_PROTOCOL,
>-			  v->tcfv_push_proto) ||
>+			  p->tcfv_push_proto) ||
> 	     (nla_put_u8(skb, TCA_VLAN_PUSH_VLAN_PRIORITY,
>-					      v->tcfv_push_prio))))
>+					      p->tcfv_push_prio))))
> 		goto nla_put_failure;
> 
> 	tcf_tm_dump(&t, &v->tcf_tm);
>-- 
>2.7.4
>

Besides the couple of nits I pointed out, this looks nice. Thanks!



Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ