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(-)

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;
         }
-- 
2.5.5

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to