diff mbox

[ovs-dev] netdev-linux: double tagged packets should use 0x88a8

Message ID 1474658127-23477-1-git-send-email-e@erig.me
State Changes Requested
Delegated to: Daniele Di Proietto
Headers show

Commit Message

Eric Garver Sept. 23, 2016, 7:15 p.m. UTC
We need to check if a packet is double tagged. If so make sure to push
0x88a8 instead of 0x8100. Without this a simple port redirect of 802.1ad
frames means the outer tag gets translated from 0x88a8 to 0x8100 by the
userspace datapath.

This only affected kernels that don't use TP_STATUS_VLAN_TPID_VALID,
which is kernels < 3.14.

Signed-off-by: Eric Garver <e@erig.me>
---
 lib/netdev-linux.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

Comments

Ben Pfaff Oct. 3, 2016, 8:16 p.m. UTC | #1
On Fri, Sep 23, 2016 at 03:15:27PM -0400, Eric Garver wrote:
> We need to check if a packet is double tagged. If so make sure to push
> 0x88a8 instead of 0x8100. Without this a simple port redirect of 802.1ad
> frames means the outer tag gets translated from 0x88a8 to 0x8100 by the
> userspace datapath.
> 
> This only affected kernels that don't use TP_STATUS_VLAN_TPID_VALID,
> which is kernels < 3.14.
> 
> Signed-off-by: Eric Garver <e@erig.me>

...

>          if (auxdata_has_vlan_tci(aux)) {
> +            struct eth_header *eth = dp_packet_data(buffer);
> +            bool doubleTagged = eth->eth_type == htons(ETH_TYPE_VLAN_8021Q);
> +
>              if (retval < ETH_HEADER_LEN) {
>                  return EINVAL;
>              }
>  
> -            eth_push_vlan(buffer, auxdata_to_vlan_tpid(aux),
> +            eth_push_vlan(buffer, auxdata_to_vlan_tpid(aux, doubleTagged),
>                            htons(aux->tp_vlan_tci));
>              break;
>          }

The new code here dereferences eth->eth_type before checking that the
packet is long enough.  That is, the retval check should precede the
doubletagged check.

As a minor point of style, we prefer underscores over capitals:
s/doubleTagged/double_tagged/.
Eric Garver Oct. 3, 2016, 8:56 p.m. UTC | #2
On Mon, Oct 03, 2016 at 01:16:55PM -0700, Ben Pfaff wrote:
> On Fri, Sep 23, 2016 at 03:15:27PM -0400, Eric Garver wrote:
> > We need to check if a packet is double tagged. If so make sure to push
> > 0x88a8 instead of 0x8100. Without this a simple port redirect of 802.1ad
> > frames means the outer tag gets translated from 0x88a8 to 0x8100 by the
> > userspace datapath.
> > 
> > This only affected kernels that don't use TP_STATUS_VLAN_TPID_VALID,
> > which is kernels < 3.14.
> > 
> > Signed-off-by: Eric Garver <e@erig.me>
> 
> ...
> 
> >          if (auxdata_has_vlan_tci(aux)) {
> > +            struct eth_header *eth = dp_packet_data(buffer);
> > +            bool doubleTagged = eth->eth_type == htons(ETH_TYPE_VLAN_8021Q);
> > +
> >              if (retval < ETH_HEADER_LEN) {
> >                  return EINVAL;
> >              }
> >  
> > -            eth_push_vlan(buffer, auxdata_to_vlan_tpid(aux),
> > +            eth_push_vlan(buffer, auxdata_to_vlan_tpid(aux, doubleTagged),
> >                            htons(aux->tp_vlan_tci));
> >              break;
> >          }
> 
> The new code here dereferences eth->eth_type before checking that the
> packet is long enough.  That is, the retval check should precede the
> doubletagged check.
> 

Oops. Thanks for catching.
Will send a v2.

> As a minor point of style, we prefer underscores over capitals:
> s/doubleTagged/double_tagged/.
diff mbox

Patch

diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index ef8471995a3d..0f929c9cfc3b 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -995,12 +995,14 @@  netdev_linux_rxq_dealloc(struct netdev_rxq *rxq_)
 }
 
 static ovs_be16
-auxdata_to_vlan_tpid(const struct tpacket_auxdata *aux)
+auxdata_to_vlan_tpid(const struct tpacket_auxdata *aux, bool doubleTagged)
 {
     if (aux->tp_status & TP_STATUS_VLAN_TPID_VALID) {
         return htons(aux->tp_vlan_tpid);
+    } else if (doubleTagged) {
+        return htons(ETH_TYPE_VLAN_8021AD);
     } else {
-        return htons(ETH_TYPE_VLAN);
+        return htons(ETH_TYPE_VLAN_8021Q);
     }
 }
 
@@ -1060,11 +1062,14 @@  netdev_linux_rxq_recv_sock(int fd, struct dp_packet *buffer)
 
         aux = ALIGNED_CAST(struct tpacket_auxdata *, CMSG_DATA(cmsg));
         if (auxdata_has_vlan_tci(aux)) {
+            struct eth_header *eth = dp_packet_data(buffer);
+            bool doubleTagged = eth->eth_type == htons(ETH_TYPE_VLAN_8021Q);
+
             if (retval < ETH_HEADER_LEN) {
                 return EINVAL;
             }
 
-            eth_push_vlan(buffer, auxdata_to_vlan_tpid(aux),
+            eth_push_vlan(buffer, auxdata_to_vlan_tpid(aux, doubleTagged),
                           htons(aux->tp_vlan_tci));
             break;
         }