diff mbox

[net-next,2/2] net/sched: act_vlan: Introduce TCA_VLAN_ACT_MODIFY vlan action

Message ID 1474209225-23665-3-git-send-email-shmulik.ladkani@gmail.com
State Superseded, archived
Delegated to: David Miller
Headers show

Commit Message

Shmulik Ladkani Sept. 18, 2016, 2:33 p.m. UTC
TCA_VLAN_ACT_MODIFY allows one to change an existing tag.

It accepts same attributes as TCA_VLAN_ACT_PUSH (protocol, id,
priority).
If packet is vlan tagged, then the tag gets overwritten according to
user specified attributes.

For example, this allows user to replace a tag's vid while preserving
its priority bits (as opposed to "action vlan pop pipe action vlan push").

Signed-off-by: Shmulik Ladkani <shmulik.ladkani@gmail.com>
---
 include/uapi/linux/tc_act/tc_vlan.h |  1 +
 net/sched/act_vlan.c                | 29 ++++++++++++++++++++++++++++-
 2 files changed, 29 insertions(+), 1 deletion(-)

Comments

Jamal Hadi Salim Sept. 18, 2016, 7:41 p.m. UTC | #1
On 16-09-18 10:33 AM, Shmulik Ladkani wrote:
> TCA_VLAN_ACT_MODIFY allows one to change an existing tag.
>
> It accepts same attributes as TCA_VLAN_ACT_PUSH (protocol, id,
> priority).
> If packet is vlan tagged, then the tag gets overwritten according to
> user specified attributes.
>
> For example, this allows user to replace a tag's vid while preserving
> its priority bits (as opposed to "action vlan pop pipe action vlan push").
>
> Signed-off-by: Shmulik Ladkani <shmulik.ladkani@gmail.com>
> ---
>  include/uapi/linux/tc_act/tc_vlan.h |  1 +
>  net/sched/act_vlan.c                | 29 ++++++++++++++++++++++++++++-
>  2 files changed, 29 insertions(+), 1 deletion(-)
>
> diff --git a/include/uapi/linux/tc_act/tc_vlan.h b/include/uapi/linux/tc_act/tc_vlan.h
> index be72b6e384..bddb272b84 100644
> --- a/include/uapi/linux/tc_act/tc_vlan.h
> +++ b/include/uapi/linux/tc_act/tc_vlan.h
> @@ -16,6 +16,7 @@
>
>  #define TCA_VLAN_ACT_POP	1
>  #define TCA_VLAN_ACT_PUSH	2
> +#define TCA_VLAN_ACT_MODIFY	3
>
>  struct tc_vlan {
>  	tc_gen;
> diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
> index 59a8d3150a..e5eeaa7a01 100644
> --- a/net/sched/act_vlan.c
> +++ b/net/sched/act_vlan.c
> @@ -30,6 +30,7 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
>  	struct tcf_vlan *v = to_vlan(a);
>  	int action;
>  	int err;
> +	u16 tci;
>
>  	spin_lock(&v->tcf_lock);
>  	tcf_lastuse_update(&v->tcf_tm);
> @@ -48,6 +49,30 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
>  		if (err)
>  			goto drop;
>  		break;
> +	case TCA_VLAN_ACT_MODIFY:
> +		if (!skb_vlan_tagged(skb))
> +			goto unlock;
> +		/* extract existing tag (and guarantee no hwaccel tag) */
> +		if (skb_vlan_tag_present(skb)) {
> +			tci = skb_vlan_tag_get(skb);
> +			skb->vlan_tci = 0;
> +		} else {
> +			if (skb->mac_len < VLAN_ETH_HLEN)
> +				goto unlock;
> +			err = __skb_vlan_pop(skb, &tci);
> +			if (err)
> +				goto drop;
> +		}
> +		/* replace the vid */
> +		tci = (tci & ~VLAN_VID_MASK) | v->tcfv_push_vid;
> +		/* replace prio bits, if tcfv_push_prio specified */
> +		if (v->tcfv_push_prio) {
> +			tci &= ~VLAN_PRIO_MASK;
> +			tci |= v->tcfv_push_prio << VLAN_PRIO_SHIFT;
> +		}
> +		/* put updated tci as hwaccel tag */
> +		__vlan_hwaccel_put_tag(skb, v->tcfv_push_proto, tci);
> +		break;
>  	default:
>  		BUG();
>  	}
> @@ -102,6 +127,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
>  	case TCA_VLAN_ACT_POP:
>  		break;
>  	case TCA_VLAN_ACT_PUSH:
> +	case TCA_VLAN_ACT_MODIFY:
>  		if (!tb[TCA_VLAN_PUSH_VLAN_ID]) {
>  			if (exists)
>  				tcf_hash_release(*a, bind);
> @@ -185,7 +211,8 @@ static int tcf_vlan_dump(struct sk_buff *skb, struct tc_action *a,
>  	if (nla_put(skb, TCA_VLAN_PARMS, sizeof(opt), &opt))
>  		goto nla_put_failure;
>
> -	if (v->tcfv_action == TCA_VLAN_ACT_PUSH &&
> +	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) ||
>  	     nla_put_be16(skb, TCA_VLAN_PUSH_VLAN_PROTOCOL,
>  			  v->tcfv_push_proto) ||
>


Nice. If you didnt do it I would have ;->

Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>

cheers,
jamal
diff mbox

Patch

diff --git a/include/uapi/linux/tc_act/tc_vlan.h b/include/uapi/linux/tc_act/tc_vlan.h
index be72b6e384..bddb272b84 100644
--- a/include/uapi/linux/tc_act/tc_vlan.h
+++ b/include/uapi/linux/tc_act/tc_vlan.h
@@ -16,6 +16,7 @@ 
 
 #define TCA_VLAN_ACT_POP	1
 #define TCA_VLAN_ACT_PUSH	2
+#define TCA_VLAN_ACT_MODIFY	3
 
 struct tc_vlan {
 	tc_gen;
diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
index 59a8d3150a..e5eeaa7a01 100644
--- a/net/sched/act_vlan.c
+++ b/net/sched/act_vlan.c
@@ -30,6 +30,7 @@  static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
 	struct tcf_vlan *v = to_vlan(a);
 	int action;
 	int err;
+	u16 tci;
 
 	spin_lock(&v->tcf_lock);
 	tcf_lastuse_update(&v->tcf_tm);
@@ -48,6 +49,30 @@  static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
 		if (err)
 			goto drop;
 		break;
+	case TCA_VLAN_ACT_MODIFY:
+		if (!skb_vlan_tagged(skb))
+			goto unlock;
+		/* extract existing tag (and guarantee no hwaccel tag) */
+		if (skb_vlan_tag_present(skb)) {
+			tci = skb_vlan_tag_get(skb);
+			skb->vlan_tci = 0;
+		} else {
+			if (skb->mac_len < VLAN_ETH_HLEN)
+				goto unlock;
+			err = __skb_vlan_pop(skb, &tci);
+			if (err)
+				goto drop;
+		}
+		/* replace the vid */
+		tci = (tci & ~VLAN_VID_MASK) | v->tcfv_push_vid;
+		/* replace prio bits, if tcfv_push_prio specified */
+		if (v->tcfv_push_prio) {
+			tci &= ~VLAN_PRIO_MASK;
+			tci |= v->tcfv_push_prio << VLAN_PRIO_SHIFT;
+		}
+		/* put updated tci as hwaccel tag */
+		__vlan_hwaccel_put_tag(skb, v->tcfv_push_proto, tci);
+		break;
 	default:
 		BUG();
 	}
@@ -102,6 +127,7 @@  static int tcf_vlan_init(struct net *net, struct nlattr *nla,
 	case TCA_VLAN_ACT_POP:
 		break;
 	case TCA_VLAN_ACT_PUSH:
+	case TCA_VLAN_ACT_MODIFY:
 		if (!tb[TCA_VLAN_PUSH_VLAN_ID]) {
 			if (exists)
 				tcf_hash_release(*a, bind);
@@ -185,7 +211,8 @@  static int tcf_vlan_dump(struct sk_buff *skb, struct tc_action *a,
 	if (nla_put(skb, TCA_VLAN_PARMS, sizeof(opt), &opt))
 		goto nla_put_failure;
 
-	if (v->tcfv_action == TCA_VLAN_ACT_PUSH &&
+	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) ||
 	     nla_put_be16(skb, TCA_VLAN_PUSH_VLAN_PROTOCOL,
 			  v->tcfv_push_proto) ||