Commit 1fbafcb8 authored by David S. Miller's avatar David S. Miller

Merge branch 'vlan_act_modify'

Shmulik Ladkani says:

====================
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 avatarDavid S. Miller <davem@davemloft.net>
parents 688dc536 45a497f2
...@@ -3085,6 +3085,7 @@ bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu); ...@@ -3085,6 +3085,7 @@ bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu);
struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
struct sk_buff *skb_vlan_untag(struct sk_buff *skb); struct sk_buff *skb_vlan_untag(struct sk_buff *skb);
int skb_ensure_writable(struct sk_buff *skb, int write_len); int skb_ensure_writable(struct sk_buff *skb, int write_len);
int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci);
int skb_vlan_pop(struct sk_buff *skb); int skb_vlan_pop(struct sk_buff *skb);
int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci); int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci);
struct sk_buff *pskb_extract(struct sk_buff *skb, int off, int to_copy, struct sk_buff *pskb_extract(struct sk_buff *skb, int off, int to_copy,
......
...@@ -16,6 +16,7 @@ ...@@ -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;
......
...@@ -4522,8 +4522,10 @@ int skb_ensure_writable(struct sk_buff *skb, int write_len) ...@@ -4522,8 +4522,10 @@ int skb_ensure_writable(struct sk_buff *skb, int write_len)
} }
EXPORT_SYMBOL(skb_ensure_writable); EXPORT_SYMBOL(skb_ensure_writable);
/* remove VLAN header from packet and update csum accordingly. */ /* remove VLAN header from packet and update csum accordingly.
static int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci) * expects a non skb_vlan_tag_present skb with a vlan tag payload
*/
int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci)
{ {
struct vlan_hdr *vhdr; struct vlan_hdr *vhdr;
unsigned int offset = skb->data - skb_mac_header(skb); unsigned int offset = skb->data - skb_mac_header(skb);
...@@ -4554,6 +4556,7 @@ static int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci) ...@@ -4554,6 +4556,7 @@ static int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci)
return err; return err;
} }
EXPORT_SYMBOL(__skb_vlan_pop);
int skb_vlan_pop(struct sk_buff *skb) int skb_vlan_pop(struct sk_buff *skb)
{ {
......
...@@ -30,6 +30,7 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment