LVS
lvs-users
Google
 
Web LinuxVirtualServer.org

Re: lvs_nat blocking port?

To: lvs-users@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: lvs_nat blocking port?
From: Ben North <ben@xxxxxxxxxxxxx>
Date: Thu, 6 Dec 2001 09:08:36 +0000
>       I've set up a small LVS_NAT-based http load
> balancer but can't seem to connect to the realservers
> behind them via IP on port 80.
> [...]
> Trying to connect directly to the real servers
> on port 80, though, translates everything correctly,
> but generates an ICMP port unreach.
> 
> Anyone dealt with something like this before?

Yes.  I came across this recently, and coincidentally it was
discussed on the list within the last week or so too.  The
problem is that LVS takes an interest in all packets with a
source IP:port of a Real Service's IP:port, as they're passing
through the FORWARD block.  This is of course necessary ---
normally such packets would exist because of a connection
between some client and the Virtual Service, mapped by LVS to
some Real Service.  The packets then have their source address
altered so that they're addressed VIP:VPort -> CIP:CPort.

However, if some route exists for a client to make connections
directly to the Real Service, then the packets from the Real
Service to the client will not be matched with any existing LVS
connection (because there isn't one).  At this point, the LVS
NAT code will steal the packet and send the "Port unreachable"
message you've observed back to the Real Server.  A fix to the
problem is to #ifdef out this code --- it's in ip_vs_out() in
the file ip_vs_core.c, and it should be modified along the lines
of

        /*
         *      Now hunt the list to see if we have an old entry
         */
        cp = ip_vs_conn_out_get(iph->protocol, iph->saddr, h.portp[0],
                                iph->daddr, h.portp[1]);
        if (!cp) {
#if 0
                if (ip_vs_lookup_real_service(iph->protocol,
                                              iph->saddr, h.portp[0])) {
                        /*
                         * Notify the real server: there is no existing
                         * entry if it is not RST packet or not TCP packet.
                         */
                        if (!h.th->rst || iph->protocol != IPPROTO_TCP) {
                                icmp_send(skb, ICMP_DEST_UNREACH,
                                          ICMP_PORT_UNREACH, 0);
                                kfree_skb(skb);
                                return NF_STOLEN;
                        }
                }
#endif
                IP_VS_DBG(12, "packet for %s %d.%d.%d.%d:%d "
                          "continue traversal as normal.\n",
                          ip_vs_proto_name(iph->protocol),
                          NIPQUAD(iph->daddr),
                          ntohs(h.portp[1]));
                return NF_ACCEPT;
        }

As to why this code was ever there, there was some discussion on
the list recently, but I can't remember the details, sorry.
Maybe somebody else will remember, or the archives might help.

Hope this helps,

Ben.

-- 
_______________________________________
Ben North             Software Engineer
a n t e f a c t o     t: +353 1 8586008
www.antefacto.com     f: +353 1 8586014
181 Parnell Street - Dublin 1 - Ireland


<Prev in Thread] Current Thread [Next in Thread>