ipvs: fix CHECKSUM_PARTIAL for TCP, UDP
authorJulian Anastasov <ja@ssi.bg>
Sun, 17 Oct 2010 13:14:31 +0000 (16:14 +0300)
committerSimon Horman <horms@verge.net.au>
Thu, 21 Oct 2010 08:49:39 +0000 (10:49 +0200)
  Fix CHECKSUM_PARTIAL handling. Tested for IPv4 TCP,
UDP not tested because it needs network card with HW CSUM support.
May be fixes problem where IPVS can not be used in virtual boxes.
Problem appears with DNAT to local address when the local stack
sends reply in CHECKSUM_PARTIAL mode.

  Fix tcp_dnat_handler and udp_dnat_handler to provide
vaddr and daddr in right order (old and new IP) when calling
tcp_partial_csum_update/udp_partial_csum_update (CHECKSUM_PARTIAL).

Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
net/netfilter/ipvs/ip_vs_proto_tcp.c
net/netfilter/ipvs/ip_vs_proto_udp.c

index 282d24de8592e659466657533b10ad6eadf4bd5c..318d011036db3710c685fc142ea9e7df5100b1a7 100644 (file)
@@ -101,15 +101,15 @@ tcp_partial_csum_update(int af, struct tcphdr *tcph,
 #ifdef CONFIG_IP_VS_IPV6
        if (af == AF_INET6)
                tcph->check =
-                       csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
+                       ~csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
                                         ip_vs_check_diff2(oldlen, newlen,
-                                               ~csum_unfold(tcph->check))));
+                                               csum_unfold(tcph->check))));
        else
 #endif
        tcph->check =
-               csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
+               ~csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
                                ip_vs_check_diff2(oldlen, newlen,
-                                               ~csum_unfold(tcph->check))));
+                                               csum_unfold(tcph->check))));
 }
 
 
@@ -223,7 +223,7 @@ tcp_dnat_handler(struct sk_buff *skb,
         *      Adjust TCP checksums
         */
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
+               tcp_partial_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr,
                                        htons(oldlen),
                                        htons(skb->len - tcphoff));
        } else if (!cp->app) {
index 8553231b5d412ca557f8699ee998e05351152213..f9290893bd93b7a360410c7f43a4ca989421c5db 100644 (file)
@@ -102,15 +102,15 @@ udp_partial_csum_update(int af, struct udphdr *uhdr,
 #ifdef CONFIG_IP_VS_IPV6
        if (af == AF_INET6)
                uhdr->check =
-                       csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
+                       ~csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
                                         ip_vs_check_diff2(oldlen, newlen,
-                                               ~csum_unfold(uhdr->check))));
+                                               csum_unfold(uhdr->check))));
        else
 #endif
        uhdr->check =
-               csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
+               ~csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
                                ip_vs_check_diff2(oldlen, newlen,
-                                               ~csum_unfold(uhdr->check))));
+                                               csum_unfold(uhdr->check))));
 }
 
 
@@ -229,7 +229,7 @@ udp_dnat_handler(struct sk_buff *skb,
         *      Adjust UDP checksums
         */
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
+               udp_partial_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
                                        htons(oldlen),
                                        htons(skb->len - udphoff));
        } else if (!cp->app && (udph->check != 0)) {