From 7cd594b8bb61c2e83ac2e821bb1d8eedc47071fc Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 16 Apr 2009 15:16:28 -0700 Subject: [PATCH] datapath: Attempt to checksum packets sent to controller on non-Xen kernel. Commit 96660ad113 "datapath: Fix up checksum on Xen before forwarding to controller" made sure that packets sent to the controller were properly checksummed on Xen, where it happens pretty commonly that they are not. It seems possible that on non-Xen machines this could also happen, even though it does not seem to be common, so this commit tries to fix up packets in that case also. This commit adds a WARN_ON_ONCE() call to make it clear that it has triggered. If we ever see this warning, then we should figure out what triggered it and make sure that this code actually works properly. --- datapath/datapath.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index eb2c7db0..ce0042bb 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -682,13 +683,33 @@ dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no, if (skb_queue_len(queue) >= DP_MAX_QUEUE_LEN) goto err; -#ifdef CONFIG_XEN /* If a checksum-deferred packet is forwarded to the controller, - * correct the pointers and checksum. + * correct the pointers and checksum. This happens on a regular basis + * only on Xen (the CHECKSUM_HW case), on which VMs can pass up packets + * that do not have their checksum computed. We also implement it for + * the non-Xen case, but it is difficult to trigger or test this case + * there, hence the WARN_ON_ONCE(). */ err = skb_checksum_setup(skb); if (err) goto err; +#ifndef CHECKSUM_HW + if (skb->ip_summed == CHECKSUM_PARTIAL) { + WARN_ON_ONCE(1); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) + /* Until 2.6.22, the start of the transport header was also the + * start of data to be checksummed. Linux 2.6.22 introduced + * the csum_start field for this purpose, but we should point + * the transport header to it anyway for backward + * compatibility, as dev_queue_xmit() does even in 2.6.28. */ + skb_set_transport_header(skb, skb->csum_start - + skb_headroom(skb)); +#endif + err = skb_checksum_help(skb); + if (err) + goto err; + } +#else if (skb->ip_summed == CHECKSUM_HW) { err = skb_checksum_help(skb, 0); if (err) -- 2.30.2