2010-05-27 15:13:26 +00:00
|
|
|
# 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::NetworkUtils;
|
|
|
|
use xCAT::MsgUtils;
|
|
|
|
use Getopt::Long;
|
|
|
|
use xCAT::NodeRange;
|
|
|
|
use Data::Dumper;
|
|
|
|
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
#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 {
|
|
|
|
my $reqcopy = {%$request};
|
|
|
|
$reqcopy->{_xcatpreprocessed}->[0] = 1;
|
|
|
|
return [$reqcopy];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#-------------------------------------------------------
|
|
|
|
|
|
|
|
=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 $args = $request->{arg};
|
|
|
|
|
|
|
|
# parse the options
|
|
|
|
@ARGV=();
|
|
|
|
if ($args) {
|
|
|
|
@ARGV=@{$args};
|
|
|
|
}
|
|
|
|
Getopt::Long::Configure("bundling");
|
|
|
|
Getopt::Long::Configure("no_pass_through");
|
|
|
|
|
|
|
|
my $netmask_in;
|
|
|
|
my $net_in;
|
|
|
|
my $gateway_in;
|
|
|
|
my $routelist_in;
|
|
|
|
my $delete=0;
|
|
|
|
if(!GetOptions(
|
|
|
|
'h|help' => \$::HELP,
|
|
|
|
'v|version' => \$::VERSION,
|
|
|
|
'r|routename=s' => \$routelist_in,
|
|
|
|
'n|net=s' => \$net_in,
|
|
|
|
'm|mask=s' => \$netmask_in,
|
|
|
|
'g|gateway=s' => \$gateway_in,
|
|
|
|
'd|delete' => \$delete,))
|
|
|
|
{
|
|
|
|
&usage($callback);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
# display the usage if -h or --help is specified
|
|
|
|
if ($::HELP) {
|
|
|
|
&usage($callback);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (@ARGV > 0) {
|
|
|
|
&usage($callback);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
# display the version statement if -v or --verison is specified
|
|
|
|
if ($::VERSION)
|
|
|
|
{
|
|
|
|
my $rsp={};
|
|
|
|
$rsp->{data}->[0]= xCAT::Utils->Version();
|
|
|
|
$callback->($rsp);
|
|
|
|
return 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'));
|
2010-12-20 10:03:58 +00:00
|
|
|
if (@tmp1 > 0) {
|
2010-05-27 15:13:26 +00:00
|
|
|
foreach(@tmp1) {
|
|
|
|
$all_routes{$_->{routename}} = $_;
|
|
|
|
$_->{process} = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#print Dumper(%all_routes);
|
|
|
|
|
|
|
|
#get the routes to be handled
|
|
|
|
if ($routelist_in) {
|
|
|
|
if ($net_in || $gateway_in || $netmask_in) {
|
|
|
|
my $rsp={};
|
|
|
|
$rsp->{error}->[0]= "-r cannot be combined with -n,-g or -m flag.";
|
|
|
|
$callback->($rsp);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#check if the route names are valid
|
|
|
|
foreach(split(',', $routelist_in)) {
|
|
|
|
if (! exists($all_routes{$_})) {
|
|
|
|
my $rsp={};
|
|
|
|
$rsp->{error}->[0]= "route $_ is not defined in the routes table.";
|
|
|
|
$callback->($rsp);
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
$all_routes{$_}->{process}=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elsif ( $net_in || $gateway_in || $netmask_in) {
|
|
|
|
my $count=0;
|
|
|
|
foreach (keys %all_routes) {
|
|
|
|
my $process=1;
|
|
|
|
if (($net_in) && ($all_routes{$_}->{net} ne $net_in)) { $process=0; }
|
|
|
|
if (($netmask_in) && ($all_routes{$_}->{mask} ne $netmask_in)) { $process=0; }
|
|
|
|
if (($gateway_in) && ($all_routes{$_}->{gateway} ne $gateway_in)) { $process=0; }
|
|
|
|
$all_routes{$_}->{process}=$process;
|
|
|
|
|
|
|
|
if ($process == 1) { $count++; }
|
|
|
|
}
|
|
|
|
if ($count==0) {
|
|
|
|
my $rsp={};
|
|
|
|
$rsp->{data}->[0]= "No route in the routes table matches the input.";
|
|
|
|
$callback->($rsp);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
#handle all routes
|
|
|
|
foreach (keys %all_routes) {
|
|
|
|
$all_routes{$_}->{process}= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#print Dumper(%all_routes);
|
|
|
|
|
|
|
|
#now let handle the route creatation and deletion
|
|
|
|
my @sns=();
|
|
|
|
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 ($delete) {
|
|
|
|
delete_route($callback, $route_hash->{net}, $route_hash->{mask}, $gw_ip, $gw_name);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
set_route($callback, $route_hash->{net}, $route_hash->{mask}, $gw_ip, $gw_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#not all gateways are service nodes
|
|
|
|
my %sn_hash=();
|
|
|
|
my @allSN=xCAT::Utils->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";
|
|
|
|
$rsp->{data}->[3]= " makeroutes -d";
|
|
|
|
$rsp->{data}->[4]= " makeroutes -r routename[,routename...]";
|
|
|
|
$rsp->{data}->[5]= " makeroutes -r routename[,routename...] -d";
|
|
|
|
$rsp->{data}->[6]= " makeroutes [-n network] [-m mask] [-g gateway]";
|
|
|
|
$rsp->{data}->[7]= " makeroutes [-n network] [-m mask]] [-g gateway] -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;
|
|
|
|
|
2010-05-28 15:09:45 +00:00
|
|
|
my $islinux=xCAT::Utils->isLinux();
|
2010-05-27 15:13:26 +00:00
|
|
|
my $result;
|
2010-05-28 15:09:45 +00:00
|
|
|
$result=`netstat -nr|grep $net`;
|
2010-05-27 15:13:26 +00:00
|
|
|
if ($? == 0) {
|
|
|
|
if ($result) {
|
|
|
|
my @b=split('\n', $result);
|
|
|
|
foreach my $tmp (@b) {
|
|
|
|
chomp($tmp);
|
|
|
|
my @a=split(' ', $tmp);
|
2010-05-28 15:09:45 +00:00
|
|
|
if ($islinux) { #Linux
|
|
|
|
if (@a >= 3) {
|
|
|
|
my $net1=$a[0];
|
|
|
|
my $mask1=$a[2];
|
|
|
|
my $gw1=$a[1];
|
|
|
|
if (($net1 eq $net) && ($mask1 eq $mask) && (($gw1 eq $gw) || ($gw1 eq $gw_ip))) {
|
|
|
|
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;
|
|
|
|
}
|
2010-05-27 15:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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 $result;
|
|
|
|
if (!route_exists($net, $mask, $gw_ip, $gw)) {
|
|
|
|
#set temporay route
|
2010-05-28 15:09:45 +00:00
|
|
|
my $cmd;
|
|
|
|
if (xCAT::Utils->isLinux()) {
|
|
|
|
$cmd="route add -net $net netmask $mask gw $gw_ip";
|
|
|
|
} else {
|
|
|
|
$cmd="route add -net $net -netmask $mask $gw_ip";
|
|
|
|
}
|
|
|
|
print "cmd=$cmd\n";
|
|
|
|
$result=`$cmd 2>&1`;
|
2010-05-27 15:13:26 +00:00
|
|
|
if ($? != 0) {
|
|
|
|
my $rsp={};
|
2010-05-28 15:09:45 +00:00
|
|
|
$rsp->{error}->[0]= "$cmd\nerror code=$?, result=$result\n";
|
2010-05-27 15:13:26 +00:00
|
|
|
$callback->($rsp);
|
|
|
|
return 1;
|
|
|
|
} else {
|
2010-05-28 15:09:45 +00:00
|
|
|
#TODO: set per permanent route
|
2010-05-27 15:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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 $result;
|
|
|
|
if (route_exists($net, $mask, $gw_ip, $gw)) {
|
|
|
|
#delete route temporarily
|
2010-05-28 15:09:45 +00:00
|
|
|
my $cmd;
|
|
|
|
if (xCAT::Utils->isLinux()) {
|
|
|
|
$cmd="route delete -net $net netmask $mask gw $gw_ip";
|
|
|
|
} else {
|
|
|
|
$cmd="route delete -net $net -netmask $mask $gw_ip";
|
|
|
|
}
|
|
|
|
print "cmd=$cmd\n";
|
|
|
|
$result=`$cmd 2>&1`;
|
2010-05-27 15:13:26 +00:00
|
|
|
if ($? != 0) {
|
|
|
|
my $rsp={};
|
2010-05-28 15:09:45 +00:00
|
|
|
$rsp->{error}->[0]= "$cmd\nerror code=$?, result=$result\n";
|
2010-05-27 15:13:26 +00:00
|
|
|
$callback->($rsp);
|
|
|
|
return 1;
|
|
|
|
} else {
|
2010-05-28 15:09:45 +00:00
|
|
|
#TODO: delete route permanently
|
2010-05-27 15:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|