mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-05-29 09:13:08 +00:00
576 lines
15 KiB
Perl
Executable File
576 lines
15 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
use strict;
|
|
use Socket;
|
|
use Data::Dumper;
|
|
use Getopt::Long;
|
|
|
|
# each 0 is four bits: 0000 0000
|
|
# thus its broken down:
|
|
# - ports 1-8 are in the first hex number
|
|
# - ports 9-16 are in the second hex number
|
|
# - ports 17-24 are in the third hex number
|
|
# - ports 25-32 are in the fourth hex number
|
|
# - ports 33-40 are in the fifth hex number
|
|
# - ports 41-48 are in the sixth hex number
|
|
# - ports 49-56 are in the seventh hex number
|
|
my @bitmap = (0x01, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02);
|
|
|
|
|
|
sub getVlanMask {
|
|
my $session = shift;
|
|
my $vlan = shift;
|
|
my @xs;
|
|
my @hs;
|
|
my $oid = ".1.3.6.1.2.1.17.7.1.4.3.1.4.$vlan";
|
|
my $hs = $session->get($oid);
|
|
if ($session->{ErrorNum}) {
|
|
die "Couldn't get OID!" . $session->{ErrorStr} . "\n";
|
|
}
|
|
$hs =~ s/\"//g; # get rid of quotes!
|
|
@hs = split(" ", $hs);
|
|
|
|
#foreach(@hs){ print "$_\n"; }
|
|
@xs = map(hex, @hs);
|
|
|
|
#foreach (@xs){
|
|
# print $_ . "\n";
|
|
#}
|
|
unless (scalar(@xs) == 7) {
|
|
print "Could not get vlan mask for $vlan\n";
|
|
}
|
|
|
|
#print "Switch mask:\n";
|
|
#printf("%02x %02x %02x %02x %02x %02x %02x\n", @xs);
|
|
return (@xs);
|
|
}
|
|
|
|
# add port 1
|
|
# returns a 7 digit hex string to logically or with existing
|
|
# to add this port to the subnet
|
|
sub getPortMask {
|
|
my $port = shift;
|
|
my @portMask;
|
|
my $hex;
|
|
my $xIndex;
|
|
if ($port < 9) { $xIndex = 0;
|
|
} elsif ($port < 17) { $xIndex = 1;
|
|
} elsif ($port < 25) { $xIndex = 2;
|
|
} elsif ($port < 33) { $xIndex = 3;
|
|
} elsif ($port < 41) { $xIndex = 4;
|
|
} elsif ($port < 49) { $xIndex = 5;
|
|
} elsif ($port < 57) { $xIndex = 6;
|
|
} else {
|
|
print "I don't know how to handle this port...\n";
|
|
exit;
|
|
}
|
|
$port = $port % 8;
|
|
|
|
#print "$port\n";
|
|
$hex = $bitmap[$port];
|
|
|
|
#printf("%02x\n", $hex);
|
|
for (0 .. 6) {
|
|
if ($_ eq $xIndex) {
|
|
push @portMask, $hex;
|
|
} else {
|
|
push @portMask, hex(0);
|
|
}
|
|
}
|
|
|
|
#print "Port mask:\n";
|
|
#printf("%02x %02x %02x %02x %02x %02x %02x\n", @portMask);
|
|
return @portMask;
|
|
|
|
}
|
|
|
|
|
|
sub getSwitchInfo {
|
|
my $switch = shift;
|
|
my ($version, $community, @junk);
|
|
|
|
# bunch of xCAT tables stuff here to connect to switch
|
|
my $info = `tabdump switches | grep smc001 | sed 's/"//g'`;
|
|
if ($?) {
|
|
|
|
# if not in here, we try the defaults.
|
|
$version = 1;
|
|
$community = "public";
|
|
} else {
|
|
(undef, $version, undef, $community, @junk) = split(/,/, $info);
|
|
}
|
|
|
|
if ($::DEBUG) {
|
|
print "switch parameters for $switch:\n";
|
|
print "\tSNMP Version: $version\n";
|
|
print "\tSNMP Community: $community\n";
|
|
}
|
|
return ($community, $version);
|
|
}
|
|
|
|
sub connectToSwitch {
|
|
my $switch = shift;
|
|
my $session;
|
|
my ($community, $snmpver) = getSwitchInfo($switch);
|
|
$session = new SNMP::Session(
|
|
DestHost => $switch,
|
|
Version => $snmpver,
|
|
Community => $community,
|
|
UseSprintValue => 1,
|
|
);
|
|
unless ($session) {
|
|
|
|
#ERROR:
|
|
print "Failed to communicate with $switch\n";
|
|
print "$SNMP::Session::ErrorStr\n";
|
|
|
|
#xCAT::MsgUtils->message("S","Failed to communicate with $switch");
|
|
}
|
|
return $session;
|
|
}
|
|
|
|
sub xorMasks {
|
|
my $sm = shift;
|
|
my $pm = shift;
|
|
my @nm;
|
|
foreach (0 .. 6) {
|
|
my $foo = @$sm[$_] ^ @$pm[$_];
|
|
##printf("%02x\n", $foo);
|
|
$nm[$_] = $foo;
|
|
}
|
|
return @nm;
|
|
}
|
|
|
|
|
|
sub orMasks {
|
|
my $sm = shift;
|
|
my $pm = shift;
|
|
my @nm;
|
|
foreach (0 .. 6) {
|
|
my $foo = @$sm[$_] | @$pm[$_];
|
|
##printf("%02x\n", $foo);
|
|
$nm[$_] = $foo;
|
|
}
|
|
return @nm;
|
|
}
|
|
|
|
|
|
sub andMasks {
|
|
my $sm = shift;
|
|
my $pm = shift;
|
|
my @nm;
|
|
foreach (0 .. 6) {
|
|
my $foo = @$sm[$_] & @$pm[$_];
|
|
##printf("%02x\n", $foo);
|
|
$nm[$_] = $foo;
|
|
}
|
|
return @nm;
|
|
}
|
|
|
|
|
|
# KLUDGE function because I can't figure out how to do this with
|
|
# SNMP.pm and I give up after a week of trying.
|
|
|
|
sub snmpset {
|
|
my $sess = shift;
|
|
my $oid = shift;
|
|
my $type = shift;
|
|
my $val = shift;
|
|
my $snmpset = "/usr/bin/snmpset";
|
|
my ($cmd, $comm, $vers, $switch);
|
|
unless (-r "/usr/bin/snmpset") {
|
|
print "/usr/bin/snmpset command not found! Please install net-snmp-utils\n";
|
|
exit 1;
|
|
}
|
|
|
|
$comm = $sess->{Community};
|
|
$vers = $sess->{Version};
|
|
$switch = $sess->{DestHost};
|
|
|
|
$cmd = "$snmpset -c $comm -v $vers $switch $oid $type $val";
|
|
|
|
#print "$cmd\n";
|
|
system("$cmd >/dev/null");
|
|
|
|
#print "ec: $?\n";
|
|
if ($? > 0) {
|
|
print "Failed to execute command $cmd\n";
|
|
exit 1;
|
|
}
|
|
return $?;
|
|
}
|
|
|
|
|
|
sub addNodeToVlan {
|
|
|
|
# to run: switchport allowed vlan add $port (use bitmap)
|
|
# snmpset .. $oid1.$vlan x 00 00 00 00 00 00 00
|
|
|
|
my $oid1 = '.1.3.6.1.2.1.17.7.1.4.3.1.4';
|
|
|
|
# to run: switchport native vlan $vlan
|
|
# snmpset .. $oid2.$port u $vlan
|
|
my $oid2 = '.1.3.6.1.2.1.17.7.1.4.5.1.1';
|
|
my $session = shift;
|
|
my $vlan = shift;
|
|
my $port = shift;
|
|
|
|
#$oid1 .= ".$vlan";
|
|
#print "$oid1 \n";
|
|
my @xs; # netmask for current switch
|
|
my @pm; # netmask for port
|
|
my @jm; # the joined netmask
|
|
@xs = getVlanMask($session, $vlan);
|
|
@pm = getPortMask($port);
|
|
@jm = orMasks(\@xs, \@pm);
|
|
|
|
#print "Join mask:\n";
|
|
printf("%02x %02x %02x %02x %02x %02x %02x\n", @jm) if $::DEBUG;
|
|
my $mask = sprintf("%02x %02x %02x %02x %02x %02x %02x ", @jm);
|
|
|
|
#################################
|
|
# PART 1: add the switchport allowed capability
|
|
#################################
|
|
|
|
# TODO: This part I can't get working so I'm just going to do an
|
|
# snmpset command here instead.
|
|
#my $v1 = new SNMP::Varbind([$oid1,$vlan,$mask, 'OCTETSTR']);
|
|
#print Dumper($v1);
|
|
#$session->set($v1);
|
|
#if($session->{ErrorStr}) {
|
|
# print "Error! " . $session->{ErrorStr} . "\n";
|
|
#}
|
|
snmpset($session, "$oid1.$vlan", "x", "\'$mask\'");
|
|
|
|
#######################################
|
|
# PART 2: add the switchport native
|
|
#######################################
|
|
|
|
# first get the current one for part 3:
|
|
my $currNativeVlan = $session->get("$oid2.$port");
|
|
if ($session->{ErrorNum}) {
|
|
die "Couldn't get OID!" . $session->{ErrorStr} . "\n";
|
|
}
|
|
print "currNativeVLAN: $currNativeVlan\n" if $::DEBUG;
|
|
print "$currNativeVlan -> ";
|
|
|
|
# set the new switchport native vlan
|
|
my $v2 = new SNMP::Varbind([ $oid2, $port, $vlan, 'GAUGE32' ]);
|
|
|
|
#print Dumper($v2);
|
|
$session->set($v2);
|
|
if ($session->{ErrorStr}) {
|
|
print "Error! $session->{ErrorStr} \n";
|
|
}
|
|
|
|
#######################################
|
|
# PART 3: take it off the other one it is on
|
|
#######################################
|
|
delPortFromVlan($session, $port, $currNativeVlan);
|
|
|
|
}
|
|
|
|
# returns the vlan number
|
|
sub getVlans {
|
|
my $session = shift;
|
|
my %vlans;
|
|
|
|
# IF-MIB:ifName: .1.3.6.1.2.1.31.1.1.1.1
|
|
my $ifName = '.1.3.6.1.2.1.31.1.1.1.1';
|
|
my $varbind = new SNMP::Varbind([ $ifName, '' ]);
|
|
$session->getnext($varbind);
|
|
if ($session->{ErrorStr}) {
|
|
print "Error! " . $session->{ErrorStr} . "\n";
|
|
}
|
|
|
|
# varbind: name: ifName, 1, Port1, OCTETSTR
|
|
while ($varbind->[2]) {
|
|
|
|
#print $varbind->[2] . "\n";
|
|
my $name = $varbind->[2];
|
|
if ($name =~ /VLAN/) {
|
|
|
|
#print "Found $name on " . $session->{DestHost} . "\n";
|
|
$name =~ s/VLAN//g;
|
|
|
|
# we subtract 1000 off the name to give us the actual VLAN.
|
|
$vlans{$name} = $varbind->[1] - 1000;
|
|
|
|
#foreach(@$varbind){
|
|
# print "\t$_\n";
|
|
#}
|
|
}
|
|
$session->getnext($varbind);
|
|
}
|
|
|
|
#print Dumper(%vlans);
|
|
#foreach(keys %vlans){
|
|
# print "VLAN: $_ has value: ". $vlans{$_} ."\n";
|
|
#}
|
|
return \%vlans;
|
|
}
|
|
|
|
# return 1 if port is on vlan return 0 if not on vlan
|
|
sub checkPortVlan {
|
|
my $rc = 0;
|
|
my $session = shift;
|
|
my $p = shift;
|
|
my $v = shift;
|
|
my @xs; # netmask for current switch
|
|
my @pm; # netmask for port
|
|
my @jm; # the joined netmask
|
|
@xs = getVlanMask($session, $v);
|
|
@pm = getPortMask($p);
|
|
@jm = andMasks(\@xs, \@pm);
|
|
|
|
#print "And Mask:\n";
|
|
#printf("%02x %02x %02x %02x %02x %02x %02x\n", @jm);
|
|
my $m = sprintf("%x%x%x%x%x%x%x", @jm);
|
|
|
|
#print "m: $m\n";
|
|
if ($m > 0) {
|
|
|
|
#print "port $p is on VLAN $v on switch " . $session->{DestHost} . "\n";
|
|
$rc = 1;
|
|
}
|
|
return $rc;
|
|
|
|
}
|
|
|
|
sub delPortFromVlan {
|
|
my $session = shift;
|
|
my $port = shift;
|
|
my $vlan = shift;
|
|
print "removing port $port from vlan $vlan\n" if $::DEBUG;
|
|
|
|
# first check and see if its on there:
|
|
unless (checkPortVlan($session, $port, $vlan)) {
|
|
print "Port $port is not on VLAN $vlan\n";
|
|
}
|
|
my @vm = getVlanMask($session, $vlan);
|
|
my @pm = getPortMask($port);
|
|
my @xm = xorMasks(\@vm, \@pm);
|
|
|
|
#print "portmask:\n";
|
|
#printf("%02x %02x %02x %02x %02x %02x %02x\n", @pm);
|
|
#print "vlanmask:\n";
|
|
#printf("%02x %02x %02x %02x %02x %02x %02x\n", @vm);
|
|
#print "xormask:\n";
|
|
#printf("%02x %02x %02x %02x %02x %02x %02x\n", @xm);
|
|
|
|
# this is the untagged remove
|
|
my $oid1 = '.1.3.6.1.2.1.17.7.1.4.3.1.4';
|
|
my $mask = sprintf("%02x %02x %02x %02x %02x %02x %02x ", @xm);
|
|
snmpset($session, "$oid1.$vlan", "x", "\'$mask\'");
|
|
|
|
|
|
# this is the tagged remove
|
|
my $oid2 = '.1.3.6.1.2.1.17.7.1.4.3.1.2';
|
|
|
|
#my $mask = sprintf("%02x %02x %02x %02x %02x %02x %02x ", @xm);
|
|
#print "tagged mask: $mask\n";
|
|
snmpset($session, "$oid2.$vlan", "x", "\'$mask\'");
|
|
|
|
}
|
|
|
|
|
|
sub displayHelp {
|
|
my $ec = shift;
|
|
print "nodesw changes the vlan of a node to a specified vlan\n";
|
|
print "requires xCAT 2.0, Switch configured with SNMP sets, and only tested on SMC8648T\n";
|
|
print "nodesw -h|--help\n";
|
|
print "nodesw [-v] <noderange> vlan <vlan number>\n";
|
|
print "nodesw [-v] <noderange> show\n\n";
|
|
print "Author: Vallard Benincosa\n";
|
|
exit $ec;
|
|
}
|
|
|
|
sub getNodeRange {
|
|
my $nr = shift;
|
|
my @nr = `/opt/xcat/bin/nodels $nr switch.switch switch.port`;
|
|
my $nh;
|
|
chomp(@nr);
|
|
if ($?) {
|
|
print $nr[0];
|
|
exit 1;
|
|
}
|
|
foreach (@nr) {
|
|
my ($n, $char, $val) = split(/:/, $_);
|
|
$char = (split(/\./, $char))[1];
|
|
$val =~ s/ //g;
|
|
$nh->{$n}{$char} = $val;
|
|
}
|
|
|
|
if ($::DEBUG) {
|
|
foreach (keys %$nh) {
|
|
print $_ . ":";
|
|
print " switch:" . $nh->{$_}{'switch'};
|
|
print " port:" . $nh->{$_}{'port'};
|
|
print "\n";
|
|
}
|
|
}
|
|
|
|
|
|
# make sure all fields are defined
|
|
my $e = 0;
|
|
foreach my $node (keys %$nh) {
|
|
unless ($nh->{$node}{'switch'}) {
|
|
print "$node does not have a defined switch in xCAT! (nodels $node switch.switch)\n";
|
|
$e++;
|
|
}
|
|
unless ($nh->{$node}{'port'}) {
|
|
print "$node does not have a defined port in xCAT! (nodels $node switch.port)\n";
|
|
$e++;
|
|
}
|
|
|
|
}
|
|
if ($e > 0) {
|
|
exit 1;
|
|
}
|
|
|
|
# return the node hash
|
|
return $nh;
|
|
}
|
|
|
|
|
|
sub show {
|
|
my $oid2 = '.1.3.6.1.2.1.17.7.1.4.5.1.1';
|
|
my $nh = shift;
|
|
foreach my $node (keys %$nh) {
|
|
my $port = $nh->{$node}{'port'};
|
|
my $switch = $nh->{$node}{'switch'};
|
|
my $session = connectToSwitch($switch);
|
|
my $currNativeVlan = $session->get("$oid2.$port");
|
|
if ($session->{ErrorNum}) {
|
|
die "Couldn't get OID!" . $session->{ErrorStr} . "\n";
|
|
}
|
|
print "$node: $currNativeVlan\n";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
##### commands:
|
|
# get VLANS
|
|
# check VLANs that contain port X
|
|
|
|
|
|
# we want to put this port on this new vlan, here is how we do it:
|
|
# connect to switch to see:
|
|
|
|
|
|
my $help = 0;
|
|
$::DEBUG = 0;
|
|
GetOptions(
|
|
'h|help' => \$help,
|
|
'v|verbose' => \$::DEBUG
|
|
);
|
|
|
|
if ($help) {
|
|
displayHelp(0);
|
|
}
|
|
|
|
require SNMP;
|
|
$SNMP::debugging = 1;
|
|
$SNMP::verbose = 1;
|
|
$SNMP::best_guess = 1;
|
|
|
|
if ($::DEBUG) {
|
|
print "verbose is set to on!\n";
|
|
}
|
|
|
|
my $nr = "";
|
|
my $nodeRange = shift;
|
|
my $cmd = shift;
|
|
my $vlan = shift;
|
|
|
|
unless ($nodeRange) {
|
|
print "missing noderange!\n\n";
|
|
displayHelp(1);
|
|
}
|
|
|
|
unless ($cmd) {
|
|
print "missing operation! [show | vlan ]\n\n";
|
|
displayHelp(1);
|
|
}
|
|
|
|
if ($cmd eq 'vlan') {
|
|
unless ($vlan) {
|
|
print "missing vlan number!\n\n";
|
|
displayHelp(1);
|
|
}
|
|
$nr = getNodeRange($nodeRange);
|
|
chVlan($nr, $vlan);
|
|
|
|
} elsif ($cmd eq 'show') {
|
|
print "showing $nodeRange vlan settings\n" if $::DEBUG;
|
|
$nr = getNodeRange($nodeRange);
|
|
show($nr);
|
|
|
|
} else {
|
|
print "unrecognized operation requested: $cmd\n\n";
|
|
displayHelp(1);
|
|
}
|
|
|
|
|
|
|
|
################################################################################
|
|
# getVlans
|
|
# find all vlans of a switch
|
|
################################################################################
|
|
#my $vlans = getVlans($session);
|
|
|
|
|
|
|
|
################################################################################
|
|
# checkPort Vlan
|
|
################################################################################
|
|
#checkPortVlan($session, $port, $vlans->{$_};
|
|
|
|
|
|
################################################################################
|
|
# addPortToVLAN
|
|
################################################################################
|
|
# get all VLANs
|
|
sub chVlan {
|
|
my $nh = shift;
|
|
my $currSwitch = '';
|
|
my ($session, $vlans, $exists);
|
|
foreach my $node (keys %$nh) {
|
|
my $port = $nh->{$node}{'port'};
|
|
my $switch = $nh->{$node}{'switch'};
|
|
unless ($switch eq $currSwitch) {
|
|
$session = connectToSwitch($switch);
|
|
$vlans = getVlans($session);
|
|
$exists = 0;
|
|
$currSwitch = $switch;
|
|
}
|
|
|
|
foreach (keys %$vlans) {
|
|
|
|
# see if the requested VLAN actually exists
|
|
if ($_ eq $vlan) {
|
|
print "VLAN $_ exists on $switch\n" if $::DEBUG;
|
|
|
|
# if it exists see if its already on it
|
|
$exists = 1;
|
|
if (checkPortVlan($session, $port, $vlans->{$_})) {
|
|
print "$node: port $port already exists on $switch VLAN $vlan\n";
|
|
exit 1;
|
|
} else {
|
|
print "Adding Port: $port to VLAN: $vlan\n" if $::DEBUG;
|
|
print $node . ": ";
|
|
if (addNodeToVlan($session, $vlan, $port) eq 0) {
|
|
print "Added port: $port to VLAN: $vlan\n" if $::DEBUG;
|
|
print "$vlan\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
unless ($exists) {
|
|
print "VLAN $vlan does not exist on " . $session->{DestHost} . "\n";
|
|
exit 1;
|
|
}
|
|
}
|
|
}
|
|
|