This is a port of Carlos Lozano's 2.4 patch[1] to 2.6.16.  I believe
Carlos's comments about the original 2.4 patch still pertain here:

        We have a machine that must be both a client and director. The
        two problems to solve are:
                * ipvs doesn't handle loopback packets
                * the return packets are handled by ip_vs_in, and not
                  by ip_vs_out.

With kernel 2.6 there's an additional problem to solve:
  * there's a shortcut used to recompute the tcp checksum that doesn't
    work in this case

The attached patch fixes the problems listed above.

1. 
http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.LVS-NAT.html#carlos_solution
diff -Naur linux-source-2.6.16/net/ipv4/ipvs/ip_vs_core.c 
linux-source-2.6.16-ipvs_loopback/net/ipv4/ipvs/ip_vs_core.c
--- linux-source-2.6.16/net/ipv4/ipvs/ip_vs_core.c      2006-03-19 
23:53:29.000000000 -0600
+++ linux-source-2.6.16-ipvs_loopback/net/ipv4/ipvs/ip_vs_core.c        
2006-10-02 17:28:18.000000000 -0500
@@ -953,7 +953,7 @@
         *      ... don't know why 1st test DOES NOT include 2nd (?)
         */
        if (unlikely(skb->pkt_type != PACKET_HOST
-                    || skb->dev == &loopback_dev || skb->sk)) {
+                    || skb->sk)) {
                IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d 
ignored\n",
                          skb->pkt_type,
                          skb->nh.iph->protocol,
@@ -978,6 +978,14 @@
 
        ihl = iph->ihl << 2;
 
+       cp = pp->conn_out_get(skb, pp, iph, ihl, 0);
+
+       if (cp) {
+               __ip_vs_conn_put(cp);
+
+               return (ip_vs_out(hooknum,pskb,in,out,okfn));
+       }
+
        /*
         * Check if the packet belongs to an existing connection entry
         */
diff -Naur linux-source-2.6.16/net/ipv4/ipvs/ip_vs_proto_tcp.c 
linux-source-2.6.16-ipvs_loopback/net/ipv4/ipvs/ip_vs_proto_tcp.c
--- linux-source-2.6.16/net/ipv4/ipvs/ip_vs_proto_tcp.c 2006-03-19 
23:53:29.000000000 -0600
+++ linux-source-2.6.16-ipvs_loopback/net/ipv4/ipvs/ip_vs_proto_tcp.c   
2006-10-02 17:27:08.000000000 -0500
@@ -200,23 +200,15 @@
        /*
         *      Adjust TCP checksums
         */
-       if (!cp->app) {
-               /* Only port and addr are changed, do fast csum update */
-               tcp_fast_csum_update(tcph, cp->vaddr, cp->daddr,
-                                    cp->vport, cp->dport);
-               if ((*pskb)->ip_summed == CHECKSUM_HW)
-                       (*pskb)->ip_summed = CHECKSUM_NONE;
-       } else {
-               /* full checksum calculation */
-               tcph->check = 0;
-               (*pskb)->csum = skb_checksum(*pskb, tcphoff,
-                                            (*pskb)->len - tcphoff, 0);
-               tcph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
-                                               (*pskb)->len - tcphoff,
-                                               cp->protocol,
-                                               (*pskb)->csum);
-               (*pskb)->ip_summed = CHECKSUM_UNNECESSARY;
-       }
+       /* full checksum calculation */
+       tcph->check = 0;
+       (*pskb)->csum = skb_checksum(*pskb, tcphoff,
+                                                (*pskb)->len - tcphoff, 0);
+       tcph->check = csum_tcpudp_magic(cp->caddr, cp->daddr,
+                                       (*pskb)->len - tcphoff,
+                                       cp->protocol,
+                                       (*pskb)->csum);
+       (*pskb)->ip_summed = CHECKSUM_UNNECESSARY;
        return 1;
 }
 

Reply via email to