On Mon, Oct 10, 2005 at 10:21:05AM +0100, Struan Bartlett wrote:
> Hi -
>
> I'm new to this list but I hope you'll forgive me getting right to the
> point.
>
> Our organisation is testing a new version of ldirectord - version 1.77.2.6
> from Debian package 1.2.3-9sarge3 - and have encountered a serious problem
> that shows different behaviour to the previous version we used (1.26) and,
> unlike that previous version, seems to prevent it from working properly.
>
> Here is our ldirectord.cf:
>
> checktimeout=60
> checkinterval=15
> fallback=127.0.0.1
>
> virtual=217.204.41.132:80
> scheduler=wlc
> real=192.168.2.32:80 masq 1024
> real=192.168.2.52:80 masq 1024
> real=192.168.2.62:80 masq 1024
> real=192.168.2.72:80 masq 1024
> service=http
> request="/cgi/NewsNow/Status/"
> receive="ldirectord-ok-string"
> protocol=tcp
>
> Now observe the results on startup:
>
> # /etc/init.d/ldirectord start
> Starting ldirectord
>
> # ipvsadm -Ln
> IP Virtual Server version 1.0.10 (size=4096)
> Prot LocalAddress:Port Scheduler Flags
> -> RemoteAddress:Port Forward Weight ActiveConn InActConn
> TCP 217.204.41.132:80 wlc
> -> 192.168.2.62:80 Masq 1024 0 0
> -> 192.168.2.72:80 Masq 1024 0 0
> -> 192.168.2.52:80 Masq 1024 0 0
> -> 192.168.2.32:80 Masq 1024 0 0
> -> 127.0.0.1:80 Local 1 0 0
>
> As I hope you see, the failover server weight has not been switched to
> zero, which appears to continue to allow some traffic to reach the
> failover servers. I understand this is incorrect.
>
> Please could you advise: is this a known bug, an unknown bug, or an error
> in our configuration of ldirectord?
>
> Kind regards,
>
> Struan Bartlett
>
> P.S. For your information, the situation is not the same after a reload:
>
> # /etc/init.d/ldirectord reload
>
> # ipvsadm -Ln
> IP Virtual Server version 1.0.10 (size=4096)
> Prot LocalAddress:Port Scheduler Flags
> -> RemoteAddress:Port Forward Weight ActiveConn InActConn
> TCP 217.204.41.132:80 wlc
> -> 192.168.2.62:80 Masq 1024 0 0
> -> 192.168.2.72:80 Masq 1024 0 0
> -> 192.168.2.52:80 Masq 1024 0 0
> -> 192.168.2.32:80 Masq 1024 0 0
Hi Struan,
Sorry for letting your bug report fester in my inbox for such a long
time. I've been doing a bit of a blitz on ldirectord bugs over the past
few days, and I found that inadvertantly I had a fix for this problem -
which is still present in the latest version of ldirectord. I'm not sure
if the patch below applied against 1.77.2.6, and it is rather long.
But here is is, just for the record.
--
Horms
H: http://www.vergenet.net/~horms/
W: http://www.valinux.co.jp/en/
Subject: [LDIRECTORD] Tidy up fallback
* Use the same parsing sequence for per-virtual and global fallback
* Cope with the fallback not having a port specified by using
the port of the virtual service
* Split the server feild up into server (ip) and port, and also
add a weight feild so that when its passed to get_real_id_str()
it has the relevant feilds that would be in a real server,
otherwise get_real_id_str() tries to access non-existent values.
This patch solves a bug discovered by Struan Bartlett whereby
the failack server will not be removed as expected if it doesn't
have a port specified.
Thanks also to Tuomo Soini for pointing me in this direction
Signed-off-by: Simon Horman <horms@xxxxxxxxxxxx>
Index: heartbeat/ldirectord/ldirectord.in
===================================================================
--- heartbeat.orig/ldirectord/ldirectord.in 2007-07-05 14:21:42.000000000
+0900
+++ heartbeat/ldirectord/ldirectord.in 2007-07-05 14:21:42.000000000 +0900
@@ -1173,7 +1173,9 @@ sub read_config
$vsrv{virtualhost} = $1;
} elsif ($rcmd =~ /^fallback\s*=\s*(.*)/) {
# Allow specification of a virtual-specific fallback host
$fallback_line=$line;
- $vsrv{fallback}=parse_fallback($line,
$1);
+ $vsrv{fallback} =
+ parse_fallback($line, $1,
+ \%vsrv);
} elsif ($rcmd =~ /^quiescent\s*=\s*(.*)/) {
($1 eq "yes" || $1 eq "no")
or &config_error($line,
"quiescent must be 'yes' or 'no'");
@@ -1240,21 +1242,11 @@ sub read_config
"invalid check count value");
$CHECKCOUNT = $1;
} elsif ($linedata =~ /^fallback\s*=\s*(.*)/) {
- my $tcp = &ld_gethostservbyname($1, "tcp");
- my $udp = &ld_gethostservbyname($1, "udp");
- my $tcp_fb;
- my $udp_fb;
- if(!defined($tcp) and !defined($udp)){
- &config_error($line,
- "invalid address for fallback server");
- }
- if(defined($tcp)) {
- $tcp_fb=&parse_fallback($line, $tcp);
- }
- if(defined($udp)) {
- $udp_fb=&parse_fallback($line, $udp);
- }
- $FALLBACK = { "tcp" => $tcp_fb, "udp" => $udp_fb };
+ my $tcp = parse_fallback($line, $1, undef);
+ my $udp = parse_fallback($line, $1, undef);
+ &_ld_read_config_fallback_resolve($line, "tcp", $tcp);
+ &_ld_read_config_fallback_resolve($line, "udp", $udp);
+ $FALLBACK = { "tcp" => $tcp, "udp" => $udp };
} elsif ($linedata =~ /^autoreload\s*=\s*(.*)/) {
($1 eq "yes" || $1 eq "no")
or &config_error($line,
@@ -1477,16 +1469,20 @@ sub _ld_read_config_fallback_resolve
{
my($line, $protocol, $fallback)=(@_);
- my $ip_port;
-
unless($fallback) {
return;
}
- $fallback->{server}=&ld_gethostservbyname(
- $fallback->{server}, $protocol)
- or &config_error($line,
- "invalid address for fallback server");
+ $fallback->{server} = &ld_gethostbyname($fallback->{server}) or
+ &config_error($line, "invalid address for fallback server: " .
+ $fallback->{server});
+
+ unless($fallback->{"port"}) {
+ return;
+ }
+
+ $fallback->{port} = &ld_getservbyname($fallback->{port}, $protocol) or
+ &config_error($line, "invalid port for fallback server");
}
@@ -1696,17 +1692,22 @@ sub add_real_server
sub parse_fallback
{
- my ($line, $fallback) = (@_);
+ my ($line, $fallback, $vsrv) = (@_);
- my $ip_port;
+ my $server;
+ my $port;
my $fwd;
- $fallback =~ /^\s*(\S+)(\s+(\S+))?\s*/ or
+ $fallback =~ /^\s*([^: ]+)(:(\S+))?(\s+(\S+))?\s*/ or
&config_error($line, "invalid fallback server: $fallback");
- $ip_port=$1;
- $fwd=$3;
+ $server=$1;
+ $port=$3;
+ $fwd=$5;
+ if (not defined($port) and defined($vsrv)) {
+ $port = $vsrv->{"port"};
+ }
if($fwd) {
($fwd eq "gate" || $fwd eq "masq" || $fwd eq "ipip")
@@ -1717,7 +1718,8 @@ sub parse_fallback
$fwd="gate"
}
- return({"server"=>$ip_port, "forward"=>$fwd});
+ return({"server"=>$server, "port"=>$port, "forward"=>$fwd,
+ "weight"=>1});
}
@@ -1999,7 +2001,7 @@ sub ld_start
my $fallback = fallback_find($nv);
if (defined($fallback)) {
- delete($or->{$fallback->{server}});
+ delete($or->{"$fallback->{server}:$fallback->{port}"});
}
for $nr (@$nreal) {
@@ -3251,7 +3253,7 @@ sub fallback_on
return;
}
- &_restore_service($v, $fallback->{server},
+ &_restore_service($v, $fallback->{server} . ":" . $fallback->{port},
get_forward_flag($fallback->{forward}),
"1", "fallback");
}
@@ -3274,7 +3276,7 @@ sub fallback_off
return;
}
- &_remove_service($v, $fallback->{server},
+ &_remove_service($v, $fallback->{server} . ":" . $fallback->{port},
get_forward_flag($fallback->{forward}),
"fallback");
}
@@ -3294,11 +3296,20 @@ sub fallback_find
if( defined $virtual->{"fallback"} ) {
return($virtual->{"fallback"});
- } elsif ( defined($FALLBACK) ) {
- return($FALLBACK->{$virtual->{"protocol"}});
+ } elsif ( not defined($FALLBACK) ) {
+ return undef;
}
- return undef;
+ # If the global fallback has a port, it can be used as is
+ if (defined($FALLBACK->{$virtual->{"protocol"}}->{"port"})) {
+ return $FALLBACK->{$virtual->{"protocol"}};
+ }
+
+ # Else create an anonymous fallback
+ my %anon_fallback = %{$FALLBACK->{$virtual->{"protocol"}}};
+ $anon_fallback{"port"} = $virtual->{"port"};
+
+ return \%anon_fallback;
}
|