| From 96eb2dd53cccb2f2eb6bc468e457e2894799a523 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 1 Jun 2021 15:30:50 +0300 |
| Subject: net/sched: act_vlan: Fix modify to allow 0 |
| |
| From: Boris Sukholitko <boris.sukholitko@broadcom.com> |
| |
| [ Upstream commit 9c5eee0afca09cbde6bd00f77876754aaa552970 ] |
| |
| Currently vlan modification action checks existence of vlan priority by |
| comparing it to 0. Therefore it is impossible to modify existing vlan |
| tag to have priority 0. |
| |
| For example, the following tc command will change the vlan id but will |
| not affect vlan priority: |
| |
| tc filter add dev eth1 ingress matchall action vlan modify id 300 \ |
| priority 0 pipe mirred egress redirect dev eth2 |
| |
| The incoming packet on eth1: |
| |
| ethertype 802.1Q (0x8100), vlan 200, p 4, ethertype IPv4 |
| |
| will be changed to: |
| |
| ethertype 802.1Q (0x8100), vlan 300, p 4, ethertype IPv4 |
| |
| although the user has intended to have p == 0. |
| |
| The fix is to add tcfv_push_prio_exists flag to struct tcf_vlan_params |
| and rely on it when deciding to set the priority. |
| |
| Fixes: 45a497f2d149a4a8061c (net/sched: act_vlan: Introduce TCA_VLAN_ACT_MODIFY vlan action) |
| Signed-off-by: Boris Sukholitko <boris.sukholitko@broadcom.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| include/net/tc_act/tc_vlan.h | 1 + |
| net/sched/act_vlan.c | 7 +++++-- |
| 2 files changed, 6 insertions(+), 2 deletions(-) |
| |
| diff --git a/include/net/tc_act/tc_vlan.h b/include/net/tc_act/tc_vlan.h |
| index f051046ba034..f94b8bc26f9e 100644 |
| --- a/include/net/tc_act/tc_vlan.h |
| +++ b/include/net/tc_act/tc_vlan.h |
| @@ -16,6 +16,7 @@ struct tcf_vlan_params { |
| u16 tcfv_push_vid; |
| __be16 tcfv_push_proto; |
| u8 tcfv_push_prio; |
| + bool tcfv_push_prio_exists; |
| struct rcu_head rcu; |
| }; |
| |
| diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c |
| index 1cac3c6fbb49..a108469c664f 100644 |
| --- a/net/sched/act_vlan.c |
| +++ b/net/sched/act_vlan.c |
| @@ -70,7 +70,7 @@ static int tcf_vlan_act(struct sk_buff *skb, const struct tc_action *a, |
| /* replace the vid */ |
| tci = (tci & ~VLAN_VID_MASK) | p->tcfv_push_vid; |
| /* replace prio bits, if tcfv_push_prio specified */ |
| - if (p->tcfv_push_prio) { |
| + if (p->tcfv_push_prio_exists) { |
| tci &= ~VLAN_PRIO_MASK; |
| tci |= p->tcfv_push_prio << VLAN_PRIO_SHIFT; |
| } |
| @@ -121,6 +121,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, |
| struct tc_action_net *tn = net_generic(net, vlan_net_id); |
| struct nlattr *tb[TCA_VLAN_MAX + 1]; |
| struct tcf_chain *goto_ch = NULL; |
| + bool push_prio_exists = false; |
| struct tcf_vlan_params *p; |
| struct tc_vlan *parm; |
| struct tcf_vlan *v; |
| @@ -189,7 +190,8 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, |
| push_proto = htons(ETH_P_8021Q); |
| } |
| |
| - if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) |
| + push_prio_exists = !!tb[TCA_VLAN_PUSH_VLAN_PRIORITY]; |
| + if (push_prio_exists) |
| push_prio = nla_get_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]); |
| break; |
| case TCA_VLAN_ACT_POP_ETH: |
| @@ -241,6 +243,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, |
| p->tcfv_action = action; |
| p->tcfv_push_vid = push_vid; |
| p->tcfv_push_prio = push_prio; |
| + p->tcfv_push_prio_exists = push_prio_exists || action == TCA_VLAN_ACT_PUSH; |
| p->tcfv_push_proto = push_proto; |
| |
| if (action == TCA_VLAN_ACT_PUSH_ETH) { |
| -- |
| 2.30.2 |
| |