mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 11:22:27 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			2755 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2755 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head1
 | |
|   xCAT plugin package to handle xdsh
 | |
| 
 | |
|    Supported command:
 | |
|          nodenetconn
 | |
|          ipforward (internal command)
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| package xCAT_plugin::vlan;
 | |
| 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;
 | |
| use Text::Balanced qw(extract_bracketed);
 | |
| use xCAT::SwitchHandler;
 | |
| use Safe;
 | |
| my $evalcpt = new Safe;
 | |
| $evalcpt->share('&mknum');
 | |
| $evalcpt->permit('require');
 | |
| 
 | |
| my %Switches=();
 | |
|   
 | |
| 1;
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3  handled_commands
 | |
| 
 | |
| Return list of commands handled by this plugin
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| sub handled_commands
 | |
| {
 | |
|     return {
 | |
|             mkvlan => "vlan",
 | |
|             chvlan => "vlan",
 | |
|             rmvlan => "vlan",
 | |
|             lsvlan => "vlan",
 | |
|             chvlanports => "vlan",
 | |
|            };
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =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];
 | |
|     $::CALLBACK = $callback;
 | |
| 
 | |
|     #if already preprocessed, go straight to request
 | |
|     if ((defined($request->{_xcatpreprocessed}))
 | |
|         && ($request->{_xcatpreprocessed}->[0] == 1))
 | |
|     {
 | |
|         return [$request];
 | |
|     }
 | |
| 
 | |
|     if ($command eq "mkvlan") {
 | |
| 	return preprocess_mkvlan($request,$callback,$sub_req);
 | |
|     } elsif($command eq "chvlanports"){
 | |
|         return preprocess_chvlanports($request,$callback,$sub_req);
 | |
|     } elsif ($command eq "chvlan") {
 | |
| 	return preprocess_chvlan($request,$callback,$sub_req);
 | |
|     } elsif ($command eq "rmvlan") {
 | |
| 	return preprocess_rmvlan($request,$callback,$sub_req);
 | |
|     } elsif ($command eq "lsvlan") {
 | |
| 	return preprocess_lsvlan($request,$callback,$sub_req);
 | |
|     } else {
 | |
| 	my $rsp={};
 | |
| 	$rsp->{error}->[0]= "$command: unsupported command.";
 | |
| 	$callback->($rsp);
 | |
| 	return 1;
 | |
|     }
 | |
| }
 | |
| 
 | |
| sub preprocess_mkvlan {
 | |
|     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 $nr;
 | |
|     my $net;
 | |
|     my $netmask;
 | |
|     my $prefix;
 | |
|     my $nic;
 | |
|     if(!GetOptions(
 | |
| 	    'h|help'      => \$::HELP,
 | |
| 	    'v|version'   => \$::VERSION,
 | |
| 	    'n|nodes=s'   => \$nr,
 | |
| 	    't|net=s'   => \$net,
 | |
| 	    'm|mask=s'   => \$netmask,
 | |
| 	    'p|prefix=s'   => \$prefix,
 | |
|             'i|interface=s' => \$nic,
 | |
|        ))
 | |
|     {
 | |
| 	&mkvlan_usage($callback);
 | |
| 	return 1;
 | |
|     }
 | |
|     # display the usage if -h or --help is specified
 | |
|     if ($::HELP) {
 | |
| 	&mkvlan_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;
 | |
|     }
 | |
| 
 | |
|     my $vlan_id=0;
 | |
|     if (@ARGV>0) {
 | |
| 	$vlan_id=$ARGV[0];   
 | |
|     }
 | |
| 
 | |
|     my @nodes=();
 | |
|     if ($nr) {
 | |
| 	#get nodes
 | |
| 	@nodes = noderange($nr);
 | |
| 	if (nodesmissed) {
 | |
| 	    my $rsp={};
 | |
| 	    $rsp->{data}->[0]= "Invalid nodes in noderange:".join(',',nodesmissed);
 | |
| 	    $callback->($rsp);
 | |
| 	    return 1;
 | |
| 	}
 | |
|     } else {
 | |
| 	my $rsp={};
 | |
| 	$rsp->{data}->[0]= "Please specify a list of nodes to be added to the new vlan.";
 | |
| 	$callback->($rsp);
 | |
| 	return 1;
 | |
|     }
 | |
| 
 | |
|     
 | |
|     if ($net && (!$netmask)) {
 | |
| 	my $rsp={};
 | |
| 	$rsp->{data}->[0]= "Please specify a netmask for the vlan.";
 | |
| 	$callback->($rsp);
 | |
| 	return 1;
 | |
|     }
 | |
|     if ($netmask && (!$net)) {
 | |
| 	my $rsp={};
 | |
| 	$rsp->{data}->[0]= "Please specify a network address for the vlan.";
 | |
| 	$callback->($rsp);
 | |
| 	return 1;
 | |
|     }
 | |
| 
 | |
|     #let process _request to handle it
 | |
|     my $reqcopy = {%$request};
 | |
|     $reqcopy->{_xcatpreprocessed}->[0] = 1;
 | |
|     $reqcopy->{vlanid}->[0] = $vlan_id; 
 | |
|     $reqcopy->{node} = \@nodes;
 | |
|     if ($net) { $reqcopy->{net}->[0]=$net; }
 | |
|     if ($netmask) { $reqcopy->{netmask}->[0]=$netmask; }
 | |
|     if ($prefix) { $reqcopy->{prefix}->[0]=$prefix; }
 | |
|     if ($nic) { $reqcopy->{nic}->[0]=$nic; }
 | |
|     return [$reqcopy];
 | |
| }
 | |
| # TODO: finish this
 | |
| sub preprocess_chvlanports {
 | |
|     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 $nr;
 | |
|     my $delete;
 | |
|     my $nic;
 | |
|     if(!GetOptions(
 | |
|         'h|help'      => \$::HELP,
 | |
|         'v|version'   => \$::VERSION,
 | |
|         'n|nodes=s'   => \$nr,
 | |
|         'd|delete'    => \$delete,
 | |
|         'i|interface=s' => \$nic,
 | |
|     ))
 | |
|     {
 | |
|         &chvlanports_usage($callback);
 | |
|         return 1;
 | |
|     }
 | |
|     # display the usage if -h or --help is specified
 | |
|     if ($::HELP) {
 | |
|         &chvlanports_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;
 | |
|     }
 | |
|     if (@ARGV==0) {
 | |
|         my $rsp={};
 | |
|         $rsp->{data}->[0]= "Please specify a vlan id.";
 | |
|         $callback->($rsp);
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     my $vlan_id=$ARGV[0];   
 | |
| 
 | |
|     my @nodes=();
 | |
|     if (!$nr) {
 | |
|         my $rsp={};
 | |
|         $rsp->{data}->[0]= "Please specify a range of nodes to be added to vlan $vlan_id.";
 | |
|         $callback->($rsp);
 | |
|         return 1;
 | |
|     } else {
 | |
|         #get nodes
 | |
|         @nodes = noderange($nr);
 | |
|         if (nodesmissed) {
 | |
|             my $rsp={};
 | |
|             $rsp->{data}->[0]= "Invalid nodes in noderange:".join(',',nodesmissed);
 | |
|             $callback->($rsp);
 | |
|             return 1;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     if (!$nic) {
 | |
|         my $rsp={};
 | |
|         $rsp->{data}->[0]= "Please specify a network interface for nodes";
 | |
|         $callback->($rsp);
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     #let process _request to handle it
 | |
|     my $reqcopy = {%$request};
 | |
|     $reqcopy->{_xcatpreprocessed}->[0] = 1;
 | |
|     $reqcopy->{vlanid}->[0]=$vlan_id;
 | |
|     $reqcopy->{node} = \@nodes;
 | |
|     $reqcopy->{delete}->[0] = $delete;
 | |
|     $reqcopy->{nic}->[0]=$nic;
 | |
|     return [$reqcopy];
 | |
| }
 | |
| 
 | |
| sub preprocess_chvlan {
 | |
|     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 $nr;
 | |
|     my $delete;
 | |
|     my $nic;
 | |
|     if(!GetOptions(
 | |
| 	    'h|help'      => \$::HELP,
 | |
| 	    'v|version'   => \$::VERSION,
 | |
| 	    'n|nodes=s'   => \$nr,
 | |
| 	    'd|delete'    => \$delete,
 | |
|             'i|interface=s' => \$nic,
 | |
|        ))
 | |
|     {
 | |
| 	&chvlan_usage($callback);
 | |
| 	return 1;
 | |
|     }
 | |
|     # display the usage if -h or --help is specified
 | |
|     if ($::HELP) {
 | |
| 	&chvlan_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;
 | |
|     }
 | |
|     if (@ARGV==0) {
 | |
| 	my $rsp={};
 | |
| 	$rsp->{data}->[0]= "Please specify a vlan id.";
 | |
| 	$callback->($rsp);
 | |
| 	return 1;
 | |
|     }
 | |
| 
 | |
|     my $vlan_id=$ARGV[0];   
 | |
| 
 | |
|     my @nodes=();
 | |
|     if (!$nr) {
 | |
| 	my $rsp={};
 | |
| 	$rsp->{data}->[0]= "Please specify a range of nodes to be added to vlan $vlan_id.";
 | |
| 	$callback->($rsp);
 | |
| 	return 1;
 | |
|     } else {
 | |
| 	#get nodes
 | |
| 	@nodes = noderange($nr);
 | |
| 	if (nodesmissed) {
 | |
| 	    my $rsp={};
 | |
| 	    $rsp->{data}->[0]= "Invalid nodes in noderange:".join(',',nodesmissed);
 | |
| 	    $callback->($rsp);
 | |
| 	    return 1;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     #let process _request to handle it
 | |
|    my $reqcopy = {%$request};
 | |
|     $reqcopy->{_xcatpreprocessed}->[0] = 1;
 | |
|     $reqcopy->{vlanid}->[0]=$vlan_id;
 | |
|     $reqcopy->{node} = \@nodes;
 | |
|     $reqcopy->{delete}->[0] = $delete;
 | |
|     if ($nic) { $reqcopy->{nic}->[0]=$nic; }
 | |
|     return [$reqcopy];
 | |
| }
 | |
| 
 | |
| sub preprocess_rmvlan {
 | |
|     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 $nodes;
 | |
|     if(!GetOptions(
 | |
| 	    'h|help'      => \$::HELP,
 | |
| 	    'v|version'   => \$::VERSION,
 | |
|        ))
 | |
|     {
 | |
| 	&rmvlan_usage($callback);
 | |
| 	return 1;
 | |
|     }
 | |
|     # display the usage if -h or --help is specified
 | |
|     if ($::HELP) {
 | |
| 	&rmvlan_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;
 | |
|     }
 | |
| 
 | |
|     if (@ARGV==0) {
 | |
| 	my $rsp={};
 | |
| 	$rsp->{data}->[0]= "Please specify a vlan id.";
 | |
| 	$callback->($rsp);
 | |
| 	return 1;
 | |
|     }
 | |
| 
 | |
|     my $vlan_id=$ARGV[0];   
 | |
| 
 | |
|     #let process _request to handle it
 | |
|     my $reqcopy = {%$request};
 | |
|     $reqcopy->{_xcatpreprocessed}->[0] = 1;
 | |
|     $reqcopy->{vlanid}->[0]=$vlan_id;
 | |
|     return [$reqcopy];
 | |
| }
 | |
| 
 | |
| sub preprocess_lsvlan {
 | |
|     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 $nodes;
 | |
|     if(!GetOptions(
 | |
| 	    'h|help'      => \$::HELP,
 | |
| 	    'v|version'   => \$::VERSION,
 | |
|        ))
 | |
|     {
 | |
| 	&lsvlan_usage($callback);
 | |
| 	return 1;
 | |
|     }
 | |
|     # display the usage if -h or --help is specified
 | |
|     if ($::HELP) {
 | |
| 	&lsvlan_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;
 | |
|     }
 | |
| 
 | |
|     my $vlan_id=0;
 | |
|     if (@ARGV>0) {
 | |
| 	$vlan_id=$ARGV[0];   
 | |
|     }
 | |
| 
 | |
|     #let process _request to handle it
 | |
|     my $reqcopy = {%$request};
 | |
|     $reqcopy->{_xcatpreprocessed}->[0] = 1;
 | |
|     $reqcopy->{vlanid}->[0]=$vlan_id;
 | |
|     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];
 | |
|     my $args    = $request->{arg};
 | |
|     $::CALLBACK = $callback;
 | |
| 
 | |
|     if ($command eq "mkvlan") {
 | |
| 	return process_mkvlan($request,$callback,$sub_req);
 | |
|     } elsif ($command eq "chvlanports"){
 | |
|         return process_chvlanports($request,$callback,$sub_req);
 | |
|     } elsif ($command eq "chvlan") {
 | |
| 	return process_chvlan($request,$callback,$sub_req);
 | |
|     } elsif ($command eq "rmvlan") {
 | |
| 	return process_rmvlan($request,$callback,$sub_req);
 | |
|     } elsif ($command eq "lsvlan") {
 | |
| 	return process_lsvlan($request,$callback,$sub_req);
 | |
|     } else {
 | |
| 	my $rsp={};
 | |
| 	$rsp->{error}->[0]= "$command: unsupported command.";
 | |
| 	$callback->($rsp);
 | |
| 	return 1;
 | |
|     }
 | |
| 
 | |
| 
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| sub process_mkvlan {
 | |
|     my $request  = shift;
 | |
|     my $callback = shift;
 | |
|     my $sub_req  = shift;
 | |
|     
 | |
|     my $vlan_id=0;
 | |
|     if (exists($request->{vlanid})) {
 | |
| 	$vlan_id=$request->{vlanid}->[0];
 | |
|     }
 | |
|     my @nodes=();
 | |
|     if (exists($request->{node})) {
 | |
| 	@nodes=@{$request->{node}};
 | |
|     }
 | |
| 
 | |
|     my $net;
 | |
|     if (exists($request->{net})) {
 | |
| 	$net=$request->{net}->[0];
 | |
|     }
 | |
|     my $netmask;
 | |
|     if (exists($request->{netmask})) {
 | |
| 	$netmask=$request->{netmask}->[0];
 | |
|     }
 | |
|     my $prefix;
 | |
|     if (exists($request->{prefix})) {
 | |
| 	$prefix=$request->{prefix}->[0];
 | |
|     } 
 | |
| 
 | |
|     my $nic;
 | |
|     if (exists($request->{nic})) {
 | |
| 	$nic=$request->{nic}->[0];
 | |
|     } 
 | |
| 
 | |
|     #check if the vlan is already defined on the table 
 | |
|     my $nwtab=xCAT::Table->new("networks", -create =>1);
 | |
|     if ($vlan_id > 0) {
 | |
| 	if ($nwtab) {
 | |
| 	    my @tmp1=$nwtab->getAllAttribs(('vlanid', 'net', 'mask'));
 | |
| 	    if ((@tmp1) && (@tmp1 > 0)) {
 | |
| 		foreach(@tmp1) {
 | |
| 		    if ($vlan_id eq $_->{vlanid}) {
 | |
| 			my $rsp={};
 | |
| 			$rsp->{error}->[0]= "The vlan $vlan_id is already used. Please choose another vlan id.";
 | |
| 			$callback->($rsp);
 | |
| 			return 1;
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     #make sure the vlan id is not currently used by another vlan
 | |
|     #if no vlan id is supplied, automatically generate a new vlan id
 | |
|     if ($vlan_id > 0) {
 | |
| 	if (!verify_vlanid($vlan_id, $callback)) { return 1; }
 | |
|     } else {
 | |
| 	$vlan_id=get_next_vlanid($callback);
 | |
| 	if (!$vlan_id) { return 1;}
 | |
|     }
 | |
| 
 | |
|     if (!$prefix) {
 | |
| 	$prefix="v". $vlan_id . "n"; #default
 | |
|     }
 | |
|     
 | |
| 
 | |
|     ####now get the switch ports for the nodes
 | |
|     my %swinfo=();  # example: %swinfo=( switch1=>{ 23=>{ nodes: [node1]
 | |
|                          #                                interface: eth0
 | |
|                          #                               },
 | |
|                          #                          24=>{ nodes: [node2,node3], 
 | |
|                          #                                vmhost: kvm1
 | |
|                          #                                interface: eth1
 | |
|                          #                              }
 | |
|                          #                         },
 | |
|                          #               switch12=>{ 3=>{ nodes: [node4]},
 | |
|                          #                           7=>{ nodes: [node4]
 | |
|                          #                                interface: eth0 }, 
 | |
|                          #                           9=>{ nodes: [node6]}
 | |
|                          #                        }
 | |
|                          #             )
 | |
| 
 | |
|     my %vminfo=();       # example: %vminfo=( kvm1=>{clients:[node1,node2...]},
 | |
|                          #                    kvm2=>{clients:[node2,node3...]},
 | |
|                          #                   )
 | |
|                          #                  
 | |
|     my @vmnodes=();      # vm clients
 | |
|     my @snodes=();       # stand alone nodes
 | |
| 
 | |
|     
 | |
|     #get the vm hosts  
 | |
|     my $vmtab=xCAT::Table->new("vm", -create =>1);
 | |
|     my $vmtmphash = $vmtab->getNodesAttribs(\@nodes, ['host', 'nics']) ;
 | |
|     foreach my $node (@nodes) {
 | |
| 	my $host;
 | |
| 	my $ent=$vmtmphash->{$node}->[0];
 | |
| 	if (ref($ent) and defined $ent->{host}) { 
 | |
| 	    $host = $ent->{host}; 
 | |
| 	    if (exists($vminfo{$host})) {
 | |
| 		my $pa=$vminfo{$host}->{clients};
 | |
| 		push(@$pa, $node);
 | |
| 	    } else {
 | |
| 		$vminfo{$host}->{clients}=[$node];
 | |
| 	    }
 | |
| 
 | |
| 	    push(@vmnodes, $node);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|    
 | |
|     if (@vmnodes > 0) {
 | |
| 	foreach my $node (@nodes) {
 | |
| 	    if (! grep /^$node$/, @vmnodes) {
 | |
| 		push(@snodes, $node);
 | |
| 	    }
 | |
| 	}
 | |
|     } else {
 | |
| 	@snodes=@nodes;
 | |
|     }
 | |
|  
 | |
|     #get the switch and port numbers for each node
 | |
|     my @vmhosts=keys(%vminfo);
 | |
|     my @anodes=(@snodes, @vmhosts); #nodes that connects to the switch
 | |
|     my %swsetup=();
 | |
|     my $swtab=xCAT::Table->new("switch", -create =>1);
 | |
|     my $swtmphash = $swtab->getNodesAttribs(\@anodes, ['switch', 'port', 'vlan', 'interface']) ;
 | |
|     my @missed_nodes=();
 | |
|     foreach my $node (@anodes) {
 | |
| 	my $node_enties=$swtmphash->{$node}; 
 | |
| 	if ($node_enties) {
 | |
| 	    my $i=-1;
 | |
|             my $use_this=0;
 | |
| 	    foreach my $ent (@$node_enties) {
 | |
| 		$i++;
 | |
| 		if (ref($ent) and defined $ent->{switch} and defined $ent->{port}) { 
 | |
| 		    my $switch;
 | |
| 		    my $port;
 | |
| 		    $switch = $ent->{switch};
 | |
| 		    $port = $ent->{port};
 | |
| 		    my $interface="primary";		    
 | |
| 		    if (defined $ent->{interface}) { $interface=$ent->{interface};}
 | |
|                     # for primary nic, the interface can be empty, "primary" or "primary:eth0"
 | |
| 		    #print "***nic=$nic, interface=$interface\n";
 | |
| 		    if ($nic) {
 | |
| 			if ($interface =~ /primary/) {
 | |
| 			    $interface =~ s/primary(:)?//g;
 | |
| 			}
 | |
| 			if ($interface && ($interface eq $nic)) { $use_this=1; }
 | |
| 		    } else {
 | |
| 			if ($interface =~ /primary/) {  $use_this=1; }
 | |
| 		    } 
 | |
| 
 | |
| 		    if (! $use_this) { 
 | |
| 			next; 
 | |
| 		    }
 | |
| 		    else { 
 | |
| 			$swsetup{$node}->{port}=$port;
 | |
| 			$swsetup{$node}->{switch}=$switch;
 | |
| 			if (defined $ent->{vlan}) { 
 | |
| 			    $swsetup{$node}->{vlan}=$ent->{vlan};
 | |
| 			} else {
 | |
| 			    $swsetup{$node}->{vlan}="";
 | |
| 			}
 | |
| 		    }
 | |
| 
 | |
| 		    if ($interface) { 			
 | |
| 			$swinfo{$switch}->{$port}->{interface}=$interface;
 | |
| 		    }
 | |
| 		    
 | |
| 		    if (exists($vminfo{$node})) {
 | |
| 			$swinfo{$switch}->{$port}->{vmhost}=$node;
 | |
| 			$swinfo{$switch}->{$port}->{nodes}=$vminfo{$node}->{clients};
 | |
| 		    } else {
 | |
| 			$swinfo{$switch}->{$port}->{nodes}=[$node];
 | |
| 		    }
 | |
| 		    last;
 | |
| 		    
 | |
| 		} 
 | |
| 	    }
 | |
|             if ( $use_this != 1 ) {
 | |
|                 push (@missed_nodes, $node);
 | |
|             }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     if (@missed_nodes > 0) {
 | |
| 	my $rsp={};
 | |
| 	$rsp->{error}->[0]= "Cannot proceed, please define switch and port info on the switch table for the following nodes:\n  @missed_nodes\n";
 | |
| 	$callback->($rsp);
 | |
| 	return 1;
 | |
|     }
 | |
|     
 | |
|     #print "vminfo=" . Dumper(%vminfo) . "\n";
 | |
|     #print "swinfo=" . Dumper(%swinfo) . "\n";
 | |
|     #print "snodes=" . Dumper(@snodes) . "\n";
 | |
|     #print "anodes=" . Dumper(@anodes) . "\n";
 | |
|     #print "vmnodes=" . Dumper(@vmnodes) . "\n";
 | |
|     #print "swtmphash" . Dumper($swtmphash). "\n";
 | |
| 
 | |
|     ### verify the ports are not used by other vlans
 | |
|     #if (!verify_switch_ports($vlan_id, \%swinfo, $callback)) { return 1;}
 | |
|     
 | |
|     ### now pick a network address for the vlan
 | |
|     if (!$net) {
 | |
| 	($net, $netmask)=get_subnet($vlan_id, $callback);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     ### save the vlan on the networks table
 | |
|     my %key_col = (netname=>"vlan$vlan_id");
 | |
|     my %tb_cols=(vlanid=>$vlan_id, net=>$net, mask=>$netmask);
 | |
|     $nwtab->setAttribs(\%key_col, \%tb_cols);
 | |
| 
 | |
| 
 | |
|     ### configure vlan on the switch
 | |
|     if (!create_vlan($vlan_id, \%swinfo, $callback)) { return 1;}
 | |
|     if (!add_ports($vlan_id, \%swinfo, $callback)) { return 1;}
 | |
|     my @sws=keys(%swinfo);
 | |
|     if (!add_crossover_ports($vlan_id, \@sws, $callback)) { return 1;}
 | |
| 
 | |
|     ### add the vlanid for the standalone nodes on the switch table
 | |
|     ### append the vlan id for the vmhosts on the switch table
 | |
|     add_vlan_to_switch_table(\%swsetup, $vlan_id);
 | |
| 
 | |
|     ### get node ip and vlan hostname from the hosts table. 
 | |
|     #If it is not defined, put the default into the host table
 | |
|     my @allnodes=(@anodes, @vmnodes);
 | |
|     if (!add_vlan_ip_host($net, $netmask, $prefix, 1, \@allnodes, $callback)) { return 1;}
 | |
| 
 | |
|     ### for vm nodes, add an additional nic on the vm.nics
 | |
|     if (@vmnodes > 0) {
 | |
| 	my %setupnics=();
 | |
| 	my $new_nic="vl$vlan_id";
 | |
| 	foreach my $node (@vmnodes) {
 | |
| 	    my $ent=$vmtmphash->{$node}->[0];
 | |
| 	    my $nics;
 | |
| 	    if (ref($ent) and defined $ent->{nics}) { 
 | |
| 		$nics=$ent->{nics};
 | |
| 		my @a=split(",", $nics);
 | |
| 		if (!grep(/^$new_nic$/, @a)) { $nics="$nics,$new_nic"; }
 | |
| 	    } else {
 | |
| 		$nics=$new_nic;
 | |
| 	    }
 | |
| 	    $setupnics{$node}={nics=>"$nics"};
 | |
| 	}
 | |
| 	$vmtab->setNodesAttribs(\%setupnics);
 | |
|     }
 | |
| 
 | |
|     ### populate the /etc/hosts and make the DNS server on the mn aware this change
 | |
|     $::CALLBACK = $callback;
 | |
|     my $res = xCAT::Utils->runxcmd(  {
 | |
|             command => ['makehosts'],
 | |
|             }, $sub_req, 0, 1);
 | |
|     my $rsp = {};
 | |
|     $rsp->{data}->[0] = "Running makehosts...";
 | |
|     $callback->($rsp);
 | |
|     if ($res && (@$res > 0)) {
 | |
| 	$rsp = {};
 | |
| 	$rsp->{data} = $res;
 | |
| 	$callback->($rsp);
 | |
|     }
 | |
| 
 | |
|     $::CALLBACK = $callback;
 | |
|     my $res = xCAT::Utils->runxcmd(  {
 | |
|             command => ['makedns'],
 | |
|             }, $sub_req, 0, 1);
 | |
|     my $rsp = {};
 | |
|     $rsp->{data}->[0] = "Running makedns...";
 | |
|     $callback->($rsp);
 | |
|     if ($res && (@$res > 0)) {
 | |
| 	$rsp->{data} = $res;
 | |
| 	$callback->($rsp);
 | |
|     }
 | |
| 
 | |
|     my $cmd = "service named restart";
 | |
|     my $rc=system $cmd;
 | |
| 
 | |
|     ### now go to the nodes to configure the vlan interface
 | |
|     $::CALLBACK = $callback;
 | |
|     my $args = ["-P", "configvlan $vlan_id --keephostname"];
 | |
|     my $res = xCAT::Utils->runxcmd(  {
 | |
|             command => ['updatenode'],
 | |
| 	    node    => \@snodes,
 | |
| 	    arg     => $args
 | |
|             }, $sub_req, 0, 1);
 | |
|     my $rsp = {};
 | |
|     $rsp->{data}->[0] = "Running updatenode...";
 | |
|     $callback->($rsp);
 | |
|     if ($res && (@$res > 0)) {
 | |
| 	$rsp->{data} = $res;
 | |
| 	$callback->($rsp);
 | |
|     }
 | |
| 
 | |
|     ### add configvlan postscripts to the postscripts table for the node
 | |
|     #   so that next time the node bootup, the vlan can get configured
 | |
|     my @pnodes=(@snodes, @vmnodes);
 | |
|     add_postscript($callback, \@pnodes);
 | |
| 
 | |
|     my $rsp={};
 | |
|     $rsp->{data}->[0]= "The vlan is successfully configured. ";
 | |
|     $rsp->{data}->[1]= "  vlan id: $vlan_id";
 | |
|     $rsp->{data}->[2]= "  vlan subnet: $net";
 | |
|     $rsp->{data}->[3]= "  vlan netmask: $netmask";
 | |
|     #$rsp->{data}->[4]= "  vlan dhcp server:";
 | |
|     #$rsp->{data}->[5]= "  vlan dns server:";
 | |
|     #$rsp->{data}->[6]= "  vlan gateway:";
 | |
|     $callback->($rsp);
 | |
| 
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  add_vlan_to_switch_table
 | |
| 
 | |
|   It adds the vlan id to the switch.vlan for the given nodes.
 | |
| 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub add_vlan_to_switch_table {
 | |
|     my $swsetup=shift;
 | |
|     my $vlan_id=shift;
 | |
| 
 | |
|     my $swtab1 = xCAT::Table->new( 'switch', -create=>1, -autocommit=>0 );
 | |
|     foreach my $node (keys(%$swsetup)) {
 | |
| 	my %keyhash=();
 | |
| 	my %updates=();
 | |
| 	$keyhash{'node'} = $node;
 | |
| 	$keyhash{'switch'}= $swsetup->{$node}->{switch};
 | |
| 	$keyhash{'port'} = $swsetup->{$node}->{port};
 | |
| 	$updates{'vlan'}=$vlan_id;
 | |
| 	my $vlan;
 | |
| 	if($swsetup->{$node}->{vlan}) { 
 | |
| 	    $vlan=$swsetup->{$node}->{vlan};
 | |
| 	    my @a=split(",", $vlan);
 | |
| 	    if (!grep(/^$vlan_id$/, @a)) { $vlan="$vlan,$vlan_id";}
 | |
| 	    $updates{'vlan'}=$vlan;
 | |
| 	}
 | |
| 	  
 | |
| 	$swtab1->setAttribs( \%keyhash,\%updates );
 | |
|     }
 | |
|     $swtab1->commit;
 | |
| }
 | |
| 
 | |
| sub remove_vlan_from_switch_table {
 | |
|     my $swsetup=shift;
 | |
|     my $vlan_id=shift;
 | |
|     #remove the vlan id from the switch table for standalone nodes 
 | |
|     my $swtab1 = xCAT::Table->new('switch', -create=>1, -autocommit=>0 );
 | |
|     foreach my $node (keys(%$swsetup)) {
 | |
| 	my %keyhash=();
 | |
| 	my %updates=();
 | |
| 	$keyhash{'node'} = $node;
 | |
| 	$keyhash{'switch'}= $swsetup->{$node}->{switch};
 | |
| 	$keyhash{'port'} = $swsetup->{$node}->{port};
 | |
| 	$updates{'vlan'} = "";
 | |
| 	if($swsetup->{$node}->{vlan}) {
 | |
| 	    my @a=split(',', $swsetup->{$node}->{vlan});
 | |
| 	    my @b=grep(!/^$vlan_id$/,@a);
 | |
| 	    if (@b>0) {
 | |
| 		$updates{'vlan'}=join(',', @b);
 | |
| 	    }
 | |
| 	}
 | |
| 	$swtab1->setAttribs( \%keyhash,\%updates );
 | |
|     }
 | |
|     $swtab1->commit;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  add_postscript
 | |
| 
 | |
|   It adds the 'configvlan' postscript to the postscript table
 | |
|   for the given nodes.
 | |
| 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub  add_postscript {
 | |
|     my $callback=shift;
 | |
|     my $anodes=shift;
 | |
| 
 | |
|     my $posttab=xCAT::Table->new("postscripts", -create =>1);
 | |
|     if ($posttab) {
 | |
| 	(my $ref1) = $posttab->getAttribs({node => 'xcatdefaults'}, ('postscripts', 'postbootscripts'));
 | |
|         #if configvlan is in xcadefaults, then do nothing
 | |
| 	if ($ref1) {
 | |
| 	    if ($ref1->{postscripts}) {
 | |
| 		my @a = split(/,/, $ref1->{postscripts});
 | |
| 		if (grep(/^configvlan$/, @a)) { next; }
 | |
| 	    }
 | |
| 	    if ($ref1->{postbootscripts}) {
 | |
| 		my @a = split(/,/, $ref1->{postbootscripts});
 | |
| 		if (grep(/^configvlan$/, @a)) { next; }
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
| 	#now check for each node
 | |
| 	my %setup_hash;
 | |
| 	my $postcache = $posttab->getNodesAttribs($anodes,[qw(postscripts postbootscripts)]);
 | |
| 	foreach my $node (@$anodes) {
 | |
| 	    my $ref = $postcache->{$node}->[0]; 
 | |
| 	    if ($ref) {
 | |
| 		if (exists($ref->{postscripts})) {
 | |
| 		    my @a = split(/,/, $ref->{postscripts});
 | |
| 		    if (grep(/^configvlan$/, @a)) { next; }
 | |
| 		}
 | |
| 
 | |
| 		if (exists($ref->{postbootscripts})) {
 | |
| 		    my $post=$ref->{postbootscripts};
 | |
| 		    my @old_a=split(',', $post);
 | |
| 		    if (grep(/^configvlan$/, @old_a)) {
 | |
| 			next;
 | |
| 		    } else {
 | |
| 			$setup_hash{$node}={postbootscripts=>"$post,configvlan"};
 | |
| 		    }
 | |
| 		} else {
 | |
| 		    $setup_hash{$node}={postbootscripts=>"configvlan"};
 | |
| 		}
 | |
| 	    } else {
 | |
| 		$setup_hash{$node}={postbootscripts=>"configvlan"};
 | |
| 	    }
 | |
| 	}
 | |
| 	if (keys(%setup_hash) > 0) {
 | |
| 	    $posttab->setNodesAttribs(\%setup_hash);
 | |
| 	}
 | |
|     }   
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  add_vlan_ip_host
 | |
| 
 | |
|   It goes to the hosts.otherinterfaces to see if the vlan ip and hostname
 | |
|   is defined. If not, it will add the default in the table. 
 | |
|   The default is v<vlanid>n<node#>
 | |
| 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub  add_vlan_ip_host {
 | |
|     my $subnet=shift;
 | |
|     my $netmask=shift;
 | |
|     my $prefix=shift;
 | |
|     my $node_number=shift;
 | |
|     my $nodes=shift;
 | |
|     my $callback=shift;
 | |
| 
 | |
|     my $hoststab = xCAT::Table->new('hosts');
 | |
|     my $hostscache = $hoststab->getNodesAttribs($nodes,[qw(node otherinterfaces)]);
 | |
|     my %setup_hash;
 | |
|     foreach my $node (@$nodes) {
 | |
| 	my $ref = $hostscache->{$node}->[0]; 
 | |
| 	my $found=0;
 | |
| 	my $otherinterfaces;
 | |
| 	if ($ref && exists($ref->{otherinterfaces})){
 | |
| 	    $otherinterfaces = $ref->{otherinterfaces};
 | |
| 	    my @itf_pairs=split(/,/, $otherinterfaces);
 | |
| 	    foreach (@itf_pairs) {
 | |
|             	my ($name,$ip)=split(/:/, $_);
 | |
| 	    	if ($name =~ /^-/ ) {
 | |
| 	    	    $name = $node.$name;
 | |
| 	    	}
 | |
| 	    	if(xCAT::NetworkUtils->ishostinsubnet($ip, $netmask, $subnet)) {
 | |
| 	    	    $found=1;
 | |
| 	    	}
 | |
| 	    }	    
 | |
| 	}
 | |
| 	if (!$found) {
 | |
| 	    my $hostname=$prefix . "$node_number"; 
 | |
| 	    my $ip="";
 | |
| 	    if ($subnet =~ /\d+\.\d+\.\d+\.\d+/) {# ipv4 address
 | |
| 		$subnet =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
 | |
| 		my $netnum = ($1<<24)+($2<<16)+($3<<8)+$4;
 | |
| 		my $ipnum=$netnum + $node_number;
 | |
| 		my @a=();
 | |
| 		for (my $i=3; $i>-1; $i--) {
 | |
| 		    $a[$i]=$ipnum % 256;
 | |
| 		    $ipnum = int($ipnum / 256);
 | |
| 		}
 | |
| 		$ip= "$a[0].$a[1].$a[2].$a[3]";
 | |
| 		#print "ip=$ip\n";
 | |
| 	    } else {
 | |
| 		my $rsp={};
 | |
| 		$rsp->{error}->[0]= "Does not support IPV6 address yet.";
 | |
| 		$callback->($rsp);
 | |
| 		return 0; 
 | |
| 	    }
 | |
| 	    $node_number++;
 | |
| 
 | |
| 	    if ($otherinterfaces) {
 | |
| 		$setup_hash{$node}={otherinterfaces=>"$hostname:$ip,$otherinterfaces"};
 | |
| 	    } else {
 | |
| 		$setup_hash{$node}={otherinterfaces=>"$hostname:$ip"};
 | |
| 	    }
 | |
| 	}
 | |
|     } #foreach node
 | |
| 
 | |
|     if (keys(%setup_hash) > 0) {
 | |
| 	$hoststab->setNodesAttribs(\%setup_hash);
 | |
|     }
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3 get_prefix_and_nodenumber
 | |
| 
 | |
|   It gets the prefix and max node number from the current nodes
 | |
|   in the given vlan. 
 | |
| 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub get_prefix_and_nodenumber {
 | |
|     my $vlan_id = shift;
 | |
|     my $subnet = shift;
 | |
|     my $netmask = shift;
 | |
| 
 | |
|     #get all the nodes that are in the vlan
 | |
|     my $swtab=xCAT::Table->new("switch", -create =>0);
 | |
|     my @nodes=();
 | |
|     my @tmp1=$swtab->getAllAttribs(('node', 'vlan'));
 | |
|     if ((@tmp1) && (@tmp1 > 0)) {
 | |
| 	foreach my $ent (@tmp1) {
 | |
| 	    my @nodes_tmp=noderange($ent->{node});
 | |
| 	    foreach my $node (@nodes_tmp) {
 | |
| 		if ($ent->{vlan}) {
 | |
| 		    my @a=split(",", $ent->{vlan});
 | |
| 		    if (grep(/^$vlan_id$/,@a)) {
 | |
| 			push(@nodes, $node);
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
| 
 | |
|     #get all the vm clients if the node is a vm host
 | |
|     my $vmtab=xCAT::Table->new("vm", -create =>0);
 | |
|     my @vmnodes=();
 | |
|     if ($vmtab) {
 | |
| 	my @tmp1=$vmtab->getAllAttribs('node', 'host');
 | |
| 	if ((@tmp1) && (@tmp1 > 0)) {
 | |
| 	    foreach(@tmp1) {
 | |
| 		my $host = $_->{host};
 | |
| 		if (grep(/^$host$/, @nodes)) {
 | |
| 		    my @nodes_tmp=noderange($_->{node});
 | |
| 		    foreach my $node (@nodes_tmp) {
 | |
| 			push(@vmnodes, $node);
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     
 | |
|     @nodes=(@nodes, @vmnodes);
 | |
|     #print "nodes=@nodes\n";	
 | |
| 
 | |
|     #now go to hosts table to get the prefix and max node number
 | |
|     my $hoststab = xCAT::Table->new('hosts');
 | |
|     my $hostscache = $hoststab->getNodesAttribs(\@nodes,[qw(node otherinterfaces)]);
 | |
|     my $max=0;
 | |
|     my $prefix;
 | |
|     foreach my $node (@nodes) {
 | |
| 	my $ref = $hostscache->{$node}->[0]; 
 | |
| 	my $otherinterfaces;
 | |
| 	if ($ref && exists($ref->{otherinterfaces})){
 | |
| 	    $otherinterfaces = $ref->{otherinterfaces};
 | |
| 	    my @itf_pairs=split(/,/, $otherinterfaces);
 | |
| 	    my @itf_pairs2=();
 | |
| 	    foreach (@itf_pairs) {
 | |
|             	my ($name,$ip)=split(/:/, $_);
 | |
| 	    	if(xCAT::NetworkUtils->ishostinsubnet($ip, $netmask, $subnet)) {
 | |
| 		   $name =~ /^(.*)([\d]+)$/;
 | |
|                    if ($2 > $max) { $max=$2;}
 | |
| 		   if (!$prefix) { $prefix=$1;}
 | |
| 		   #print "name=$name\n, 1=$1, 2=$2\n";
 | |
| 	    	}
 | |
| 	    }
 | |
| 	}
 | |
|     } #foreach node
 | |
| 
 | |
|     return ($prefix, $max);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  remove_vlan_ip_host
 | |
| 
 | |
|   It goes to the hosts.otherinterfaces to see if the vlan ip and hostname
 | |
|   is defined. If it is, it will remove it. It also remove the entried in 
 | |
|   the /etc/hosts file
 | |
| 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub  remove_vlan_ip_host {
 | |
|     my $subnet=shift;
 | |
|     my $netmask=shift;
 | |
|     my $nodes=shift;
 | |
|     my $callback=shift;
 | |
| 
 | |
|     my $hoststab = xCAT::Table->new('hosts');
 | |
|     my $hostscache = $hoststab->getNodesAttribs($nodes,[qw(node otherinterfaces)]);
 | |
|     my %setup_hash;
 | |
|     foreach my $node (@$nodes) {
 | |
| 	my $ref = $hostscache->{$node}->[0]; 
 | |
| 	my $otherinterfaces;
 | |
| 	if ($ref && exists($ref->{otherinterfaces})){
 | |
| 	    $otherinterfaces = $ref->{otherinterfaces};
 | |
| 	    my @itf_pairs=split(/,/, $otherinterfaces);
 | |
| 	    my @itf_pairs2=();
 | |
| 	    my $index=0;
 | |
| 	    foreach (@itf_pairs) {
 | |
|             	my ($name,$ip)=split(/:/, $_);
 | |
| 	    	if(!xCAT::NetworkUtils->ishostinsubnet($ip, $netmask, $subnet)) {
 | |
| 	    	    $itf_pairs2[$index]=$_;
 | |
| 		    $index++;
 | |
| 	    	} else {
 | |
| 		    my $cmd="sed -i /$ip/d /etc/hosts";
 | |
| 		    my $rc=system $cmd;
 | |
| 		}
 | |
| 	    }
 | |
| 	    if (@itf_pairs2 > 0) {
 | |
| 		my $new_intf=join(",", @itf_pairs2);
 | |
| 		$setup_hash{$node}={otherinterfaces=>$new_intf}
 | |
| 	    } else {
 | |
| 		$setup_hash{$node}={otherinterfaces=>""};
 | |
| 	    }
 | |
| 	}
 | |
|     } #foreach node
 | |
| 
 | |
|     if (keys(%setup_hash) > 0) {
 | |
| 	$hoststab->setNodesAttribs(\%setup_hash);
 | |
|     }
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  verify_vlanid
 | |
| 
 | |
|   It goes to all the switches to make sure that the vlan 
 | |
|   id is not used by other vlans.
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub verify_vlanid {
 | |
|     my $vlan_id=shift;
 | |
|     my $callback=shift;
 | |
| 
 | |
|     my $switchestab=xCAT::Table->new('switches',-create=>0);
 | |
|     my @tmp1=$switchestab->getAllAttribs(('switch'));
 | |
|     if ((@tmp1) && (@tmp1 > 0)) {
 | |
| 	foreach(@tmp1) {
 | |
| 	    my @switches_tmp=noderange($_->{switch});
 | |
| 	    if (@switches_tmp==0) { push @switches_tmp, $_->{switch}; } #sometimes the switch name is not on the node list table.  
 | |
| 	    foreach my $switch (@switches_tmp) {
 | |
| 		my $swh;
 | |
| 		if (exists($Switches{$switch})) { $swh=$Switches{$switch};}
 | |
| 		else {
 | |
| 		    $swh=new xCAT::SwitchHandler->new($switch);
 | |
| 		    $Switches{$switch}=$swh;
 | |
| 		}
 | |
| 		my @ids=$swh->get_vlan_ids();
 | |
| 		print "ids=@ids\n";
 | |
| 		foreach my $id (@ids) {
 | |
| 		    if ($id == $vlan_id) {
 | |
| 			my $rsp={};
 | |
| 			$rsp->{error}->[0]= "The vlan id $vlan_id already exists on switch $switch. Please choose another vlan id.\n";
 | |
| 			$callback->($rsp);
 | |
| 			return 0; 
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  get_next_vlanid
 | |
| 
 | |
|   It automatically generates the vlan ID. It goes to all the
 | |
|   switches, get the smallest common integer that is not used
 | |
|   by any existing vlans. 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub get_next_vlanid {
 | |
|     my $callback=shift;
 | |
|     my $switchestab=xCAT::Table->new('switches',-create=>0);
 | |
|     my @tmp1=$switchestab->getAllAttribs(('switch'));
 | |
|     my %vlanids=();
 | |
|     if ((@tmp1) && (@tmp1 > 0)) {
 | |
| 	foreach(@tmp1) {
 | |
| 	    my @switches_tmp=noderange($_->{switch});
 | |
| 	    if (@switches_tmp==0) { push @switches_tmp, $_->{switch}; } #sometimes the switch name is not on the node list table.  
 | |
| 	    foreach my $switch (@switches_tmp) {
 | |
| 		my $swh;
 | |
| 		if (exists($Switches{$switch})) { $swh=$Switches{$switch};}
 | |
| 		else {
 | |
| 		    $swh=new xCAT::SwitchHandler->new($switch);
 | |
| 		    $Switches{$switch}=$swh;
 | |
| 		}
 | |
| 		my @ids=$swh->get_vlan_ids();
 | |
| 		foreach my $id (@ids) {
 | |
| 		    $vlanids{$id}=1;
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     
 | |
|     for (my $index=2; $index<255; $index++) {
 | |
| 	if (! exists($vlanids{$index})) { return $index; }
 | |
|     }
 | |
| 
 | |
|     my $rsp={};
 | |
|     $rsp->{data}->[0]= "No valid vlan ID can be used any more, Please remove unused vlans.\n";
 | |
|     $callback->($rsp);
 | |
|     
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  verify_switch_ports
 | |
| 
 | |
|   It checks if the switch ports to be configured are used by other vlans.
 | |
| 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub verify_switch_ports {
 | |
|     my $vlan_id=shift;
 | |
|     my $swinfo=shift;
 | |
|     my $callback=shift;
 | |
| 
 | |
|     my $ret=1;
 | |
|     foreach my $switch (keys %$swinfo) {
 | |
| 	my $porthash=$swinfo->{$switch};
 | |
| 	my $swh;
 | |
| 	if (exists($Switches{$switch})) { $swh=$Switches{$switch};}
 | |
| 	else {
 | |
| 	    $swh=new xCAT::SwitchHandler->new($switch);
 | |
| 	    $Switches{$switch}=$swh;
 | |
| 	}
 | |
|  	my $port_vlan_hash=$swh->get_vlanids_for_ports(keys(%$porthash));
 | |
| 	print "port_vlan_hash=" . Dumper($port_vlan_hash) . "\n";
 | |
| 	my @error_ports=();
 | |
| 	foreach my $port (keys(%$port_vlan_hash)) {
 | |
| 	    my $val=$port_vlan_hash->{$port};
 | |
| 	    foreach my $tmp_vid (@$val) {
 | |
| 		if (($tmp_vid != $vlan_id) && ($tmp_vid != 1) && ($tmp_vid ne 'NA')) {
 | |
|         if (exists($porthash->{$port}->{vmhost})) { next; } #skip the vmhost, vmhost can have more than one vlans
 | |
| 		    push(@error_ports, $port);
 | |
| 		    last;
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| 	if (@error_ports >0) {
 | |
| 	    $ret=0;
 | |
| 	    my $error_str;
 | |
| 	    foreach(@error_ports) {
 | |
| 		my @tmp=@{$porthash->{$_}->{nodes}};
 | |
| 		my $ids_tmp=$port_vlan_hash->{$_};
 | |
| 		$error_str .= "$_: vlan-ids=@$ids_tmp  nodes=@tmp\n";
 | |
| 	    }
 | |
| 	    my $rsp={};
 | |
| 	    $rsp->{error}->[0]= "The following ports on switch $switch are used by other vlans.\n$error_str";
 | |
| 	    $callback->($rsp);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     return $ret;
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  create_vlan
 | |
| 
 | |
|   It goes to the switches and create a new vlan. 
 | |
|   Returns:  1 -- suggessful
 | |
|             0 -- fail 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub create_vlan {
 | |
|     my $vlan_id=shift;
 | |
|     my $swinfo=shift;
 | |
|     my $callback=shift;
 | |
|     my $ret=1;
 | |
|     foreach my $switch (keys %$swinfo) {
 | |
| 	my $swh;
 | |
| 	if (exists($Switches{$switch})) { $swh=$Switches{$switch};}
 | |
| 	else {
 | |
| 	    $swh=new xCAT::SwitchHandler->new($switch);
 | |
| 	    $Switches{$switch}=$swh;
 | |
| 	}
 | |
| 	#check if the vlan already exists on the switch
 | |
| 	my @ids=$swh->get_vlan_ids(); 
 | |
|         my $vlan_exists=0;
 | |
| 	foreach my $id (@ids) {
 | |
| 	    if ($id == $vlan_id) { 
 | |
| 		$vlan_exists=1;
 | |
| 		last;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
| 	if (!$vlan_exists) {
 | |
| 	    #create the vlan
 | |
|             print "create vlan $vlan_id on switch $switch\n";
 | |
| 	    my @ret=$swh->create_vlan($vlan_id);
 | |
| 	    if ($ret[0] != 0) {
 | |
| 		my $rsp={};
 | |
| 		$rsp->{error}->[0]= "create_vlan: $ret[1]";
 | |
| 		$callback->($rsp);
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  add_ports
 | |
| 
 | |
|   It adds the ports to the vlan.
 | |
|   Returns:  1 -- suggessful
 | |
|             0 -- fail 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub add_ports {
 | |
|     my $vlan_id=shift;
 | |
|     my $swinfo=shift;
 | |
|     my $callback=shift;
 | |
|     my $portmode=shift;
 | |
|     my $ret=1;
 | |
|     foreach my $switch (keys %$swinfo) {
 | |
| 	my $porthash=$swinfo->{$switch};
 | |
| 	my $swh;
 | |
| 	if (exists($Switches{$switch})) { $swh=$Switches{$switch};}
 | |
| 	else {
 | |
| 	    $swh=new xCAT::SwitchHandler->new($switch);
 | |
| 	    $Switches{$switch}=$swh;
 | |
| 	}
 | |
| 
 | |
|  	my @ret=$swh->add_ports_to_vlan($vlan_id, $portmode, keys(%$porthash));
 | |
| 	if ($ret[0] != 0) {
 | |
| 	    my $rsp={};
 | |
| 	    $rsp->{error}->[0]= "add_ports_to_vlan: $ret[1]";
 | |
| 	    $callback->($rsp);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  add_crossover_ports
 | |
| 
 | |
|   It enables the vlan on the cross-over links.
 | |
|   Returns:  1 -- suggessful
 | |
|             0 -- fail 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub add_crossover_ports {
 | |
|     my $vlan_id=shift;
 | |
|     my $psws=shift;
 | |
|     my $callback=shift;    
 | |
| 
 | |
|     #now make sure the links between the switches allows this vlan to go through
 | |
|     my @sws=@$psws;
 | |
|     print "sws=@sws\n";
 | |
|     if (@sws > 1) {
 | |
| 	foreach my $switch (@sws) {
 | |
| 	    my $swh;
 | |
| 	    if (exists($Switches{$switch})) { $swh=$Switches{$switch};}
 | |
| 	    else {
 | |
| 		$swh=new xCAT::SwitchHandler->new($switch);
 | |
| 		$Switches{$switch}=$swh;
 | |
| 	    }
 | |
| 
 | |
| 	    my @sws_b=grep(!/^$switch$/, @sws);
 | |
| 	    my @ret=$swh->add_crossover_ports_to_vlan($vlan_id, @sws_b);
 | |
| 	    if ($ret[0] != 0) {
 | |
| 		my $rsp={};
 | |
| 		$rsp->{error}->[0]= "add_crossover_ports: $ret[1]";
 | |
| 		$callback->($rsp);
 | |
| 	    } else {
 | |
| 		if ($ret[1]) {
 | |
| 		    my $rsp={};
 | |
| 		    $rsp->{data}->[0]= "add_crossover_ports: $ret[1]";
 | |
| 		    $callback->($rsp);
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  remove_ports
 | |
| 
 | |
|   It goes to the switches and create a new vlan.
 | |
|   Returns:  1 -- suggessful
 | |
|             0 -- fail 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub remove_ports {
 | |
|     my $vlan_id=shift;
 | |
|     my $swinfo=shift;
 | |
|     my $callback=shift;
 | |
|     my $novmhost=shift;
 | |
|     my $ret=1;
 | |
|     foreach my $switch (keys %$swinfo) {
 | |
| 	my $porthash=$swinfo->{$switch};
 | |
| 	my $swh;
 | |
| 	if (exists($Switches{$switch})) { $swh=$Switches{$switch};}
 | |
| 	else {
 | |
| 	    $swh=new xCAT::SwitchHandler->new($switch);
 | |
| 	    $Switches{$switch}=$swh;
 | |
| 	}
 | |
| 
 | |
| 	my @ports=();
 | |
| 	if ($novmhost) {  #skip the vm hosts for chvlan
 | |
| 	    foreach my $port (keys(%$porthash)) {
 | |
| 		if (!exists($porthash->{$port}->{vmhost})) {
 | |
| 		    push(@ports, $port);
 | |
| 		}
 | |
| 	    } 
 | |
| 	}else {
 | |
| 	    @ports=keys(%$porthash);
 | |
| 	}
 | |
|  	my @ret=$swh->remove_ports_from_vlan($vlan_id, @ports);
 | |
| 	if ($ret[0] != 0) {
 | |
| 	    my $rsp={};
 | |
| 	    $rsp->{error}->[0]= "remove_ports_from_vlan: $ret[1]";
 | |
| 	    $callback->($rsp);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3   get_subnet
 | |
| 
 | |
|   It gets the subnet address and netmask for the given 
 | |
|   vlan ID. The pattern is defined by "vlannets" and "vlanmask"
 | |
|   on the site table.  The default is "10.<$vlanid>.0.0"/"255.255.0.0". 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub get_subnet {
 | |
|     my $vlan_id=shift;
 | |
|     my $callback = shift;
 | |
|     my $net;
 | |
|     my $mask;
 | |
| 
 | |
|     #get vlannets and vlanidmask from the site table 
 | |
|     my $vlannets="|(\\d+)|10.(\$1+0).0.0|";
 | |
|     my $vlanmask="255.255.0.0";
 | |
|     my $sitetab = xCAT::Table->new('site');
 | |
|     my $sent = $sitetab->getAttribs({key=>'vlannets'},'value');
 | |
|     if ($sent and ($sent->{value})) {
 | |
| 	$vlannets=$sent->{value};
 | |
|     } 
 | |
|     $sent = $sitetab->getAttribs({key=>'vlanmask'},'value');
 | |
|     if ($sent and ($sent->{value})) {
 | |
| 	$vlanmask=$sent->{value};
 | |
|     } 
 | |
|     $mask = $vlanmask;
 | |
| 
 | |
|     if ($vlannets =~ /^\/[^\/]*\/[^\/]*\/$/)
 | |
|     {
 | |
| 	my $exp = substr($vlannets, 1);
 | |
| 	chop $exp;
 | |
| 	my @parts = split('/', $exp, 2);
 | |
| 	$net=$vlan_id;
 | |
| 	$net =~ s/$parts[0]/$parts[1]/;
 | |
|     }
 | |
|     elsif ($vlannets =~ /^\|.*\|.*\|$/)
 | |
|     {
 | |
| 	
 | |
| 	my $exp = substr($vlannets, 1);
 | |
| 	chop $exp;
 | |
| 	my @parts = split('\|', $exp, 2);
 | |
| 	my $curr;
 | |
| 	my $next;
 | |
| 	my $prev;
 | |
| 	my $retval = $parts[1];
 | |
| 	($curr, $next, $prev) =
 | |
| 	    extract_bracketed($retval, '()', qr/[^()]*/);
 | |
| 	
 | |
| 	unless($curr) { #If there were no paramaters to save, treat this one like a plain regex
 | |
| 	    undef $@; #extract_bracketed would have set $@ if it didn't return, undef $@
 | |
| 	    $retval = $vlan_id;
 | |
| 	    $retval =~ s/$parts[0]/$parts[1]/;
 | |
| 	}
 | |
| 	while ($curr)
 | |
| 	{
 | |
| 	    my $value = $vlan_id;
 | |
| 	    $value =~ s/$parts[0]/$curr/;
 | |
| 	    $value = $evalcpt->reval('use integer;'.$value);
 | |
| 	    $retval = $prev . $value . $next;
 | |
| 	    ($curr, $next, $prev) =
 | |
| 		extract_bracketed($retval, '()', qr/[^()]*/);
 | |
| 	}
 | |
| 	undef $@;
 | |
| 	$net = $vlan_id;
 | |
| 	$net =~ s/$parts[0]/$retval/;
 | |
|     }
 | |
|     return ($net, $mask);
 | |
| }
 | |
| 
 | |
| 
 | |
| # process_chvlanports only support physical nodes
 | |
| # bond not supported and multi nics are not supported
 | |
| sub process_chvlanports {
 | |
|     my $request  = shift;
 | |
|     my $callback = shift;
 | |
|     my $sub_req  = shift;
 | |
| 	
 | |
| 	my $vlan_id=0;
 | |
|     my $nic = "";
 | |
|     my @nodes=();
 | |
|     my $delete=0;
 | |
|     
 | |
|     # validate vlan id value.
 | |
|     $vlan_id=$request->{vlanid}->[0];
 | |
|     #debug message.
 | |
|     xCAT::MsgUtils->message('S',"vlanid: $vlan_id");
 | |
|     if ($vlan_id <= 0) {
 | |
|         my $rsp={};
 | |
|         $rsp->{error}->[0]= "Invalid vlan id: $vlan_id";
 | |
|         $callback->($rsp);
 | |
|         return;
 | |
|     }
 | |
|     #Check if the vlan is defined in networks table.
 | |
|     my $net="";
 | |
|     my $netmask="";
 | |
|     my $nwtab=xCAT::Table->new("networks", -create =>1);
 | |
|     if ($nwtab) {
 | |
|         my @nwentires=$nwtab->getAllAttribs(('vlanid', 'net', 'mask'));
 | |
|         foreach(@nwentires) {
 | |
|             if ($vlan_id eq $_->{vlanid}) {
 | |
|                 $net=$_->{net};
 | |
|                 $netmask=$_->{mask};
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if ((!$net) || (!$netmask)) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = "Can not find valid network/netmask definition from table networks for vlan $vlan_id.";
 | |
|         $callback->($rsp);
 | |
|         return 1;
 | |
|     }
 | |
| 	
 | |
|     $nic=$request->{nic}->[0];
 | |
|     #debug message.
 | |
|     xCAT::MsgUtils->message('S',"nic is: $nic");
 | |
| 
 | |
|     @nodes=@{$request->{node}};
 | |
|     #debug message.
 | |
|     my $nodesstr = Dumper(@nodes);
 | |
|     xCAT::MsgUtils->message('S',"nodes are: $nodesstr");
 | |
| 
 | |
|     $delete=$request->{delete}->[0];
 | |
|     #debug message.
 | |
|     xCAT::MsgUtils->message('S',"delete flag: $delete");
 | |
| 	
 | |
| 
 | |
| 	####now get the switch ports for the nodes
 | |
|     my %swinfo=();  # example: %swinfo=( switch1=>{ 23=>{ nodes: [node1]},
 | |
|                          #                          24=>{ nodes: [node2]},
 | |
|                          #                         },
 | |
|                          #               switch12=>{ 3=>{ nodes: [node4],
 | |
|                          #                         }
 | |
|                          #             )
 | |
|     my %nodeswinfo=(); # example: %nodeswinfo=(
 | |
|                          #               node1=>{eth0=>{switch => swith1,
 | |
|                          #                              port => 1,
 | |
|                          #                              vlanids => [2,3]},
 | |
|                          #                       eth1=>{switch => switch1,
 | |
|                          #                              port => 2,
 | |
|                          #                              vlanids => [5]}}
 | |
|                          #                   )
 | |
|     my %swsetup=();
 | |
| 
 | |
|     #get the switch and port numbers for each node
 | |
|     my $swtab=xCAT::Table->new("switch", -create =>1);
 | |
|     my $swtmphash = $swtab->getNodesAttribs(\@nodes, ['switch', 'port', 'vlan', 'interface']);
 | |
|     foreach my $node (keys (%$swtmphash)) {
 | |
|         my $node_enties=$swtmphash->{$node}; 
 | |
|         foreach my $ent (@$node_enties) {
 | |
|             if (ref($ent) and defined $ent->{switch} and defined $ent->{port}){ 
 | |
|                 my $switch = $ent->{switch};
 | |
|                 my $port = $ent->{port};
 | |
|                 my $interface = "";
 | |
|                 if( defined $ent->{interface} ){ $interface = $ent->{interface}};
 | |
|                 my $vlan = "";
 | |
|                 if( defined $ent->{vlan}) {$vlan = $ent->{vlan}};
 | |
|                 
 | |
|                 if ($interface){
 | |
|                     $nodeswinfo{$node}->{$interface}->{switch}=$switch;
 | |
|                     $nodeswinfo{$node}->{$interface}->{port}=$port;
 | |
|                     $nodeswinfo{$node}->{$interface}->{vlan} = $vlan;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     #debug message.
 | |
|     my $nodesinfostr = Dumper(%nodeswinfo);
 | |
|     xCAT::MsgUtils->message('S',"nodeswinfo: $nodesinfostr");
 | |
| 
 | |
|     # Validate node's switch info %nodeswinfo and build up %swinfo, %swsetup.
 | |
|     my @missed_switch_nodes = ();
 | |
|     my @missed_vlanid_nodes = ();
 | |
|     foreach my $node (@nodes){
 | |
|         # Check whether the switch, port and interface info defined for all nodes.
 | |
|         if(defined $nodeswinfo{$node} && defined $nodeswinfo{$node}->{$nic}){
 | |
|         } else{
 | |
|             push(@missed_switch_nodes, $node);
 | |
|             next;
 | |
|         }
 | |
|     
 | |
|         if ($delete){
 | |
|             # For delete mode, must make sure all node's has such a vlan ID defined for the interface.
 | |
|             my @vlanids = split(",",$nodeswinfo{$node}->{$nic}->{vlan});
 | |
|             if (@vlanids && (grep /^$vlan_id$/, @vlanids)){
 | |
|                 my $switch = $nodeswinfo{$node}->{$nic}->{switch};
 | |
|                 my $port = $nodeswinfo{$node}->{$nic}->{port};
 | |
| 
 | |
|                 #setup swinfo and swsetup .
 | |
|                 $swinfo{$switch}->{$port}->{hosts} = [$node];
 | |
|                 $swsetup{$node}->{switch} = $switch;
 | |
|                 $swsetup{$node}->{port} = $port;
 | |
|                 $swsetup{$node}->{vlan} = $nodeswinfo{$node}->{$nic}->{vlan};
 | |
|             }else{
 | |
|                 push(@missed_vlanid_nodes, $node);
 | |
|                 next;
 | |
|             }
 | |
|         } else{
 | |
|             # non-delete mode, just setup swinfo directly.
 | |
|             my $switch = $nodeswinfo{$node}->{$nic}->{switch};
 | |
|             my $port = $nodeswinfo{$node}->{$nic}->{port};
 | |
| 
 | |
|             #setup swinfo and swsetup for add_ports, add_crossover_ports and add_vlan_to_switch_table call later.
 | |
|             $swinfo{$switch}->{$port}->{hosts} = [$node];
 | |
|             $swsetup{$node}->{switch} = $switch;
 | |
|             $swsetup{$node}->{port} = $port;
 | |
|             $swsetup{$node}->{vlan} = $nodeswinfo{$node}->{$nic}->{vlan};
 | |
|         }
 | |
|     }
 | |
|     if (@missed_switch_nodes > 0) {
 | |
|         my $rsp={};
 | |
|         $rsp->{error}->[0]= "Cannot proceed, please define switch, port and interface info on the switch table for the following nodes:\n  @missed_switch_nodes\n";
 | |
|         $callback->($rsp);
 | |
|         return 1;
 | |
|     }
 | |
|     if (@missed_vlanid_nodes > 0) {
 | |
|         my $rsp={};
 | |
|         $rsp->{error}->[0]= "Cannot proceed, no such vlan ID $vlan_id defined for following nodes:\n @missed_vlanid_nodes\n";
 | |
|         $callback->($rsp);
 | |
|         return 1;
 | |
|     }
 | |
|     #debug message.
 | |
|     my $swinfostr = Dumper(%swinfo);
 | |
|     xCAT::MsgUtils->message('S',"swinfo: $swinfostr");
 | |
|     my $swsetupstr = Dumper(%swsetup);
 | |
|     xCAT::MsgUtils->message('S',"swsetup: $swsetupstr");
 | |
|     
 | |
|     # Do actual configurations on switches
 | |
|     if (!$delete) {
 | |
|         ### add ports to the vlan
 | |
|         if (!add_ports($vlan_id, \%swinfo, $callback, 1)) { return 1;}
 | |
|         xCAT::MsgUtils->message('S',"Adding ports to switch success!");
 | |
| 
 | |
|         ### add the cross-over ports to the vlan
 | |
|         my @sws=keys(%swinfo);;
 | |
|         #get all the switches  that are in the vlan
 | |
|         my $swtab=xCAT::Table->new("switch", -create =>0);
 | |
|         if ($swtab) {
 | |
|             my @tmp1=$swtab->getAllAttribs('switch', 'vlan');
 | |
|             if ((@tmp1) && (@tmp1 > 0)) {
 | |
|                 foreach my $item (@tmp1) {
 | |
|                     my $vlan=$item->{vlan};
 | |
|                     my $sw=$item->{switch};
 | |
|                     if ($vlan) {
 | |
|                         my @a=split(",",$vlan);
 | |
|                         if (grep(/^$vlan_id$/, @a)) {
 | |
|                             if (!grep(/^$sw$/, @sws)) {
 | |
|                                 push(@sws, $sw);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if (!add_crossover_ports($vlan_id, \@sws, $callback)) { return 1;}
 | |
|         xCAT::MsgUtils->message('S',"Configuring cross over ports success!");
 | |
| 	
 | |
|         #add the vlanid for the standalone nodes on the switch table
 | |
|         #append the vlan id for the vmhosts on the switch table
 | |
|         add_vlan_to_switch_table(\%swsetup, $vlan_id); 
 | |
|         xCAT::MsgUtils->message('S',"Adding vlan to switch table success!");
 | |
|         
 | |
|         # done
 | |
|         my $rsp={};
 | |
|         $rsp->{data}->[0]= "The interface $nic of following nodes are added to the vlan $vlan_id:\n@nodes";
 | |
|         $callback->($rsp);
 | |
|         
 | |
|     } else{
 | |
|         ### remove ports from the vlan
 | |
|         my $novmhost=1;
 | |
|         if (!remove_ports($vlan_id, \%swinfo, $callback, $novmhost)) { return 1;}
 | |
|         xCAT::MsgUtils->message('S',"Removing ports from vlan success!");
 | |
|  
 | |
|         #remove the vlan id from the switch table.
 | |
|         remove_vlan_from_switch_table(\%swsetup,$vlan_id);
 | |
|         xCAT::MsgUtils->message('S',"Removing ports from switch table success!");
 | |
|         
 | |
|         # done
 | |
|         my $rsp={};
 | |
|         $rsp->{data}->[0]= "The interface $nic of following nodes are removed from the vlan $vlan_id:\n@nodes";
 | |
|         $callback->($rsp);
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| sub process_chvlan {
 | |
|     my $request  = shift;
 | |
|     my $callback = shift;
 | |
|     my $sub_req  = shift;
 | |
| 
 | |
|     my $vlan_id=0;
 | |
|     if (exists($request->{vlanid})) {
 | |
|         $vlan_id=$request->{vlanid}->[0];
 | |
|     }
 | |
|     if ($vlan_id == 0) {
 | |
|         my $rsp={};
 | |
|         $rsp->{error}->[0]= "Invalid vlan id: $vlan_id";
 | |
|         $callback->($rsp);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     my $nic;
 | |
|     if (exists($request->{nic})) {
 | |
|         $nic=$request->{nic}->[0];
 | |
|     } 
 | |
| 
 | |
|     my @nodes=();
 | |
|     if (exists($request->{node})) {
 | |
|         @nodes=@{$request->{node}};
 | |
|     }
 | |
| 
 | |
|     my $delete=0;
 | |
|     if (exists($request->{delete})) {
 | |
|         $delete=$request->{delete}->[0];
 | |
|     }
 | |
|     my $net;
 | |
|     my $netmask;
 | |
|     #check if the vlan is already defined on the table 
 | |
|     my $found=0;
 | |
|     my $nwtab=xCAT::Table->new("networks", -create =>1);
 | |
|     if ($vlan_id > 0) {
 | |
|         if ($nwtab) {
 | |
|             my @tmp1=$nwtab->getAllAttribs(('vlanid', 'net', 'mask'));
 | |
|             if ((@tmp1) && (@tmp1 > 0)) {
 | |
|                 foreach(@tmp1) {
 | |
|                     if ($vlan_id eq $_->{vlanid}) {
 | |
|                         $found=1;
 | |
|                         $net=$_->{net};
 | |
|                         $netmask=$_->{mask};
 | |
|                     }
 | |
|                 }
 | |
| 	        }
 | |
|         }
 | |
|     }
 | |
|     if (!$found) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = "The vlan $vlan_id does not exist.";
 | |
|         $callback->($rsp);
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if ((!$net) || (!$netmask)) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = "Please make sure subnet and netmask are specified on the networks table for vlan $vlan_id.";
 | |
|         $callback->($rsp);
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     ####now get the switch ports for the nodes
 | |
|     my %swinfo=();  # example: %swinfo=( switch1=>{ 23=>{ nodes: [node1]},
 | |
|                          #                          24=>{ nodes: [node2,node3], 
 | |
|                          #                                        vmhost: kvm1
 | |
|                          #                              }
 | |
|                          #                         },
 | |
|                          #               switch12=>{ 3=>{ nodes: [node4]},
 | |
|                          #                           7=>{ nodes: [node5]}, 
 | |
|                          #                           9=>{ nodes: [node6]}
 | |
|                          #                        }
 | |
|                          #             )
 | |
| 
 | |
|     my %vminfo=();       # example: %vminfo=( kvm1=>{clients:[node1,node2...]},
 | |
|                          #                    kvm2=>{clients:[node2,node3...]},
 | |
|                          #                   )
 | |
|                          #                  
 | |
|     my @vmnodes=();      # vm clients
 | |
|     my @snodes=();       # stand alone nodes
 | |
| 
 | |
|     
 | |
|     #get the vm hosts  
 | |
|     my $vmtab=xCAT::Table->new("vm", -create =>1);
 | |
|     my $vmtmphash = $vmtab->getNodesAttribs(\@nodes, ['host','nics']) ;
 | |
|     foreach(@nodes) {
 | |
|         my $node=$_;
 | |
|         my $host;
 | |
|         my $ent=$vmtmphash->{$node}->[0];
 | |
|         if (ref($ent) and defined $ent->{host}) { 
 | |
|             $host = $ent->{host}; 
 | |
|             if (exists($vminfo{$host})) {
 | |
|                 my $pa=$vminfo{$host}->{clients};
 | |
|                 push(@$pa, $node);
 | |
|             } else {
 | |
|                 $vminfo{$host}->{clients}=[$node];
 | |
|             }
 | |
| 	        push(@vmnodes, $node);
 | |
| 	    }
 | |
|     }
 | |
|    
 | |
|     if (@vmnodes > 0) {
 | |
|         foreach my $node (@nodes) {
 | |
|             if (! grep /^$node$/, @vmnodes) {
 | |
|                 push(@snodes, $node);
 | |
|             }
 | |
|         }
 | |
|     } else {
 | |
|         @snodes=@nodes;
 | |
|     }
 | |
|  
 | |
|     #get the switch and port numbers for each node
 | |
|     my @vmhosts=keys(%vminfo);
 | |
|     my @anodes=(@snodes, @vmhosts); #nodes that connects to the switch
 | |
|     my %swsetup=();
 | |
|     my $swtab=xCAT::Table->new("switch", -create =>1);
 | |
|     my $swtmphash = $swtab->getNodesAttribs(\@anodes, ['switch', 'port', 'vlan', 'interface']) ;
 | |
|     my @missed_nodes=();
 | |
|     foreach my $node (@anodes) {
 | |
|         my $switch;
 | |
|         my $port;
 | |
|         my $node_enties=$swtmphash->{$node}; 
 | |
|         if ($node_enties) {
 | |
|             my $i=-1;
 | |
|             my $use_this=0;
 | |
|             foreach my $ent (@$node_enties) {
 | |
|                 $i++;
 | |
|                 if (ref($ent) and defined $ent->{switch} and defined $ent->{port}) { 
 | |
|                     $switch = $ent->{switch};
 | |
|                     $port = $ent->{port};
 | |
|                     my $interface="primary";		    
 | |
|                     if (defined $ent->{interface}) { $interface=$ent->{interface};}
 | |
|                     # for primary nic, the interface can be empty, "primary" or "primary:eth0"		   
 | |
|                     if ($delete) {
 | |
|                         if (defined($ent->{vlan})) {
 | |
|                             my @a=split(',', $ent->{vlan});
 | |
|                             if (grep(/^$vlan_id$/, @a)) {  $use_this=1; }
 | |
|                         }			
 | |
|                     } else {
 | |
|                         if ($nic) {
 | |
|                             if ($interface =~ /primary/) {
 | |
|                                 $interface =~ s/primary(:)?//g;
 | |
|                             }
 | |
|                             if ($interface && ($interface eq $nic)) { $use_this=1; }
 | |
|                         } else {
 | |
|                             if ($interface =~ /primary/) {  $use_this=1; }
 | |
|                         } 
 | |
|                     }
 | |
| 		    
 | |
|                     if (! $use_this) { 
 | |
|                         next; 
 | |
|                     } else { 
 | |
|                         $swsetup{$node}->{port}=$port;
 | |
|                         $swsetup{$node}->{switch}=$switch;
 | |
|                         if (defined $ent->{vlan}) { 
 | |
|                             $swsetup{$node}->{vlan}=$ent->{vlan};
 | |
|                         } else {
 | |
|                             $swsetup{$node}->{vlan}="";
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     if ($interface) { 			
 | |
|                         $swinfo{$switch}->{$port}->{interface}=$interface;
 | |
|                     }
 | |
| 		    
 | |
|                     if (exists($vminfo{$node})) {
 | |
|                         $swinfo{$switch}->{$port}->{vmhost}=$node;
 | |
|                         $swinfo{$switch}->{$port}->{nodes}=$vminfo{$node}->{clients};
 | |
|                     } else {
 | |
|                         $swinfo{$switch}->{$port}->{nodes}=[$node];
 | |
|                     }
 | |
|                     last;
 | |
|                 } 
 | |
|             }
 | |
|             if ( $use_this != 1 ) {
 | |
|                 push (@missed_nodes, $node);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (@missed_nodes > 0) {
 | |
|         my $rsp={};
 | |
|         $rsp->{error}->[0]= "Cannot proceed, please define switch and port info on the switch table for the following nodes:\n  @missed_nodes\n";
 | |
|         $callback->($rsp);
 | |
|         return 1;
 | |
|     }
 | |
|     
 | |
|     #print "vminfo=" . Dumper(%vminfo) . "\n";
 | |
|     #print "swinfo=" . Dumper(%swinfo) . "\n";
 | |
|     #print "anodes=" . Dumper(@anodes) . "\n";
 | |
|     #print "vmnodes=" . Dumper(@vmnodes) . "\n";
 | |
| 
 | |
|     if (!$delete) {
 | |
|         ### verify the ports are not used by other vlans
 | |
|         #if (!verify_switch_ports($vlan_id, \%swinfo, $callback)) { return 1;}
 | |
| 	
 | |
|         ###create the vlan if it does not exist 
 | |
|          if (!create_vlan($vlan_id, \%swinfo, $callback)) { return 1;}
 | |
| 
 | |
|         ### add ports to the vlan
 | |
|         if (!add_ports($vlan_id, \%swinfo, $callback)) { return 1;}
 | |
| 
 | |
|         ### add the cross-over ports to the vlan
 | |
|         my @sws=keys(%swinfo);;
 | |
|         #get all the switches  that are in the vlan
 | |
|         my $swtab=xCAT::Table->new("switch", -create =>0);
 | |
|         if ($swtab) {
 | |
|             my @tmp1=$swtab->getAllAttribs('switch', 'vlan');
 | |
|             if ((@tmp1) && (@tmp1 > 0)) {
 | |
|                 foreach my $item (@tmp1) {
 | |
|                     my $vlan=$item->{vlan};
 | |
|                     my $sw=$item->{switch};
 | |
|                     if ($vlan) {
 | |
|                         my @a=split(",",$vlan);
 | |
|                         if (grep(/^$vlan_id$/, @a)) {
 | |
|                             if (!grep(/^$sw$/, @sws)) {
 | |
|                                 push(@sws, $sw);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if (!add_crossover_ports($vlan_id, \@sws, $callback)) { return 1;}
 | |
| 	
 | |
|         #add the vlanid for the standalone nodes on the switch table
 | |
|         #append the vlan id for the vmhosts on the switch table
 | |
|         add_vlan_to_switch_table(\%swsetup, $vlan_id);   
 | |
| 	
 | |
|         #we'll derive the prefix and the node numbers from the existing
 | |
|         #nodes on the vlan
 | |
|         my ($prefix, $start_number)=get_prefix_and_nodenumber($vlan_id, $net, $netmask);
 | |
|  
 | |
|         ### get node ip and vlan hostname from the hosts table. 
 | |
|         #If it is not defined, put the default into the host table
 | |
|         my @allnodes=(@anodes, @vmnodes);
 | |
|         if (!add_vlan_ip_host($net, $netmask, $prefix, $start_number+1, \@allnodes, $callback)) { return 1;}
 | |
| 
 | |
|         ### for vm nodes, add an additional nic on the vm.nics
 | |
|         if (@vmnodes > 0) {
 | |
|             my %setupnics=();
 | |
|             my $new_nic="vl$vlan_id";
 | |
|             foreach my $node (@vmnodes) {
 | |
|                 my $ent=$vmtmphash->{$node}->[0];
 | |
|                 my $nics;
 | |
|                 if (ref($ent) and defined $ent->{nics}) { 
 | |
|                     $nics=$ent->{nics};
 | |
|                     my @a=split(",", $nics);
 | |
|                     if (!grep(/^$new_nic$/, @a)) { $nics="$nics,$new_nic"; }
 | |
|                 } else {
 | |
|                     $nics=$new_nic;
 | |
|                 }
 | |
|                 $setupnics{$node}={nics=>"$nics"};
 | |
|             }
 | |
|             $vmtab->setNodesAttribs(\%setupnics);
 | |
|         }
 | |
| 
 | |
|         ### populate the /etc/hosts and make the DNS server on the mn aware this change
 | |
|         $::CALLBACK = $callback;
 | |
|         my $res = xCAT::Utils->runxcmd({
 | |
|                                         command => ['makehosts'],
 | |
|                                        }, $sub_req, 0, 1);
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = "Running makehosts...";
 | |
|         $callback->($rsp);
 | |
|         if ($res && (@$res > 0)) {
 | |
|             $rsp = {};
 | |
|             $rsp->{data} = $res;
 | |
|             $callback->($rsp);
 | |
|         }
 | |
|         $callback->($rsp);
 | |
| 	
 | |
|         $::CALLBACK = $callback;
 | |
|         my $res = xCAT::Utils->runxcmd({
 | |
|                                         command => ['makedns'],
 | |
|                                        }, $sub_req, 0, 1);
 | |
| 	
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = "Running makedns...";
 | |
|         if ($res && (@$res > 0)) {
 | |
|             $callback->($rsp);
 | |
|             $rsp->{data} = $res;
 | |
|             $callback->($rsp);
 | |
|         }
 | |
| 	
 | |
|         my $cmd = "service named restart";
 | |
|         my $rc=system $cmd;
 | |
| 	
 | |
|         ### now go to the nodes to configure the vlan interface
 | |
|         $::CALLBACK = $callback;
 | |
|         my $args = ["-P", "configvlan $vlan_id --keephostname"]; 
 | |
|         my $res = xCAT::Utils->runxcmd( {
 | |
|                                           command => ['updatenode'],
 | |
|                                           node    => \@snodes,
 | |
|                                           arg     => $args
 | |
|                                         }, $sub_req, 0, 1);
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = "Running updatenode...";
 | |
|         if ($res && (@$res > 0)) {
 | |
|             $callback->($rsp);
 | |
|             $rsp->{data} = $res;
 | |
|             $callback->($rsp);
 | |
|         }
 | |
| 	
 | |
|         ### add configvlan postscripts to the postscripts table for the node
 | |
|         my @pnodes=(@snodes, @vmnodes);
 | |
|         add_postscript($callback, \@pnodes);
 | |
| 	
 | |
|         # done
 | |
|         my $rsp={};
 | |
|         $rsp->{data}->[0]= "The following nodes are added to the vlan $vlan_id:\n@nodes";
 | |
|         $callback->($rsp);
 | |
|     } else {
 | |
|         ### go to the nodes to de-configure the vlan interface
 | |
|         if (@snodes > 0) {
 | |
|             my $args = ["-P", "deconfigvlan $vlan_id"];
 | |
|             my $res = xCAT::Utils->runxcmd(  {
 | |
|                                               command => ['updatenode'],
 | |
|                                               node    => \@snodes,
 | |
|                                               arg     => $args
 | |
|                                              }, $sub_req, 0, 1);
 | |
|             my $rsp = {};
 | |
|             $rsp->{data}->[0] = "Running updatenode...";
 | |
|             if ($res && (@$res > 0)) {
 | |
|                 $callback->($rsp);
 | |
|                 $rsp->{data} = $res;
 | |
|                 $callback->($rsp);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         ### remove ports from the vlan
 | |
|         my $novmhost=1;
 | |
|         if (!remove_ports($vlan_id, \%swinfo, $callback, $novmhost)) { return 1;}
 | |
|  
 | |
|         #remove the vlan id from the switch table for standalone nodes
 | |
|         #cannot call this function because %swsetup contains vmhosts
 | |
|         #remove_vlan_from_switch_table(\%swsetup,$vlan_id); 
 | |
|         #print "swsetup=". Dumper(%swsetup);
 | |
|         my $swtab1 = xCAT::Table->new('switch', -create=>1, -autocommit=>0 );
 | |
|         foreach my $node (@snodes) {
 | |
|             if (exists($swsetup{$node})) {
 | |
|                 my %keyhash=();
 | |
|                 my %updates=();
 | |
|                 $keyhash{'node'} = $node;
 | |
|                 $keyhash{'switch'}= $swsetup{$node}->{switch};
 | |
|                 $keyhash{'port'} = $swsetup{$node}->{port};
 | |
|                 $updates{'vlan'} = "";
 | |
|                 if($swsetup{$node}->{vlan}) {
 | |
|                     my @a=split(',', $swsetup{$node}->{vlan});
 | |
|                     my @b=grep(!/^$vlan_id$/,@a);
 | |
|                     if (@b>0) {
 | |
|                         $updates{'vlan'}=join(',', @b);
 | |
|                     }
 | |
|                 }
 | |
|                 $swtab1->setAttribs( \%keyhash,\%updates );
 | |
|             }
 | |
|         }
 | |
|         $swtab1->commit;
 | |
| 
 | |
|         #remove the vlan from the vm.nic for vm clients
 | |
|         if (@vmnodes > 0) {
 | |
|             my %setupnics=();
 | |
|             my $new_nic="vl$vlan_id";
 | |
|             foreach my $node (@vmnodes) {
 | |
|                 my $ent=$vmtmphash->{$node}->[0];
 | |
|                 my $nics='';
 | |
|                 if (ref($ent) and defined $ent->{nics}) { 
 | |
|                     $nics=$ent->{nics};
 | |
|                     my @a=split(",", $nics);
 | |
|                     my @b=grep(!/^$new_nic$/, @a);
 | |
|                     if (@b>0) { $nics=join(',', @b); }
 | |
|                 }
 | |
|                 $setupnics{$node}={nics=>"$nics"};
 | |
|             }
 | |
|             $vmtab->setNodesAttribs(\%setupnics);
 | |
|         }
 | |
| 	
 | |
|         #remove the node's vlan hostname and the ip from the host table and /etc/hosts
 | |
|         my @pnodes=(@snodes, @vmnodes);
 | |
|         if (!remove_vlan_ip_host($net, $netmask, \@pnodes, $callback)) { return 1;}
 | |
| 
 | |
|         #refresh the DNS server
 | |
|         my $res = xCAT::Utils->runxcmd(  {
 | |
|                                            command => ['makedns'],
 | |
|                                          }, $sub_req, 0, 1);
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = "Running makedns...";
 | |
|         if ($res && (@$res > 0)) {
 | |
|             $callback->($rsp);
 | |
|             $rsp->{data} = $res;
 | |
|             $callback->($rsp);
 | |
|         }
 | |
|         my $cmd = "service named restart";
 | |
|         my $rc=system $cmd;
 | |
| 	
 | |
|         # remove configvlan postscripts from the postscripts table for the node
 | |
|         remove_postscript($callback, \@pnodes);	
 | |
| 
 | |
|         # done
 | |
|         my $rsp={};
 | |
|         $rsp->{data}->[0]= "The following nodes are removed from the vlan $vlan_id:\n@nodes";
 | |
|         $callback->($rsp);
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| sub process_rmvlan {
 | |
|     my $request  = shift;
 | |
|     my $callback = shift;
 | |
|     my $sub_req  = shift;
 | |
|     
 | |
|     my $vlan_id=0;
 | |
|     if (exists($request->{vlanid})) {
 | |
| 	$vlan_id=$request->{vlanid}->[0];
 | |
|     }
 | |
| 
 | |
|     my @anodes=();
 | |
|     my %swportinfo=();
 | |
|     my %swsetup=();
 | |
|     my $swtab=xCAT::Table->new("switch", -create =>0);
 | |
|     if ($swtab) {
 | |
| 	my @tmp1=$swtab->getAllAttribs(('node', 'switch', 'port', 'vlan'));
 | |
| 	if ((@tmp1) && (@tmp1 > 0)) {
 | |
| 	    foreach my $ent (@tmp1) {
 | |
| 		my @nodes_tmp=noderange($ent->{node});
 | |
| 		foreach my $node (@nodes_tmp) {
 | |
| 		    my $switch=$ent->{switch};
 | |
| 		    my $port=$ent->{port};
 | |
| 		    if ($ent->{vlan}) {
 | |
| 			my @a=split(",", $ent->{vlan});
 | |
| 			if (grep(/^$vlan_id$/,@a)) {
 | |
| 			    push(@anodes, $node);
 | |
| 			    if (exists($swportinfo{$switch})) {
 | |
| 				my $pa=$swportinfo{$switch};
 | |
| 				push(@$pa, $port);
 | |
| 			    } else {
 | |
| 				$swportinfo{$switch}=[$port];
 | |
| 			    }
 | |
| 			    $swsetup{$node}->{port}=$port;
 | |
| 			    $swsetup{$node}->{switch}=$switch;
 | |
| 			    $swsetup{$node}->{vlan}=$ent->{vlan};
 | |
| 			}
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     my $switchestab=xCAT::Table->new('switches',-create=>0);
 | |
|     if ($switchestab) {
 | |
| 	my @tmp1=$switchestab->getAllAttribs(('switch'));
 | |
| 	if ((@tmp1) && (@tmp1 > 0)) {
 | |
| 	    foreach(@tmp1) {
 | |
| 		my @switches_tmp=noderange($_->{switch});
 | |
| 		if (@switches_tmp==0) { push @switches_tmp, $_->{switch}; } #sometimes the switch name is not on the node list table.  
 | |
| 		foreach my $switch (@switches_tmp) {
 | |
| 		    my $ports=[];
 | |
| 		    if (exists($swportinfo{$switch})) {
 | |
| 			$ports = $swportinfo{$switch};
 | |
| 		    }
 | |
| 		    
 | |
| 		    my $swh;
 | |
| 		    if (exists($Switches{$switch})) { $swh=$Switches{$switch};}
 | |
| 		    else {
 | |
| 			$swh=new xCAT::SwitchHandler->new($switch);
 | |
| 			$Switches{$switch}=$swh;
 | |
| 		    }
 | |
| 		
 | |
| 		    print "switch=$switch, ports=@$ports\n";
 | |
| 		    if (@$ports > 0) {
 | |
| 			my @ret=$swh->remove_ports_from_vlan($vlan_id, @$ports);
 | |
| 			if ($ret[0] != 0) {
 | |
| 			    my $rsp={};
 | |
| 			    $rsp->{error}->[0]= "remove_ports_from_vlan: $ret[1]";
 | |
| 			    $callback->($rsp);
 | |
| 			}
 | |
| 		    
 | |
| 			my @ret=$swh->remove_vlan($vlan_id);
 | |
| 			if ($ret[0] != 0) {
 | |
| 			    my $rsp={};
 | |
| 			    $rsp->{error}->[0]= "remove_vlan: $ret[1]";
 | |
| 			    $callback->($rsp);
 | |
| 			}
 | |
| 		    } else { 
 | |
| 			#check if the vlan exists on the switch
 | |
| 			my @ids=$swh->get_vlan_ids(); 
 | |
| 			foreach my $id (@ids) {
 | |
| 			    if ($id == $vlan_id) { 
 | |
| 				#remove it if exists
 | |
| 				my @ret=$swh->remove_vlan($vlan_id);
 | |
| 				if ($ret[0] != 0) {
 | |
| 				    my $rsp={};
 | |
| 				    $rsp->{error}->[0]= "remove_vlan: $ret[1]";
 | |
| 				    $callback->($rsp);
 | |
| 				}
 | |
| 				last; 
 | |
| 			    }
 | |
| 			}
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     ### now go to the nodes to de-configure the vlan interface
 | |
|     my $args = ["-P", "deconfigvlan $vlan_id"];
 | |
|     my $res = xCAT::Utils->runxcmd(  {
 | |
|             command => ['updatenode'],
 | |
| 	    node    => \@anodes,
 | |
| 	    arg     => $args
 | |
|             }, $sub_req, 0, 1);
 | |
|     my $rsp = {};
 | |
|     $rsp->{data}->[0] = "Running updatenode...";
 | |
|     if ($res && (@$res > 0)) {
 | |
| 	$callback->($rsp);
 | |
| 	$rsp->{data} = $res;
 | |
| 	$callback->($rsp);
 | |
|     }
 | |
| 
 | |
|     #remove the vlan from the networks table
 | |
|     my $nwtab=xCAT::Table->new("networks", -create =>1);
 | |
|     my $sent = $nwtab->getAttribs({vlanid=>"$vlan_id"},'net','mask');
 | |
|     my $net;
 | |
|     my $netmask;
 | |
|     if ($sent and ($sent->{net})) {
 | |
| 	$net=$sent->{net};
 | |
| 	$netmask=$sent->{mask};
 | |
|     } 
 | |
|     
 | |
|     my %key_col = (vlanid=>$vlan_id);
 | |
|     $nwtab->delEntries(\%key_col);
 | |
|  
 | |
|     #remove the vlan from the switch table for standalone nodes and vm hosts
 | |
|     remove_vlan_from_switch_table(\%swsetup,$vlan_id);   
 | |
| 
 | |
|     #remove the vlan nic from vm.nics for the vm clients
 | |
|     my @vmnodes=();
 | |
|     my %vmsetup=();
 | |
|     my $vmtab=xCAT::Table->new("vm", -create =>0);
 | |
|     if ($vmtab) {
 | |
| 	my @tmp1=$vmtab->getAllAttribs(('node','host', 'nics'));
 | |
| 	if ((@tmp1) && (@tmp1 > 0)) {
 | |
| 	    foreach(@tmp1) {
 | |
| 		my @nodes_tmp=noderange($_->{node});
 | |
| 		my $nics=$_->{nics};
 | |
| 		my $new_nic="vl$vlan_id";
 | |
| 		if ($nics) {
 | |
| 		    foreach my $node (@nodes_tmp) {
 | |
| 			my @a=split(",", $nics);
 | |
| 			if (grep(/^$new_nic$/,@a)) {
 | |
| 			    push(@vmnodes, $node);
 | |
| 			    my @b=grep(!/^$new_nic$/,@a);
 | |
| 			    if (@b>0) {
 | |
| 				$vmsetup{$node}={nics=>join(',', @b)};
 | |
| 			    } else {
 | |
| 				$vmsetup{$node}={nics=>''};
 | |
| 			    }
 | |
| 			}
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| 	if (keys(%vmsetup) > 0) {
 | |
| 	    $vmtab->setNodesAttribs(\%vmsetup);
 | |
| 	}
 | |
|     }
 | |
|     
 | |
|  
 | |
| 
 | |
|     #remove the node's vlan hostname and the ip from the host table and /etc/hosts
 | |
|     my @allnodes=(@anodes, @vmnodes);
 | |
|     if (!remove_vlan_ip_host($net, $netmask, \@allnodes, $callback)) { return 1;}
 | |
| 
 | |
|     #refresh the DNS server
 | |
|     my $res = xCAT::Utils->runxcmd(  {
 | |
|             command => ['makedns'],
 | |
|             }, $sub_req, 0, 1);
 | |
|     my $rsp = {};
 | |
|     $rsp->{data}->[0] = "Running makedns...";
 | |
|     if ($res && (@$res > 0)) {
 | |
| 	$callback->($rsp);
 | |
| 	$rsp->{data} = $res;
 | |
| 	$callback->($rsp);
 | |
|     }
 | |
|     my $cmd = "service named restart";
 | |
|     my $rc=system $cmd;
 | |
| 
 | |
|     ### remove configvlan postscripts from the postscripts table for the node
 | |
|     #   note: if configvlan is in xcatdefaults, it will not get removed becase 
 | |
|     #   it may affect other vlans
 | |
|     #remove_postscript($callback, \@allnodes);  --- will not remove for multi-vlan support
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  remove_postscript
 | |
| 
 | |
|     It removes configvlan postscripts from the postscripts table for the node
 | |
|     Note: if configvlan is in xcatdefaults, it will not get removed becase 
 | |
|        it may affect other vlans
 | |
| 
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub  remove_postscript {
 | |
|     my $callback=shift;
 | |
|     my $anodes=shift;
 | |
|     my $posttab=xCAT::Table->new("postscripts", -create =>0);
 | |
|     if ($posttab) {
 | |
| 	my %setup_hash;
 | |
| 	my $postcache = $posttab->getNodesAttribs($anodes,[qw(postscripts postbootscripts)]);
 | |
| 	foreach my $node (@$anodes) {
 | |
| 	    my $ref = $postcache->{$node}->[0]; 
 | |
| 	    if ($ref) {
 | |
| 		if (exists($ref->{postbootscripts})) {
 | |
| 		    my $post=$ref->{postbootscripts};
 | |
| 		    my @old_a=split(',', $post);
 | |
| 		    my @new_a = grep (!/^configvlan$/, @old_a);
 | |
| 		    if (scalar(@new_a) != scalar(@old_a)) {
 | |
| 			#print "newa =@new_a\n";
 | |
| 			$setup_hash{$node}={postbootscripts=>join(',', @new_a)};
 | |
| 		    }
 | |
| 		}
 | |
| 		if (exists($ref->{postscripts})) {
 | |
| 		    my $post=$ref->{postscripts};
 | |
| 		    my @old_a=split(',', $post);
 | |
| 		    my @new_a = grep (!/^configvlan$/, @old_a);
 | |
| 		    if (scalar(@new_a) != scalar(@old_a)) {
 | |
| 			$setup_hash{$node}={postscripts=>join(',', @new_a)};
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| 	if (keys(%setup_hash) > 0) {
 | |
| 	    $posttab->setNodesAttribs(\%setup_hash);
 | |
| 	}
 | |
|     }   
 | |
| }
 | |
| 
 | |
| sub process_lsvlan {
 | |
|     my $request  = shift;
 | |
|     my $callback = shift;
 | |
|     my $sub_req  = shift;
 | |
|     
 | |
|     my $vlan_id=0;
 | |
|     if (exists($request->{vlanid})) {
 | |
| 	$vlan_id=$request->{vlanid}->[0];
 | |
|     }
 | |
|    
 | |
|     my %vlans=();
 | |
|     #get all the vm clients if the node is a vm host
 | |
|     my $nwtab=xCAT::Table->new("networks", -create =>0);
 | |
|     if ($nwtab) {
 | |
| 	my @tmp1=$nwtab->getAllAttribs('net', 'mask', 'vlanid');
 | |
| 	if ((@tmp1) && (@tmp1 > 0)) {
 | |
| 	    foreach(@tmp1) {
 | |
| 		if (exists($_->{vlanid})) {
 | |
| 		    $vlans{$_->{vlanid}}->{net}=$_->{net};
 | |
| 	            $vlans{$_->{vlanid}}->{mask}=$_->{mask};
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|    
 | |
|     if($vlan_id !=0 && !exists($vlans{$vlan_id})) {
 | |
| 	my $rsp={};
 | |
|         $rsp->{data}->[0] = "the vlan $vlan_id is not defined for the cluster nodes.";
 | |
|         $rsp->{errorcode} = -1;
 | |
| 	$callback->($rsp);
 | |
|         return;
 | |
|     }
 | |
| 	
 | |
|     if ($vlan_id == 0) { #just show the existing vlan ids
 | |
| 	my $rsp={};
 | |
| 	my $index=0;
 | |
| 	if (keys(%vlans) > 0) {
 | |
| 	    foreach my $id (sort keys(%vlans)) {
 | |
| 		$rsp->{data}->[$index] = "vlan $id:\n    subnet " . $vlans{$id}->{net}. "\n    netmask " . $vlans{$id}->{mask} . "\n";
 | |
| 		$index++;
 | |
| 	    }
 | |
| 	} else {
 | |
| 	    $rsp->{data}->[0] = "No vlans defined for the cluster nodes."
 | |
| 	}
 | |
| 	$callback->($rsp);
 | |
| 
 | |
|     } else { #shows the details
 | |
| 	#get all the nodes that are in the vlan
 | |
| 	my $swtab=xCAT::Table->new("switch", -create =>0);
 | |
| 	my @nodes=();
 | |
| 	if ($swtab) {
 | |
| 	    my @tmp1=$swtab->getAllAttribs('node', 'vlan', 'interface');
 | |
| 	    if ((@tmp1) && (@tmp1 > 0)) {
 | |
| 		foreach my $grp (@tmp1) {
 | |
| 		    my $vlan=$grp->{vlan};
 | |
| 		    my $nic="primary";
 | |
| 		    if ($grp->{interface}) { $nic=$grp->{interface};}
 | |
| 
 | |
| 		    my @nodes_tmp=noderange($grp->{node});
 | |
| 		    if ($vlan) {
 | |
| 			my @a=split(",",$vlan);
 | |
| 			if (grep(/^$vlan_id$/, @a)) {
 | |
| 			    foreach my $node (@nodes_tmp) {
 | |
| 				push(@nodes, $node);
 | |
| 				$vlans{$vlan_id}->{node}->{$node}->{name} = $node;
 | |
| 				$vlans{$vlan_id}->{node}->{$node}->{interface} = $nic;
 | |
| 			    }
 | |
| 			}
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
| 	
 | |
| 	#get all the vm clients if the node is a vm host
 | |
| 	my $vmtab=xCAT::Table->new("vm", -create =>0);
 | |
| 	my @vmnodes=();
 | |
| 	if ($vmtab) {
 | |
| 	    my @tmp1=$vmtab->getAllAttribs('node', 'host', 'nics');
 | |
| 	    if ((@tmp1) && (@tmp1 > 0)) {
 | |
| 		my $new_nic="vl$vlan_id";
 | |
| 		foreach(@tmp1) {
 | |
| 		    my $host = $_->{host};
 | |
| 		    my $nics = $_->{nics};
 | |
| 		    if ($nics) {
 | |
| 			my @a=split(",", $nics);
 | |
| 			if (grep(/^$new_nic$/, @a)) {
 | |
| 			    my @nodes_tmp=noderange($_->{node});
 | |
| 			    foreach my $node (@nodes_tmp) {
 | |
| 				push(@vmnodes, $node);
 | |
| 				$vlans{$vlan_id}->{node}->{$node}->{name} = $node;
 | |
| 				$vlans{$vlan_id}->{node}->{$node}->{vmhost} = $host;
 | |
| 			    }
 | |
| 			}
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| 	
 | |
| 	@nodes=(@nodes, @vmnodes);
 | |
| 	
 | |
| 	#now go to hosts table to get the host name and ip on the vlan
 | |
| 	my $hoststab = xCAT::Table->new('hosts');
 | |
| 	my $hostscache = $hoststab->getNodesAttribs(\@nodes,[qw(node otherinterfaces)]);
 | |
| 	my $max=0;
 | |
| 	my $prefix;
 | |
| 	foreach my $node (@nodes) {
 | |
| 	    my $ref = $hostscache->{$node}->[0]; 
 | |
| 	    my $otherinterfaces;
 | |
| 	    if ($ref && exists($ref->{otherinterfaces})){
 | |
| 		$otherinterfaces = $ref->{otherinterfaces};
 | |
| 		my @itf_pairs=split(/,/, $otherinterfaces);
 | |
| 		my @itf_pairs2=();
 | |
| 		foreach (@itf_pairs) {
 | |
| 		    my ($name,$ip)=split(/:/, $_);
 | |
| 		    if(xCAT::NetworkUtils->ishostinsubnet($ip, $vlans{$vlan_id}->{mask}, $vlans{$vlan_id}->{net})) {
 | |
| 			$vlans{$vlan_id}->{node}->{$node}->{ip}=$ip;
 | |
| 			$vlans{$vlan_id}->{node}->{$node}->{vname}=$name;
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	} #foreach node
 | |
| 
 | |
| 	my $rsp={};
 | |
| 	$rsp->{data}->[0]="vlan $vlan_id";
 | |
|         $rsp->{data}->[1]="    subnet " . $vlans{$vlan_id}->{net};
 | |
|         $rsp->{data}->[2]="    netmask " . $vlans{$vlan_id}->{mask} . "\n";
 | |
| 	my $node_hash=$vlans{$vlan_id}->{node};
 | |
| 	#print Dumper($node_hash);
 | |
| 	if ($node_hash && keys(%$node_hash) > 0) {
 | |
| 	    $rsp->{data}->[3]="    hostname\tip address\tnode    \tvm host \tinterface";
 | |
| 	    my $index=4;
 | |
| 	    foreach (sort keys(%$node_hash)) {
 | |
| 		my $vname=$node_hash->{$_}->{vname};
 | |
| 		if (!$vname) { $vname="      ";}
 | |
| 		my $ip=$node_hash->{$_}->{ip};
 | |
| 		if (!$ip) { $ip="               "; }
 | |
| 		my $name=$node_hash->{$_}->{name};
 | |
| 		if (!$name) { $name="      ";}	   
 | |
| 		my $host=$node_hash->{$_}->{vmhost};
 | |
| 		if (!$host) { $host="        ";}	  
 | |
| 		my $nic=$node_hash->{$_}->{interface};
 | |
| 		$rsp->{data}->[$index] = "    $vname\t$ip\t$name\t$host\t$nic";
 | |
| 		$index++;
 | |
| 	    }
 | |
| 	}
 | |
| 	$callback->($rsp);
 | |
|     } 
 | |
| }
 | |
| 
 | |
| sub mkvlan_usage {
 | |
|     my $cb=shift;
 | |
|     my $rsp={};
 | |
| 
 | |
|     $rsp->{data}->[0]= "Usage: mkvlan -h";
 | |
|     $rsp->{data}->[1]= "       mkvlan -v";
 | |
|     $rsp->{data}->[2]= "       mkvlan [vlanid] -n noderange [-t net -m mask] [-p node_prefix] [-i nic]";
 | |
| 
 | |
|     $cb->($rsp);
 | |
| }
 | |
| 
 | |
| sub rmvlan_usage {
 | |
|     my $cb=shift;
 | |
|     my $rsp={};
 | |
| 
 | |
|     $rsp->{data}->[0]= "Usage: rmvlan -h";
 | |
|     $rsp->{data}->[1]= "       rmvlan -v";
 | |
|     $rsp->{data}->[2]= "       rmvlan vlanid";
 | |
| 
 | |
|     $cb->($rsp);
 | |
| }
 | |
| 
 | |
| sub chvlanports_usage{
 | |
|     my $cb=shift;
 | |
|     my $rsp={};
 | |
| 
 | |
|     $rsp->{data}->[0]= "Usage: chvlanports -h";
 | |
|     $rsp->{data}->[1]= "       chvlanports -v";
 | |
|     $rsp->{data}->[2]= "       chvlanports vlanid -n noderange -i nic";
 | |
|     $rsp->{data}->[3]= "       chvlanports vlanid -n noderange -i nic -d";
 | |
|     $cb->($rsp);
 | |
| }
 | |
| sub chvlan_usage {
 | |
|     my $cb=shift;
 | |
|     my $rsp={};
 | |
| 
 | |
|     $rsp->{data}->[0]= "Usage: chvlan -h";
 | |
|     $rsp->{data}->[1]= "       chvlan -v";
 | |
|     $rsp->{data}->[2]= "       chvlan vlanid -n noderange [-i nic]";
 | |
|     $rsp->{data}->[3]= "       chvlan vlanid -n noderange -d";
 | |
|     $cb->($rsp);
 | |
| }
 | |
| 
 | |
| sub lsvlan_usage {
 | |
|     my $cb=shift;
 | |
|     my $rsp={};
 | |
| 
 | |
|     $rsp->{data}->[0]= "Usage: lsvlan -h";
 | |
|     $rsp->{data}->[1]= "       lsvlan -v";
 | |
|     $rsp->{data}->[2]= "       lsvlan";
 | |
|     $rsp->{data}->[3]= "       lsvlan vlanid";
 | |
| 
 | |
|     $cb->($rsp);
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  getNodeVlanConfData
 | |
|    This function is called by Postage.pm to collect all the 
 | |
|    environmental variables for setting up a vlan for a given 
 | |
|    node.  
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub getNodeVlanConfData {
 | |
|     my $node=shift;
 | |
|     if ($node =~ /xCAT_plugin::vlan/) {
 | |
| 	$node=shift;
 | |
|     }
 | |
| 
 | |
|     my @scriptd=();
 | |
|     my $swtab = xCAT::Table->new("switch", -create => 0);
 | |
|     if ($swtab) {
 | |
| 	my $tmp_switch = $swtab->getNodesAttribs([$node], ['vlan','interface'],prefetchcache=>1);
 | |
|         #print Dumper($tmp_switch);
 | |
| 	if (defined($tmp_switch) && (exists($tmp_switch->{$node})) && (defined($tmp_switch->{$node}->[0]))) { 
 | |
| 	    my $tmp_node_array=$tmp_switch->{$node};
 | |
| 	    my $index=0;
 | |
| 	    foreach my $tmp (@$tmp_node_array) {
 | |
| 		if (exists($tmp->{vlan})) {
 | |
| 		    my $nic="primary";
 | |
| 		    if (exists($tmp->{interface})) { $nic=$tmp->{interface};}
 | |
| 		    my @vlanid_array = split(',', $tmp->{vlan});
 | |
| 		    foreach my $vlan (@vlanid_array) {
 | |
| 			$index++;
 | |
| 			push @scriptd, "VLANID_$index='" . $vlan . "'\n";
 | |
| 			push @scriptd, "export VLANID_$index\n";
 | |
| 			push @scriptd, "VLANNIC_$index='" . $nic . "'\n";
 | |
| 			push @scriptd, "export VLANNIC_$index\n";
 | |
| 			my @temp_data=getNodeVlanOtherConfData($node, $vlan, $index);
 | |
| 			@scriptd = (@scriptd,@temp_data);
 | |
| 		    } 
 | |
| 		}
 | |
| 	    }
 | |
| 	    if ($index > 0) { 
 | |
| 		push @scriptd, "VLANMAXINDEX='" . $index . "'\n";
 | |
| 		push @scriptd, "export VLANMAXINDEX\n";
 | |
| 	    }   
 | |
| 	} else {
 | |
| 	    my $vmtab = xCAT::Table->new("vm", -create => 0);
 | |
| 	    if ($vmtab) {
 | |
| 		my $tmp1 = $vmtab->getNodeAttribs($node, ['nics','host'],prefetchcache=>1);
 | |
| 		
 | |
| 		my $vlan;
 | |
| 		my $index=0;
 | |
| 		if (defined($tmp1) && ($tmp1) && $tmp1->{nics})
 | |
| 		{
 | |
| 		    push @scriptd, "VMNODE='YES'\n";
 | |
| 		    push @scriptd, "export VMNODE\n";
 | |
| 		    push @scriptd, "VMNICS='" . $tmp1->{nics} . "'\n";
 | |
| 		    push @scriptd, "export VMNICS\n";
 | |
| 		    
 | |
| 		    my @nics=split(',', $tmp1->{nics});
 | |
| 
 | |
| 		    #get the vlan id and interface from the host
 | |
| 		    my $host=$tmp1->{host};
 | |
| 		    #my $host_vlan_info=get_vm_host_vlan_info($host);
 | |
|                     my $nic_position=0;
 | |
| 		    foreach my $nic (@nics) {
 | |
| 			$nic_position++;
 | |
| 			if ($nic =~ /^vl([\d]+)$/) {
 | |
| 			    $vlan = $1;
 | |
| 			    $index++;
 | |
| 			    push @scriptd, "VLANID_$index='" . $vlan . "'\n";
 | |
| 			    push @scriptd, "export VLANID_$index\n";
 | |
| 			    push @scriptd, "VLAN_VMNICPOS_$index='" . $nic_position . "'\n";
 | |
| 			    push @scriptd, "export VLAN_VMNICPOS_$index\n";
 | |
| 			    #if ($host_vlan_info && (exists($host_vlan_info->{$vlan}))) {
 | |
| 			    #	push @scriptd, "HOST_VLANNIC_$index='" . $host_vlan_info->{$vlan} . "'\n";
 | |
| 			    #	push @scriptd, "export HOST_VLANNIC_$index\n";
 | |
| 			    #}
 | |
| 			    my @temp_data=getNodeVlanOtherConfData($node, $vlan, $index);
 | |
| 			    @scriptd = (@scriptd,@temp_data); 
 | |
| 			}
 | |
|    		    } #end foreach
 | |
| 		}
 | |
| 		if ($index > 0) { 
 | |
| 		    push @scriptd, "VLANMAXINDEX='" . $index . "'\n";
 | |
| 		    push @scriptd, "export VLANMAXINDEX\n";
 | |
| 		}		
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     
 | |
|     return @scriptd;
 | |
| }
 | |
| 
 | |
| sub getNodeVlanOtherConfData {
 | |
|     my $node=shift;
 | |
|     if ($node =~ /xCAT_plugin::vlan/) {
 | |
| 	$node=shift;
 | |
|     }
 | |
|     my $vlan=shift;
 | |
|     my $index=shift;
 | |
| 
 | |
|     my @scriptd=();
 | |
|     my $nwtab=xCAT::Table->new("networks", -create =>0);
 | |
|     if ($nwtab) {
 | |
| 	my $sent = $nwtab->getAttribs({vlanid=>"$vlan"},'net','mask');
 | |
| 	my $subnet;
 | |
| 	my $netmask;
 | |
| 	if ($sent and ($sent->{net})) {
 | |
| 	    $subnet=$sent->{net};
 | |
| 	    $netmask=$sent->{mask};
 | |
| 	} 
 | |
| 	if (($subnet) && ($netmask)) {
 | |
| 	    my $hoststab = xCAT::Table->new("hosts", -create => 0);
 | |
| 	    if ($hoststab) {
 | |
| 		my $tmp = $hoststab->getNodeAttribs($node, ['otherinterfaces'],prefetchcache=>1);
 | |
| 		if (defined($tmp) && ($tmp) && $tmp->{otherinterfaces})
 | |
| 		{
 | |
| 		    my $otherinterfaces = $tmp->{otherinterfaces};
 | |
| 		    my @itf_pairs=split(/,/, $otherinterfaces);
 | |
| 		    foreach (@itf_pairs) {
 | |
| 			my ($name,$ip)=split(/:/, $_);
 | |
| 			if(xCAT::NetworkUtils->ishostinsubnet($ip, $netmask, $subnet)) {
 | |
| 			    if ($name =~ /^-/ ) {
 | |
| 				$name = $node.$name;
 | |
| 			    }
 | |
| 			    push @scriptd, "VLANHOSTNAME_$index='" . $name . "'\n";
 | |
| 			    push @scriptd, "export VLANHOSTNAME_$index\n";
 | |
| 			    push @scriptd, "VLANIP_$index='" . $ip . "'\n";
 | |
| 			    push @scriptd, "export VLANIP_$index\n";
 | |
| 			    push @scriptd, "VLANSUBNET_$index='" . $subnet . "'\n";
 | |
| 			    push @scriptd, "export VLANSUBNET_$index\n";
 | |
| 			    push @scriptd, "VLANNETMASK_$index='" . $netmask . "'\n";
 | |
| 			    push @scriptd, "export VLANNETMASK_$index\n";
 | |
| 			    last;
 | |
| 			}
 | |
| 		    }	    
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     
 | |
|     return @scriptd;
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| =head3  get_vm_host_vlan_info
 | |
|    This function returns a hash pointer that has the vlan id
 | |
|    and the interface info for the given KVM host. A host can
 | |
|    support more than one vlans for a interface. For example:
 | |
|    {1=>"eth0", 2=>"eth0", 3=>"eth1" ...}
 | |
| =cut
 | |
| #-------------------------------------------------------
 | |
| sub get_vm_host_vlan_info {
 | |
|     my $host=shift;
 | |
|     my $host_vlan_info={};
 | |
|     my $swtab = xCAT::Table->new("switch", -create => 0);
 | |
|     if ($swtab) {
 | |
| 	my $tmp_switch = $swtab->getNodesAttribs([$host], ['vlan','interface'],prefetchcache=>1);
 | |
| 	if (defined($tmp_switch) && (exists($tmp_switch->{$host}))) { 
 | |
| 	    my $tmp_node_array=$tmp_switch->{$host};
 | |
| 	    foreach my $tmp (@$tmp_node_array) {
 | |
| 		if (exists($tmp->{vlan})) {
 | |
| 		    my $vlans = $tmp->{vlan};
 | |
| 		    my $nic="primary";
 | |
| 		    if (exists($tmp->{interface})) {
 | |
| 			$nic=$tmp->{interface};
 | |
| 		    }
 | |
| 		    foreach my $vlan (split(',',$vlans)) {
 | |
| 			$host_vlan_info->{$vlan}=$nic;
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| 	return $host_vlan_info;  
 | |
|     }
 | |
| }
 |