From fe30dd3adcc780e90911e10fae84ae2327c56be3 Mon Sep 17 00:00:00 2001 From: linggao Date: Thu, 27 May 2010 15:13:26 +0000 Subject: [PATCH] makeroutes phase 1 git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@6260 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- perl-xCAT/xCAT/NetworkUtils.pm | 28 ++ perl-xCAT/xCAT/Schema.pm | 47 +++ xCAT-server/lib/xcat/plugins/AAsn.pm | 42 +-- xCAT-server/lib/xcat/plugins/route.pm | 400 ++++++++++++++++++++++++++ 4 files changed, 488 insertions(+), 29 deletions(-) create mode 100644 xCAT-server/lib/xcat/plugins/route.pm diff --git a/perl-xCAT/xCAT/NetworkUtils.pm b/perl-xCAT/xCAT/NetworkUtils.pm index e2126c1f0..2e65fc1e0 100755 --- a/perl-xCAT/xCAT/NetworkUtils.pm +++ b/perl-xCAT/xCAT/NetworkUtils.pm @@ -338,4 +338,32 @@ sub ishostinsubnet { } } +#----------------------------------------------------------------------------- + +=head3 setup_ip_forwarding + + Sets up ip forwarding on localhost + +=cut + +#----------------------------------------------------------------------------- +sub setup_ip_forwarding +{ + my ($class, $enable)=@_; + if (xCAT::Utils->isLinux()) { + my $conf_file="/etc/sysctl.conf"; + `grep "net.ipv4.ip_forward" $conf_file`; + if ($? == 0) { + `sed -i "s/^net.ipv4.ip_forward = .*/net.ipv4.ip_forward = $enable/" $conf_file`; + } else { + `echo "net.ipv4.ip_forward = $enable" >> $conf_file`; + } + `sysctl -p $conf_file`; + } + else + { #AIX: TODO + } + return 0; +} + 1; diff --git a/perl-xCAT/xCAT/Schema.pm b/perl-xCAT/xCAT/Schema.pm index 514eee9e2..72288f6de 100644 --- a/perl-xCAT/xCAT/Schema.pm +++ b/perl-xCAT/xCAT/Schema.pm @@ -884,6 +884,21 @@ prescripts => { }, }, +routes => { + cols => [qw(routename net mask gateway ifname comments disable)], + keys => [qw(routename)], + table_desc => 'Describes the additional routes needed to be setup in the os routing table. These routes usually are used to connect the management node to the compute node using the servie node as gateway.', + descriptions => { + routename => 'Name used to identify this route.', + net => 'The network address.', + mask => 'The network mask.', + ifname => 'The interface name of the management node facing the gateway.', + gateway => 'The gateway that routes the ip traffic from the mn to the nodes. It is usually a service node.', + comments => 'Any user-written notes.', + disable => "Set to 'yes' or '1' to comment out this row.", + }, +}, + zvm => { cols => [qw(node hcp userid comments disable)], keys => [qw(node)], @@ -959,6 +974,7 @@ foreach my $tabname (keys(%xCAT::ExtTab::ext_tabspec)) { node => { attrs => [], attrhash => {}, objkey => 'node' }, osimage => { attrs => [], attrhash => {}, objkey => 'imagename' }, network => { attrs => [], attrhash => {}, objkey => 'netname' }, + route => { attrs => [], attrhash => {}, objkey => 'routename' }, group => { attrs => [], attrhash => {}, objkey => 'groupname' }, site => { attrs => [], attrhash => {}, objkey => 'master' }, policy => { attrs => [], attrhash => {}, objkey => 'priority' }, @@ -1857,6 +1873,37 @@ push(@{$defspec{node}->{'attrs'}}, @nodeattrs); access_tabentry => 'networks.netname=attr:netname', }, ); +######################### +# route data object # +######################### +# routes table # +######################### +@{$defspec{route}->{'attrs'}} = ( + {attr_name => 'routename', + tabentry => 'routes.routename', + access_tabentry => 'routes.routename=attr:routename', + }, + {attr_name => 'net', + tabentry => 'routes.net', + access_tabentry => 'routes.routename=attr:routename', + }, + {attr_name => 'mask', + tabentry => 'routes.mask', + access_tabentry => 'routes.routename=attr:routename', + }, + {attr_name => 'gateway', + tabentry => 'routes.gateway', + access_tabentry => 'routes.routename=attr:routename', + }, + {attr_name => 'ifname', + tabentry => 'routes.ifname', + access_tabentry => 'routes.routename=attr:routename', + }, + {attr_name => 'usercomment', + tabentry => 'routes.comments', + access_tabentry => 'routes.routename=attr:routename', + }, + ); ##################### # site data object # diff --git a/xCAT-server/lib/xcat/plugins/AAsn.pm b/xCAT-server/lib/xcat/plugins/AAsn.pm index 07dccaa1a..1c484b55b 100644 --- a/xCAT-server/lib/xcat/plugins/AAsn.pm +++ b/xCAT-server/lib/xcat/plugins/AAsn.pm @@ -6,6 +6,7 @@ use strict; use xCAT::Table; use xCAT::Utils; +use xCAT::NetworkUtils; use xCAT::MsgUtils; use xCAT_plugin::dhcp; @@ -256,11 +257,22 @@ sub init_plugin if (grep(/$service/, @servicelist)) { - $rc = &setup_ip_forwarding($nodename, $doreq); # setup ip forwarding + $rc = xCAT::NetworkUtils->setup_ip_forwarding(1); # enable ip forwarding if ($rc == 0) { xCAT::Utils->update_xCATSN($service); } + } else { + + $rc = xCAT::NetworkUtils->setup_ip_forwarding(0); # disable ip forwarding + if ($rc == 0) + { + #remove the service from the /etc/xCATSN file + my $text=`sed -e "/$service/d" /etc/xCATSN`; + if ($?==0) { + `echo "$text" > /etc/xCATSN`; + } + } } } else # management node @@ -1244,33 +1256,5 @@ sub setup_HTTP return $rc; } -#----------------------------------------------------------------------------- - -=head3 setup_ip_forwarding - - Sets up ip forwarding on the sn - -=cut - -#----------------------------------------------------------------------------- -sub setup_ip_forwarding -{ - my $rc=0; - if (xCAT::Utils->isLinux()) { - my $conf_file="/etc/sysctl.conf"; - $rc=`grep "net.ipv4.ip_forward" $conf_file`; - if ($? == 0) { - `sed -i "s/^net.ipv4.ip_forward = 0/net.ipv4.ip_forward = 1/" $conf_file`; - } else { - `echo "net.ipv4.ip_forward = 1" >> $conf_file`; - } - $rc = `sysctl -p $conf_file`; - } - else - { #AIX: TODO - } - return $rc; -} - 1; diff --git a/xCAT-server/lib/xcat/plugins/route.pm b/xCAT-server/lib/xcat/plugins/route.pm new file mode 100644 index 000000000..ad6a795a8 --- /dev/null +++ b/xCAT-server/lib/xcat/plugins/route.pm @@ -0,0 +1,400 @@ +# 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')); + if (defined(@tmp1) && (@tmp1 > 0)) { + 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; + + my $result; + $result=`route|grep $net`; + if ($? == 0) { + if ($result) { + my @b=split('\n', $result); + foreach my $tmp (@b) { + chomp($tmp); + my @a=split(' ', $tmp); + 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; + } + } + } + } + } + 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 + print "cmd=route add -net $net netmask $mask gw $gw_ip\n"; + $result=`route add -net $net netmask $mask gw $gw_ip 2>&1`; + if ($? != 0) { + my $rsp={}; + $rsp->{error}->[0]= "route add -net $net netmask $mask gw $gw_ip\nerror code=$?, result=$result\n"; + $callback->($rsp); + return 1; + } else { + #set per permanent route + } + } + 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 + print "cmd=route delete -net $net netmask $mask gw $gw_ip\n"; + $result=`route delete -net $net netmask $mask gw $gw_ip 2>&1`; + if ($? != 0) { + my $rsp={}; + $rsp->{error}->[0]= "route delete -net $net netmask $mask gw $gw_ip\nerror code=$?, result=$result\n"; + $callback->($rsp); + return 1; + } else { + #delete route permanently + } + } + return 0; +} + +