Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45a497f2 authored by Shmulik Ladkani's avatar Shmulik Ladkani Committed by David S. Miller
Browse files

net/sched: act_vlan: Introduce TCA_VLAN_ACT_MODIFY vlan action



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: default avatarShmulik Ladkani <shmulik.ladkani@gmail.com>
Acked-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bfca4c52
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


#define TCA_VLAN_ACT_POP	1
#define TCA_VLAN_ACT_POP	1
#define TCA_VLAN_ACT_PUSH	2
#define TCA_VLAN_ACT_PUSH	2
#define TCA_VLAN_ACT_MODIFY	3


struct tc_vlan {
struct tc_vlan {
	tc_gen;
	tc_gen;
+28 −1
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
	struct tcf_vlan *v = to_vlan(a);
	struct tcf_vlan *v = to_vlan(a);
	int action;
	int action;
	int err;
	int err;
	u16 tci;


	spin_lock(&v->tcf_lock);
	spin_lock(&v->tcf_lock);
	tcf_lastuse_update(&v->tcf_tm);
	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)
		if (err)
			goto drop;
			goto drop;
		break;
		break;
	case TCA_VLAN_ACT_MODIFY:
		/* No-op if no vlan tag (either hw-accel or in-payload) */
		if (!skb_vlan_tagged(skb))
			goto unlock;
		/* extract existing tag (and guarantee no hw-accel tag) */
		if (skb_vlan_tag_present(skb)) {
			tci = skb_vlan_tag_get(skb);
			skb->vlan_tci = 0;
		} else {
			/* in-payload vlan tag, pop it */
			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:
	default:
		BUG();
		BUG();
	}
	}
@@ -102,6 +127,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
	case TCA_VLAN_ACT_POP:
	case TCA_VLAN_ACT_POP:
		break;
		break;
	case TCA_VLAN_ACT_PUSH:
	case TCA_VLAN_ACT_PUSH:
	case TCA_VLAN_ACT_MODIFY:
		if (!tb[TCA_VLAN_PUSH_VLAN_ID]) {
		if (!tb[TCA_VLAN_PUSH_VLAN_ID]) {
			if (exists)
			if (exists)
				tcf_hash_release(*a, bind);
				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))
	if (nla_put(skb, TCA_VLAN_PARMS, sizeof(opt), &opt))
		goto nla_put_failure;
		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_u16(skb, TCA_VLAN_PUSH_VLAN_ID, v->tcfv_push_vid) ||
	     nla_put_be16(skb, TCA_VLAN_PUSH_VLAN_PROTOCOL,
	     nla_put_be16(skb, TCA_VLAN_PUSH_VLAN_PROTOCOL,
			  v->tcfv_push_proto) ||
			  v->tcfv_push_proto) ||