#!/usr/local/bin/perl # vip_setup v2.3.2 (c) 7.5.2003 by Andreas Ley (u) 16.8.2011 # Run interface setup commands to add virtual interfaces for virtual IPs # Send list of virtual interfaces and real servers to director instances # Option -a requires installed package "iputils-arping", not "arping" ! $arp_count = 10; $direct_routing_if = "lo"; use Getopt::Std; sub usage { my $image = $0; $image =~ s!.*/!!; print STDERR "Usage: $image [-u|-a|-A] [-i|-I if [-m mask]] [-d cluster-directory] [-v] [-n] [IP [...]]\n"; print STDERR "-u Unconfigure interfaces\n"; print STDERR "-a Also send gratious ARPs\n"; print STDERR "-A Also send gratious ARPs, but don't wait for it\n"; print STDERR "-i Force interface to use\n"; print STDERR "-I Default interface if none matches\n"; print STDERR "-m Force mask to use\n"; print STDERR "-d Also run director setup\n"; print STDERR "-v Verbose mode\n"; print STDERR "-n Dry run\n"; print STDERR "If not given as parameters, virtual IPs are read from stdin\n"; exit(1); } getopts('DhxuaAi:I:m:d:vn') || &usage; &usage if ($opt_h || $opt_u && ($opt_a || $optA) || $opt_a && $opt_A || $opt_i && $opt_I || $opt_m && !($opt_i || $opt_I)); # We need to parse ifconfig output undef $ENV{'LANG'}; undef $ENV{'LC_ALL'}; undef $ENV{'LC_MESSAGES'}; ################################################################################ # # Read virtual IPs # if ($#ARGV >= 0) { %vip = map {$_ => 1} @ARGV; } else { while (<>) { chomp; $vip{$1} = 1 if (/^\s*(\d+\.\d+\.\d+\.\d+)\s*$/); } } ################################################################################ # # Check /etc/rc.values for DIRECT_ROUTING # if (open(RC,"/etc/rc.values")) { while () { chomp; if (/^DIRECT_ROUTING=/) { for (split(/ /,$')) { if (/\//) { print "Using direct routing for $`/$'\n" if ($opt_v); &add_ip_mask($direct_routing_if,$`,$'); } } last; } } close(RC); } ################################################################################ # # Read interfaces # sub if_match { my ($if,$ip) = @_; for $i (0..$#{$if_ip{$if}}) { print STDERR "&if_match($if,$ip): ",${$if_ip{$if}}[$i]," ",${$if_mask{$if}}[$i],"\n" if ($opt_D); print STDERR "&if_match($if,$ip) = ",${$if_mask{$if}}[$i],"\n" if ($opt_D && &mask($ip,${$if_mask{$if}}[$i]) eq ${$if_ip{$if}}[$i]); return (${$if_mask{$if}}[$i]) if (&mask($ip,${$if_mask{$if}}[$i]) eq ${$if_ip{$if}}[$i]); } print STDERR "&if_match($if,$ip) = undef\n" if ($opt_D); return (undef); } sub add_ip_mask { my ($if,$ip,$mask) = @_; #print STDERR "add_ip_mask($if,$ip,$mask)\n" if ($opt_D); return if (&if_match($if,$ip)); print STDERR "Adding $ip/$mask to $if\n" if ($opt_D); push(@{$if_ip{$if}},&mask($ip,$mask)); push(@{$if_mask{$if}},$mask); } open(IFCONFIG,"/sbin/ifconfig |") || die "Can't run /sbin/ifconfig: $!\n"; while () { chomp; if (/^(\S+)/) { $if = $1; } elsif (/^\s+inet addr:(\d+\.\d+\.\d+\.\d+).*Mask:(\d+\.\d+\.\d+\.\d+)/) { $ip = $1; $mask = $2; $if{$ip} = $if; $ip{$if} = $ip; $mask{$if} = $mask unless ($if =~ /:/ || defined($mask{$if})); $if =~ s/:.*//; &add_ip_mask($if,$ip,$mask); } } close(IFCONFIG); if (defined($opt_i) && !defined($mask{$opt_i})) { die "No such interface: $opt_i\n"; } ################################################################################ # # Setup virtual interfaces # sub byip { my ($a1,$a2,$a3,$a4) = split(/\./,$a); my ($b1,$b2,$b3,$b4) = split(/\./,$b); return ($a1 <=> $b1) if ($a1 != $b1); return ($a2 <=> $b2) if ($a2 != $b2); return ($a3 <=> $b3) if ($a3 != $b3); return ($a4 <=> $b4); } sub mask { my ($ip,$mask) = @_; my (@ip) = split(/\./,$ip); my (@mask) = split(/\./,$mask); my ($i,@result); for my $i (0..$#ip) { $result[$i] = 0+$ip[$i] & 0+$mask[$i]; } print STDERR "mask($ip,$mask) = ",join('.',@result),"\n" if ($opt_D); return (join('.',@result)); } sub bcast { my ($ip,$mask) = @_; my (@ip) = split(/\./,$ip); my (@mask) = split(/\./,$mask); my ($i,@result); for my $i (0..$#ip) { $result[$i] = 0+$ip[$i] & 0+$mask[$i] | 255 & ~(0+$mask[$i]); } #print STDERR "bcast($ip,$mask) = ",join('.',@result),"\n" if ($opt_D); return (join('.',@result)); } for $ip (sort byip keys %vip) { if ($opt_u) { if (defined($if{$ip})) { print "Unconfiguring $ip from $if{$ip}\n" if ($opt_v); @ifconfig = ('/sbin/ifconfig',$if{$ip},'down'); if ($opt_n) { print join(" ",@ifconfig)."\n"; } else { system(@ifconfig) && die "Failed to run ".join(" ",@ifconfig)."\n"; } } elsif ($opt_v) { print "$ip not configured on any interface\n"; } } else { unless (defined($if{$ip})) { my @if; if (defined($opt_i)) { push(@if,$opt_i); $mask = defined($opt_m)?$opt_m:$mask{$opt_i}; } else { for $if (keys %if_ip) { $_ = &if_match($if,$ip); if (defined($_)) { push(@if,$if); $mask = $_; } } } print STDERR "Interface list for $ip: ",join(', ',@if),"\n" if ($opt_D); if (defined($opt_I) && $#if < 0) { push(@if,$opt_I); $mask = defined($opt_m)?$opt_m:$mask{$opt_I}; } if ($#if < 0) { print STDERR "No suitable interface for $ip found!\n"; } elsif ($#if > 0) { print STDERR "More than one interface match $ip: ",join(" ",@if),"\n"; } else { $if = $if[0]; $mask = "255.255.255.255" if ($if eq $direct_routing_if); print "Configuring $ip on $if\n" if ($opt_v); do { $cnt{$if}++; } while (defined($ip{$if.":".$cnt{$if}})); $bcast = &bcast($ip,$mask); @ifconfig = ('/sbin/ifconfig',$if.':'.$cnt{$if},$ip,'broadcast',$bcast,'netmask',$mask); $arping = -x '/usr/bin/arping' ? '/usr/bin/arping' : '/usr/sbin/arping'; @arping = ($arping,'-U','-q','-c',$arp_count,'-I',$if,$ip); if ($opt_n) { print join(" ",@ifconfig)."\n"; print join(" ",@arping)."\n" if ($opt_a || $opt_A); } else { system(@ifconfig) && die "Failed to run ".join(" ",@ifconfig)."\n"; if ($opt_a || $opt_A) { #system(@arping) && die "Failed to run ".join(" ",@arping)."\n"; die "Can't fork: $!\n" unless (defined($pid = fork)); if ($pid) { print "Child process $pid started for ".join(" ",@arping)."\n" if ($opt_D); if ($opt_a) { push(@wait,$pid); $cmd{$pid} = join(" ",@arping); } } else { print "Child process running ".join(" ",@arping)."\n" if ($opt_D); exec(@arping); die "Failed to exec ".join(" ",@arping)."\n"; } } } } } elsif ($opt_v) { print "$ip already configured on $if{$ip}\n"; } } } if ($opt_a) { for $pid (@wait) { warn "Failed to run ".$cmd{$pid}.": return code $?\n" if (waitpid($pid,0) && $?); } } ################################################################################ # # Setup director instances # sub private { my ($ip) = @_; my (@ip) = split(/\./,$ip); return ($ip[0] == 10 || $ip[0] == 172 && 16 <= $ip[1] && $ip[1] <= 31 || $ip[0] == 192 && $ip[1] == 168); } if (defined($opt_d)) { open(SERVERS,"$opt_d/servers") || die "Can't open $opt_d/servers: $!\n"; while () { chomp; $servers .= "\t$_"; } close(SERVERS); open(CONFIG,">$opt_d/config") || die "Can't write to $opt_d/config: $!\n"; for $ip (sort byip keys %vip) { print CONFIG "$ip$servers\n" if (&if_match($direct_routing_if,$ip)); } close(CONFIG); open(DIRECTORS,"$opt_d/directors") || die "Can't open $opt_d/directors: $!\n"; while () { chomp; if ($opt_n) { print "/usr/machine/bin/scp1 -i $opt_d/identity $opt_d/config $_:\n" } else { system("/usr/machine/bin/scp1","-i","$opt_d/identity","$opt_d/config","$_:") && die "Failed to run /usr/machine/bin/scp1 -i $opt_d/identity $opt_d/config $_:\n"; } } close(DIRECTORS); }