Followng patch fixes bug in pop_vlan code by setting network and
transport header offsets after untagging vlan.
pop_vlan is updated to make it in sync with newer kernel.

Signed-off-by: Pravin B Shelar <pshe...@nicira.com>
---
 acinclude.m4                                 |    2 +
 datapath/actions.c                           |   28 +++++++++++---------
 datapath/linux/compat/include/linux/skbuff.h |    6 ++++
 datapath/vlan.c                              |   35 ++++++++++++++++++++++++++
 datapath/vlan.h                              |    3 ++
 5 files changed, 61 insertions(+), 13 deletions(-)

diff --git a/acinclude.m4 b/acinclude.m4
index 648132a..458b9e5 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -238,6 +238,7 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [skb_warn_if_lro],
                   [OVS_DEFINE([HAVE_SKB_WARN_LRO])])
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [consume_skb])
+  OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [skb_reset_mac_len])
 
   OVS_GREP_IFELSE([$KSRC/include/linux/string.h], [kmemdup], [],
                   [OVS_GREP_IFELSE([$KSRC/include/linux/slab.h], [kmemdup])])
@@ -254,6 +255,7 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_get_be16])
   OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_find_nested])
 
+  OVS_GREP_IFELSE([$KSRC/include/linux/if_vlan.h], [vlan_set_encap_proto])
   OVS_GREP_IFELSE([$KSRC/include/linux/if_vlan.h], [ADD_ALL_VLANS_CMD],
                   [OVS_DEFINE([HAVE_VLAN_BUG_WORKAROUND])])
 
diff --git a/datapath/actions.c b/datapath/actions.c
index ac7187b..f9746ff 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -39,30 +39,32 @@ static int make_writable(struct sk_buff *skb, int write_len)
        return pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
 }
 
+static void vlan_reorder_header(struct sk_buff *skb)
+{
+       memmove(skb->data, skb->data - VLAN_HLEN, 2 * ETH_ALEN);
+       skb->mac_header += VLAN_HLEN;
+       skb_reset_mac_len(skb);
+}
+
 /* remove VLAN header from packet and update csum accrodingly. */
 static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci)
 {
-       struct ethhdr *eh;
-       struct vlan_ethhdr *veth;
+       struct vlan_hdr *vhdr;
        int err;
 
        err = make_writable(skb, VLAN_ETH_HLEN);
        if (unlikely(err))
                return err;
 
-       if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
-               skb->csum = csum_sub(skb->csum, csum_partial(skb->data
-                                       + ETH_HLEN, VLAN_HLEN, 0));
-
-       veth = (struct vlan_ethhdr *) skb->data;
-       *current_tci = veth->h_vlan_TCI;
+       vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);
+       *current_tci = vhdr->h_vlan_TCI;
+       vlan_set_encap_proto(skb, vhdr);
 
-       memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN);
+       skb_pull_rcsum(skb, VLAN_HLEN);
+       vlan_reorder_header(skb);
 
-       eh = (struct ethhdr *)__skb_pull(skb, VLAN_HLEN);
-
-       skb->protocol = eh->h_proto;
-       skb->mac_header += VLAN_HLEN;
+       skb_set_network_header(skb, VLAN_HLEN);
+       skb_set_transport_header(skb, VLAN_HLEN);
 
        return 0;
 }
diff --git a/datapath/linux/compat/include/linux/skbuff.h 
b/datapath/linux/compat/include/linux/skbuff.h
index 456d744..22ba2e6 100644
--- a/datapath/linux/compat/include/linux/skbuff.h
+++ b/datapath/linux/compat/include/linux/skbuff.h
@@ -239,4 +239,10 @@ static inline struct page *skb_frag_page(const skb_frag_t 
*frag)
 }
 #endif
 
+#ifndef HAVE_SKB_RESET_MAC_LEN
+static inline void skb_reset_mac_len(struct sk_buff *skb)
+{
+       skb->mac_len = skb->network_header - skb->mac_header;
+}
+#endif
 #endif
diff --git a/datapath/vlan.c b/datapath/vlan.c
index 9aebecd..395fa5e 100644
--- a/datapath/vlan.c
+++ b/datapath/vlan.c
@@ -46,3 +46,38 @@ struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, 
u16 vlan_tci)
        return skb;
 }
 #endif /* NEED_VLAN_FIELD */
+
+#ifndef HAVE_VLAN_SET_ENCAP_PROTO
+void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr)
+{
+       __be16 proto;
+       unsigned char *rawp;
+
+       /*
+        * Was a VLAN packet, grab the encapsulated protocol, which the layer
+        * three protocols care about.
+        */
+
+       proto = vhdr->h_vlan_encapsulated_proto;
+       if (ntohs(proto) >= 1536) {
+               skb->protocol = proto;
+               return;
+       }
+
+       rawp = skb->data;
+       if (*(unsigned short *) rawp == 0xFFFF)
+               /*
+                * This is a magic hack to spot IPX packets. Older Novell
+                * breaks the protocol design and runs IPX over 802.3 without
+                * an 802.2 LLC layer. We look for FFFF which isn't a used
+                * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
+                * but does for the rest.
+                */
+               skb->protocol = htons(ETH_P_802_3);
+       else
+               /*
+                * Real 802.2 LLC
+                */
+               skb->protocol = htons(ETH_P_802_2);
+}
+#endif
diff --git a/datapath/vlan.h b/datapath/vlan.h
index 7e1084e..1374f43 100644
--- a/datapath/vlan.h
+++ b/datapath/vlan.h
@@ -87,4 +87,7 @@ static inline int vlan_deaccel_tag(struct sk_buff *skb)
        return 0;
 }
 
+#ifndef HAVE_VLAN_SET_ENCAP_PROTO
+void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr);
+#endif
 #endif /* vlan.h */
-- 
1.7.1

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

Reply via email to