About this list Date view Thread view Subject view Author view Attachment view

From: Herbert Poetzl (herbert_at_13thfloor.at)
Date: Thu 19 Feb 2004 - 01:40:50 GMT


On Wed, Feb 18, 2004 at 04:33:52PM -0800, Cathy Sarisky wrote:
>
> This isn't unique to port 54 either - I see it with http.
>
> It seems that it's actually a question of which service binds first. If
> you have "$a $b" for your IPROOT, you can get both services bound *IF* the
> service on $b binds before the service on $a. If $a gets bound first, the
> service that should bind $b will fail to do so. You can stop the service
> on $a, start the service listening on $b, and then start the service on $a
> to get both listening.
>
> I suspect that by changing the order of ips in your IPROOT you've just
> manipulated the situation so that the first IP in the list isn't bound
> until the service that needs to bind the second IP on the list has
> started. This is pretty unreliable, so you may want to rethink that -
> what happens if your services don't come up in that order, or one crashes
> and is restarted?
>
> BTW, the problem is unique to the first IP. If you assign another IP to
> this vserver, you can bind services to both the second and third IPs in
> any order, provided you leave the first one unused.
>
> Hope that helps clarify the problem, and may I offer a virtual beer and a
> modest gift certificate to an online retailer as incentive to someone for
> fixing it?

okay, that should do the trick ;)

--- net/ipv4/af_inet.c.orig 2004-02-18 15:36:38.000000000 +0100
+++ net/ipv4/af_inet.c 2004-02-19 02:33:54.000000000 +0100
@@ -513,8 +513,7 @@ int inet_bind(struct socket *sock, struc
                 } else if (s_addr == 0x0100007f) {
                         s_addr = s_addr1 = ipv4root;
                         ip_info = NULL;
- } else if (s_addr != v4_bcast
- && s_addr != ipv4root) {
+ } else if (s_addr != v4_bcast /* && s_addr != ipv4root */) {
                         int i;
                         for (i=0; i<nbipv4; i++) {
                                 if (s_addr == ip_info->ipv4[i])

untested and I do not know the sideeffects yet, but I
guess it is the reason for that behaviour ;)

HTH,
Herbert

> Cathy Sarisky
>
>
> On Thu, 19 Feb 2004, Jaap Verhoeven wrote:
>
> > Hi,
> >
> > Our setup: vanilla kernel 2.4.24 with vserver 1.26. On it is
> > a vserver with two IP-adresses assigned to it:
> >
> > IPROOT="$a $b"
> >
> > These adresses are on the same interface. In this vserver, we
> > have the djbdns tool set running. (among others) Two processes
> > get started via the djbdns svscan daemon. Their (happenstance)
> > startup sequence:
> >
> > - first, dnscache starts and binds (listens) to TCP address $b port 54
> > - next, axfrdns starts and binds (listens) to TCP address $a port 54
> >
> > In this setup, axfrdns fails with error EADDRINUSE. Which it isn't:
> > a 'netstat -ln' shows that IP $a port 53 is still available.
> >
> > Manually switching the startup sequence (first axfrdns and
> > next dnscache) shows different behaviour: both processes bind and
> > function properly.
> >
> > This led us to change the IPROOT setting to:
> >
> > IPROOT="$b $a"
> >
> > The result was that both processes bound correctly from the svscan
> > daemon during normal startup.
> >
> > Looking into the relevant code, which is a bit cryptic for me (no
> > offense!), the following bit from the vserver patch to net/ipv4/tcp_ipv4.c
> > may be important:
> >
> > +/*
> > + Return 1 if addr match the socket IP list
> > + or the socket is INADDR_ANY
> > +*/
> > +static inline int tcp_in_list (struct sock *sk, u32 addr)
> > +{
> > + struct iproot_info *ip_info = sk->ip_info;
> > +
> > + if (ip_info) {
> > + int n = ip_info->nbipv4;
> > + int i;
> > +
> > + for (i=0; i<n; i++)
> > + if (ip_info->ipv4[i] == addr)
> > + return 1;
> > + }
> > + else if (!sk->rcv_saddr || sk->rcv_saddr == addr)
> > + return 1;
> > + return 0;
> > +}
> > +
> > +/*
> > + Check if the addresses in sk1 conflict with those in sk2
> > +*/
> > +int tcp_ipv4_addr_conflict (struct sock *sk1, struct sock *sk2)
> > +{
> > + if (sk1->rcv_saddr) {
> > + /* Bind to one address only */
> > + return tcp_in_list (sk2,sk1->rcv_saddr);
> > + } else if (sk1->ip_info) {
> > + /* A restricted bind(any) */
> > + struct iproot_info *ip_info = sk1->ip_info;
> > + int n = ip_info->nbipv4;
> > + int i;
> > +
> > + for (i=0; i<n; i++)
> > + if (tcp_in_list (sk2,ip_info->ipv4[i]))
> > + return 1;
> > + } else /* A bind(any) do not allow other bind on the same port */
> > + return 1;
> > + return 0;
> > +}
> > +
> >
> > The way I read this (and the surrounding code)
> >
> > In tcp_v4_get_port() the requested port to bind gets checked against the
> > already used sockets. This check is only on the port number, so if we request
> > a IP $a port 53 and process #1 is already bound to IP $b port 53, this will
> > lead to a match. This match triggers (via tcp_bind_conflict() ) to a call to
> > tcp_ipv4_addr_conflict() above. Which returns a false positive (which in turn
> > leads to the EADDRINUSE error).
> >
> > I cannot exactly pinpoint where the ordering problem lies (needs more time),
> > but I hope that this (half) analysis is good enough to pinpoint the exact
> > cause by others...
> >
> > BTW: it looks to me that the same code is in version 1.3.6
> >
> > -j
> >
> > _______________________________________________
> > Vserver mailing list
> > Vserver_at_list.linux-vserver.org
> > http://list.linux-vserver.org/mailman/listinfo/vserver
> >
>
> _______________________________________________
> Vserver mailing list
> Vserver_at_list.linux-vserver.org
> http://list.linux-vserver.org/mailman/listinfo/vserver
_______________________________________________
Vserver mailing list
Vserver_at_list.linux-vserver.org
http://list.linux-vserver.org/mailman/listinfo/vserver


About this list Date view Thread view Subject view Author view Attachment view
[Next/Previous Months] [Main vserver Project Homepage] [Howto Subscribe/Unsubscribe] [Paul Sladen's vserver stuff]
Generated on Thu 19 Feb 2004 - 01:42:10 GMT by hypermail 2.1.3