# IBM(c) 2010 EPL license http://www.eclipse.org/legal/epl-v10.html #------------------------------------------------------- =head1 xCAT plugin package to handle xdsh Supported command: nodenetconn ipforward (internal command) =cut #------------------------------------------------------- package xCAT_plugin::route; BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; } use lib "$::XCATROOT/lib/perl"; use strict; use xCAT::Table; use xCAT::Utils; use xCAT::TableUtils; use xCAT::ServiceNodeUtils; use xCAT::NetworkUtils; use xCAT::MsgUtils; use Getopt::Long; use xCAT::NodeRange; use Data::Dumper; use xCAT::NodeRange; use IO::File; use File::Copy; use File::Path; use Sys::Hostname; my $xcat_config_start="# xCAT_CONFIG_START"; my $xcat_config_end="# xCAT_CONFIG_END"; 1; #------------------------------------------------------- =head3 handled_commands Return list of commands handled by this plugin =cut #------------------------------------------------------- sub handled_commands { return { makeroutes => "route", ipforward => "route" }; } #------------------------------------------------------- =head3 preprocess_request Preprocess the command =cut #------------------------------------------------------- sub preprocess_request { my $request = shift; my $callback = shift; my $sub_req = shift; my $command = $request->{command}->[0]; my $args = $request->{arg}; #if already preprocessed, go straight to request if ((defined($request->{_xcatpreprocessed})) && ($request->{_xcatpreprocessed}->[0] == 1)) { return [$request]; } if ($command eq "ipforward") { my $nodes=$request->{node}; my @sns=(); if ($nodes) { @sns=@$nodes; } #print "sns=@sns\n"; my @requests=(); foreach (@sns) { my $reqcopy = {%$request}; $reqcopy->{'node'}=[]; $reqcopy->{'_xcatdest'}=$_; $reqcopy->{_xcatpreprocessed}->[0] = 1; push @requests, $reqcopy; } return \@requests; } else { # parse the options @ARGV=(); if ($args) { @ARGV=@{$args}; } Getopt::Long::Configure("bundling"); Getopt::Long::Configure("no_pass_through"); my $routelist_in; my $delete=0; if(!GetOptions( 'h|help' => \$::HELP, 'v|version' => \$::VERSION, 'r|routename=s' => \$routelist_in, 'd|delete' => \$delete, )) { &usage($callback); return 1; } # display the usage if -h or --help is specified if ($::HELP) { &usage($callback); return 0; } # display the version statement if -v or --verison is specified if ($::VERSION) { my $rsp={}; $rsp->{data}->[0]= xCAT::Utils->Version(); $callback->($rsp); return 0; } #make sure the input routes are in the routes table. if ($routelist_in) { my %all_routes=(); my $routestab=xCAT::Table->new("routes", -create =>1); if ($routestab) { my @tmp1=$routestab->getAllAttribs(('routename', 'net')); if (@tmp1 > 0) { foreach(@tmp1) { $all_routes{$_->{routename}} = $_; $_->{process} = 0; } } } my @badroutes=(); foreach(split(',', $routelist_in)) { if (!exists($all_routes{$_})) { push(@badroutes, $_); } } if (@badroutes>0) { my $rsp={}; my $badroutes_s=join(',', @badroutes); if (@badroutes==1) { $rsp->{error}->[0]= "The route $badroutes_s is not defined in the routes table."; } else { $rsp->{error}->[0]= "The routes $badroutes_s are not defined in the routes table."; } $callback->($rsp); return 1; } } if (@ARGV == 0) { #no noderange is specifiled, assume it is on the mn my $reqcopy = {%$request}; $reqcopy->{_xcatpreprocessed}->[0] = 1; if ($routelist_in) { $reqcopy->{routelist}->[0]=$routelist_in; } if ($delete) { $reqcopy->{delete}->[0]=1; } return [$reqcopy]; } else { #noderange is specified, my $ret=[]; my $nr=$ARGV[0]; my @noderange = xCAT::NodeRange::noderange($nr, 1); my @missednodes=xCAT::NodeRange::nodesmissed(); if (@missednodes > 0) { my $rsp={}; $rsp->{error}->[0]= "Invalide nodes in noderange: " . join(',', @missednodes); $callback->($rsp); return 1; } my @servicenodes=xCAT::ServiceNodeUtils->getSNList(); #print "noderange=@noderange, missednodes=@missednodes, servicenodes=@servicenodes\n"; #pick out the service nodes from the node list foreach my $sn (@servicenodes) { if (grep /^$sn$/, @noderange) { @noderange=grep(!/^$sn$/, @noderange); my $reqcopy = {%$request}; $reqcopy->{_xcatpreprocessed}->[0] = 1; $reqcopy->{'_xcatdest'} = $sn; $reqcopy->{node} = [$sn]; if ($routelist_in) { $reqcopy->{routelist}->[0]=$routelist_in; } if ($delete) { $reqcopy->{delete}->[0]=1; } push(@$ret, $reqcopy); } } #now find out the service nodes for each node and #send the request to the service node my $sn_hash = xCAT::ServiceNodeUtils->get_ServiceNode(\@noderange, "xcat", "MN"); # build each request for each service node foreach my $sn (keys %$sn_hash) { my $reqcopy = {%$request}; $reqcopy->{node} = $sn_hash->{$sn}; $reqcopy->{'_xcatdest'} = $sn; $reqcopy->{_xcatpreprocessed}->[0] = 1; $reqcopy->{remote}->[0] = 1; if ($routelist_in) { $reqcopy->{routelist}->[0]=$routelist_in; } if ($delete) { $reqcopy->{delete}->[0]=1; } push(@$ret, $reqcopy); } return $ret; } } } #------------------------------------------------------- =head3 process_request Process the command =cut #------------------------------------------------------- sub process_request { my $request = shift; my $callback = shift; my $sub_req = shift; my $command = $request->{command}->[0]; if ($command eq "makeroutes") { return process_makeroutes($request, $callback, $sub_req); } elsif ($command eq "ipforward") { return process_ipforward($request, $callback, $sub_req); } return; } sub process_makeroutes { my $request = shift; my $callback = shift; my $sub_req = shift; my $command = $request->{command}->[0]; my $nodes; if (exists($request->{node})) { $nodes=$request->{node}; } my $delete=0; if (exists($request->{delete})) { $delete=$request->{delete}->[0]; } my $remote=0; if (exists($request->{remote})) { $remote=$request->{remote}->[0]; } my $routelist; if (exists($request->{routelist})) { $routelist=$request->{routelist}->[0]; } #get all the routes from the routes table my %all_routes=(); my $routestab=xCAT::Table->new("routes", -create =>1); if ($routestab) { my @tmp1=$routestab->getAllAttribs(('routename', 'net', 'mask', 'gateway', 'ifname')); if (@tmp1 > 0) { foreach(@tmp1) { $all_routes{$_->{routename}} = $_; $_->{process} = 0; } } } if ($routelist) { foreach(split(',', $routelist)) { $all_routes{$_}->{process}=1; if (($nodes) && ($remote)) { $all_routes{$_}->{nodes}=$nodes; } } } else { #get the routes for each nodes from the noderes table (for sn and cn) and site table (for mn) if ($nodes) { my $nrtab=xCAT::Table->new("noderes", -create =>1); my $nrhash = $nrtab->getNodesAttribs($nodes, ['routenames']) ; foreach(@$nodes) { my $node=$_; my $rn; my $ent=$nrhash->{$node}->[0]; if (ref($ent) and defined $ent->{routenames}) { $rn = $ent->{routenames}; } if ($rn) { my @a=split(',', $rn); my @badroutes=(); foreach my $r (@a) { if (! exists($all_routes{$r})) { push(@badroutes, $r); } else { #print "got here...., remote=$remote\n"; $all_routes{$r}->{process}=1; if ($remote) { my $pa=$all_routes{$r}->{nodes}; if ($pa) { push(@$pa, $node); } else { $all_routes{$r}->{nodes}=[$node]; } } } } if (@badroutes > 0) { my $badroutes_s=join(',', @badroutes); my $rsp={}; if (@badroutes==1) { $rsp->{error}->[0]= "The route $badroutes_s is not defined in the routes table. Please check noderes.routenames for node $node."; } else { $rsp->{error}->[0]= "The routes $badroutes_s are not defined in the routes table. Please check noderes.routenames for node $node."; } $callback->($rsp); return 1; } } else { my $rsp={}; $rsp->{data}->[0]= "No routes defined in noderes.routenames for node $node, skiping $node."; $callback->($rsp); } } } else { #this is mn, get the routes from the site table my @mnroutes = xCAT::TableUtils->get_site_attribute("mnroutenames"); if ($mnroutes[0]) { my @a=split(',', $mnroutes[0]); my @badroutes=(); foreach my $r (@a) { if (! exists($all_routes{$r})) { push(@badroutes, $r); } else { $all_routes{$r}->{process}=1; } } if (@badroutes > 0) { my $badroutes_s=join(',', @badroutes); my $rsp={}; if (@badroutes==1) { $rsp->{error}->[0]= "The route $badroutes_s is not defined in the routes table. Please check site.mnroutenames for the management node."; } else { $rsp->{error}->[0]= "The routes $badroutes_s are not defined in the routes table. Please check site.mnroutenames for the management node."; } $callback->($rsp); return 1; } } else { my $rsp={}; $rsp->{data}->[0]= "No routes defined in the site.mnroutenames for the management node."; $callback->($rsp); return 1; } } } #print Dumper(%all_routes); #now let's handle the route creatation and deletion my @sns=(); my $installdir = xCAT::TableUtils->getInstallDir(); while (my ($routename, $route_hash) = each(%all_routes)) { if ($route_hash->{process}) { my ($gw_name, $gw_ip)=xCAT::NetworkUtils->gethostnameandip($route_hash->{gateway}); push(@sns, $gw_name); if ($route_hash->{net} =~ /:/) { # Remove the subnet postfix like /64 if ($route_hash->{net} =~ /\//) { $route_hash->{net} =~ s/\/.*$//; } # Remove the "/" from the ipv6 prefixlength if ($route_hash->{mask}) { if ($route_hash->{mask} =~ /\//) { $route_hash->{mask} =~ s/^\///; } } } if ($remote) { #to the nodes my $nodes_tmp=$route_hash->{nodes}; #print "nodes=@$nodes_tmp, remote=$remote, delete=$delete\n"; my $op="add"; if ($delete) { $op="delete"; } my $output = xCAT::Utils->runxcmd( { command => ["xdsh"], node => $nodes_tmp, arg => ["-e", "/$installdir/postscripts/routeop $op " . $route_hash->{net} . " " . $route_hash->{mask} . " $gw_ip" . " $route_hash->{ifname}"], _xcatpreprocessed => [1], }, $sub_req, -1, 1); my $rsp={}; $rsp->{data}=$output; $callback->($rsp); } else { #local on mn or sn if ($delete) { delete_route($callback, $route_hash->{net}, $route_hash->{mask}, $gw_ip, $gw_name, $route_hash->{ifname}); } else { set_route($callback, $route_hash->{net}, $route_hash->{mask}, $gw_ip, $gw_name, $route_hash->{ifname}); } } } } #not all gateways are service nodes my %sn_hash=(); my @allSN=xCAT::ServiceNodeUtils->getAllSN(); my %allSN_hash=(); foreach(@allSN) {$allSN_hash{$_}=1;} foreach my $sn (@sns) { if (exists($allSN_hash{$sn})) { $sn_hash{$sn}=1; } } #update servicenode.ipforward my $sntab=xCAT::Table->new("servicenode", -create => 1,-autocommit => 1); my %valuehash=(); my $value=1; if ($delete) {$value=0;} foreach my $sn (keys %sn_hash) { $valuehash{$sn} = { ipforward=>$value }; } $sntab->setNodesAttribs(\%valuehash); #go to the service nodes to enable/disable ipforwarding my @nodes=keys(%sn_hash); $sub_req->({ command=>['ipforward'], node=>\@nodes, arg=>[$delete]}, $callback); } sub process_ipforward { my $request = shift; my $callback = shift; my $sub_req = shift; my $args = $request->{arg}; my $delete=0; if ($args) { $delete = $args->[0]; } if ($delete) { xCAT::NetworkUtils->setup_ip_forwarding(0); } else { xCAT::NetworkUtils->setup_ip_forwarding(1); } } sub usage { my $cb=shift; my $rsp={}; $rsp->{data}->[0]= "Usage: makeroutes -h"; $rsp->{data}->[1]= " makeroutes -v"; $rsp->{data}->[2]= " makeroutes [-r routename[,routename...]]"; $rsp->{data}->[3]= " makeroutes [-r routename[,routename...]] -d "; $rsp->{data}->[4]= " makeroutes noderange [-r routename[,routename...]]"; $rsp->{data}->[5]= " makeroutes noderange [-r routename[,routename...]] -d"; $cb->($rsp); } #check if the route exits or not from the route table sub route_exists { my $net = shift; my $mask = shift; my $gw_ip = shift; my $gw=shift; my $ifname = shift; my $islinux=xCAT::Utils->isLinux(); # ipv6 net if ($net =~ /:/) { if ($islinux) { my $result = `ip -6 route show $net/$mask`; # ip -6 route show will return nothing if the route does not exist if (!$result || ($? != 0)) { return 0; } else { return 1; } } else { # AIX # TODO } } else { my $result; $result=`netstat -nr|grep $net`; if ($? == 0) { if ($result) { my @b=split('\n', $result); foreach my $tmp (@b) { chomp($tmp); my @a=split(' ', $tmp); if ($islinux) { #Linux if (@a >= 3) { my $net1=$a[0]; my $mask1=$a[2]; my $gw1=$a[1]; my $ifname1=$a[7]; if (($net1 eq $net) && ($mask1 eq $mask) && (($gw1 eq $gw) || ($gw1 eq $gw_ip) || ($ifname1 eq $ifname))) { return 1; } } } else { #AIX if (@a >= 2) { my $tmp1=$a[0]; my $gw1=$a[1]; #now convert $mask to bits $net =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/; my $netnum = ($1<<24)+($2<<16)+($3<<8)+$4; my $bits=32; while (($netnum % 2) == 0) { $bits--; $netnum=$netnum>>1; } my $tmp2="$net/$bits"; if (($tmp1 eq $tmp2) && (($gw1 eq $gw) || ($gw1 eq $gw_ip))) { return 1; } } # end if (@a >= 2) } #end else linux/aix } # end foreach } # end if ($result) } # end if ($? == 0 } # end else ipv4/ipv6 return 0; } # sets the route with given parameters sub set_route { my $callback=shift; my $net = shift; my $mask = shift; my $gw_ip = shift; my $gw=shift; my $ifname=shift; my $host=hostname(); #print "set_route get called\n"; my $result; if (!route_exists($net, $mask, $gw_ip, $gw, $ifname)) { #set temporay route my $cmd; # ipv6 network if ($net =~ /:/) { if (xCAT::Utils->isLinux()) { if ( $gw_ip == "" || $gw_ip == "::" ) { $cmd="ip -6 route add $net/$mask dev $ifname"; } else { $cmd="ip -6 route add $net/$mask via $gw_ip"; } } else { # AIX TODO } } else { if (xCAT::Utils->isLinux()) { if ( $gw_ip == "" || $gw_ip == "0.0.0.0" ) { $cmd="route add -net $net netmask $mask dev $ifname"; } else { $cmd="route add -net $net netmask $mask gw $gw_ip"; } } else { $cmd="route add -net $net -netmask $mask $gw_ip"; } } #print "cmd=$cmd\n"; my $rsp={}; $rsp->{data}->[0]= "$host: Adding temporary route: $cmd"; $callback->($rsp); $result=`$cmd 2>&1`; if ($? != 0) { my $rsp={}; $rsp->{error}->[0]= "$host: $cmd\nerror code=$?, result=$result\n"; $callback->($rsp); #return 1; } } else { my $rsp={}; $rsp->{data}->[0]= "$host: The temporary route already exists for $net."; $callback->($rsp); } #handle persistent routes if (xCAT::Utils->isLinux()) { #Linux my $os = xCAT::Utils->osver(); #print "os=$os $net, $mask, $gw_ip, $gw, $ifname\n"; if ($os =~ /sles/) { #sles addPersistentRoute_Sles($callback, $net, $mask, $gw_ip, $gw, $ifname); } elsif ($os =~ /ubuntu|debian/) { #ubuntu or Debian? addPersistentRoute_Debian($callback, $net, $mask, $gw_ip, $gw, $ifname); } elsif ($os =~ /rh|fedora|centos/) { #RH, Ferdora, CentOS addPersistentRoute_RH($callback, $net, $mask, $gw_ip, $gw, $ifname); } } else { #AIX # chdev -l inet0 -a route=net,-hopcount,0,,0,192.168.1.1 # chdev -l inet0 -a route=net, -hopcount,255.255.255.128,,,,,192.168.3.155,192.168.2.1 # lsattr -El inet0 -a route my $rsp={}; $rsp->{data}->[0]= "$host: Adding persistent route on AIX is not supported yet."; $callback->($rsp); } return 0; } # deletes the route with given parameters sub delete_route { my $callback=shift; my $net = shift; my $mask = shift; my $gw_ip = shift; my $gw=shift; my $ifname=shift; my $host=hostname(); #print "delete_route get called\n"; my $result; if (route_exists($net, $mask, $gw_ip, $gw, $ifname)) { #delete route temporarily my $cmd; if ($net =~ /:/) { if (xCAT::Utils->isLinux()) { if ( $gw_ip == "" || $gw_ip == "::" ) { $cmd = "ip -6 route delete $net/$mask dev $ifname"; } else { $cmd = "ip -6 route delete $net/$mask via $gw_ip"; } } else { # AIX TODO } } else { if (xCAT::Utils->isLinux()) { if ( $gw_ip == "" || $gw_ip == "0.0.0.0" ) { $cmd="route delete -net $net netmask $mask dev $ifname"; } else { $cmd="route delete -net $net netmask $mask gw $gw_ip"; } } else { $cmd="route delete -net $net -netmask $mask $gw_ip"; } } #print "cmd=$cmd\n"; my $rsp={}; $rsp->{data}->[0]= "$host: Removing the temporary route: $cmd"; $callback->($rsp); $result=`$cmd 2>&1`; if ($? != 0) { my $rsp={}; $rsp->{error}->[0]= "$host: $cmd\nerror code=$?, result=$result\n"; $callback->($rsp); } } else { my $rsp={}; if ($net =~ /:/) { $rsp->{data}->[0]= "$host: The temporary route does not exist for $net/$mask."; } else { $rsp->{data}->[0]= "$host: The temporary route does not exist for $net."; } $callback->($rsp); } #handle persistent route if (xCAT::Utils->isLinux()) { #Linux my $os = xCAT::Utils->osver(); if ($os =~ /sles/) { #sles deletePersistentRoute_Sles($callback, $net, $mask, $gw_ip, $gw, $ifname); } elsif ($os =~ /ubuntu/) { #ubuntu or Debian? deletePersistentRoute_Debian($callback, $net, $mask, $gw_ip, $gw, $ifname); } elsif ($os =~ /rh|fedora|centos/) { #RH, Ferdora deletePersistentRoute_RH($callback, $net, $mask, $gw_ip, $gw, $ifname); } } else { #AIX # chdev -l inet0 -a delroute=net,-hopcount,0,,0,192.168.1.1 # chdev -l inet0 -a delroute=net,-hopcount,255.255.255.128,,,,,192.168.3.128,192.168.2.1 my $rsp={}; $rsp->{data}->[0]= "$host: Removing persistent route on AIX is not supported yet."; $callback->($rsp); } return 0; } #set the given route to the configuration file sub setConfig { my $filename=shift; my $new_conf_block=shift; #print "filename=$filename\n"; my $new_config=join("\n", @$new_conf_block); my $last_char = substr $new_config,-1,1; if ($last_char ne "\n") { $new_config .= "\n"; } my $filename_tmp = "$filename.$$"; open (OUTFILE, '>', $filename_tmp); my $found=0; if (-f $filename) { open (INFILE, '<', $filename); my $inblock=0; while () { my $line=$_; if (!$inblock) { print OUTFILE $line; } if ($line =~ /$xcat_config_start/) { $found=1; $inblock=1; print OUTFILE $new_config; } elsif ($line =~ /$xcat_config_end/) { $inblock=0; print OUTFILE "$xcat_config_end\n"; } } } if (!$found) { print OUTFILE "$xcat_config_start\n"; print OUTFILE $new_config; print OUTFILE "$xcat_config_end\n"; } close (INFILE); close (OUTFILE); copy($filename_tmp, $filename); unlink($filename_tmp); } #gets the xCAT configurations from the given file sub getConfig { my $filename=shift; my @output=(); if (-f $filename) { open(FILE, "<", $filename); my $xcatconf = 0; my $first=0; while () { chomp; if (/$xcat_config_start/) { $xcatconf = 1; $first=1; } elsif (/$xcat_config_end/) { $xcatconf = 0; } if ($first) { $first=0; next; } if ($xcatconf) { push @output, $_; } } } return @output; } #add the routes to the /etc/sysconfig/network/routes file #The format is: destination gateway mask ifname sub addPersistentRoute_Sles { my $callback=shift; my $net=shift; my $mask=shift; my $gw_ip=shift; my $gw=shift; my $ifname=shift; my $host=hostname(); my $filename="/etc/sysconfig/network/routes"; my @output=getConfig($filename); #print "old output=" . join("\n", @output) . "\n"; my $hasConfiged=0; if (@output && (@output > 0)) { $hasConfiged=checkConfig_Sles($net, $mask, $gw_ip, $gw, $ifname, \@output); } #print "hasConfiged=$hasConfiged\n"; my $new_config; if ($net =~ /:/) { if ( $gw_ip == "" || $gw_ip == "::" ) { $new_config = "$net/$mask :: - $ifname\n"; } else { $new_config = "$net/$mask $gw_ip - -\n"; } } else { if ( $gw_ip == "" || $gw_ip == "0.0.0.0" ) { $new_config="$net 0.0.0.0 $mask $ifname\n"; } else { $new_config="$net $gw_ip $mask $ifname\n"; } } if (!$hasConfiged) { push(@output, $new_config); #print "new output=" . join("\n", @output) . "\n"; #Add the route to the configuration file #the format is: destination gateway mask ifname setConfig($filename, \@output); chomp($new_config); my $rsp={}; $rsp->{data}->[0]= "$host: Added persistent route \"$new_config\" to $filename."; $callback->($rsp); } else { chomp($new_config); my $rsp={}; $rsp->{data}->[0]= "$host: Persistent route \"$new_config\" already exists in $filename."; $callback->($rsp); } } #remove the routes from the /etc/sysconfig/network/routes file sub deletePersistentRoute_Sles { my $callback=shift; my $net=shift; my $mask=shift; my $gw_ip=shift; my $gw=shift; my $ifname=shift; my $host=hostname(); my $filename="/etc/sysconfig/network/routes"; my @output=getConfig($filename); #print "old output=" . join("\n", @output) . "\n"; my @new_output=(); my $bigfound=0; foreach my $tmp_conf (@output) { my $found = checkConfig_Sles($net, $mask, $gw_ip, $gw, $ifname, [$tmp_conf]); if (!$found) { push(@new_output, $tmp_conf); } else { $bigfound=1; } } #print "new output=" . join("\n", @new_output) . "\n"; #set the new configuration to the configuration file setConfig($filename, \@new_output); if ($bigfound) { my $rsp={}; if ($net =~ /:/) { $rsp->{data}->[0]= "$host: Removed persistent route \"$net/$mask $gw_ip\" from $filename."; } else { $rsp->{data}->[0]= "$host: Removed persistent route \"$net $gw_ip $mask $ifname\" from $filename."; } $callback->($rsp); } else { my $rsp={}; if ($net =~ /:/) { $rsp->{data}->[0]= "$host: Persistent route \"$net/$mask $gw_ip\" does not exist in $filename."; } else { $rsp->{data}->[0]= "$host: Persistent route \"$net $gw_ip $mask $ifname\" does not exist in $filename."; } $callback->($rsp); } } #check if the route is in the SLES network configuration file sub checkConfig_Sles { my $net = shift; my $mask = shift; my $gw_ip = shift; my $gw=shift; my $ifname=shift; my $output=shift; # Format: # DESTINATION GATEWAY NETMASK INTERFACE # DESTINATION/PREFIXLEN GATEWAY - INTERFACE # ipv4 format: 192.168.0.0 207.68.156.51 255.255.0.0 eth1 # ipv6 format: fd59::/64 fd57:faaf:e1ab:336:21a:64ff:fe01:1 - - foreach my $line (@$output) { my @a=split(' ', $line); my ($net1,$mask1,$gw1,$ifname1); if ($net =~ /:/) { if (@a>0) { my $ipv6net = $a[0]; ($net1,$mask1) = split("/",$ipv6net); } if (@a>1) { $gw1=$a[1]; if ($gw1 eq '-') { $gw1=$gw_ip; } } if (@a>3) { $ifname1=$a[3]; if ($ifname1 eq '-') { $ifname1=$ifname;} } } else { if (@a>0) { $net1=$a[0]; if ($net1 eq '-') { $net1=$net;} } if (@a>1) { $gw1=$a[1]; if ($gw1 eq '-') { $gw1=$gw_ip; } } if (@a>2) { $mask1=$a[2]; if ($mask1 eq '-') { $mask1=$mask;} } if (@a>3) { $ifname1=$a[3]; if ($ifname1 eq '-') { $ifname1=$ifname;} } } #print "net=$net1,$net mask=$mask1,$mask gw=$gw1,$gw_ip ifname=$ifname1\n"; if (($net1 && $net1 eq $net) && ($mask1 && $mask1 eq $mask) && (($gw1 && $gw1 eq $gw) || ($gw1 && $gw1 eq $gw_ip) || ($ifname1 && $ifname1 eq $ifname))) { return 1; } } return 0; } #add the routes to the /etc/sysconfig/static-routes file #The format is: any net 172.16.0.0 netmask 255.240.0.0 gw 192.168.0.1 eth0 sub addPersistentRoute_RH { my $callback=shift; my $net=shift; my $mask=shift; my $gw_ip=shift; my $gw=shift; my $ifname=shift; my $host=hostname(); my $filename; # ipv6 if ($net =~ /:/) { $filename="/etc/sysconfig/static-routes-ipv6"; } else { $filename="/etc/sysconfig/static-routes"; } my @output=getConfig($filename); #print "old output=" . join("\n", @output) . "\n"; my $hasConfiged=0; if (@output && (@output > 0)) { $hasConfiged=checkConfig_RH($net, $mask, $gw_ip, $gw, $ifname, \@output); } #print "hasConfiged=$hasConfiged\n"; my $new_config; if ($net =~ /:/) { # ifname is required for ipv6 routing if (!$ifname) { my $rsp={}; $rsp->{data}->[0]= "$host: Could not add persistent route for ipv6 network $net/$mask, the ifname is required in the routes table."; $callback->($rsp); return; } $new_config="$ifname $net/$mask $gw_ip"; } else { if ( $gw_ip == "" || $gw_ip == "0.0.0.0" ) { $new_config="any net $net netmask $mask dev $ifname\n"; } else { $new_config="any net $net netmask $mask gw $gw_ip\n"; } } if (!$hasConfiged) { push(@output, $new_config); #print "new output=" . join("\n", @output) . "\n"; #Add the route to the configuration file #the format is: destination gateway mask ifname setConfig($filename, \@output); chomp($new_config); my $rsp={}; $rsp->{data}->[0]= "$host: Added persistent route \"$new_config\" to $filename."; $callback->($rsp); } else { chomp($new_config); my $rsp={}; $rsp->{data}->[0]= "$host: Persistent route \"$new_config\" already exists in $filename."; $callback->($rsp); } } #remove the routes from the /etc/sysconfig/static-routes file sub deletePersistentRoute_RH { my $callback=shift; my $net=shift; my $mask=shift; my $gw_ip=shift; my $gw=shift; my $ifname=shift; my $host=hostname(); my $filename; # ipv6 if ($net =~ /:/) { $filename="/etc/sysconfig/static-routes-ipv6"; } else { $filename="/etc/sysconfig/static-routes"; } my @output=getConfig($filename); #print "old output=" . join("\n", @output) . "\n"; my @new_output=(); my $bigfound=0; foreach my $tmp_conf (@output) { my $found = checkConfig_RH($net, $mask, $gw_ip, $gw, $ifname, [$tmp_conf]); if (!$found) { push(@new_output, $tmp_conf); } else { $bigfound=1; } } #print "new output=" . join("\n", @new_output) . "\n"; #set the new configuration to the configuration file setConfig($filename, \@new_output); if ($bigfound) { my $rsp={}; if ($net =~ /:/) { $rsp->{data}->[0]= "$host: Removed persistent route \"$ifname $net/$mask $gw_ip\" from $filename."; } else { $rsp->{data}->[0]= "$host: Removed persistent route \"any net $net netmask $mask gw $gw_ip $ifname\" from $filename."; } $callback->($rsp); } else { my $rsp={}; if ($net =~ /:/) { $rsp->{data}->[0]= "$host: Persistent route \"$ifname $net/$mask $gw_ip\" does not exist in $filename."; } else { $rsp->{data}->[0]= "$host: Persistent route \"any net $net netmask $mask gw $gw_ip $ifname\" does not exist in $filename."; } $callback->($rsp); } } sub checkConfig_RH { my $net = shift; my $mask = shift; my $gw_ip = shift; my $gw=shift; my $ifname=shift; my $output=shift; foreach my $line (@$output) { my @a=split(' ', $line); #The format is: any net 172.16.0.0 netmask 255.240.0.0 gw 192.168.0.1 eth0 # ipv6 format: eth1 fd60::/64 fd57::214:5eff:fe15:1 my ($net1,$mask1,$gw1,$ifname1); if ($net =~ /:/) { $ifname1 = $a[0]; if (@a>1) { my $ipv6net = $a[1]; ($net1,$mask1) = split("/",$ipv6net); } if (@a>2) { $gw1 = $a[2]; } } else { if (@a>2) { $net1=$a[2]; if ($net1 eq '-') { $net1=$net;} } if (@a>4) { $mask1=$a[4]; if ($mask1 eq '-') { $mask1=$mask;} } if (@a>6) { if ( $a[5] eq 'dev' ) { $ifname1=$a[6]; if ($ifname1 eq '-') { $ifname1=$ifname;} } else { $gw1=$a[6]; if ($gw1 eq '-') { $gw1=$gw_ip; } } } } #print "net=$net1,$net mask=$mask1,$mask gw=$gw1,$gw_ip ifname=$ifname1,ifname\n"; if (($net1 && $net1 eq $net) && ($mask1 && $mask1 eq $mask) && (($gw1 && $gw1 eq $gw) || ($gw1 && $gw1 eq $gw_ip) || ($ifname1 && $ifname1 eq $ifname))) { return 1; } } return 0; } sub addPersistentRoute_Debian{ my $callback = shift; my $net = shift; my $mask = shift; my $gw_ip = shift; my $gw_name = shift; my $ifname = shift; my $host=hostname(); my $conf_file = "/etc/network/interfaces.d/$ifname"; my $cmd = ''; my $route_conf = ''; preParse_Debian(); #ipv6 if ( $net =~ /:/){ if ( $gw_ip == "" || $gw_ip == "::" ) { $cmd = "grep \"$net/$mask dev $ifname\" $conf_file"; $route_conf = " up route -A inet6 add $net/$mask dev $ifname \n down route -A inet6 del $net/$mask dev $ifname \n"; } else { $cmd = "grep \"$net/$mask gw $gw_ip\" $conf_file"; $route_conf = " up route -A inet6 add $net/$mask gw $gw_ip \n down route -A inet6 del $net/$mask gw $gw_ip \n"; } } else { #ipv4 $cmd = "grep \"-net $net netmask $mask gw $gw_ip\" $conf_file"; if ( $gw_ip == "" || $gw_ip == "0.0.0.0" ) { $route_conf = " up route add -net $net netmask $mask dev $ifname \n down route del -net $net netmask $mask dev $ifname \n"; } else { $route_conf = " up route add -net $net netmask $mask gw $gw_ip \n down route del -net $net netmask $mask gw $gw_ip\n"; } } #fine the corresponding config in the config file my @returninfo = `$cmd`; if ( @returninfo ){ my $rsp={}; $rsp->{data}->[0]= "$host: Persistent route \"$returninfo[0]\" already exists in $conf_file."; callback->($rsp); return; } #add the configuration to the config file my $readyflag = 0; open(FH, "<", $conf_file); my @content = ; close(FH); #read each line of the file and find the insert place open(FH, ">", $conf_file); foreach my $line ( @content ){ #add the route line at the end of this dev part if (( $readyflag == 1 ) && ( $line =~ /iface|modprobe/ )){ $readyflag = 0; print FH $route_conf; } if ( $line =~ /iface $ifname/ ){ $readyflag = 1; } print FH $line; } #the dev is the last one, add the route at the end of the file if ( $readyflag == 1 ){ print FH $route_conf; } close(FH); } sub deletePersistentRoute_Debian{ my $callback=shift; my $net=shift; my $mask=shift; my $gw_ip=shift; my $gw=shift; my $ifname=shift; my $host=hostname(); my $conf_file = "/etc/network/interfaces.d/$ifname"; my $match = ""; my $modflag = 0; preParse_Debian(); #ipv6 if ( $net =~ /:/){ if ( $gw_ip == "" || $gw_ip == "::" ) { $match = "$net/$mask dev $ifname"; } else { $match = "$net/$mask gw $gw_ip"; } } else { if ( $gw_ip == "" || $gw_ip == "0.0.0.0" ) { $match = "net $net netmask $mask dev $ifname"; } else { $match = "net $net netmask $mask gw $gw_ip"; } } open(FH, "<", $conf_file); my @lines = ; close(FH); open(FH, ">", $conf_file); foreach my $line ( @lines ){ #match the route config, jump to next line if ( $line =~ /$match/ ){ $modflag = 1; } else{ print FH $line; } } close(FH); my $rsp = {}; if ( $modflag ){ $rsp->{data}->[0]= "$host: Removed persistent route \"$match\" from $conf_file."; } else{ $rsp->{data}->[0]= "$host: Persistent route \"$match\" does not exist in $conf_file."; } $callback->($rsp); } sub preParse_Debian{ my $configfile; open(FH, "<", "/etc/network/interfaces"); my @lines = ; close(FH); if ($lines[0] =~ /XCAT_CONFIG/i){ return; } unless ( -e "/etc/network/interfaces.bak" ){ copy ("/etc/network/interfaces", "/etc/network/interfaces.bak"); } unless ( -d "/etc/network/interfaces.d" ){ mkpath( "/etc/network/interfaces.d" ); } open(FH, ">", "/etc/network/interfaces"); print FH "#XCAT_CONFIG\n"; print FH "source /etc/network/interfaces.d/* \n"; close(FH); foreach my $line ( @lines ){ if ( $line =~ /^\s*$/){ next; } if ( $line =~ /^#.*/ ){ next; } my @attr = split /\s+/, $line; if ( $attr[0] =~ /auto|allow-hotplug/){ my $i = 1; while ( $i < @attr ){ open(SFH, ">", "/etc/network/interfaces.d/$attr[$i]"); print SFH "$attr[0] $attr[$i]\n"; close(SFH); print FH "source /etc/network/interfaces.d/$attr[$i] \n"; $i = $i + 1; } } elsif ($attr[0] =~ /mapping|iface/){ $configfile = "/etc/network/interfaces.d/$attr[1]"; open(SFH, ">>", $configfile); unless ( -e $configfile){ print SFH "auto $attr[1] \n"; } print SFH $line; close(SFH); } else{ open(SFH, ">>", $configfile); print SFH $line; close(SFH); } } return; }