aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
authorShmulik Ladkani <shmulik.ladkani@gmail.com>2016-09-19 12:11:10 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-22 01:34:20 -0400
commit45a497f2d149a4a8061c61518a79d59f1f3034b2 (patch)
tree342f1160ba3a5491dadba70104586cf9c69a083c /net/sched
parentbfca4c520f7ea78138ddccea2de18dc062b0fefd (diff)
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: Shmulik Ladkani <shmulik.ladkani@gmail.com> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/act_vlan.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
index 59a8d3150ae2..a95c00b119da 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,
30 struct tcf_vlan *v = to_vlan(a); 30 struct tcf_vlan *v = to_vlan(a);
31 int action; 31 int action;
32 int err; 32 int err;
33 u16 tci;
33 34
34 spin_lock(&v->tcf_lock); 35 spin_lock(&v->tcf_lock);
35 tcf_lastuse_update(&v->tcf_tm); 36 tcf_lastuse_update(&v->tcf_tm);
@@ -48,6 +49,30 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
48 if (err) 49 if (err)
49 goto drop; 50 goto drop;
50 break; 51 break;
52 case TCA_VLAN_ACT_MODIFY:
53 /* No-op if no vlan tag (either hw-accel or in-payload) */
54 if (!skb_vlan_tagged(skb))
55 goto unlock;
56 /* extract existing tag (and guarantee no hw-accel tag) */
57 if (skb_vlan_tag_present(skb)) {
58 tci = skb_vlan_tag_get(skb);
59 skb->vlan_tci = 0;
60 } else {
61 /* in-payload vlan tag, pop it */
62 err = __skb_vlan_pop(skb, &tci);
63 if (err)
64 goto drop;
65 }
66 /* replace the vid */
67 tci = (tci & ~VLAN_VID_MASK) | v->tcfv_push_vid;
68 /* replace prio bits, if tcfv_push_prio specified */
69 if (v->tcfv_push_prio) {
70 tci &= ~VLAN_PRIO_MASK;
71 tci |= v->tcfv_push_prio << VLAN_PRIO_SHIFT;
72 }
73 /* put updated tci as hwaccel tag */
74 __vlan_hwaccel_put_tag(skb, v->tcfv_push_proto, tci);
75 break;
51 default: 76 default:
52 BUG(); 77 BUG();
53 } 78 }
@@ -102,6 +127,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
102 case TCA_VLAN_ACT_POP: 127 case TCA_VLAN_ACT_POP:
103 break; 128 break;
104 case TCA_VLAN_ACT_PUSH: 129 case TCA_VLAN_ACT_PUSH:
130 case TCA_VLAN_ACT_MODIFY:
105 if (!tb[TCA_VLAN_PUSH_VLAN_ID]) { 131 if (!tb[TCA_VLAN_PUSH_VLAN_ID]) {
106 if (exists) 132 if (exists)
107 tcf_hash_release(*a, bind); 133 tcf_hash_release(*a, bind);
@@ -185,7 +211,8 @@ static int tcf_vlan_dump(struct sk_buff *skb, struct tc_action *a,
185 if (nla_put(skb, TCA_VLAN_PARMS, sizeof(opt), &opt)) 211 if (nla_put(skb, TCA_VLAN_PARMS, sizeof(opt), &opt))
186 goto nla_put_failure; 212 goto nla_put_failure;
187 213
188 if (v->tcfv_action == TCA_VLAN_ACT_PUSH && 214 if ((v->tcfv_action == TCA_VLAN_ACT_PUSH ||
215 v->tcfv_action == TCA_VLAN_ACT_MODIFY) &&
189 (nla_put_u16(skb, TCA_VLAN_PUSH_VLAN_ID, v->tcfv_push_vid) || 216 (nla_put_u16(skb, TCA_VLAN_PUSH_VLAN_ID, v->tcfv_push_vid) ||
190 nla_put_be16(skb, TCA_VLAN_PUSH_VLAN_PROTOCOL, 217 nla_put_be16(skb, TCA_VLAN_PUSH_VLAN_PROTOCOL,
191 v->tcfv_push_proto) || 218 v->tcfv_push_proto) ||