mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-11-04 05:12:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			2834 lines
		
	
	
		
			91 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2834 lines
		
	
	
		
			91 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;
 | 
						|
    }
 | 
						|
}
 |