diff mbox series

[net-next,v2,1/3] net/sched: act_vlan: Fix modify to allow 0

Message ID 20210525153601.6705-2-boris.sukholitko@broadcom.com
State Superseded
Headers show
Series net/sched: act_vlan: Fix modify to allow 0 | expand

Commit Message

Boris Sukholitko May 25, 2021, 3:35 p.m. UTC
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>
---
 include/net/tc_act/tc_vlan.h | 1 +
 net/sched/act_vlan.c         | 7 +++++--
 2 files changed, 6 insertions(+), 2 deletions(-)

Comments

Davide Caratti May 25, 2021, 8:35 p.m. UTC | #1
On Tue, May 25, 2021 at 06:35:59PM +0300, Boris Sukholitko wrote:
> 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

hello Boris, thanks a lot for following up! A small nit below:
 
> diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
> index 1cac3c6fbb49..cca10b5e99c9 100644
> --- a/net/sched/act_vlan.c
> +++ b/net/sched/act_vlan.c

[...]

> @@ -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];

when the VLAN tag is pushed, not modified, the value of 'push_prio' is
used in the traffic path regardless of the true/false value of
'push_prio_exists'. See below:

 50         case TCA_VLAN_ACT_PUSH:
 51                 err = skb_vlan_push(skb, p->tcfv_push_proto, p->tcfv_push_vid |
 52                                     (p->tcfv_push_prio << VLAN_PRIO_SHIFT));

So, I think that 'p->push_prio_exists' should be identically set to
true when 'v_action' is TCA_VLAN_ACT_PUSH. That would allow a better
display of rules once patch 2 of your series is applied: otherwise,
2 rules configuring the same TCA_VLAN_ACT_PUSH rule would be displayed
differently, depending on whether userspace provided or not the
TCA_VLAN_PUSH_VLAN_PRIORITY attribute set to 0. In other words, the
last hunk should be something like:

@@ -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;


WDYT?

thanks!
Boris Sukholitko May 26, 2021, 11:45 a.m. UTC | #2
Hi Davide,

On Tue, May 25, 2021 at 10:35:50PM +0200, Davide Caratti wrote:
> On Tue, May 25, 2021 at 06:35:59PM +0300, Boris Sukholitko wrote:

[snip]
> 

> > @@ -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];

> 

> when the VLAN tag is pushed, not modified, the value of 'push_prio' is

> used in the traffic path regardless of the true/false value of

> 'push_prio_exists'. See below:

> 

>  50         case TCA_VLAN_ACT_PUSH:

>  51                 err = skb_vlan_push(skb, p->tcfv_push_proto, p->tcfv_push_vid |

>  52                                     (p->tcfv_push_prio << VLAN_PRIO_SHIFT));

> 


Yes, the tcfv_push_prio is 0 here by default.

> So, I think that 'p->push_prio_exists' should be identically set to

> true when 'v_action' is TCA_VLAN_ACT_PUSH. That would allow a better

> display of rules once patch 2 of your series is applied: otherwise,

> 2 rules configuring the same TCA_VLAN_ACT_PUSH rule would be displayed

> differently, depending on whether userspace provided or not the

> TCA_VLAN_PUSH_VLAN_PRIORITY attribute set to 0.


Sorry for being obtuse, but I was under impression that we want to
display priority if and only if it has been set by the userspace.
Therefore the fact that the default vlan priority for the push is 0 has
no relevance to such logic.

Why do you think that the push should be made special regarding the
display? Is there something I am missing here?

Thanks,
Boris.

> In other words, the last hunk should be something like:

> 

> @@ -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;

> 

> 

> WDYT?

> 

> thanks!

> -- 

> davide

>
Davide Caratti May 27, 2021, 5 p.m. UTC | #3
On Wed, May 26, 2021 at 02:45:53PM +0300, Boris Sukholitko wrote:
> Hi Davide,

> 

> On Tue, May 25, 2021 at 10:35:50PM +0200, Davide Caratti wrote:

> > On Tue, May 25, 2021 at 06:35:59PM +0300, Boris Sukholitko wrote:


hello Boris,

[...]

> > > @@ -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];

> > 

> > when the VLAN tag is pushed, not modified, the value of 'push_prio' is

> > used in the traffic path regardless of the true/false value of

> > 'push_prio_exists'. See below:

> > 

> >  50         case TCA_VLAN_ACT_PUSH:

> >  51                 err = skb_vlan_push(skb, p->tcfv_push_proto, p->tcfv_push_vid |

> >  52                                     (p->tcfv_push_prio << VLAN_PRIO_SHIFT));

> > 

> 

> Yes, the tcfv_push_prio is 0 here by default.

> 

> > So, I think that 'p->push_prio_exists' should be identically set to

> > true when 'v_action' is TCA_VLAN_ACT_PUSH. That would allow a better

> > display of rules once patch 2 of your series is applied: otherwise,

> > 2 rules configuring the same TCA_VLAN_ACT_PUSH rule would be displayed

> > differently, depending on whether userspace provided or not the

> > TCA_VLAN_PUSH_VLAN_PRIORITY attribute set to 0.

> 

> Sorry for being obtuse, but I was under impression that we want to

> display priority if and only if it has been set by the userspace.


don't get me wrong, I don't have strong opinions on this (I don't have
strong opinions at all :) ). In my understanding, the patch was adding
'push_prio_exists' to allow using 0 in 'p->tcfv_push_prio' in the
traffic path, instead of assuming that '0' implies no configuration by
the user.

My suggestion was just to simplify the end-user dump experience, so
that the value of 'p->tcfv_push_prio' is dumped always in case of
TCA_VLAN_ACT_PUSH. In this way, rules with equal "behavior" in the
traffic path are always dumped in the same way. IOW,

# tc action add action vlan push id 42 prio 0 index 1

and

# tc action add action vlan push id 42 index 1

do exactly the same thing in the traffic path, so there is no need to
dump them differently. On the contrary, these 2 rules:

# tc action add action vlan modify id 42 prio 0 index 1

and

# tc action add action vlan modify id 42 index 1

don't do the same thing, because packet hitting the first rule will have
their priority identically set to 0, while the second one will leave the
VLAN priority unmodified. So, I think it makes sense to have different
dumps here (that was my comment to your v1).

Another small nit - forgive me, I didn't spot it in the first review:

not 100% sure, but I think that in tcf_vlan_get_fill_size() we need
to avoid accounting for TCA_VLAN_PUSH_VLAN_PRIORITY in case the rule
has 'push_prio_exists' equal to false. Otherwise we allocate an
extra u8 netlink attribute in case of batch dump. Correct?

thanks!
-- 
davide
Boris Sukholitko May 30, 2021, 11:47 a.m. UTC | #4
On Thu, May 27, 2021 at 07:00:52PM +0200, Davide Caratti wrote:
[...]
> 

> My suggestion was just to simplify the end-user dump experience, so

> that the value of 'p->tcfv_push_prio' is dumped always in case of

> TCA_VLAN_ACT_PUSH. In this way, rules with equal "behavior" in the

> traffic path are always dumped in the same way. IOW,

> 

> # tc action add action vlan push id 42 prio 0 index 1

> 

> and

> 

> # tc action add action vlan push id 42 index 1

> 

> do exactly the same thing in the traffic path, so there is no need to

> dump them differently. On the contrary, these 2 rules:

> 

> # tc action add action vlan modify id 42 prio 0 index 1

> 

> and

> 

> # tc action add action vlan modify id 42 index 1

> 

> don't do the same thing, because packet hitting the first rule will have

> their priority identically set to 0, while the second one will leave the

> VLAN priority unmodified. So, I think it makes sense to have different

> dumps here (that was my comment to your v1).


I am convinced. I've done this in v3.

> 

> Another small nit - forgive me, I didn't spot it in the first review:

> 

> not 100% sure, but I think that in tcf_vlan_get_fill_size() we need

> to avoid accounting for TCA_VLAN_PUSH_VLAN_PRIORITY in case the rule

> has 'push_prio_exists' equal to false. Otherwise we allocate an

> extra u8 netlink attribute in case of batch dump. Correct?


Also done in v3.

Thanks,
Boris.

> 

> thanks!

> -- 

> davide

> 

> 

>
diff mbox series

Patch

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..cca10b5e99c9 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;
 	p->tcfv_push_proto = push_proto;
 
 	if (action == TCA_VLAN_ACT_PUSH_ETH) {