[ovs-dev] [PATCH 10/16] datapath: Add function to copy skb checksum bits.

Jesse Gross jesse at nicira.com
Tue Apr 13 14:41:12 UTC 2010


Some kernels don't copy the checksum offload state in the skb
header when doing different types of copies.  Xen adds even more
fields, which are also not consistently copied.  The result is
uninitialized memory and random outcomes.  This adds a function to
consistenly copy these bits across all kernel versions.
---
 datapath/actions.c |   30 ++++++++++++++++++------------
 datapath/actions.h |    2 ++
 2 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 3bc676e..e8c5631 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -22,28 +22,34 @@
 #include "actions.h"
 #include "openvswitch/datapath-protocol.h"
 
-static struct sk_buff *
-make_writable(struct sk_buff *skb, unsigned min_headroom, gfp_t gfp)
+void
+set_skb_csum_bits(const struct sk_buff *old_skb, struct sk_buff *new_skb)
 {
-	if (skb_shared(skb) || skb_cloned(skb)) {
-		struct sk_buff *nskb;
-		unsigned headroom = max(min_headroom, skb_headroom(skb));
-
-		nskb = skb_copy_expand(skb, headroom, skb_tailroom(skb), gfp);
-		if (nskb) {
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
 			/* Before 2.6.24 these fields were not copied when
 			 * doing an skb_copy_expand. */
-			nskb->ip_summed = skb->ip_summed;
-			nskb->csum = skb->csum;
+			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. */
-			nskb->proto_data_valid = skb->proto_data_valid;
-			nskb->proto_csum_blank = skb->proto_csum_blank;
+			new_skb->proto_data_valid = old_skb->proto_data_valid;
+			new_skb->proto_csum_blank = old_skb->proto_csum_blank;
 #endif
+}
+
+static struct sk_buff *
+make_writable(struct sk_buff *skb, unsigned min_headroom, gfp_t gfp)
+{
+	if (skb_shared(skb) || skb_cloned(skb)) {
+		struct sk_buff *nskb;
+		unsigned headroom = max(min_headroom, skb_headroom(skb));
+
+		nskb = skb_copy_expand(skb, headroom, skb_tailroom(skb), gfp);
+		if (nskb) {
+			set_skb_csum_bits(skb, nskb);
 			kfree_skb(skb);
 			return nskb;
 		}
diff --git a/datapath/actions.h b/datapath/actions.h
index c014b36..98b8274 100644
--- a/datapath/actions.h
+++ b/datapath/actions.h
@@ -21,4 +21,6 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
 		    const union odp_action *, int n_actions,
 		    gfp_t gfp);
 
+void set_skb_csum_bits(const struct sk_buff *old_skb, struct sk_buff *new_skb);
+
 #endif /* actions.h */
-- 
1.6.3.3





More information about the dev mailing list