Fixed according to comments from Jesse. --8<--------------------------cut here-------------------------->8--
Followng patch fixes bug in pop_vlan code by setting network and transport header offsets. pop_vlan is updated to make it in sync with newer kernel. Signed-off-by: Pravin B Shelar <pshe...@nicira.com> --- acinclude.m4 | 1 + datapath/actions.c | 26 +++++++++++------- datapath/linux/compat/include/linux/if_vlan.h | 34 +++++++++++++++++++++++++ datapath/linux/compat/include/linux/skbuff.h | 6 ++++ 4 files changed, 57 insertions(+), 10 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 648132a..8c33690 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -254,6 +254,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..c3fcece 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -39,11 +39,19 @@ static int make_writable(struct sk_buff *skb, int write_len) return pskb_expand_head(skb, 0, 0, GFP_ATOMIC); } +static void pop_vlan_header(struct sk_buff *skb) +{ + memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN); + __skb_pull(skb, VLAN_HLEN); + + 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); @@ -54,16 +62,14 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci) 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; - - memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN); + vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN); + *current_tci = vhdr->h_vlan_TCI; + vlan_set_encap_proto(skb, vhdr); - eh = (struct ethhdr *)__skb_pull(skb, VLAN_HLEN); - - skb->protocol = eh->h_proto; - skb->mac_header += VLAN_HLEN; + pop_vlan_header(skb); + skb->network_header += VLAN_HLEN; + skb->transport_header += VLAN_HLEN; return 0; } diff --git a/datapath/linux/compat/include/linux/if_vlan.h b/datapath/linux/compat/include/linux/if_vlan.h index f418407..8857edb 100644 --- a/datapath/linux/compat/include/linux/if_vlan.h +++ b/datapath/linux/compat/include/linux/if_vlan.h @@ -54,4 +54,38 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci) #define VLAN_TAG_PRESENT VLAN_CFI_MASK #endif +#ifndef HAVE_VLAN_SET_ENCAP_PROTO +static inline 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 #endif /* linux/if_vlan.h wrapper */ diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h index 456d744..311bfdb 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 +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) +static inline void skb_reset_mac_len(struct sk_buff *skb) +{ + skb->mac_len = skb->network_header - skb->mac_header; +} +#endif #endif -- 1.7.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev