Index: ldirectord =================================================================== RCS file: /home/cvs/linux-ha/linux-ha/ldirectord/ldirectord,v retrieving revision 1.33 diff -u -r1.33 ldirectord --- ldirectord 2001/05/22 08:31:50 1.33 +++ ldirectord 2001/07/15 02:25:32 @@ -328,7 +328,7 @@ # main code if ($opt_h) { - &system_wrapper("/usr/bin/perldoc $LDIRECTORD"); + &system_wrapper("/usr/bin/perldoc -U $LDIRECTORD"); } else { $initializing = 1; init(); @@ -362,7 +362,7 @@ # search for the correct configuration file if ( !defined $ARGV[0] ) { - init_error("Usage ldirectord [configfile] \{start|stop|restart|reload|status\}\nRun ldirectord -h for more information"); + init_error("Usage ldirectord [configfile] [-d] \{start|stop|restart|reload|status\}\nRun ldirectord -h for more information"); } if ( defined $ARGV[0] && defined $ARGV[1] ) { $CONFIG = $ARGV[0]; @@ -375,6 +375,9 @@ $CFGNAME = "ldirectord"; $CMD = $ARGV[0]; } + if ( $CMD ne "start" && $CMD ne "stop" && $CMD ne "status" && $CMD ne "restart" && $CMD ne "reload") { + init_error("Usage ldirectord [configfile] [-d] \{start|stop|restart|reload|status\}\nType ldirectord -h for more information"); + } if ( -f "/etc/ha.d/$CONFIG" ) { $CONFIG = "/etc/ha.d/$CONFIG"; } elsif ( -f "/etc/ha.d/conf/$CONFIG" ) { @@ -382,9 +385,6 @@ } elsif ( ! -f "$CONFIG" ) { init_error("Config file $CONFIG not found"); } - if ( $CMD ne "start" && $CMD ne "stop" && $CMD ne "status" && $CMD ne "restart" && $CMD ne "reload") { - init_error("Usage ldirectord [configfile] \{start|stop|restart|reload|status\}\nType ldirectord -h for more information"); - } my $oldpid; if (open(FILE, "<$RUNPID.$CFGNAME.pid")) { $_ = ; @@ -1079,14 +1079,56 @@ } -sub ld_start +# ld_read_ipvsadm +# Parses the output of "ipvsadm -L -n" and puts into a structure of +# the following from: +# +# { +# (vip_address:vport|fwmark) protocol => { +# "scheduler" => scheduler, +# "persistent" => timeout, # May be omitted +# "netmask" => netmask, # May be omitted +# "real" => { +# rip_address:rport => { +# "forward" => forwarding_mechanism, +# "weight" => weight +# }, +# ... +# } +# }, +# ... +# } +# +# where: +# vip_address: IP address of virtual service +# vport: Port of virtual service +# fwmark: Firewall Mark of virtual service +# scheduler: Scheduler for virtual service +# timeout: Timeout for persistancy. Omitted if service is not persistant. +# nemask: Netmask for persistancy. Omitted if service is not persistant. +# +# rip_address: IP address of real server +# rport: Port of real server +# forwarding_mechanism: Forwarding mechanism for real server. +# One of: gate, ipip, masq. +# weight: Weight of real server +# +# pre: none +# post: ipvsadm -L -n is parsed +# result: reference to sructure detailed above. + +sub ld_read_ipvsadm { - # read status of current ipvsadm -L -n - open(IPVS, "$IPVSADM -L -n |"); - $_ = ; $_ = ; $_ = ; my %oldsrv; my $real_service; my $fwd; + + # read status of current ipvsadm -L -n + unless(open(IPVS, "$IPVSADM -L -n |")){ + &ld_exit(-1, "Could not run $IPVSADM -L -n"); + } + $_ = ; $_ = ; $_ = ; + while () { if ($_ =~ /(\w+)\s+(\d+\.\d+\.\d+\.\d+\:\d+|\d+)\s+(\w+)\s+persistent\s+(\d+)\s+mask\s+(.*)/) { $real_service = "$2 ".lc($1); @@ -1115,18 +1157,29 @@ } close(IPVS); - # modify service, if changed + return(\%oldsrv); +} + +sub ld_start +{ + my $oldsrv; + my $real_service; my $nv; my $nr; + + # read status of current ipvsadm -L -n + $oldsrv=&ld_read_ipvsadm(); + + # modify service, if changed foreach $nv (@VIRTUAL) { my $nreal = $$nv{real}; $$nv{status} = 0; my $real_service = &get_virtual($nv) . " " . $$nv{protocol}; - if (exists($oldsrv{"$real_service"})) { + if (exists($oldsrv->{"$real_service"})) { # service exists, modify it &system_wrapper("$IPVSADM -E $$nv{flags}"); &ld_log("Changed virtual server: " . &get_virtual($nv)); - my $ov = $oldsrv{&get_virtual($nv) . " " . $$nv{protocol}}; + my $ov = $oldsrv->{&get_virtual($nv) . " " . $$nv{protocol}}; my $or = $$ov{real}; for $nr (@$nreal) { if (exists($$or{"$$nr{server}:$$nr{port}"})) { @@ -1144,7 +1197,7 @@ &system_wrapper("$IPVSADM -d $$nv{proto} " . &get_virtual($nv) . " -R $k"); print ("Removed real server: $$nr{server}:$$nr{port} ($$nv{status} x " . &get_virtual($nv) . ")\n"); } - delete $oldsrv{&get_virtual($nv) . " " . $$nv{protocol}}; + delete $oldsrv->{&get_virtual($nv) . " " . $$nv{protocol}}; } else { # no such service, create a new one &system_wrapper("$IPVSADM -A $$nv{flags}"); @@ -1159,7 +1212,7 @@ # remove remaining entries for virtual servers foreach $nv (@OLDVIRTUAL) { - if (exists($oldsrv{&get_virtual($nv) . " " . $$nv{protocol}})) { + if (exists($oldsrv->{&get_virtual($nv) . " " . $$nv{protocol}})) { # service still exists, remove it &system_wrapper("$IPVSADM -D $$nv{proto} " . &get_virtual($nv)); &ld_log("Removed virtual server: " . &get_virtual($nv) . "\n"); @@ -1460,6 +1513,109 @@ } +# _quiecent_service +# Make a real server quiecent +# Should be called by _service_down or fallback_off +# I.e. If you want to change the state of a real server call set_service. +# If you call this function directly then ldirectord will lose track +# of the state of real servers. +# If the real server exists (which it should) make it quiecent. If it +# doesn't exist, just leave it as it will be added by the _service_up code +# as appropriate. +# pre: v: reference to virtual service to with the real server belongs +# rservice: service to restore. Of the form server:port for a tcp or +# udp service. Of the form fwmark for a fwm service. +# rforw: Forwarding mechanism of service. Sould be one of "-g" "-i" or +# "-m" +# tag: Tag to use for logging. Should be either "real" or "fallback" +# post: real service is taken up from the respective virtual service +# if it is inactive +# return: none + +sub _quiecent_service { + my ($v, $rservice, $rforw, $tag) = (@_); + + my $oldsrv; + my $ov; + my $or; + my $ipvsadm_args; + my $log_args; + + $ipvsadm_args = "$$v{proto} " . &get_virtual($v) . " -R $rservice"; + $log_args = "$tag server: $rservice " + . "($$v{status} x " . &get_virtual($v) . ")"; + + $oldsrv=&ld_read_ipvsadm(); + $ov=$oldsrv->{&get_virtual($v) . " " . $v->{"protocol"}}; + if(defined($ov)){ + $or=$ov->{"real"}->{$rservice}; + } + if(defined($or)){ + unless($or->{"weight"} eq 0 and + $or->{"forward"} eq $rforw){ + &system_wrapper("$IPVSADM -e $ipvsadm_args $rforw -w 0"); + &ld_log("Quiecent $log_args"); + } + } +} + + +# _restore_service +# Make a retore a real server. The opposite of _quiecent_server. +# Should be called by _service_up or fallback_on +# I.e. If you want to change the state of a real server call set_service. +# If you call this function directly then ldirectord will lose track +# of the state of real servers. +# If the real server exists (which it should) make it quiecent. If it +# doesn't exist, just leave it as it will be added by the _service_up code +# as appropriate. +# pre: v: reference to virtual service to with the real server belongs +# rservice: service to restore. Of the form server:port for a tcp or +# udp service. Of the form fwmark for a fwm service. +# rforw: Forwarding mechanism of service. Sould be one of "-g" "-i" or +# "-m" +# rwght: Weight of service. Sold be of the form "-w " +# e.g. "-w 1" +# tag: Tag to use for logging. Should be either "real" or "fallback" +# post: real service is taken up from the respective virtual service +# if it is inactive +# return: none + +sub _restore_service { + my ($v, $rservice, $rforw, $rwght, $tag) = (@_); + + my $oldsrv; + my $ov; + my $or; + my $ipvsadm_args; + my $log_args; + + $ipvsadm_args = "$$v{proto} " . &get_virtual($v) + . " -R $rservice $rforw $rwght"; + $log_args = "$tag server: $rservice " + . "($$v{status} x " . &get_virtual($v) . ")"; + + #if the server exists then restore its weight + # otherwise add the server + $oldsrv=&ld_read_ipvsadm(); + $ov=$oldsrv->{&get_virtual($v) . " " . $v->{"protocol"}}; + if(defined($ov)){ + $or=$ov->{"real"}->{$rservice}; + } + if(defined($or)){ + unless("-r " . $or->{"weight"} eq $rwght and + $or->{"forward"} eq $rforw){ + &system_wrapper("$IPVSADM -e $ipvsadm_args"); + &ld_log("Restored $log_args"); + } + } + else { + &system_wrapper("$IPVSADM -a $ipvsadm_args"); + &ld_log("Added $log_args"); + } +} + + # _service_up # Bring a real service up if it is down # Should be called by set_service only @@ -1474,12 +1630,13 @@ sub _service_up { - my ($v, $r) = @_; + my ($v, $r) = (@_); + if ($$r{status}==0) { - &system_wrapper("$IPVSADM -a $$v{proto} " . &get_virtual($v) . " -R $$r{server}:$$r{port} $$r{forw} $$r{wght}"); + &_restore_service($v, $r->{server} . ":" . $r->{port}, + $r->{forw}, $r->{wght}, "real"); $$r{status} = 1; $$v{status}++; - &ld_log("Added real server: $$r{server}:$$r{port} ($$v{status} x " . &get_virtual($v) . ")"); &fallback_off($v); } } @@ -1500,11 +1657,12 @@ sub _service_down { my ($v, $r) = @_; + if ($$r{status}==1) { - &system_wrapper("$IPVSADM -d $$v{proto} " . &get_virtual($v) . " -R $$r{server}:$$r{port}"); + &_quiecent_service($v, $r->{server} . ":" . $r->{port}, + $r->{forw}, "real"); $$r{status} = 0; $$v{status}--; - &ld_log("Removed real server: $$r{server}:$$r{port} ($$v{status} x " . &get_virtual($v) . ")"); &fallback_on($v); } } @@ -1512,38 +1670,34 @@ # fallback_on # Turn on the fallback server for a virtual service if it is inactive -# pre: virtaual: virtual to turn fallback service on for +# pre: v: virtual to turn fallback service on for # post: fallback server is turned on if it was inactive # return: none sub fallback_on { - my ($virtual) = (@_); + my ($v) = (@_); - my $fallback=&fallback_find($virtual); - if (defined $fallback and $$virtual{status}==0) { - # turn on fallback service - &system_wrapper("$IPVSADM -a $$virtual{proto} " . &get_virtual($virtual) . " -R $fallback"); - &ld_log("Started fallback server for: " . &get_virtual($virtual) . " ($fallback)"); + my $fallback=&fallback_find($v); + if (defined $fallback and $$v{status}==0) { + _restore_service($v, $fallback, "", "-w 1", "fallback"); } } # fallback_off # Turn off the fallback server for a virtual service if it is active -# pre: virtaual: virtual to turn fallback service off for +# pre: v: virtual to turn fallback service off for # post: fallback server is turned off if it was active # return: none sub fallback_off { - my ($virtual) = (@_); + my ($v) = (@_); - my $fallback=&fallback_find($virtual); - if (defined $fallback and $$virtual{status}==1) { - # turn off fallback service - &system_wrapper("$IPVSADM -d $$virtual{proto} " . &get_virtual($virtual) . " -R $fallback"); - &ld_log("Turned off fallback server for: " . &get_virtual($virtual) . " ($fallback)"); + my $fallback=&fallback_find($v); + if (defined $fallback and $$v{status}==1) { + _quiecent_service($v, $fallback, "", "fallback"); } } Index: ldirectord.cf =================================================================== RCS file: /home/cvs/linux-ha/linux-ha/ldirectord/ldirectord.cf,v retrieving revision 1.5 diff -u -r1.5 ldirectord.cf --- ldirectord.cf 2000/12/13 18:40:55 1.5 +++ ldirectord.cf 2001/07/15 02:25:32 @@ -14,6 +14,7 @@ checktimeout=3 checkinterval=1 fallback=127.0.0.1:80 +autoreload=yes # A sample virual with a fallback that will override the gobal setting virtual=192.168.6.240:80