diff mbox

[v3,net-next,2/3] openvswitch: Use is_skb_forwardable() for length check.

Message ID 1480462253-114713-2-git-send-email-jarno@ovn.org
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Jarno Rajahalme Nov. 29, 2016, 11:30 p.m. UTC
Use is_skb_forwardable() instead of an explicit length check.  This
gets around the apparent MTU check failure in OVS test cases when
skb->protocol is not properly set in case of non-accelerated VLAN
skbs.

Suggested-by: Pravin Shelar <pshelar@ovn.org>
Fixes: 5108bbaddc ("openvswitch: add processing of L3 packets")
Signed-off-by: Jarno Rajahalme <jarno@ovn.org>
---
v3: New patch suggested by Pravin.

net/openvswitch/vport.c | 38 ++++++++++++++------------------------
 1 file changed, 14 insertions(+), 24 deletions(-)

Comments

Pravin Shelar Nov. 30, 2016, 7:23 a.m. UTC | #1
On Tue, Nov 29, 2016 at 3:30 PM, Jarno Rajahalme <jarno@ovn.org> wrote:
> Use is_skb_forwardable() instead of an explicit length check.  This
> gets around the apparent MTU check failure in OVS test cases when
> skb->protocol is not properly set in case of non-accelerated VLAN
> skbs.
>
> Suggested-by: Pravin Shelar <pshelar@ovn.org>
> Fixes: 5108bbaddc ("openvswitch: add processing of L3 packets")
> Signed-off-by: Jarno Rajahalme <jarno@ovn.org>
> ---
> v3: New patch suggested by Pravin.
>
> net/openvswitch/vport.c | 38 ++++++++++++++------------------------
>  1 file changed, 14 insertions(+), 24 deletions(-)
>
> diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
> index b6c8524..076b39f 100644
> --- a/net/openvswitch/vport.c
> +++ b/net/openvswitch/vport.c

>  void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto)
>  {
> -       int mtu = vport->dev->mtu;
> -
>         switch (vport->dev->type) {
>         case ARPHRD_NONE:
>                 if (mac_proto == MAC_PROTO_ETHERNET) {
> @@ -504,11 +485,20 @@ void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto)
>                 goto drop;
>         }
>
> -       if (unlikely(packet_length(skb, vport->dev) > mtu &&
> -                    !skb_is_gso(skb))) {
> -               net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n",
> -                                    vport->dev->name,
> -                                    packet_length(skb, vport->dev), mtu);
> +       if (unlikely(!is_skb_forwardable(vport->dev, skb))) {

This would easy to read if you inverse the if condition here.

> +               /* Log only if the device is up. */
> +               if (vport->dev->flags & IFF_UP) {

since is_skb_forwardable() is checking for IFF_UP we can remove same
check from internal-device send() op.

> +                       unsigned int length = skb->len
> +                               - vport->dev->hard_header_len;
> +
> +                       if (!skb_vlan_tag_present(skb)
> +                           && eth_type_vlan(skb->protocol))
> +                               length -= VLAN_HLEN;
> +
> +                       net_warn_ratelimited("%s: dropped over-mtu packet %d > %d\n",
> +                                            vport->dev->name, length,
> +                                            vport->dev->mtu);
> +               }
>                 vport->dev->stats.tx_errors++;
>                 goto drop;
>         }
> --
> 2.1.4
>
Jiri Benc Nov. 30, 2016, 1:51 p.m. UTC | #2
On Tue, 29 Nov 2016 15:30:52 -0800, Jarno Rajahalme wrote:
> @@ -504,11 +485,20 @@ void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto)
>  		goto drop;
>  	}
>  
> -	if (unlikely(packet_length(skb, vport->dev) > mtu &&
> -		     !skb_is_gso(skb))) {
> -		net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n",
> -				     vport->dev->name,
> -				     packet_length(skb, vport->dev), mtu);
> +	if (unlikely(!is_skb_forwardable(vport->dev, skb))) {

How does this work when the vlan tag is accelerated? Then we can be
over MTU, yet the check will pass.

 Jiri
Jarno Rajahalme Nov. 30, 2016, 9:30 p.m. UTC | #3
> On Nov 30, 2016, at 5:51 AM, Jiri Benc <jbenc@redhat.com> wrote:
> 
> On Tue, 29 Nov 2016 15:30:52 -0800, Jarno Rajahalme wrote:
>> @@ -504,11 +485,20 @@ void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto)
>> 		goto drop;
>> 	}
>> 
>> -	if (unlikely(packet_length(skb, vport->dev) > mtu &&
>> -		     !skb_is_gso(skb))) {
>> -		net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n",
>> -				     vport->dev->name,
>> -				     packet_length(skb, vport->dev), mtu);
>> +	if (unlikely(!is_skb_forwardable(vport->dev, skb))) {
> 
> How does this work when the vlan tag is accelerated? Then we can be
> over MTU, yet the check will pass.
> 

I’ll check how other call sites use this.

  Jarno

> Jiri
Pravin Shelar Dec. 1, 2016, 7:50 p.m. UTC | #4
On Wed, Nov 30, 2016 at 5:51 AM, Jiri Benc <jbenc@redhat.com> wrote:
> On Tue, 29 Nov 2016 15:30:52 -0800, Jarno Rajahalme wrote:
>> @@ -504,11 +485,20 @@ void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto)
>>               goto drop;
>>       }
>>
>> -     if (unlikely(packet_length(skb, vport->dev) > mtu &&
>> -                  !skb_is_gso(skb))) {
>> -             net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n",
>> -                                  vport->dev->name,
>> -                                  packet_length(skb, vport->dev), mtu);
>> +     if (unlikely(!is_skb_forwardable(vport->dev, skb))) {
>
> How does this work when the vlan tag is accelerated? Then we can be
> over MTU, yet the check will pass.
>

This is not changing any behavior compared to current OVS vlan checks.
Single vlan header is not considered for MTU check.
Jiri Benc Dec. 2, 2016, 9:25 a.m. UTC | #5
On Thu, 1 Dec 2016 11:50:00 -0800, Pravin Shelar wrote:
> This is not changing any behavior compared to current OVS vlan checks.
> Single vlan header is not considered for MTU check.

It is changing it.

Consider the case when there's an interface with MTU 1500 forwarding to
an interface with MTU 1496. Obviously, full-sized vlan frames
ingressing on the first interface are not forwardable to the second
one. Yet, if the vlan tag is accelerated (and thus not counted in
skb->len), is_skb_forwardable happily returns true because of the check

        len = dev->mtu + dev->hard_header_len + VLAN_HLEN;
        if (skb->len <= len)

 Jiri
Pravin Shelar Dec. 5, 2016, 12:22 a.m. UTC | #6
On Fri, Dec 2, 2016 at 1:25 AM, Jiri Benc <jbenc@redhat.com> wrote:
> On Thu, 1 Dec 2016 11:50:00 -0800, Pravin Shelar wrote:
>> This is not changing any behavior compared to current OVS vlan checks.
>> Single vlan header is not considered for MTU check.
>
> It is changing it.
>
> Consider the case when there's an interface with MTU 1500 forwarding to
> an interface with MTU 1496. Obviously, full-sized vlan frames
> ingressing on the first interface are not forwardable to the second
> one. Yet, if the vlan tag is accelerated (and thus not counted in
> skb->len), is_skb_forwardable happily returns true because of the check
>
>         len = dev->mtu + dev->hard_header_len + VLAN_HLEN;
>         if (skb->len <= len)
>
ok, This case would be allowed due to this patch. But core linux stack
and bridge is using this check then why not just use same forwarding
check in OVS too, this make it consistent with core networking
forwarding expectations.
Eric Garver Dec. 8, 2016, 8:50 p.m. UTC | #7
On Sun, Dec 04, 2016 at 04:22:40PM -0800, Pravin Shelar wrote:
> On Fri, Dec 2, 2016 at 1:25 AM, Jiri Benc <jbenc@redhat.com> wrote:
> > On Thu, 1 Dec 2016 11:50:00 -0800, Pravin Shelar wrote:
> >> This is not changing any behavior compared to current OVS vlan checks.
> >> Single vlan header is not considered for MTU check.
> >
> > It is changing it.
> >
> > Consider the case when there's an interface with MTU 1500 forwarding to
> > an interface with MTU 1496. Obviously, full-sized vlan frames
> > ingressing on the first interface are not forwardable to the second
> > one. Yet, if the vlan tag is accelerated (and thus not counted in
> > skb->len), is_skb_forwardable happily returns true because of the check
> >
> >         len = dev->mtu + dev->hard_header_len + VLAN_HLEN;
> >         if (skb->len <= len)
> >
> ok, This case would be allowed due to this patch. But core linux stack
> and bridge is using this check then why not just use same forwarding
> check in OVS too, this make it consistent with core networking
> forwarding expectations.

Should we not also follow the "skbs are untagged" approach that the rest
of the kernel uses? I'm referring to patches 1 and 2 form Jiri's series
"openvswitch: make vlan handling consistent".

With those changes is_skb_forwardable() would behave as expected here.
Jiri Benc Dec. 9, 2016, 8:49 a.m. UTC | #8
On Thu, 8 Dec 2016 15:50:41 -0500, Eric Garver wrote:
> Should we not also follow the "skbs are untagged" approach that the rest
> of the kernel uses? I'm referring to patches 1 and 2 form Jiri's series
> "openvswitch: make vlan handling consistent".
> 
> With those changes is_skb_forwardable() would behave as expected here.

Yes, this would make the check easy and consistent (and was actually my
original motivation for the mentioned patchset).

Still, is_skb_forwardable would be off by 4 bytes. I wonder whether
it's not off even for the bridge case. And dev_forward_skb seems to be
fishy, too.

 Jiri
diff mbox

Patch

diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index b6c8524..076b39f 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -464,27 +464,8 @@  int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
 	return 0;
 }
 
-static unsigned int packet_length(const struct sk_buff *skb,
-				  struct net_device *dev)
-{
-	unsigned int length = skb->len - dev->hard_header_len;
-
-	if (!skb_vlan_tag_present(skb) &&
-	    eth_type_vlan(skb->protocol))
-		length -= VLAN_HLEN;
-
-	/* Don't subtract for multiple VLAN tags. Most (all?) drivers allow
-	 * (ETH_LEN + VLAN_HLEN) in addition to the mtu value, but almost none
-	 * account for 802.1ad. e.g. is_skb_forwardable().
-	 */
-
-	return length;
-}
-
 void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto)
 {
-	int mtu = vport->dev->mtu;
-
 	switch (vport->dev->type) {
 	case ARPHRD_NONE:
 		if (mac_proto == MAC_PROTO_ETHERNET) {
@@ -504,11 +485,20 @@  void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto)
 		goto drop;
 	}
 
-	if (unlikely(packet_length(skb, vport->dev) > mtu &&
-		     !skb_is_gso(skb))) {
-		net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n",
-				     vport->dev->name,
-				     packet_length(skb, vport->dev), mtu);
+	if (unlikely(!is_skb_forwardable(vport->dev, skb))) {
+		/* Log only if the device is up. */
+		if (vport->dev->flags & IFF_UP) {
+			unsigned int length = skb->len
+				- vport->dev->hard_header_len;
+
+			if (!skb_vlan_tag_present(skb)
+			    && eth_type_vlan(skb->protocol))
+				length -= VLAN_HLEN;
+
+			net_warn_ratelimited("%s: dropped over-mtu packet %d > %d\n",
+					     vport->dev->name, length,
+					     vport->dev->mtu);
+		}
 		vport->dev->stats.tx_errors++;
 		goto drop;
 	}