[ovs-dev] [PATCH 14/14] datapath: Consolidate checksum compatibility code.

Jesse Gross jesse at nicira.com
Thu Dec 2 20:37:03 UTC 2010


Checksum offloading has changed quite a bit across different kernel
and Xen versions.  Since it is part of the skb data structure it is
unfortunately difficult to separate out into compatibility code.
This consolidates all of the checksum code in one, place which makes
it easier read and remove as we prepare for upstreaming.  On newer
kernels it also puts everything in inline functions, eliminating the
need to run through the compat code or make extra function calls.

Signed-off-by: Jesse Gross <jesse at nicira.com>
---
 datapath/Modules.mk           |    2 +
 datapath/actions.c            |   11 ++-
 datapath/actions.h            |   18 ----
 datapath/checksum.c           |  164 +++++++++++++++++++++++++++++++++++++
 datapath/checksum.h           |   96 ++++++++++++++++++++++
 datapath/datapath.c           |  178 +----------------------------------------
 datapath/datapath.h           |   20 ++---
 datapath/tunnel.c             |    1 +
 datapath/vport-internal_dev.c |    1 +
 datapath/vport-netdev.c       |    1 +
 10 files changed, 283 insertions(+), 209 deletions(-)
 create mode 100644 datapath/checksum.c
 create mode 100644 datapath/checksum.h

diff --git a/datapath/Modules.mk b/datapath/Modules.mk
index cbf65a6..b4d40fd 100644
--- a/datapath/Modules.mk
+++ b/datapath/Modules.mk
@@ -11,6 +11,7 @@ dist_modules = $(both_modules)	# Modules to distribute
 
 openvswitch_sources = \
 	actions.c \
+	checksum.c \
 	datapath.c \
 	dp_notify.c \
 	dp_sysfs_dp.c \
@@ -29,6 +30,7 @@ openvswitch_sources = \
 
 openvswitch_headers = \
 	actions.h \
+	checksum.h \
 	compat.h \
 	datapath.h \
 	dp_sysfs.h \
diff --git a/datapath/actions.c b/datapath/actions.c
index 5904c83..56fa423 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -21,6 +21,7 @@
 #include <net/checksum.h>
 
 #include "actions.h"
+#include "checksum.h"
 #include "datapath.h"
 #include "openvswitch/datapath-protocol.h"
 #include "vport.h"
@@ -56,7 +57,7 @@ static struct sk_buff *vlan_pull_tag(struct sk_buff *skb)
 	if (vh->h_vlan_proto != htons(ETH_P_8021Q) || skb->len < VLAN_ETH_HLEN)
 		return skb;
 
-	if (OVS_CB(skb)->ip_summed == OVS_CSUM_COMPLETE)
+	if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
 		skb->csum = csum_sub(skb->csum, csum_partial(skb->data
 					+ ETH_HLEN, VLAN_HLEN, 0));
 
@@ -93,7 +94,7 @@ static struct sk_buff *modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
 
 		vh->h_vlan_TCI = tci;
 
-		if (OVS_CB(skb)->ip_summed == OVS_CSUM_COMPLETE) {
+		if (get_ip_summed(skb) == OVS_CSUM_COMPLETE) {
 			__be16 diff[] = { ~old_tci, vh->h_vlan_TCI };
 
 			skb->csum = ~csum_partial((char *)diff, sizeof(diff),
@@ -182,7 +183,7 @@ static struct sk_buff *modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
 
 		/* GSO doesn't fix up the hardware computed checksum so this
 		 * will only be hit in the non-GSO case. */
-		if (OVS_CB(skb)->ip_summed == OVS_CSUM_COMPLETE)
+		if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
 			skb->csum = csum_add(skb->csum, csum_partial(skb->data
 						+ ETH_HLEN, VLAN_HLEN, 0));
 	}
@@ -221,10 +222,10 @@ static void update_csum(__sum16 *sum, struct sk_buff *skb,
 {
 	__be32 diff[] = { ~from, to };
 
-	if (OVS_CB(skb)->ip_summed != OVS_CSUM_PARTIAL) {
+	if (get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
 		*sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
 				~csum_unfold(*sum)));
-		if (OVS_CB(skb)->ip_summed == OVS_CSUM_COMPLETE && pseudohdr)
+		if (get_ip_summed(skb) == OVS_CSUM_COMPLETE && pseudohdr)
 			skb->csum = ~csum_partial((char *)diff, sizeof(diff),
 						~skb->csum);
 	} else if (pseudohdr)
diff --git a/datapath/actions.h b/datapath/actions.h
index f2962a7..a258551 100644
--- a/datapath/actions.h
+++ b/datapath/actions.h
@@ -21,22 +21,4 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
 		    const struct odp_flow_key *key,
 		    const union odp_action *, int n_actions);
 
-static inline void set_skb_csum_bits(const struct sk_buff *old_skb,
-				     struct sk_buff *new_skb)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-	/* Before 2.6.24 these fields were not copied when
-	 * doing an skb_copy_expand. */
-	new_skb->ip_summed = old_skb->ip_summed;
-	new_skb->csum = old_skb->csum;
-#endif
-#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
-	/* These fields are copied in skb_clone but not in
-	 * skb_copy or related functions.  We need to manually
-	 * copy them over here. */
-	new_skb->proto_data_valid = old_skb->proto_data_valid;
-	new_skb->proto_csum_blank = old_skb->proto_csum_blank;
-#endif
-}
-
 #endif /* actions.h */
diff --git a/datapath/checksum.c b/datapath/checksum.c
new file mode 100644
index 0000000..2ded40c
--- /dev/null
+++ b/datapath/checksum.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2010 Nicira Networks.
+ * Distributed under the terms of the GNU GPL version 2.
+ *
+ * Significant portions of this file may be copied from parts of the Linux
+ * kernel, by Linus Torvalds and others.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+
+#include "checksum.h"
+
+ /* Types of checksums that we can receive (these all refer to L4 checksums):
+ * 1. CHECKSUM_NONE: Device that did not compute checksum, contains full
+ *	(though not verified) checksum in packet but not in skb->csum.  Packets
+ *	from the bridge local port will also have this type.
+ * 2. CHECKSUM_COMPLETE (CHECKSUM_HW): Good device that computes checksums,
+ *	also the GRE module.  This is the same as CHECKSUM_NONE, except it has
+ *	a valid skb->csum.  Importantly, both contain a full checksum (not
+ *	verified) in the packet itself.  The only difference is that if the
+ *	packet gets to L4 processing on this machine (not in DomU) we won't
+ *	have to recompute the checksum to verify.  Most hardware devices do not
+ *	produce packets with this type, even if they support receive checksum
+ *	offloading (they produce type #5).
+ * 3. CHECKSUM_PARTIAL (CHECKSUM_HW): Packet without full checksum and needs to
+ *	be computed if it is sent off box.  Unfortunately on earlier kernels,
+ *	this case is impossible to distinguish from #2, despite having opposite
+ *	meanings.  Xen adds an extra field on earlier kernels (see #4) in order
+ *	to distinguish the different states.
+ * 4. CHECKSUM_UNNECESSARY (with proto_csum_blank true): This packet was
+ *	generated locally by a Xen DomU and has a partial checksum.  If it is
+ *	handled on this machine (Dom0 or DomU), then the checksum will not be
+ *	computed.  If it goes off box, the checksum in the packet needs to be
+ *	completed.  Calling skb_checksum_setup converts this to CHECKSUM_HW
+ *	(CHECKSUM_PARTIAL) so that the checksum can be completed.  In later
+ *	kernels, this combination is replaced with CHECKSUM_PARTIAL.
+ * 5. CHECKSUM_UNNECESSARY (with proto_csum_blank false): Packet with a correct
+ *	full checksum or using a protocol without a checksum.  skb->csum is
+ *	undefined.  This is common from devices with receive checksum
+ *	offloading.  This is somewhat similar to CHECKSUM_NONE, except that
+ *	nobody will try to verify the checksum with CHECKSUM_UNNECESSARY.
+ *
+ * Note that on earlier kernels, CHECKSUM_COMPLETE and CHECKSUM_PARTIAL are
+ * both defined as CHECKSUM_HW.  Normally the meaning of CHECKSUM_HW is clear
+ * based on whether it is on the transmit or receive path.  After the datapath
+ * it will be intepreted as CHECKSUM_PARTIAL.  If the packet already has a
+ * checksum, we will panic.  Since we can receive packets with checksums, we
+ * assume that all CHECKSUM_HW packets have checksums and map them to
+ * CHECKSUM_NONE, which has a similar meaning (the it is only different if the
+ * packet is processed by the local IP stack, in which case it will need to
+ * be reverified).  If we receive a packet with CHECKSUM_HW that really means
+ * CHECKSUM_PARTIAL, it will be sent with the wrong checksum.  However, there
+ * shouldn't be any devices that do this with bridging.
+ */
+#ifdef NEED_CSUM_NORMALIZE
+void compute_ip_summed(struct sk_buff *skb, bool xmit)
+{
+	/* For our convenience these defines change repeatedly between kernel
+	 * versions, so we can't just copy them over...
+	 */
+	switch (skb->ip_summed) {
+	case CHECKSUM_NONE:
+		OVS_CB(skb)->ip_summed = OVS_CSUM_NONE;
+		break;
+	case CHECKSUM_UNNECESSARY:
+		OVS_CB(skb)->ip_summed = OVS_CSUM_UNNECESSARY;
+		break;
+#ifdef CHECKSUM_HW
+	/* In theory this could be either CHECKSUM_PARTIAL or CHECKSUM_COMPLETE.
+	 * However, on the receive side we should only get CHECKSUM_PARTIAL
+	 * packets from Xen, which uses some special fields to represent this
+	 * (see below).  Since we can only make one type work, pick the one
+	 * that actually happens in practice.
+	 *
+	 * On the transmit side (basically after skb_checksum_setup()
+	 * has been run or on internal dev transmit), packets with
+	 * CHECKSUM_COMPLETE aren't generated, so assume CHECKSUM_PARTIAL.
+	 */
+	case CHECKSUM_HW:
+		if (!xmit)
+			OVS_CB(skb)->ip_summed = OVS_CSUM_COMPLETE;
+		else
+			OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL;
+
+		break;
+#else
+	case CHECKSUM_COMPLETE:
+		OVS_CB(skb)->ip_summed = OVS_CSUM_COMPLETE;
+		break;
+	case CHECKSUM_PARTIAL:
+		OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL;
+		break;
+#endif
+	}
+
+#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
+	/* Xen has a special way of representing CHECKSUM_PARTIAL on older
+	 * kernels. It should not be set on the transmit path though.
+	 */
+	if (skb->proto_csum_blank)
+		OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL;
+
+	WARN_ON_ONCE(skb->proto_csum_blank && xmit);
+#endif
+}
+#endif /* Linux version < 2.6.22 */
+
+#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
+/* This code is based on skb_checksum_setup() from Xen's net/dev/core.c.  We
+ * can't call this function directly because it isn't exported in all
+ * versions. */
+int vswitch_skb_checksum_setup(struct sk_buff *skb)
+{
+	struct iphdr *iph;
+	unsigned char *th;
+	int err = -EPROTO;
+	__u16 csum_start, csum_offset;
+
+	if (!skb->proto_csum_blank)
+		return 0;
+
+	if (skb->protocol != htons(ETH_P_IP))
+		goto out;
+
+	if (!pskb_may_pull(skb, skb_network_header(skb) + sizeof(struct iphdr) - skb->data))
+		goto out;
+
+	iph = ip_hdr(skb);
+	th = skb_network_header(skb) + 4 * iph->ihl;
+
+	csum_start = th - skb->head;
+	switch (iph->protocol) {
+	case IPPROTO_TCP:
+		csum_offset = offsetof(struct tcphdr, check);
+		break;
+	case IPPROTO_UDP:
+		csum_offset = offsetof(struct udphdr, check);
+		break;
+	default:
+		if (net_ratelimit())
+			pr_err("Attempting to checksum a non-TCP/UDP packet, "
+			       "dropping a protocol %d packet",
+			       iph->protocol);
+		goto out;
+	}
+
+	if (!pskb_may_pull(skb, th + csum_offset + 2 - skb->data))
+		goto out;
+
+	skb->ip_summed = CHECKSUM_PARTIAL;
+	skb->proto_csum_blank = 0;
+	set_skb_csum_pointers(skb, csum_start, csum_offset);
+
+	err = 0;
+
+out:
+	return err;
+}
+#endif /* CONFIG_XEN && HAVE_PROTO_DATA_VALID */
diff --git a/datapath/checksum.h b/datapath/checksum.h
new file mode 100644
index 0000000..08587dd
--- /dev/null
+++ b/datapath/checksum.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2010 Nicira Networks.
+ * Distributed under the terms of the GNU GPL version 2.
+ *
+ * Significant portions of this file may be copied from parts of the Linux
+ * kernel, by Linus Torvalds and others.
+ */
+
+#ifndef CHECKSUM_H
+#define CHECKSUM_H 1
+
+#include <linux/skbuff.h>
+#include <linux/version.h>
+
+#include "datapath.h"
+
+#ifdef NEED_CSUM_NORMALIZE
+void compute_ip_summed(struct sk_buff *skb, bool xmit);
+
+static inline u8 get_ip_summed(struct sk_buff *skb)
+{
+	return OVS_CB(skb)->ip_summed;
+}
+#else
+static inline void compute_ip_summed(struct sk_buff *skb, bool xmit) { }
+static inline u8 get_ip_summed(struct sk_buff *skb)
+{
+	return skb->ip_summed;
+}
+#endif
+
+/* This function closely resembles skb_forward_csum() used by the bridge.  It
+ * is slightly different because we are only concerned with bridging and not
+ * other types of forwarding and can get away with slightly more optimal
+ * behavior.
+ */
+static inline void forward_ip_summed(struct sk_buff *skb)
+{
+#ifdef CHECKSUM_HW
+	if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
+		skb->ip_summed = CHECKSUM_NONE;
+#endif
+}
+
+#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
+int vswitch_skb_checksum_setup(struct sk_buff *skb);
+#else
+static inline int vswitch_skb_checksum_setup(struct sk_buff *skb)
+{
+	return 0;
+}
+#endif
+
+static inline void set_skb_csum_bits(const struct sk_buff *old_skb,
+				     struct sk_buff *new_skb)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+	/* Before 2.6.24 these fields were not copied when
+	 * doing an skb_copy_expand. */
+	new_skb->ip_summed = old_skb->ip_summed;
+	new_skb->csum = old_skb->csum;
+#endif
+#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
+	/* These fields are copied in skb_clone but not in
+	 * skb_copy or related functions.  We need to manually
+	 * copy them over here. */
+	new_skb->proto_data_valid = old_skb->proto_data_valid;
+	new_skb->proto_csum_blank = old_skb->proto_csum_blank;
+#endif
+}
+
+static inline void get_skb_csum_pointers(const struct sk_buff *skb,
+					 u16 *csum_start, u16 *csum_offset)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+	*csum_start = skb->csum_start - skb_headroom(skb);
+	*csum_offset = skb->csum_offset;
+#else
+	*csum_start = skb_transport_header(skb) - skb->data;
+	*csum_offset = skb->csum;
+#endif
+}
+
+static inline void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
+					 u16 csum_offset)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+	skb->csum_start = csum_start;
+	skb->csum_offset = csum_offset;
+#else
+	skb_set_transport_header(skb, csum_start - skb_headroom(skb));
+	skb->csum = csum_offset;
+#endif
+}
+
+#endif /* checksum.h */
diff --git a/datapath/datapath.c b/datapath/datapath.c
index bed4803..4195958 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -44,6 +44,7 @@
 #include <linux/compat.h>
 
 #include "openvswitch/datapath-protocol.h"
+#include "checksum.h"
 #include "datapath.h"
 #include "actions.h"
 #include "flow.h"
@@ -591,171 +592,6 @@ out:
 	local_bh_enable();
 }
 
-#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
-/* This code is based on skb_checksum_setup() from Xen's net/dev/core.c.  We
- * can't call this function directly because it isn't exported in all
- * versions. */
-int vswitch_skb_checksum_setup(struct sk_buff *skb)
-{
-	struct iphdr *iph;
-	unsigned char *th;
-	int err = -EPROTO;
-	__u16 csum_start, csum_offset;
-
-	if (!skb->proto_csum_blank)
-		return 0;
-
-	if (skb->protocol != htons(ETH_P_IP))
-		goto out;
-
-	if (!pskb_may_pull(skb, skb_network_header(skb) + sizeof(struct iphdr) - skb->data))
-		goto out;
-
-	iph = ip_hdr(skb);
-	th = skb_network_header(skb) + 4 * iph->ihl;
-
-	csum_start = th - skb->head;
-	switch (iph->protocol) {
-	case IPPROTO_TCP:
-		csum_offset = offsetof(struct tcphdr, check);
-		break;
-	case IPPROTO_UDP:
-		csum_offset = offsetof(struct udphdr, check);
-		break;
-	default:
-		if (net_ratelimit())
-			pr_err("Attempting to checksum a non-TCP/UDP packet, "
-			       "dropping a protocol %d packet",
-			       iph->protocol);
-		goto out;
-	}
-
-	if (!pskb_may_pull(skb, th + csum_offset + 2 - skb->data))
-		goto out;
-
-	skb->ip_summed = CHECKSUM_PARTIAL;
-	skb->proto_csum_blank = 0;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-	skb->csum_start = csum_start;
-	skb->csum_offset = csum_offset;
-#else
-	skb_set_transport_header(skb, csum_start - skb_headroom(skb));
-	skb->csum = csum_offset;
-#endif
-
-	err = 0;
-
-out:
-	return err;
-}
-#endif /* CONFIG_XEN && HAVE_PROTO_DATA_VALID */
-
- /* Types of checksums that we can receive (these all refer to L4 checksums):
- * 1. CHECKSUM_NONE: Device that did not compute checksum, contains full
- *	(though not verified) checksum in packet but not in skb->csum.  Packets
- *	from the bridge local port will also have this type.
- * 2. CHECKSUM_COMPLETE (CHECKSUM_HW): Good device that computes checksums,
- *	also the GRE module.  This is the same as CHECKSUM_NONE, except it has
- *	a valid skb->csum.  Importantly, both contain a full checksum (not
- *	verified) in the packet itself.  The only difference is that if the
- *	packet gets to L4 processing on this machine (not in DomU) we won't
- *	have to recompute the checksum to verify.  Most hardware devices do not
- *	produce packets with this type, even if they support receive checksum
- *	offloading (they produce type #5).
- * 3. CHECKSUM_PARTIAL (CHECKSUM_HW): Packet without full checksum and needs to
- *	be computed if it is sent off box.  Unfortunately on earlier kernels,
- *	this case is impossible to distinguish from #2, despite having opposite
- *	meanings.  Xen adds an extra field on earlier kernels (see #4) in order
- *	to distinguish the different states.
- * 4. CHECKSUM_UNNECESSARY (with proto_csum_blank true): This packet was
- *	generated locally by a Xen DomU and has a partial checksum.  If it is
- *	handled on this machine (Dom0 or DomU), then the checksum will not be
- *	computed.  If it goes off box, the checksum in the packet needs to be
- *	completed.  Calling skb_checksum_setup converts this to CHECKSUM_HW
- *	(CHECKSUM_PARTIAL) so that the checksum can be completed.  In later
- *	kernels, this combination is replaced with CHECKSUM_PARTIAL.
- * 5. CHECKSUM_UNNECESSARY (with proto_csum_blank false): Packet with a correct
- *	full checksum or using a protocol without a checksum.  skb->csum is
- *	undefined.  This is common from devices with receive checksum
- *	offloading.  This is somewhat similar to CHECKSUM_NONE, except that
- *	nobody will try to verify the checksum with CHECKSUM_UNNECESSARY.
- *
- * Note that on earlier kernels, CHECKSUM_COMPLETE and CHECKSUM_PARTIAL are
- * both defined as CHECKSUM_HW.  Normally the meaning of CHECKSUM_HW is clear
- * based on whether it is on the transmit or receive path.  After the datapath
- * it will be intepreted as CHECKSUM_PARTIAL.  If the packet already has a
- * checksum, we will panic.  Since we can receive packets with checksums, we
- * assume that all CHECKSUM_HW packets have checksums and map them to
- * CHECKSUM_NONE, which has a similar meaning (the it is only different if the
- * packet is processed by the local IP stack, in which case it will need to
- * be reverified).  If we receive a packet with CHECKSUM_HW that really means
- * CHECKSUM_PARTIAL, it will be sent with the wrong checksum.  However, there
- * shouldn't be any devices that do this with bridging. */
-void compute_ip_summed(struct sk_buff *skb, bool xmit)
-{
-	/* For our convenience these defines change repeatedly between kernel
-	 * versions, so we can't just copy them over... */
-	switch (skb->ip_summed) {
-	case CHECKSUM_NONE:
-		OVS_CB(skb)->ip_summed = OVS_CSUM_NONE;
-		break;
-	case CHECKSUM_UNNECESSARY:
-		OVS_CB(skb)->ip_summed = OVS_CSUM_UNNECESSARY;
-		break;
-#ifdef CHECKSUM_HW
-	/* In theory this could be either CHECKSUM_PARTIAL or CHECKSUM_COMPLETE.
-	 * However, on the receive side we should only get CHECKSUM_PARTIAL
-	 * packets from Xen, which uses some special fields to represent this
-	 * (see below).  Since we can only make one type work, pick the one
-	 * that actually happens in practice.
-	 *
-	 * On the transmit side (basically after skb_checksum_setup()
-	 * has been run or on internal dev transmit), packets with
-	 * CHECKSUM_COMPLETE aren't generated, so assume CHECKSUM_PARTIAL. */
-	case CHECKSUM_HW:
-		if (!xmit)
-			OVS_CB(skb)->ip_summed = OVS_CSUM_COMPLETE;
-		else
-			OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL;
-
-		break;
-#else
-	case CHECKSUM_COMPLETE:
-		OVS_CB(skb)->ip_summed = OVS_CSUM_COMPLETE;
-		break;
-	case CHECKSUM_PARTIAL:
-		OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL;
-		break;
-#endif
-	default:
-		pr_err("unknown checksum type %d\n", skb->ip_summed);
-		/* None seems the safest... */
-		OVS_CB(skb)->ip_summed = OVS_CSUM_NONE;
-	}
-
-#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
-	/* Xen has a special way of representing CHECKSUM_PARTIAL on older
-	 * kernels. It should not be set on the transmit path though. */
-	if (skb->proto_csum_blank)
-		OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL;
-
-	WARN_ON_ONCE(skb->proto_csum_blank && xmit);
-#endif
-}
-
-/* This function closely resembles skb_forward_csum() used by the bridge.  It
- * is slightly different because we are only concerned with bridging and not
- * other types of forwarding and can get away with slightly more optimal
- * behavior.*/
-void forward_ip_summed(struct sk_buff *skb)
-{
-#ifdef CHECKSUM_HW
-	if (OVS_CB(skb)->ip_summed == OVS_CSUM_COMPLETE)
-		skb->ip_summed = CHECKSUM_NONE;
-#endif
-}
-
 /* Append each packet in 'skb' list to 'queue'.  There will be only one packet
  * unless we broke up a GSO packet. */
 static int queue_control_packets(struct sk_buff *skb, struct sk_buff_head *queue,
@@ -2119,15 +1955,9 @@ success:
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		if (copy_bytes == skb->len) {
 			__wsum csum = 0;
-			unsigned int csum_start, csum_offset;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-			csum_start = skb->csum_start - skb_headroom(skb);
-			csum_offset = skb->csum_offset;
-#else
-			csum_start = skb_transport_header(skb) - skb->data;
-			csum_offset = skb->csum;
-#endif
+			u16 csum_start, csum_offset;
+
+			get_skb_csum_pointers(skb, &csum_start, &csum_offset);
 			BUG_ON(csum_start >= skb_headlen(skb));
 			retval = skb_copy_and_csum_datagram(skb, csum_start, buf + csum_start,
 							    copy_bytes - csum_start, &csum);
diff --git a/datapath/datapath.h b/datapath/datapath.h
index 3a38235..95a04ba 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -125,6 +125,7 @@ struct dp_port {
 	atomic_t sflow_pool;
 };
 
+/* These are the same values as the checksum constants in 2.6.22+. */
 enum csum_type {
 	OVS_CSUM_NONE = 0,
 	OVS_CSUM_UNNECESSARY = 1,
@@ -132,6 +133,11 @@ enum csum_type {
 	OVS_CSUM_PARTIAL = 3,
 };
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) || \
+	(defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID))
+#define NEED_CSUM_NORMALIZE
+#endif
+
 /**
  * struct ovs_skb_cb - OVS data in skb CB
  * @dp_port: The datapath port on which the skb entered the switch.
@@ -144,7 +150,9 @@ enum csum_type {
 struct ovs_skb_cb {
 	struct dp_port		*dp_port;
 	struct sw_flow		*flow;
+#ifdef NEED_CSUM_NORMALIZE
 	enum csum_type		ip_summed;
+#endif
 	__be32			tun_id;
 };
 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
@@ -161,16 +169,4 @@ void set_internal_devs_mtu(const struct datapath *dp);
 struct datapath *get_dp(int dp_idx);
 const char *dp_name(const struct datapath *dp);
 
-#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
-int vswitch_skb_checksum_setup(struct sk_buff *skb);
-#else
-static inline int vswitch_skb_checksum_setup(struct sk_buff *skb)
-{
-	return 0;
-}
-#endif
-
-void compute_ip_summed(struct sk_buff *skb, bool xmit);
-void forward_ip_summed(struct sk_buff *skb);
-
 #endif /* datapath.h */
diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index 2a959ae..f2fe7e3 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -29,6 +29,7 @@
 #include <net/xfrm.h>
 
 #include "actions.h"
+#include "checksum.h"
 #include "datapath.h"
 #include "table.h"
 #include "tunnel.h"
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index a09669b..7141a01 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -14,6 +14,7 @@
 #include <linux/skbuff.h>
 #include <linux/version.h>
 
+#include "checksum.h"
 #include "datapath.h"
 #include "vport-generic.h"
 #include "vport-internal_dev.h"
diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
index 11421bf..949d119 100644
--- a/datapath/vport-netdev.c
+++ b/datapath/vport-netdev.c
@@ -16,6 +16,7 @@
 
 #include <net/llc.h>
 
+#include "checksum.h"
 #include "datapath.h"
 #include "vport-internal_dev.h"
 #include "vport-netdev.h"
-- 
1.7.1





More information about the dev mailing list