aboutsummaryrefslogtreecommitdiff
path: root/datapath
diff options
context:
space:
mode:
authorPravin B Shelar <pshelar@nicira.com>2011-11-18 11:48:01 -0800
committerPravin B Shelar <pshelar@nicira.com>2011-11-18 11:48:01 -0800
commitceb176fdb72bb7ce90debc66e1eeb1d25823d30a (patch)
tree3946be2e5e891f249bfc4b64f6cd6fcd1c4eb429 /datapath
parent0be6140a9a7de46f07e09d3ba200bd7f0cf73838 (diff)
datapath: Fix pop_vlan().
Following patch fixes bug in pop_vlan code by updating ethernet header len. Signed-off-by: Pravin B Shelar <pshelar@nicira.com> Acked-by: Jesse Gross <jesse@nicira.com>
Diffstat (limited to 'datapath')
-rw-r--r--datapath/actions.c13
-rw-r--r--datapath/linux/compat/include/linux/if_vlan.h34
-rw-r--r--datapath/linux/compat/include/linux/skbuff.h6
3 files changed, 46 insertions, 7 deletions
diff --git a/datapath/actions.c b/datapath/actions.c
index b430090c..70fe153a 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -50,8 +50,7 @@ static int make_writable(struct sk_buff *skb, int write_len)
/* 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);
@@ -62,15 +61,15 @@ 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;
+ vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);
+ *current_tci = vhdr->h_vlan_TCI;
memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN);
+ __skb_pull(skb, VLAN_HLEN);
- eh = (struct ethhdr *)__skb_pull(skb, VLAN_HLEN);
-
- skb->protocol = eh->h_proto;
+ vlan_set_encap_proto(skb, vhdr);
skb->mac_header += VLAN_HLEN;
+ skb_reset_mac_len(skb);
return 0;
}
diff --git a/datapath/linux/compat/include/linux/if_vlan.h b/datapath/linux/compat/include/linux/if_vlan.h
index f4184074..326abb27 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
+/* This function is not exported from kernel. OVS Upstreaming patch will
+ * fix that. */
+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 /* linux/if_vlan.h wrapper */
diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h
index 456d7446..311bfdbc 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