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