datapath: Consolidate checksum compatibility code.
authorJesse Gross <jesse@nicira.com>
Mon, 22 Nov 2010 22:17:24 +0000 (14:17 -0800)
committerJesse Gross <jesse@nicira.com>
Sat, 4 Dec 2010 01:40:26 +0000 (17:40 -0800)
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@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
datapath/Modules.mk
datapath/actions.c
datapath/actions.h
datapath/checksum.c [new file with mode: 0644]
datapath/checksum.h [new file with mode: 0644]
datapath/datapath.c
datapath/datapath.h
datapath/tunnel.c
datapath/vport-internal_dev.c
datapath/vport-netdev.c

index cbf65a666176c9e57772ccab3b3be8214e692df2..b4d40fd100f21471f3f5478c5efc73908f89dde5 100644 (file)
@@ -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 \
index 41812a4546da655656bca0abe4a8394971616098..ec6a46058f1326b1963c2728047a012e411cc357 100644 (file)
@@ -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)
index f2962a73fbbfa22344f2a1be5faaba777c060403..a2585516414bc5dabf55021172eec91a5b4cf061 100644 (file)
@@ -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 (file)
index 0000000..e351949
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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"
+#include "datapath.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
+}
+
+u8 get_ip_summed(struct sk_buff *skb)
+{
+       return OVS_CB(skb)->ip_summed;
+}
+#endif /* NEED_CSUM_NORMALIZE */
+
+#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 (file)
index 0000000..bf93179
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) || \
+       (defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID))
+#define NEED_CSUM_NORMALIZE
+#endif
+
+/* These are the same values as the checksum constants in 2.6.22+. */
+enum csum_type {
+       OVS_CSUM_NONE = 0,
+       OVS_CSUM_UNNECESSARY = 1,
+       OVS_CSUM_COMPLETE = 2,
+       OVS_CSUM_PARTIAL = 3,
+};
+
+#ifdef NEED_CSUM_NORMALIZE
+void compute_ip_summed(struct sk_buff *skb, bool xmit);
+u8 get_ip_summed(struct sk_buff *skb);
+#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 */
index 7b8687d651e74a967fe331ad9e9e9ef7de968267..c8b50889a4937e9cb6dc64b683f07718dabd4ce0 100644 (file)
@@ -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"
@@ -540,171 +541,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,
@@ -2051,15 +1887,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);
index 07406da122d72fff3269d84f0e41aeeb0a14a917..e1bdb7b4ce17f621d0fbc67d6608b774244c2185 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/seqlock.h>
 #include <linux/skbuff.h>
 #include <linux/version.h>
+
+#include "checksum.h"
 #include "flow.h"
 #include "dp_sysfs.h"
 
@@ -100,13 +102,6 @@ struct datapath {
        unsigned int sflow_probability;
 };
 
-enum csum_type {
-       OVS_CSUM_NONE = 0,
-       OVS_CSUM_UNNECESSARY = 1,
-       OVS_CSUM_COMPLETE = 2,
-       OVS_CSUM_PARTIAL = 3,
-};
-
 /**
  * struct ovs_skb_cb - OVS data in skb CB
  * @vport: The datapath port on which the skb entered the switch.
@@ -119,7 +114,9 @@ enum csum_type {
 struct ovs_skb_cb {
        struct vport            *vport;
        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)
@@ -136,16 +133,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 */
index 37ec4d9ef1f5d4aa2dc59c367605fe137768ba28..ec3ad936f824fbaf6857a38ef9a79a1bb53b13df 100644 (file)
@@ -29,6 +29,7 @@
 #include <net/xfrm.h>
 
 #include "actions.h"
+#include "checksum.h"
 #include "datapath.h"
 #include "table.h"
 #include "tunnel.h"
index b4dacd0ff501b4413f10567987fc17863326bcc2..86171dbc9cb305db2ad1d84b72d9e599e56c84c2 100644 (file)
@@ -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"
index 2325959f6e7c15aa6b6b273da56f05d46ac191cf..dfeccac9ca825784ac82d8c50a1ed1f6d1f9bc3e 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <net/llc.h>
 
+#include "checksum.h"
 #include "datapath.h"
 #include "vport-internal_dev.h"
 #include "vport-netdev.h"