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