2533 lines
68 KiB
Perl
Executable File
2533 lines
68 KiB
Perl
Executable File
#!/usr/bin/env perl
|
|
# IBM(c) 2010 EPL license http://www.eclipse.org/legal/epl-v10.html
|
|
package xCAT::NetworkUtils;
|
|
|
|
BEGIN
|
|
{
|
|
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
|
|
}
|
|
|
|
# if AIX - make sure we include perl 5.8.2 in INC path.
|
|
# Needed to find perl dependencies shipped in deps tarball.
|
|
if ($^O =~ /^aix/i) {
|
|
unshift(@INC, qw(/usr/opt/perl5/lib/5.8.2/aix-thread-multi /usr/opt/perl5/lib/5.8.2 /usr/opt/perl5/lib/site_perl/5.8.2/aix-thread-multi /usr/opt/perl5/lib/site_perl/5.8.2));
|
|
}
|
|
|
|
use lib "$::XCATROOT/lib/perl";
|
|
use POSIX qw(ceil);
|
|
use File::Path;
|
|
use Math::BigInt;
|
|
use Socket;
|
|
use xCAT::GlobalDef;
|
|
#use Data::Dumper;
|
|
use strict;
|
|
use warnings "all";
|
|
my $socket6support = eval { require Socket6 };
|
|
|
|
our @ISA = qw(Exporter);
|
|
our @EXPORT_OK = qw(getipaddr);
|
|
|
|
my $utildata; #data to persist locally
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head1 xCAT::NetworkUtils
|
|
|
|
=head2 Package Description
|
|
|
|
This program module file, is a set of network utilities used by xCAT commands.
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 getNodeDomains
|
|
|
|
Gets the network domain for a list of nodes
|
|
|
|
The domain value comes from the network definition
|
|
associated with the node ip address.
|
|
|
|
If the network domain is not set then the default is to
|
|
use the site.domain value
|
|
|
|
Arguments:
|
|
list of nodes
|
|
Returns:
|
|
error - undef
|
|
success - hash ref of domains for each node
|
|
Globals:
|
|
$::VERBOSE
|
|
Error:
|
|
Example:
|
|
my $nodedomains = xCAT::NetworkUtils->getNodeDomains(\@nodes, $callback);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub getNodeDomains()
|
|
{
|
|
my $class = shift;
|
|
my $nodes = shift;
|
|
|
|
my @nodelist = @$nodes;
|
|
my %nodedomains;
|
|
|
|
# Get the network info for each node
|
|
my %nethash = xCAT::DBobjUtils->getNetwkInfo(\@nodelist);
|
|
|
|
# get the site domain value
|
|
my @domains = xCAT::TableUtils->get_site_attribute("domain");
|
|
my $sitedomain = $domains[0];
|
|
|
|
# for each node - set hash value to network domain or default
|
|
# to site domain
|
|
foreach my $node (@nodelist) {
|
|
unless (defined($node)) {next;}
|
|
if (defined($nethash{$node}) && $nethash{$node}{domain}) {
|
|
$nodedomains{$node} = $nethash{$node}{domain};
|
|
} else {
|
|
$nodedomains{$node} = $sitedomain;
|
|
}
|
|
}
|
|
|
|
return \%nodedomains;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 gethostnameandip
|
|
Works for both IPv4 and IPv6.
|
|
Takes either a host name or an IP address string
|
|
and performs a lookup on that name,
|
|
returns an array with two elements: the hostname, the ip address
|
|
if the host name or ip address can not be resolved,
|
|
the corresponding element in the array will be undef
|
|
Arguments:
|
|
hostname or ip address
|
|
Returns: the hostname and the ip address
|
|
Globals:
|
|
|
|
Error:
|
|
none
|
|
Example:
|
|
my ($host, $ip) = xCAT::NetworkUtils->gethostnameandip($iporhost);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub gethostnameandip()
|
|
{
|
|
my ($class, $iporhost) = @_;
|
|
|
|
if (($iporhost =~ /\d+\.\d+\.\d+\.\d+/) || ($iporhost =~ /:/)) #ip address
|
|
{
|
|
return (xCAT::NetworkUtils->gethostname($iporhost), $iporhost);
|
|
}
|
|
else #hostname
|
|
{
|
|
return ($iporhost, xCAT::NetworkUtils->getipaddr($iporhost));
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 gethostname
|
|
Works for both IPv4 and IPv6.
|
|
Takes an IP address string and performs a lookup on that name,
|
|
returns the hostname of the ip address
|
|
if the ip address can not be resolved, returns undef
|
|
Arguments:
|
|
ip address
|
|
Returns: the hostname
|
|
Globals:
|
|
cache: %::iphosthash
|
|
Error:
|
|
none
|
|
Example:
|
|
my $host = xCAT::NetworkUtils->gethostname($ip);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub gethostname()
|
|
{
|
|
my ($class, $iporhost) = @_;
|
|
|
|
if (!defined($iporhost))
|
|
{
|
|
return undef;
|
|
}
|
|
|
|
if (ref($iporhost) eq 'ARRAY')
|
|
{
|
|
$iporhost = @{$iporhost}[0];
|
|
if (!$iporhost)
|
|
{
|
|
return undef;
|
|
}
|
|
}
|
|
|
|
if (($iporhost !~ /\d+\.\d+\.\d+\.\d+/) && ($iporhost !~ /:/))
|
|
{
|
|
#why you do so? pass in a hostname and only want a hostname??
|
|
return $iporhost;
|
|
}
|
|
#cache, do not lookup DNS each time
|
|
if (defined($::iphosthash{$iporhost}) && $::iphosthash{$iporhost})
|
|
{
|
|
return $::iphosthash{$iporhost};
|
|
}
|
|
else
|
|
{
|
|
if ($socket6support) # the getaddrinfo and getnameinfo supports both IPv4 and IPv6
|
|
{
|
|
my ($family, $socket, $protocol, $ip, $name) = Socket6::getaddrinfo($iporhost,0,AF_UNSPEC,SOCK_STREAM,6); #specifically ask for TCP capable records, maximizing chance of no more than one return per v4/v6
|
|
my $host = (Socket6::getnameinfo($ip))[0];
|
|
if ($host eq $iporhost) # can not resolve
|
|
{
|
|
return undef;
|
|
}
|
|
if ($host)
|
|
{
|
|
$host =~ s/\..*//; #short hostname
|
|
}
|
|
return $host;
|
|
}
|
|
else
|
|
{
|
|
#it is possible that no Socket6 available,
|
|
#but passing in IPv6 address, such as ::1 on loopback
|
|
if ($iporhost =~ /:/)
|
|
{
|
|
return undef;
|
|
}
|
|
my $hostname = gethostbyaddr(inet_aton($iporhost), AF_INET);
|
|
if ( $hostname ) {
|
|
$hostname =~ s/\..*//; #short hostname
|
|
}
|
|
return $hostname;
|
|
}
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 getipaddr
|
|
Works for both IPv4 and IPv6.
|
|
Takes a hostname string and performs a lookup on that name,
|
|
returns the the ip address of the hostname
|
|
if the hostname can not be resolved, returns undef
|
|
Arguments:
|
|
hostname
|
|
Optional:
|
|
GetNumber=>1 (return the address as a BigInt instead of readable string)
|
|
Returns: ip address
|
|
Globals:
|
|
cache: %::hostiphash
|
|
Error:
|
|
none
|
|
Example:
|
|
my $ip = xCAT::NetworkUtils->getipaddr($hostname);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub getipaddr
|
|
{
|
|
my $iporhost = shift;
|
|
if ($iporhost eq 'xCAT::NetworkUtils') { #was called with -> syntax
|
|
$iporhost = shift;
|
|
}
|
|
my %extraarguments = @_;
|
|
|
|
if (!defined($iporhost))
|
|
{
|
|
return undef;
|
|
}
|
|
|
|
if (ref($iporhost) eq 'ARRAY')
|
|
{
|
|
$iporhost = @{$iporhost}[0];
|
|
if (!$iporhost)
|
|
{
|
|
return undef;
|
|
}
|
|
}
|
|
|
|
#go ahead and do the reverse lookup on ip, useful to 'frontend' aton/pton and also to
|
|
#spit out a common abbreviation if leading zeroes or using different ipv6 presentation rules
|
|
#if ($iporhost and ($iporhost =~ /\d+\.\d+\.\d+\.\d+/) || ($iporhost =~ /:/))
|
|
#{
|
|
# #pass in an ip and only want an ip??
|
|
# return $iporhost;
|
|
#}
|
|
|
|
#cache, do not lookup DNS each time
|
|
if ($::hostiphash and defined($::hostiphash{$iporhost}) && $::hostiphash{$iporhost})
|
|
{
|
|
return $::hostiphash{$iporhost};
|
|
}
|
|
else
|
|
{
|
|
if ($socket6support) # the getaddrinfo and getnameinfo supports both IPv4 and IPv6
|
|
{
|
|
my @returns;
|
|
my $reqfamily=AF_UNSPEC;
|
|
if ($extraarguments{OnlyV6}) {
|
|
$reqfamily=AF_INET6;
|
|
} elsif ($extraarguments{OnlyV4}) {
|
|
$reqfamily=AF_INET;
|
|
}
|
|
my @addrinfo = Socket6::getaddrinfo($iporhost,0,$reqfamily,SOCK_STREAM,6);
|
|
my ($family, $socket, $protocol, $ip, $name) = splice(@addrinfo,0,5);
|
|
while ($ip)
|
|
{
|
|
if ($extraarguments{GetNumber}) { #return a BigInt for compare, e.g. for comparing ip addresses for determining if they are in a common network or range
|
|
my $ip = (Socket6::getnameinfo($ip, Socket6::NI_NUMERICHOST()))[0];
|
|
my $bignumber = Math::BigInt->new(0);
|
|
foreach (unpack("N*",Socket6::inet_pton($family,$ip))) { #if ipv4, loop will iterate once, for v6, will go 4 times
|
|
$bignumber->blsft(32);
|
|
$bignumber->badd($_);
|
|
}
|
|
push(@returns,$bignumber);
|
|
} else {
|
|
push @returns,(Socket6::getnameinfo($ip, Socket6::NI_NUMERICHOST()))[0];
|
|
}
|
|
if (scalar @addrinfo and $extraarguments{GetAllAddresses}) {
|
|
($family, $socket, $protocol, $ip, $name) = splice(@addrinfo,0,5);
|
|
} else {
|
|
$ip=0;
|
|
}
|
|
}
|
|
unless ($extraarguments{GetAllAddresses}) {
|
|
return $returns[0];
|
|
}
|
|
return @returns;
|
|
}
|
|
else
|
|
{
|
|
#return inet_ntoa(inet_aton($iporhost))
|
|
#TODO, what if no scoket6 support, but passing in a IPv6 hostname?
|
|
if ($iporhost =~ /:/) { #ipv6
|
|
return undef;
|
|
#die "Attempt to process IPv6 address, but system does not have requisite IPv6 perl support";
|
|
}
|
|
my $packed_ip;
|
|
$iporhost and $packed_ip = inet_aton($iporhost);
|
|
if (!$packed_ip)
|
|
{
|
|
return undef;
|
|
}
|
|
if ($extraarguments{GetNumber}) { #only 32 bits, no for loop needed.
|
|
return Math::BigInt->new(unpack("N*",$packed_ip));
|
|
}
|
|
return inet_ntoa($packed_ip);
|
|
}
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 linklocaladdr
|
|
Only for IPv6.
|
|
Takes a mac address, calculate the IPv6 link local address
|
|
Arguments:
|
|
mac address
|
|
Returns:
|
|
ipv6 link local address. returns undef if passed in a invalid mac address
|
|
Globals:
|
|
Error:
|
|
none
|
|
Example:
|
|
my $linklocaladdr = xCAT::NetworkUtils->linklocaladdr($mac);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub linklocaladdr {
|
|
my ($class, $mac) = @_;
|
|
$mac = lc($mac);
|
|
my $localprefix = "fe80";
|
|
|
|
my ($m1, $m2, $m3, $m6, $m7, $m8);
|
|
# mac address can be 00215EA376B0 or 00:21:5E:A3:76:B0
|
|
if($mac =~ /^([0-9A-Fa-f]{2}).*?([0-9A-Fa-f]{2}).*?([0-9A-Fa-f]{2}).*?([0-9A-Fa-f]{2}).*?([0-9A-Fa-f]{2}).*?([0-9A-Fa-f]{2})$/)
|
|
{
|
|
($m1, $m2, $m3, $m6, $m7, $m8) = ($1, $2, $3, $4, $5, $6);
|
|
}
|
|
else
|
|
{
|
|
#not a valid mac address
|
|
return undef;
|
|
}
|
|
my ($m4, $m5) = ("ff","fe");
|
|
|
|
#my $bit = (int $m1) & 2;
|
|
#if ($bit) {
|
|
# $m1 = $m1 - 2;
|
|
#} else {
|
|
# $m1 = $m1 + 2;
|
|
#}
|
|
$m1 = hex($m1);
|
|
$m1 = $m1 ^ 2;
|
|
$m1 = sprintf("%x", $m1);
|
|
|
|
$m1 = $m1 . $m2;
|
|
$m3 = $m3 . $m4;
|
|
$m5 = $m5 . $m6;
|
|
$m7 = $m7 . $m8;
|
|
|
|
my $laddr = join ":", $m1, $m3, $m5, $m7;
|
|
$laddr = join "::", $localprefix, $laddr;
|
|
|
|
return $laddr;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 ishostinsubnet
|
|
Works for both IPv4 and IPv6.
|
|
Takes an ip address, the netmask and a subnet,
|
|
chcek if the ip address is in the subnet
|
|
Arguments:
|
|
ip address, netmask, subnet
|
|
Returns:
|
|
1 - if the ip address is in the subnet
|
|
0 - if the ip address is NOT in the subnet
|
|
Globals:
|
|
Error:
|
|
none
|
|
Example:
|
|
if(xCAT::NetworkUtils->ishostinsubnet($ip, $netmask, $subnet);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub ishostinsubnet {
|
|
my ($class, $ip, $mask, $subnet) = @_;
|
|
|
|
#safe guard
|
|
if (!defined($ip) || !defined($mask) || !defined($subnet))
|
|
{
|
|
return 0;
|
|
}
|
|
my $numbits=32;
|
|
if ($ip =~ /:/) {#ipv6
|
|
$numbits=128;
|
|
}
|
|
if ($mask) {
|
|
if ($mask =~ /\//) {
|
|
$mask =~ s/^\///;
|
|
$mask=Math::BigInt->new("0b".("1"x$mask).("0"x($numbits-$mask)));
|
|
} else {
|
|
$mask=getipaddr($mask,GetNumber=>1);
|
|
}
|
|
} else { #CIDR notation supported
|
|
if ($subnet && ($subnet =~ /\//)) {
|
|
($subnet,$mask) = split /\//,$subnet,2;
|
|
$mask=Math::BigInt->new("0b".("1"x$mask).("0"x($numbits-$mask)));
|
|
} else {
|
|
die "ishostinsubnet must either be called with a netmask or CIDR /bits notation";
|
|
}
|
|
}
|
|
if ($subnet && ($subnet =~ /\//)) #remove CIDR suffix from subnet
|
|
{
|
|
$subnet =~ s/\/.*$//;
|
|
}
|
|
$ip = getipaddr($ip,GetNumber=>1);
|
|
$subnet = getipaddr($subnet,GetNumber=>1);
|
|
$ip &= $mask;
|
|
if ($ip && $subnet && ($ip == $subnet)) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
=head3 setup_ip_forwarding
|
|
|
|
Sets up ip forwarding on localhost
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub setup_ip_forwarding
|
|
{
|
|
my ($class, $enable)=@_;
|
|
if (xCAT::Utils->isLinux()) {
|
|
my $conf_file="/etc/sysctl.conf";
|
|
`grep "net.ipv4.ip_forward" $conf_file`;
|
|
if ($? == 0) {
|
|
`sed -i "s/^net.ipv4.ip_forward = .*/net.ipv4.ip_forward = $enable/" $conf_file`;
|
|
`sed -i "s/^#net.ipv4.ip_forward *= *.*/net.ipv4.ip_forward = $enable/" $conf_file`; #debian/ubuntu have different default format
|
|
} else {
|
|
`echo "net.ipv4.ip_forward = $enable" >> $conf_file`;
|
|
}
|
|
`sysctl -e -p $conf_file`; # workaround for redhat bug 639821
|
|
}
|
|
else
|
|
{
|
|
`no -o ipforwarding=$enable`;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
=head3 setup_ipv6_forwarding
|
|
|
|
Sets up ipv6 forwarding on localhost
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub setup_ipv6_forwarding
|
|
{
|
|
my ($class, $enable)=@_;
|
|
if (xCAT::Utils->isLinux()) {
|
|
my $conf_file="/etc/sysctl.conf";
|
|
`grep "net.ipv6.conf.all.forwarding" $conf_file`;
|
|
if ($? == 0) {
|
|
`sed -i "s/^net.ipv6.conf.all.forwarding = .*/net.ipv6.conf.all.forwarding = $enable/" $conf_file`;
|
|
} else {
|
|
`echo "net.ipv6.conf.all.forwarding = $enable" >> $conf_file`;
|
|
}
|
|
`sysctl -e -p $conf_file`;
|
|
}
|
|
else
|
|
{
|
|
`no -o ip6forwarding=$enable`;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 prefixtomask
|
|
Convert the IPv6 prefix length(e.g. 64) to the netmask(e.g. ffff:ffff:ffff:ffff:0000:0000:0000:0000).
|
|
Till now, the netmask format ffff:ffff:ffff:: only works for AIX NIM
|
|
|
|
Arguments:
|
|
prefix length
|
|
Returns:
|
|
netmask - netmask like ffff:ffff:ffff:ffff:0000:0000:0000:0000
|
|
0 - if the prefix length is not correct
|
|
Globals:
|
|
Error:
|
|
none
|
|
Example:
|
|
my #netmask = xCAT::NetworkUtils->prefixtomask($prefixlength);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub prefixtomask {
|
|
my ($class, $prefixlength) = @_;
|
|
|
|
if (($prefixlength < 1) || ($prefixlength > 128))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
my $number=Math::BigInt->new("0b".("1"x$prefixlength).("0"x(128-$prefixlength)));
|
|
my $mask = $number->as_hex();
|
|
$mask =~ s/^0x//;
|
|
$mask =~ s/(....)/$1/g;
|
|
return $mask;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 my_ip_in_subnet
|
|
Get the facing ip for some specific network
|
|
|
|
Arguments:
|
|
net - subnet, such as 192.168.0.01
|
|
mask - netmask, such as 255.255.255.0
|
|
Returns:
|
|
facing_ip - The local ip address in the subnet,
|
|
returns undef if no local ip address is in the subnet
|
|
Globals:
|
|
Error:
|
|
none
|
|
Example:
|
|
my $facingip = xCAT::NetworkUtils->my_ip_in_subnet($net, $mask);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub my_ip_in_subnet
|
|
{
|
|
my ($class, $net, $mask) = @_;
|
|
|
|
if (!$net || !$mask)
|
|
{
|
|
return undef;
|
|
}
|
|
|
|
my $fmask = xCAT::NetworkUtils::formatNetmask($mask, 0, 1);
|
|
|
|
my $localnets = xCAT::NetworkUtils->my_nets();
|
|
|
|
return $localnets->{"$net\/$fmask"};
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 ip_forwarding_enabled
|
|
Check if the ip_forward enabled on the system
|
|
|
|
Arguments:
|
|
Returns:
|
|
1 - The ip_forwarding is eanbled
|
|
0 - The ip_forwarding is not eanbled
|
|
Globals:
|
|
Error:
|
|
none
|
|
Example:
|
|
if(xCAT::NetworkUtils->ip_forwarding_enabled())
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub ip_forwarding_enabled
|
|
{
|
|
|
|
my $enabled;
|
|
if (xCAT::Utils->isLinux())
|
|
{
|
|
$enabled = `sysctl -n net.ipv4.ip_forward`;
|
|
chomp($enabled);
|
|
}
|
|
else
|
|
{
|
|
$enabled = `no -o ipforwarding`;
|
|
chomp($enabled);
|
|
$enabled =~ s/ipforwarding\s+=\s+//;
|
|
}
|
|
return $enabled;
|
|
}
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 get_nic_ip
|
|
Get the ip address for the node nics
|
|
|
|
Arguments:
|
|
Returns:
|
|
Hash of the mapping of the nic and the ip addresses
|
|
Globals:
|
|
Error:
|
|
none
|
|
Example:
|
|
xCAT::NetworkUtils->get_nic_ip()
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
sub get_nic_ip
|
|
{
|
|
my $nic;
|
|
my %iphash;
|
|
my $mode = "MULTICAST";
|
|
my $payingattention=0;
|
|
my $interface;
|
|
my $keepcurrentiface;
|
|
|
|
|
|
if (xCAT::Utils->isAIX()) {
|
|
##############################################################
|
|
# Should look like this for AIX:
|
|
# en0: flags=4e080863,80<UP,BROADCAST,NOTRAILERS,RUNNING,
|
|
# SIMPLEX,MULTICAST,GROUPRT,64BIT,PSEG,CHAIN>
|
|
# inet 30.0.0.1 netmask 0xffffff00 broadcast 30.0.0.255
|
|
# inet 192.168.2.1 netmask 0xffffff00 broadcast 192.168.2.255
|
|
# en1: ...
|
|
#
|
|
##############################################################
|
|
my $cmd = "ifconfig -a";
|
|
my $result = `$cmd`;
|
|
#############################################
|
|
# Error running command
|
|
#############################################
|
|
if ( !$result ) {
|
|
return undef;
|
|
}
|
|
my @adapter = split /(\w+\d+):\s+flags=/, $result;
|
|
foreach ( @adapter ) {
|
|
if ($_ =~ /^(en\d)/) {
|
|
$nic = $1;
|
|
next;
|
|
}
|
|
if ( !($_ =~ /LOOPBACK/ ) and
|
|
$_ =~ /UP(,|>)/ and
|
|
$_ =~ /$mode/ ) {
|
|
my @ip = split /\n/;
|
|
for my $ent ( @ip ) {
|
|
if ( $ent =~ /^\s*inet\s+(\d+\.\d+\.\d+\.\d+)/ ) {
|
|
$iphash{$nic} = $1;
|
|
next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else { # linux
|
|
my @ipoutput = `ip addr`;
|
|
#############################################
|
|
# Error running command
|
|
#############################################
|
|
if ( !@ipoutput ) {
|
|
return undef;
|
|
}
|
|
foreach my $line (@ipoutput) {
|
|
if ($line =~ /^\d/) { # new interface, new context..
|
|
if ($interface and not $keepcurrentiface) {
|
|
#don't bother reporting unusable nics
|
|
delete $iphash{$interface};
|
|
}
|
|
$keepcurrentiface=0;
|
|
if ( !($line =~ /LOOPBACK/ ) and
|
|
$line =~ /UP( |,|>)/ and
|
|
$line =~ /$mode/ ) {
|
|
|
|
$payingattention=1;
|
|
$line =~ /^([^:]*): ([^:]*):/;
|
|
$interface=$2;
|
|
} else {
|
|
$payingattention=0;
|
|
next;
|
|
}
|
|
}
|
|
unless ($payingattention) { next; }
|
|
if ($line =~ /inet/) {
|
|
$keepcurrentiface=1;
|
|
}
|
|
if ( $line =~ /^\s*inet \s*(\d+\.\d+\.\d+\.\d+)/ ) {
|
|
$iphash{$interface} = $1;
|
|
}
|
|
}
|
|
}
|
|
return \%iphash;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 classful_networks_for_net_and_mask
|
|
|
|
Arguments:
|
|
network and mask
|
|
Returns:
|
|
a list of classful subnets that constitute the entire potentially classless arguments
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub classful_networks_for_net_and_mask
|
|
{
|
|
my $network = shift;
|
|
my $mask = shift;
|
|
my $given_mask = 0;
|
|
if ($mask =~ /\./)
|
|
{
|
|
$given_mask = 1;
|
|
my $masknumber = unpack("N", inet_aton($mask));
|
|
$mask = 32;
|
|
until ($masknumber % 2)
|
|
{
|
|
$masknumber = $masknumber >> 1;
|
|
$mask--;
|
|
}
|
|
}
|
|
|
|
my @results;
|
|
my $bitstoeven = (8 - ($mask % 8));
|
|
if ($bitstoeven eq 8) { $bitstoeven = 0; }
|
|
my $resultmask = $mask + $bitstoeven;
|
|
if ($given_mask)
|
|
{
|
|
$resultmask =
|
|
inet_ntoa(pack("N", (2**$resultmask - 1) << (32 - $resultmask)));
|
|
}
|
|
push @results, $resultmask;
|
|
|
|
my $padbits = (32 - ($bitstoeven + $mask));
|
|
my $numchars = int(($mask + $bitstoeven) / 4);
|
|
my $curmask = 2**$mask - 1 << (32 - $mask);
|
|
my $nown = unpack("N", inet_aton($network));
|
|
$nown = $nown & $curmask;
|
|
my $highn = $nown + ((2**$bitstoeven - 1) << (32 - $mask - $bitstoeven));
|
|
|
|
while ($nown <= $highn)
|
|
{
|
|
push @results, inet_ntoa(pack("N", $nown));
|
|
|
|
#$rethash->{substr($nowhex, 0, $numchars)} = $network;
|
|
$nown += 1 << (32 - $mask - $bitstoeven);
|
|
}
|
|
return @results;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 my_hexnets
|
|
|
|
Arguments:
|
|
none
|
|
Returns:
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
xCAT::NetworkUtils->my_hexnets
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub my_hexnets
|
|
{
|
|
my $rethash;
|
|
my @nets = split /\n/, `/sbin/ip addr`;
|
|
foreach (@nets)
|
|
{
|
|
my @elems = split /\s+/;
|
|
unless (/^\s*inet\s/)
|
|
{
|
|
next;
|
|
}
|
|
(my $curnet, my $maskbits) = split /\//, $elems[2];
|
|
my $bitstoeven = (4 - ($maskbits % 4));
|
|
if ($bitstoeven eq 4) { $bitstoeven = 0; }
|
|
my $padbits = (32 - ($bitstoeven + $maskbits));
|
|
my $numchars = int(($maskbits + $bitstoeven) / 4);
|
|
my $curmask = 2**$maskbits - 1 << (32 - $maskbits);
|
|
my $nown = unpack("N", inet_aton($curnet));
|
|
$nown = $nown & $curmask;
|
|
my $highn =
|
|
$nown + ((2**$bitstoeven - 1) << (32 - $maskbits - $bitstoeven));
|
|
|
|
while ($nown <= $highn)
|
|
{
|
|
my $nowhex = sprintf("%08x", $nown);
|
|
$rethash->{substr($nowhex, 0, $numchars)} = $curnet;
|
|
$nown += 1 << (32 - $maskbits - $bitstoeven);
|
|
}
|
|
}
|
|
return $rethash;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 get_host_from_ip
|
|
Description:
|
|
Get the hostname of an IP addresses. First from hosts table, and then try system resultion.
|
|
If there is a shortname, it will be returned. Otherwise it will return long name. If the IP cannot be resolved, return undef;
|
|
|
|
Arguments:
|
|
$ip: the IP to get;
|
|
|
|
Returns:
|
|
Return: the hostname.
|
|
For an example
|
|
|
|
Globals:
|
|
none
|
|
|
|
Error:
|
|
none
|
|
|
|
Example:
|
|
xCAT::NetworkUtils::get_host_from_ip('192.168.200.1')
|
|
|
|
Comments:
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------
|
|
sub get_host_from_ip
|
|
{
|
|
my $ip = shift;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 isPingable
|
|
Description:
|
|
Check if an IP address can be pinged
|
|
|
|
Arguments:
|
|
$ip: the IP to ping;
|
|
|
|
Returns:
|
|
Return: 1 indicates yes; 0 indicates no.
|
|
For an example
|
|
|
|
Globals:
|
|
none
|
|
|
|
Error:
|
|
none
|
|
|
|
Example:
|
|
xCAT::NetworkUtils::isPingable('192.168.200.1')
|
|
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------
|
|
my %PING_CACHE;
|
|
sub isPingable
|
|
{
|
|
my $ip = shift;
|
|
|
|
my $rc;
|
|
if ( exists $PING_CACHE{ $ip})
|
|
{
|
|
$rc = $PING_CACHE{ $ip};
|
|
}
|
|
else
|
|
{
|
|
my $res = `LANG=C ping -c 1 -w 5 $ip 2>&1`;
|
|
if ( $res =~ /100% packet loss/g)
|
|
{
|
|
$rc = 1;
|
|
}
|
|
else
|
|
{
|
|
$rc = 0;
|
|
}
|
|
$PING_CACHE{ $ip} = $rc;
|
|
}
|
|
|
|
return ! $rc;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 my_nets
|
|
Description:
|
|
Return a hash ref that contains all subnet and netmask on the mn (or sn). This subroutine can be invoked on both Linux and AIX.
|
|
|
|
Arguments:
|
|
none.
|
|
|
|
Returns:
|
|
Return a hash ref. Each entry will be: <subnet/mask>=><existing ip>;
|
|
For an example:
|
|
'192.168.200.0/255.255.255.0' => '192.168.200.246';
|
|
For an example
|
|
|
|
Globals:
|
|
none
|
|
|
|
Error:
|
|
none
|
|
|
|
Example:
|
|
xCAT::NetworkUtils::my_nets().
|
|
|
|
Comments:
|
|
none
|
|
=cut
|
|
#-----------------------------------------------------------------------
|
|
sub my_nets
|
|
{
|
|
require xCAT::Table;
|
|
my $rethash;
|
|
my @nets;
|
|
my $v6net;
|
|
my $v6ip;
|
|
if ( $^O eq 'aix')
|
|
{
|
|
@nets = split /\n/, `/usr/sbin/ifconfig -a`;
|
|
}
|
|
else
|
|
{
|
|
@nets = split /\n/, `/sbin/ip addr`; #could use ip route, but to match hexnets...
|
|
}
|
|
foreach (@nets)
|
|
{
|
|
$v6net = '';
|
|
my @elems = split /\s+/;
|
|
unless (/^\s*inet/)
|
|
{
|
|
next;
|
|
}
|
|
my $curnet; my $maskbits;
|
|
if ( $^O eq 'aix')
|
|
{
|
|
if ($elems[1] eq 'inet6')
|
|
{
|
|
$v6net=$elems[2];
|
|
$v6ip=$elems[2];
|
|
$v6ip =~ s/\/.*//; # ipv6 address 4000::99/64
|
|
$v6ip =~ s/\%.*//; # ipv6 address ::1%1/128
|
|
}
|
|
else
|
|
{
|
|
$curnet = $elems[2];
|
|
$maskbits = formatNetmask( $elems[4], 2, 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ($elems[1] eq 'inet6')
|
|
{
|
|
next; #Linux IPv6 TODO, do not return IPv6 networks on Linux for now
|
|
}
|
|
($curnet, $maskbits) = split /\//, $elems[2];
|
|
}
|
|
if (!$v6net)
|
|
{
|
|
my $curmask = 2**$maskbits - 1 << (32 - $maskbits);
|
|
my $nown = unpack("N", inet_aton($curnet));
|
|
$nown = $nown & $curmask;
|
|
my $textnet=inet_ntoa(pack("N",$nown));
|
|
$textnet.="/$maskbits";
|
|
$rethash->{$textnet} = $curnet;
|
|
}
|
|
else
|
|
{
|
|
$rethash->{$v6net} = $v6ip;
|
|
}
|
|
}
|
|
|
|
|
|
# now get remote nets
|
|
my $nettab = xCAT::Table->new("networks");
|
|
#my $sitetab = xCAT::Table->new("site");
|
|
#my $master = $sitetab->getAttribs({key=>'master'},'value');
|
|
#$master = $master->{value};
|
|
my @masters = xCAT::TableUtils->get_site_attribute("master");
|
|
my $master = $masters[0];
|
|
my @vnets = $nettab->getAllAttribs('net','mgtifname','mask');
|
|
|
|
foreach(@vnets){
|
|
my $n = $_->{net};
|
|
my $if = $_->{mgtifname};
|
|
my $nm = $_->{mask};
|
|
if (!$n || !$if || !$nm)
|
|
{
|
|
next; #incomplete network
|
|
}
|
|
if ($if =~ /!remote!/) { #only take in networks with special interface
|
|
$nm = formatNetmask($nm, 0 , 1);
|
|
$n .="/$nm";
|
|
#$rethash->{$n} = $if;
|
|
$rethash->{$n} = $master;
|
|
}
|
|
}
|
|
return $rethash;
|
|
}
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 my_if_netmap
|
|
Arguments:
|
|
none
|
|
Returns:
|
|
hash of networks to interface names
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub my_if_netmap
|
|
{
|
|
my $net;
|
|
if (scalar(@_))
|
|
{ #called with the other syntax
|
|
$net = shift;
|
|
}
|
|
my @rtable = split /\n/, `netstat -rn`;
|
|
if ($?)
|
|
{
|
|
return "Unable to run netstat, $?";
|
|
}
|
|
my %retmap;
|
|
foreach (@rtable)
|
|
{
|
|
if (/^\D/) { next; } #skip headers
|
|
if (/^\S+\s+\S+\s+\S+\s+\S*G/)
|
|
{
|
|
next;
|
|
} #Skip networks that require gateways to get to
|
|
/^(\S+)\s.*\s(\S+)$/;
|
|
$retmap{$1} = $2;
|
|
}
|
|
return \%retmap;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 my_ip_facing
|
|
Returns my ip address
|
|
Linux only
|
|
Arguments:
|
|
nodename
|
|
Returns:
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
my $ip = xCAT::NetworkUtils->my_ip_facing($peerip)
|
|
my @ip = xCAT::NetworkUtils->my_ip_facing($peerip) # return multiple
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub my_ip_facing
|
|
{
|
|
my $peer = shift;
|
|
if (@_)
|
|
{
|
|
$peer = shift;
|
|
}
|
|
return my_ip_facing_aix( $peer) if ( $^O eq 'aix');
|
|
my $peernumber = inet_aton($peer); #TODO: IPv6 support
|
|
unless ($peernumber) { return undef; }
|
|
my $noden = unpack("N", inet_aton($peer));
|
|
my @nets = split /\n/, `/sbin/ip addr`;
|
|
|
|
my @ips;
|
|
foreach (@nets)
|
|
{
|
|
my @elems = split /\s+/;
|
|
unless (/^\s*inet\s/)
|
|
{
|
|
next;
|
|
}
|
|
(my $curnet, my $maskbits) = split /\//, $elems[2];
|
|
my $curmask = 2**$maskbits - 1 << (32 - $maskbits);
|
|
my $curn = unpack("N", inet_aton($curnet));
|
|
if (($noden & $curmask) == ($curn & $curmask))
|
|
{
|
|
push @ips, $curnet;
|
|
}
|
|
}
|
|
|
|
if (@ips) {
|
|
if (wantarray) {
|
|
return @ips;
|
|
} else {
|
|
return $ips[0];
|
|
}
|
|
} else {
|
|
return undef;
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 my_ip_facing_aix
|
|
Returns my ip address
|
|
AIX only
|
|
Arguments:
|
|
nodename
|
|
Returns:
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub my_ip_facing_aix
|
|
{
|
|
my $peer = shift;
|
|
my @nets = `ifconfig -a`;
|
|
chomp @nets;
|
|
foreach my $net (@nets)
|
|
{
|
|
my ($curnet,$netmask);
|
|
if ( $net =~ /^\s*inet\s+([\d\.]+)\s+netmask\s+(\w+)\s+broadcast/)
|
|
{
|
|
($curnet,$netmask) = ($1,$2);
|
|
}
|
|
elsif ($net =~ /^\s*inet6\s+(.*)$/)
|
|
{
|
|
($curnet,$netmask) = split('/', $1);
|
|
}
|
|
else
|
|
{
|
|
next;
|
|
}
|
|
if (isInSameSubnet($peer, $curnet, $netmask, 2))
|
|
{
|
|
return $curnet;
|
|
}
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 formatNetmask
|
|
Description:
|
|
Transform netmask to one of 3 formats (255.255.255.0, 24, 0xffffff00).
|
|
|
|
Arguments:
|
|
$netmask: the original netmask
|
|
$origType: the original netmask type. The valid value can be 0, 1, 2:
|
|
Type 0: 255.255.255.0
|
|
Type 1: 24
|
|
Type 2: 0xffffff00
|
|
$newType: the new netmask type, valid values can be 0,1,2, as above.
|
|
|
|
Returns:
|
|
Return undef if any error. Otherwise return the netmask in new format.
|
|
|
|
Globals:
|
|
none
|
|
|
|
Error:
|
|
none
|
|
|
|
Example:
|
|
xCAT::NetworkUtils::formatNetmask( '24', 1, 0); #return '255.255.255.0'.
|
|
|
|
Comments:
|
|
none
|
|
=cut
|
|
#-----------------------------------------------------------------------
|
|
sub formatNetmask
|
|
{
|
|
my $mask = shift;
|
|
my $origType = shift;
|
|
my $newType = shift;
|
|
my $maskn;
|
|
if ( $origType == 0)
|
|
{
|
|
$maskn = unpack("N", inet_aton($mask));
|
|
}
|
|
elsif ( $origType == 1)
|
|
{
|
|
$maskn = 2**$mask - 1 << (32 - $mask);
|
|
}
|
|
elsif( $origType == 2)
|
|
{
|
|
$maskn = hex $mask;
|
|
}
|
|
else
|
|
{
|
|
return undef;
|
|
}
|
|
|
|
if ( $newType == 0)
|
|
{
|
|
return inet_ntoa( pack('N', $maskn));
|
|
}
|
|
if ( $newType == 1)
|
|
{
|
|
my $bin = unpack ("B32", pack("N", $maskn));
|
|
my @dup = ( $bin =~ /(1{1})0*/g);
|
|
return scalar ( @dup);
|
|
}
|
|
if ( $newType == 2)
|
|
{
|
|
return sprintf "0x%1x", $maskn;
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 isInSameSubnet
|
|
Description:
|
|
Check if 2 given IP addresses are in same subnet
|
|
|
|
Arguments:
|
|
$ip1: the first IP
|
|
$ip2: the second IP
|
|
$mask: the netmask, here are 3 possible netmask types, following are examples for these 3 types:
|
|
Type 0: 255.255.255.0
|
|
Type 1: 24
|
|
Type 2: 0xffffff00
|
|
$masktype: the netmask type, 3 possible values: 0,1,2, as indicated above
|
|
|
|
Returns:
|
|
1: they are in same subnet
|
|
2: not in same subnet
|
|
|
|
Globals:
|
|
none
|
|
|
|
Error:
|
|
none
|
|
|
|
Example:
|
|
xCAT::NetworkUtils::isInSameSubnet( '192.168.10.1', '192.168.10.2', '255.255.255.0', 0);
|
|
|
|
Comments:
|
|
none
|
|
=cut
|
|
#-----------------------------------------------------------------------
|
|
sub isInSameSubnet
|
|
{
|
|
my $ip1 = shift;
|
|
my $ip2 = shift;
|
|
my $mask = shift;
|
|
my $maskType = shift;
|
|
|
|
$ip1 = xCAT::NetworkUtils->getipaddr($ip1);
|
|
$ip2 = xCAT::NetworkUtils->getipaddr($ip2);
|
|
|
|
if (!defined($ip1) || !defined($ip2))
|
|
{
|
|
return undef;
|
|
}
|
|
|
|
if ((($ip1 =~ /\d+\.\d+\.\d+\.\d+/) && ($ip2 !~ /\d+\.\d+\.\d+\.\d+/))
|
|
||(($ip1 !~ /\d+\.\d+\.\d+\.\d+/) && ($ip2 =~ /\d+\.\d+\.\d+\.\d+/)))
|
|
{
|
|
#ipv4 and ipv6 can not be in the same subnet
|
|
return undef;
|
|
}
|
|
|
|
if (($ip1 =~ /\d+\.\d+\.\d+\.\d+/) && ($ip2 =~ /\d+\.\d+\.\d+\.\d+/))
|
|
{
|
|
my $maskn;
|
|
if ( $maskType == 0)
|
|
{
|
|
$maskn = unpack("N", inet_aton($mask));
|
|
}
|
|
elsif ( $maskType == 1)
|
|
{
|
|
$maskn = 2**$mask - 1 << (32 - $mask);
|
|
}
|
|
elsif( $maskType == 2)
|
|
{
|
|
$maskn = hex $mask;
|
|
}
|
|
else
|
|
{
|
|
return undef;
|
|
}
|
|
|
|
my $ip1n = unpack("N", inet_aton($ip1));
|
|
my $ip2n = unpack("N", inet_aton($ip2));
|
|
|
|
return ( ( $ip1n & $maskn) == ( $ip2n & $maskn) );
|
|
}
|
|
else
|
|
{
|
|
#ipv6
|
|
if (($ip1 =~ /\%/) || ($ip2 =~ /\%/))
|
|
{
|
|
return undef;
|
|
}
|
|
my $netipmodule = eval {require Net::IP;};
|
|
if ($netipmodule) {
|
|
my $eip1 = Net::IP::ip_expand_address ($ip1,6);
|
|
my $eip2 = Net::IP::ip_expand_address ($ip2,6);
|
|
my $bmask = Net::IP::ip_get_mask($mask,6);
|
|
my $bip1 = Net::IP::ip_iptobin($eip1,6);
|
|
my $bip2 = Net::IP::ip_iptobin($eip2,6);
|
|
if (($bip1 & $bmask) == ($bip2 & $bmask)) {
|
|
return 1;
|
|
}
|
|
} # else, can not check without Net::IP module
|
|
return undef;
|
|
}
|
|
}
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 nodeonmynet - checks to see if node is on any network this server is attached to or remote network potentially managed by this system
|
|
Arguments:
|
|
Node name
|
|
Returns: 1 if node is on the network
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
xCAT::NetworkUtils->nodeonmynet
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
sub nodeonmynet
|
|
{
|
|
require xCAT::Table;
|
|
my $nodetocheck = shift;
|
|
if (scalar(@_))
|
|
{
|
|
$nodetocheck = shift;
|
|
}
|
|
|
|
my $nodeip = getNodeIPaddress( $nodetocheck );
|
|
if (!$nodeip)
|
|
{
|
|
return 0;
|
|
}
|
|
unless ($nodeip =~ /\d+\.\d+\.\d+\.\d+/)
|
|
{
|
|
#IPv6
|
|
if ( $^O eq 'aix')
|
|
{
|
|
my @subnets = get_subnet_aix();
|
|
for my $net_ent (@subnets)
|
|
{
|
|
if ($net_ent !~ /-/)
|
|
{
|
|
#ipv4
|
|
next;
|
|
}
|
|
my ($net, $interface, $mask, $flag) = split/-/ , $net_ent;
|
|
if (xCAT::NetworkUtils->ishostinsubnet($nodeip, $mask, $net))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
my @v6routes = split /\n/,`ip -6 route`;
|
|
foreach (@v6routes) {
|
|
if (/via/ or /^unreachable/ or /^fe80::\/64/) {
|
|
#only count local ones, remote ones can be caught in next loop
|
|
#also, link-local would be a pitfall,
|
|
#since more context than address is
|
|
#needed to determine locality
|
|
next;
|
|
}
|
|
s/ .*//; #remove all after the space
|
|
if (xCAT::NetworkUtils->ishostinsubnet($nodeip,'',$_)) { #bank on CIDR support
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
my $nettab=xCAT::Table->new("networks");
|
|
my @vnets = $nettab->getAllAttribs('net','mgtifname','mask');
|
|
foreach (@vnets) {
|
|
if ((defined $_->{mgtifname}) && ($_->{mgtifname} eq '!remote!'))
|
|
{
|
|
if (xCAT::NetworkUtils->ishostinsubnet($nodeip, $_->{mask}, $_->{net}))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
my $noden = unpack("N", inet_aton($nodeip));
|
|
my @nets;
|
|
if ($utildata->{nodeonmynetdata} and $utildata->{nodeonmynetdata}->{pid} == $$) {
|
|
@nets = @{$utildata->{nodeonmynetdata}->{nets}};
|
|
} else {
|
|
if ( $^O eq 'aix')
|
|
{
|
|
my @subnets = get_subnet_aix();
|
|
for my $net_ent (@subnets)
|
|
{
|
|
if ($net_ent =~ /-/)
|
|
{
|
|
#ipv6
|
|
next;
|
|
}
|
|
my @ents = split /:/ , $net_ent;
|
|
push @nets, $ents[0] . '/' . $ents[2] . ' dev ' . $ents[1];
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
@nets = split /\n/, `/sbin/ip route`;
|
|
}
|
|
my $nettab=xCAT::Table->new("networks");
|
|
my @vnets = $nettab->getAllAttribs('net','mgtifname','mask');
|
|
foreach (@vnets) {
|
|
if ((defined $_->{mgtifname}) && ($_->{mgtifname} eq '!remote!'))
|
|
{ #global scoped network
|
|
my $curm = unpack("N", inet_aton($_->{mask}));
|
|
my $bits=32;
|
|
until ($curm & 1) {
|
|
$bits--;
|
|
$curm=$curm>>1;
|
|
}
|
|
push @nets,$_->{'net'}."/".$bits." dev remote";
|
|
}
|
|
}
|
|
$utildata->{nodeonmynetdata}->{pid}=$$;
|
|
$utildata->{nodeonmynetdata}->{nets} = \@nets;
|
|
}
|
|
foreach (@nets)
|
|
{
|
|
my @elems = split /\s+/;
|
|
unless ($elems[1] =~ /dev/)
|
|
{
|
|
next;
|
|
}
|
|
(my $curnet, my $maskbits) = split /\//, $elems[0];
|
|
my $curmask = 2**$maskbits - 1 << (32 - $maskbits);
|
|
my $curn = unpack("N", inet_aton($curnet));
|
|
if (($noden & $curmask) == $curn)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 getNodeIPaddress
|
|
Arguments:
|
|
Node name only one at a time
|
|
Returns: ip address(s)
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example: my $c1 = xCAT::NetworkUtils::getNodeIPaddress($nodetocheck);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
sub getNodeIPaddress
|
|
{
|
|
require xCAT::Table;
|
|
my $nodetocheck = shift;
|
|
my $port = shift;
|
|
my $nodeip;
|
|
|
|
$nodeip = xCAT::NetworkUtils->getipaddr($nodetocheck);
|
|
if (!$nodeip)
|
|
{
|
|
my $hoststab = xCAT::Table->new( 'hosts');
|
|
my $ent = $hoststab->getNodeAttribs( $nodetocheck, ['ip'] );
|
|
if ( $ent->{'ip'} ) {
|
|
$nodeip = $ent->{'ip'};
|
|
}
|
|
}
|
|
|
|
if ( $nodeip ) {
|
|
return $nodeip;
|
|
} else {
|
|
return undef;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 thishostisnot
|
|
returns 0 if host is not the same
|
|
Arguments:
|
|
hostname
|
|
Returns:
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
xCAT::NetworkUtils->thishostisnot
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
sub thishostisnot
|
|
{
|
|
my $comparison = shift;
|
|
if (scalar(@_))
|
|
{
|
|
$comparison = shift;
|
|
}
|
|
|
|
my @ips;
|
|
if ( $^O eq 'aix')
|
|
{
|
|
@ips = split /\n/, `/usr/sbin/ifconfig -a`;
|
|
}
|
|
else
|
|
{
|
|
@ips = split /\n/, `/sbin/ip addr`;
|
|
}
|
|
my $comp = xCAT::NetworkUtils->getipaddr($comparison);
|
|
if ($comp)
|
|
{
|
|
foreach (@ips)
|
|
{
|
|
if (/^\s*inet.?\s+/)
|
|
{
|
|
my @ents = split(/\s+/);
|
|
my $ip = $ents[2];
|
|
$ip =~ s/\/.*//;
|
|
$ip =~ s/\%.*//;
|
|
if ($ip eq $comp)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
=head3 gethost_ips (AIX and Linux)
|
|
Will use ifconfig to determine all possible ip addresses for the
|
|
host it is running on and then gethostbyaddr to get all possible hostnames
|
|
|
|
input:
|
|
output: array of ipaddress(s) and hostnames
|
|
example: @ips=xCAT::NetworkUtils->gethost_ips();
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
#sub gethost_ips1
|
|
#{
|
|
# my ($class) = @_;
|
|
# my $cmd;
|
|
# my @ipaddress;
|
|
# $cmd = "ifconfig" . " -a";
|
|
# $cmd = $cmd . "| grep \"inet\"";
|
|
# my @result = xCAT::Utils->runcmd($cmd, 0);
|
|
# if ($::RUNCMD_RC != 0)
|
|
# {
|
|
# xCAT::MsgUtils->message("S", "Error from $cmd\n");
|
|
# exit $::RUNCMD_RC;
|
|
# }
|
|
# foreach my $addr (@result)
|
|
# {
|
|
# my @ip;
|
|
# if (xCAT::Utils->isLinux())
|
|
# {
|
|
# if ($addr =~ /inet6/)
|
|
# {
|
|
# #TODO, Linux ipv6
|
|
# }
|
|
# else
|
|
# {
|
|
# my ($inet, $addr1, $Bcast, $Mask) = split(" ", $addr);
|
|
# #@ip = split(":", $addr1);
|
|
# #push @ipaddress, $ip[1];
|
|
# $addr1 =~ s/.*://;
|
|
# push @ipaddress, $addr1;
|
|
# }
|
|
# }
|
|
# else
|
|
# { #AIX
|
|
# if ($addr =~ /inet6/)
|
|
# {
|
|
# $addr =~ /\s*inet6\s+([\da-fA-F:]+).*\/(\d+)/;
|
|
# my $v6ip = $1;
|
|
# my $v6mask = $2;
|
|
# if ($v6ip)
|
|
# {
|
|
# push @ipaddress, $v6ip;
|
|
# }
|
|
# }
|
|
# else
|
|
# {
|
|
# my ($inet, $addr1, $netmask, $mask1, $Bcast, $bcastaddr) =
|
|
# split(" ", $addr);
|
|
# push @ipaddress, $addr1;
|
|
# }
|
|
#
|
|
# }
|
|
# }
|
|
# my @names = @ipaddress;
|
|
# foreach my $ipaddr (@names)
|
|
# {
|
|
# my $hostname = xCAT::NetworkUtils->gethostname($ipaddr);
|
|
# if ($hostname)
|
|
# {
|
|
# my @shorthost = split(/\./, $hostname);
|
|
# push @ipaddress, $shorthost[0];
|
|
# }
|
|
# }
|
|
#
|
|
# return @ipaddress;
|
|
#}
|
|
|
|
|
|
sub gethost_ips
|
|
{
|
|
my ($class) = @_;
|
|
my $cmd;
|
|
my @ipaddress;
|
|
if (xCAT::Utils->isLinux())
|
|
{
|
|
$cmd="ip -4 --oneline addr show |awk -F ' ' '{print \$4}'|awk -F '/' '{print \$1}'";
|
|
my @result =xCAT::Utils->runcmd($cmd);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
xCAT::MsgUtils->message("S", "Error from $cmd\n");
|
|
exit $::RUNCMD_RC;
|
|
}
|
|
|
|
push @ipaddress, @result;
|
|
}
|
|
else
|
|
{ #AIX
|
|
|
|
$cmd = "ifconfig" . " -a";
|
|
$cmd = $cmd . "| grep \"inet\"";
|
|
my @result = xCAT::Utils->runcmd($cmd, 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
xCAT::MsgUtils->message("S", "Error from $cmd\n");
|
|
exit $::RUNCMD_RC;
|
|
}
|
|
|
|
foreach my $addr (@result)
|
|
{
|
|
if ($addr =~ /inet6/)
|
|
{
|
|
$addr =~ /\s*inet6\s+([\da-fA-F:]+).*\/(\d+)/;
|
|
my $v6ip = $1;
|
|
my $v6mask = $2;
|
|
if ($v6ip)
|
|
{
|
|
push @ipaddress, $v6ip;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my ($inet, $addr1, $netmask, $mask1, $Bcast, $bcastaddr) =
|
|
split(" ", $addr);
|
|
push @ipaddress, $addr1;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
my @names = @ipaddress;
|
|
foreach my $ipaddr (@names)
|
|
{
|
|
my $hostname = xCAT::NetworkUtils->gethostname($ipaddr);
|
|
if ($hostname)
|
|
{
|
|
my @shorthost = split(/\./, $hostname);
|
|
push @ipaddress, $shorthost[0];
|
|
}
|
|
}
|
|
return @ipaddress;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 get_subnet_aix
|
|
Description:
|
|
To get present subnet configuration by parsing the output of 'netstat'. Only designed for AIX.
|
|
Arguments:
|
|
None
|
|
Returns:
|
|
@aix_nrn : An array with entries in format "net:nic:netmask:flag". Following is an example entry:
|
|
9.114.47.224:en0:27:U
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
my @nrn =xCAT::NetworkUtils::get_subnet_aix
|
|
Comments:
|
|
none
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub get_subnet_aix
|
|
{
|
|
my @netstat_res = `/usr/bin/netstat -rn`;
|
|
chomp @netstat_res;
|
|
my @aix_nrn;
|
|
for my $entry ( @netstat_res)
|
|
{
|
|
#We need to find entries like:
|
|
#Destination Gateway Flags Refs Use If Exp Groups
|
|
#9.114.47.192/27 9.114.47.205 U 1 1 en0
|
|
#4000::/64 link#4 UCX 1 0 en2 - -
|
|
my ( $net, $netmask, $flag, $nic);
|
|
if ( $entry =~ /^\s*([\d\.]+)\/(\d+)\s+[\d\.]+\s+(\w+)\s+\d+\s+\d+\s(\w+)/)
|
|
{
|
|
( $net, $netmask, $flag, $nic) = ($1,$2,$3,$4);
|
|
my @dotsec = split /\./, $net;
|
|
for ( my $i = 4; $i > scalar(@dotsec); $i--)
|
|
{
|
|
$net .= '.0';
|
|
}
|
|
push @aix_nrn, "$net:$nic:$netmask:$flag" if ($net ne '127.0.0.0');
|
|
}
|
|
elsif ($entry =~ /^\s*([\dA-Fa-f\:]+)\/(\d+)\s+.*?\s+(\w+)\s+\d+\s+\d+\s(\w+)/)
|
|
{
|
|
#print "=====$entry====\n";
|
|
( $net, $netmask, $flag, $nic) = ($1,$2,$3,$4);
|
|
# for ipv6, can not use : as the delimiter
|
|
push @aix_nrn, "$net-$nic-$netmask-$flag" if ($net ne '::')
|
|
}
|
|
}
|
|
return @aix_nrn;
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
=head3 determinehostname and ip address(s)
|
|
|
|
Used on the service node to figure out what hostname and ip address(s)
|
|
are valid names and addresses
|
|
Input: None
|
|
Output: ipaddress(s),nodename
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub determinehostname
|
|
{
|
|
my $hostname;
|
|
my $hostnamecmd = "/bin/hostname";
|
|
my @thostname = xCAT::Utils->runcmd($hostnamecmd, 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{ # could not get hostname
|
|
xCAT::MsgUtils->message("S",
|
|
"Error $::RUNCMD_RC from $hostnamecmd command\n");
|
|
exit $::RUNCMD_RC;
|
|
}
|
|
$hostname = $thostname[0];
|
|
|
|
#get all potentially valid abbreviations, and pick the one that is ok
|
|
#by 'noderange'
|
|
my @hostnamecandidates;
|
|
my $nodename;
|
|
while ($hostname =~ /\./) {
|
|
push @hostnamecandidates,$hostname;
|
|
$hostname =~ s/\.[^\.]*//;
|
|
}
|
|
push @hostnamecandidates,$hostname;
|
|
my $checkhostnames = join(',',@hostnamecandidates);
|
|
my @validnodenames = xCAT::NodeRange::noderange($checkhostnames);
|
|
unless (scalar @validnodenames) { #If the node in question is not in table, take output literrally.
|
|
push @validnodenames,$hostnamecandidates[0];
|
|
}
|
|
#now, noderange doesn't guarantee the order, so we search the preference order, most to least specific.
|
|
foreach my $host (@hostnamecandidates) {
|
|
if (grep /^$host$/,@validnodenames) {
|
|
$nodename = $host;
|
|
last;
|
|
}
|
|
}
|
|
my @ips = xCAT::NetworkUtils->gethost_ips;
|
|
my @hostinfo = (@ips, $nodename);
|
|
|
|
return @hostinfo;
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
=head3 toIP
|
|
|
|
IPv4 function to convert hostname to IP address
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub toIP
|
|
{
|
|
|
|
if (($_[0] =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/) || ($_[0] =~ /:/))
|
|
{
|
|
return ([0, $_[0]]);
|
|
}
|
|
my $ip = xCAT::NetworkUtils->getipaddr($_[0]);
|
|
if (!$ip)
|
|
{
|
|
return ([1, "Cannot Resolve: $_[0]\n"]);
|
|
}
|
|
return ([0, $ip]);
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 validate_ip
|
|
Validate list of IPs
|
|
Arguments:
|
|
List of IPs
|
|
Returns:
|
|
1 - Invalid IP address in the list
|
|
0 - IP addresses are all valid
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
if (xCAT::NetworkUtils->validate_ip($IP)) {}
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub validate_ip
|
|
{
|
|
my ($class, @IPs) = @_;
|
|
foreach (@IPs) {
|
|
my $ip = $_;
|
|
#TODO need more check for IPv6 address
|
|
if ($ip =~ /:/)
|
|
{
|
|
return([0]);
|
|
}
|
|
###################################
|
|
# Length is 4 for IPv4 addresses
|
|
###################################
|
|
my (@octets) = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
|
|
if ( scalar(@octets) != 4 ) {
|
|
return( [1,"Invalid IP address1: $ip"] );
|
|
}
|
|
foreach my $octet ( @octets ) {
|
|
if (( $octet < 0 ) or ( $octet > 255 )) {
|
|
return( [1,"Invalid IP address2: $ip"] );
|
|
}
|
|
}
|
|
}
|
|
return([0]);
|
|
}
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 isIpaddr
|
|
|
|
returns 1 if parameter is has a valid IP address form.
|
|
|
|
Arguments:
|
|
dot qulaified IP address: e.g. 1.2.3.4
|
|
Returns:
|
|
1 - if legal IP address
|
|
0 - if not legal IP address.
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
if ($ipAddr) { blah; }
|
|
Comments:
|
|
Doesn't test if the IP address is on the network,
|
|
just tests its form.
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub isIpaddr
|
|
{
|
|
my $addr = shift;
|
|
if (($addr) && ($addr =~ /xCAT::NetworkUtils/))
|
|
{
|
|
$addr = shift;
|
|
}
|
|
|
|
unless ( $addr )
|
|
{
|
|
return 0;
|
|
}
|
|
#print "addr=$addr\n";
|
|
if ($addr !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ($1 > 255 || $1 == 0 || $2 > 255 || $3 > 255 || $4 > 255)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
=head3 getNodeNameservers
|
|
Description:
|
|
Get nameservers of specified nodes.
|
|
The priority: noderes.nameservers > networks.nameservers > site.nameservers
|
|
Arguments:
|
|
node: node name list
|
|
Returns:
|
|
Return a hash ref, of the $nameservers{$node}
|
|
undef - Failed to get the nameservers
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
my $nameservers = xCAT::NetworkUtils::getNodeNameservers(\@node);
|
|
Comments:
|
|
none
|
|
|
|
=cut
|
|
#-------------------------------------------------------------------------------
|
|
sub getNodeNameservers{
|
|
my $nodes=shift;
|
|
if( $nodes =~ /xCAT::NetworkUtils/)
|
|
{
|
|
$nodes=shift;
|
|
}
|
|
my @nodelist = @$nodes;
|
|
my %nodenameservers;
|
|
my $nrtab = xCAT::Table->new('noderes',-create=>0);
|
|
my %nrhash = %{$nrtab->getNodesAttribs(\@nodelist,['nameservers'])};
|
|
|
|
my $nettab = xCAT::Table->new("networks");
|
|
my %nethash = xCAT::DBobjUtils->getNetwkInfo( \@nodelist );
|
|
|
|
my @nameservers = xCAT::TableUtils->get_site_attribute("nameservers");
|
|
my $sitenameservers=$nameservers[0];
|
|
|
|
|
|
foreach my $node (@nodelist){
|
|
if ($nrhash{$node} and $nrhash{$node}->[0] and $nrhash{$node}->[0]->{nameservers})
|
|
{
|
|
$nodenameservers{$node}=$nrhash{$node}->[0]->{nameservers};
|
|
}elsif($nethash{$node}{nameservers})
|
|
{
|
|
$nodenameservers{$node}=$nethash{$node}{nameservers};
|
|
}elsif($sitenameservers)
|
|
{
|
|
$nodenameservers{$node}=$sitenameservers;
|
|
}
|
|
}
|
|
|
|
return \%nodenameservers;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 getNodeNetworkCfg
|
|
Description:
|
|
Get node network configuration, including "IP, hostname(the nodename),and netmask" by this node's name.
|
|
|
|
Arguments:
|
|
node: the nodename
|
|
Returns:
|
|
Return an array, which contains (IP,hostname,gateway,netmask').
|
|
undef - Failed to get the network configuration info
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
my ($ip,$host,undef,$mask) = xCAT::NetworkUtils::getNodeNetworkCfg('node1');
|
|
Comments:
|
|
Presently gateway is always blank. Need to be improved.
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub getNodeNetworkCfg
|
|
{
|
|
my $node = shift;
|
|
if( $node =~ /xCAT::NetworkUtils/)
|
|
{
|
|
$node =shift;
|
|
}
|
|
|
|
my $ip = xCAT::NetworkUtils->getipaddr($node);
|
|
my $mask = undef;
|
|
my $gateway = undef;
|
|
|
|
my $nettab = xCAT::Table->new("networks");
|
|
if ($nettab) {
|
|
my @nets = $nettab->getAllAttribs('net','mask','gateway');
|
|
foreach my $net (@nets) {
|
|
if (xCAT::NetworkUtils::isInSameSubnet( $net->{'net'}, $ip, $net->{'mask'}, 0)) {
|
|
$gateway=$net->{'gateway'};
|
|
$mask=$net->{'mask'};
|
|
}
|
|
}
|
|
}
|
|
|
|
return ($ip, $node, $gateway, xCAT::NetworkUtils::formatNetmask($mask,0,0));
|
|
}
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 get_hdwr_ip
|
|
Description:
|
|
Get hardware(CEC, BPA) IP from the hosts table, and then /etc/hosts.
|
|
|
|
Arguments:
|
|
node: the nodename(cec, or bpa)
|
|
Returns:
|
|
Return the node IP
|
|
-1 - Failed to get the IP.
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
my $ip = xCAT::NetworkUtils::get_hdwr_ip('node1');
|
|
Comments:
|
|
Used in FSPpower FSPflash, FSPinv.
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub get_hdwr_ip
|
|
{
|
|
require xCAT::Table;
|
|
my $node = shift;
|
|
my $ip = undef;
|
|
my $Rc = undef;
|
|
|
|
my $ip_tmp_res = xCAT::NetworkUtils::toIP($node);
|
|
($Rc, $ip) = @$ip_tmp_res;
|
|
if ( $Rc ) {
|
|
my $hosttab = xCAT::Table->new( 'hosts' );
|
|
if ( $hosttab) {
|
|
my $node_ip_hash = $hosttab->getNodeAttribs( $node,[qw(ip)]);
|
|
$ip = $node_ip_hash->{ip};
|
|
}
|
|
|
|
}
|
|
|
|
if (!$ip) {
|
|
return undef;
|
|
}
|
|
|
|
return $ip;
|
|
}
|
|
|
|
#--------------------------------------------------------------------------------
|
|
=head3 pingNodeStatus
|
|
This function takes an array of nodes and returns their status using nmap or fping.
|
|
Arguments:
|
|
nodes-- an array of nodes.
|
|
Returns:
|
|
a hash that has the node status. The format is:
|
|
{alive=>[node1, node3,...], unreachable=>[node4, node2...]}
|
|
=cut
|
|
#--------------------------------------------------------------------------------
|
|
sub pingNodeStatus {
|
|
my ($class, @mon_nodes)=@_;
|
|
my %status=();
|
|
my @active_nodes=();
|
|
my @inactive_nodes=();
|
|
#print "NetworkUtils->pingNodeStatus called, nodes=@mon_nodes\n";
|
|
if ((@mon_nodes)&& (@mon_nodes > 0)) {
|
|
#get all the active nodes
|
|
my $nodes= join(' ', @mon_nodes);
|
|
if (-x '/usr/bin/nmap' or -x '/usr/local/bin/nmap') { #use nmap
|
|
#print "use nmap\n";
|
|
my %deadnodes;
|
|
foreach (@mon_nodes) {
|
|
$deadnodes{$_}=1;
|
|
}
|
|
|
|
# get additional options from site table
|
|
my @nmap_options = xCAT::TableUtils->get_site_attribute("nmapoptions");
|
|
my $more_options = $nmap_options[0];
|
|
|
|
#call namp
|
|
open (NMAP, "nmap -PE --system-dns --send-ip -sP $more_options ". $nodes . " 2> /dev/null|") or die("Cannot open nmap pipe: $!");
|
|
my $node;
|
|
while (<NMAP>) {
|
|
if (/Host (.*) \(.*\) appears to be up/) {
|
|
$node=$1;
|
|
unless ($deadnodes{$node}) {
|
|
foreach (keys %deadnodes) {
|
|
if ($node =~ /^$_\./) {
|
|
$node = $_;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
delete $deadnodes{$node};
|
|
push(@active_nodes, $node);
|
|
} elsif (/Nmap scan report for ([^ ]*) /) {
|
|
$node=$1;
|
|
} elsif (/Host is up./) {
|
|
unless ($deadnodes{$node}) {
|
|
foreach (keys %deadnodes) {
|
|
if ($node =~ /^$_\./) {
|
|
$node = $_;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
delete $deadnodes{$node};
|
|
push(@active_nodes, $node);
|
|
}
|
|
}
|
|
foreach (sort keys %deadnodes) {
|
|
push(@inactive_nodes, $_);
|
|
}
|
|
} else { #use fping
|
|
#print "use fping\n";
|
|
|
|
my $temp=`fping -a $nodes 2> /dev/null`;
|
|
chomp($temp);
|
|
@active_nodes=split(/\n/, $temp);
|
|
|
|
#get all the inactive nodes by substracting the active nodes from all.
|
|
my %temp2;
|
|
if ((@active_nodes) && ( @active_nodes > 0)) {
|
|
foreach(@active_nodes) { $temp2{$_}=1};
|
|
foreach(@mon_nodes) {
|
|
if (!$temp2{$_}) { push(@inactive_nodes, $_);}
|
|
}
|
|
}
|
|
else {@inactive_nodes=@mon_nodes;}
|
|
}
|
|
}
|
|
|
|
$status{$::STATUS_ACTIVE}=\@active_nodes;
|
|
$status{$::STATUS_INACTIVE}=\@inactive_nodes;
|
|
#use Data::Dumper;
|
|
#print Dumper(%status);
|
|
|
|
return %status;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 isValidMAC
|
|
Description : Validate whether specified string is a MAC string.
|
|
Arguments : macstr - the string to be validated.
|
|
Returns : 1 - valid MAC String.
|
|
0 - invalid MAC String.
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub isValidMAC
|
|
{
|
|
my ($class, $macstr) = @_;
|
|
if ($macstr =~ /^[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}$/){
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 isValidHostname
|
|
Description : Validate whether specified string is a valid hostname.
|
|
Arguments : hostname - the string to be validated.
|
|
Returns : 1 - valid hostname String.
|
|
0 - invalid hostname String.
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub isValidHostname
|
|
{
|
|
my ($class, $hostname) = @_;
|
|
if ($hostname =~ /^[a-z0-9]/){
|
|
if ($hostname =~ /[a-z0-9]$/){
|
|
if ($hostname =~ /^[\-a-z0-9]+$/){
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 isValidFQDN
|
|
Description : Validate whether specified string is a valid FQDN.
|
|
Arguments : hostname - the string to be validated.
|
|
Returns : 1 - valid hostname FQDN.
|
|
0 - invalid hostname FQDN.
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub isValidFQDN
|
|
{
|
|
my ($class, $hostname) = @_;
|
|
if ($hostname =~ /^[a-z0-9][\.\-a-z0-9]+[a-z0-9]$/){
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 ip_to_int
|
|
Description : convert an IPv4 string into int.
|
|
Arguments : ipstr - the IPv4 string.
|
|
Returns : ipint - int number
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub ip_to_int
|
|
{
|
|
my ($class, $ipstr) = @_;
|
|
my $ipint = 0;
|
|
my @ipnums = split('\.', $ipstr);
|
|
$ipint += $ipnums[0] << 24;
|
|
$ipint += $ipnums[1] << 16;
|
|
$ipint += $ipnums[2] << 8;
|
|
$ipint += $ipnums[3];
|
|
return $ipint;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 int_to_ip
|
|
Description : convert an int into IPv4 String.
|
|
Arguments : ipnit - the input int number.
|
|
Returns : ipstr - IPv4 String.
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub int_to_ip
|
|
{
|
|
my ($class, $ipint) = @_;
|
|
return inet_ntoa(inet_aton($ipint));
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 getBroadcast
|
|
Description : Get the broadcast ips
|
|
Arguments : ipstr - the IPv4 string ip.
|
|
netmask - the subnet mask of network
|
|
Returns : bcipint - the IPv4 string of broadcast ip.
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub getBroadcast
|
|
{
|
|
my ($class, $ipstr, $netmask) = @_;
|
|
my $ipint = xCAT::NetworkUtils->ip_to_int($ipstr);
|
|
my $maskint = xCAT::NetworkUtils->ip_to_int($netmask);
|
|
my $tmp = sprintf("%d", ~$maskint);
|
|
my $bcnum = sprintf("%d", ($ipint | $tmp) & hex('0x00000000FFFFFFFF'));
|
|
return xCAT::NetworkUtils->int_to_ip($bcnum);
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 get_allips_in_range
|
|
Description : Get all IPs in a IP range, return in a list.
|
|
Arguments : $startip - start IP address
|
|
$endip - end IP address
|
|
$increment - increment factor
|
|
Returns : IP list in this range.
|
|
Example :
|
|
my $startip = "192.168.0.1";
|
|
my $endip = "192.168.0.100";
|
|
xCAT::NetworkUtils->get_allips_in_range($startip, $endip, 1);
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub get_allips_in_range
|
|
{
|
|
my $class = shift;
|
|
my $startip = shift;
|
|
my $endip = shift;
|
|
my $increment = shift;
|
|
my @iplist = ();
|
|
my $tmpip;
|
|
|
|
my $startipnum = xCAT::NetworkUtils->ip_to_int($startip);
|
|
my $endipnum = xCAT::NetworkUtils->ip_to_int($endip);
|
|
|
|
if ($increment > 0){
|
|
while ($startipnum <= $endipnum){
|
|
$tmpip = xCAT::NetworkUtils->int_to_ip($startipnum);
|
|
$startipnum += $increment;
|
|
push (@iplist, $tmpip);
|
|
}
|
|
}elsif($increment < 0){
|
|
while ($endipnum >= $startipnum){
|
|
$tmpip = xCAT::NetworkUtils->int_to_ip($endipnum);
|
|
$endipnum += $increment;
|
|
push (@iplist, $tmpip);
|
|
}
|
|
}
|
|
return \@iplist;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 get_all_ips
|
|
Description : Get all IP addresses from table nics, column nicips.
|
|
Arguments : hashref - if not set, will return a reference of list,
|
|
if set, will return a reference of hash.
|
|
Returns : All IPs reference.
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub get_all_nicips{
|
|
my ($class, $hashref) = @_;
|
|
my %allipshash;
|
|
my @allipslist;
|
|
|
|
my $table = xCAT::Table->new('nics');
|
|
my @entries = $table->getAllNodeAttribs(['nicips']);
|
|
foreach (@entries){
|
|
# $_->{nicips} looks like "eth0:ip1,eth1:ip2,bmc:ip3..."
|
|
if($_->{nicips}){
|
|
my @nicandiplist = split(',', $_->{nicips});
|
|
# Each record in @nicandiplist looks like "eth0:ip1"
|
|
# delimiter has been changed to use "!" in xCAT 2.8
|
|
foreach (@nicandiplist){
|
|
my @nicandip;
|
|
if ($_ =~ /!/) {
|
|
@nicandip = split('!', $_);
|
|
} else {
|
|
@nicandip = split(':', $_);
|
|
}
|
|
if ($hashref){
|
|
$allipshash{$nicandip[1]} = 0;
|
|
} else{
|
|
push (@allipslist, $nicandip[1]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($hashref){
|
|
return \%allipshash;
|
|
} else{
|
|
return \@allipslist;
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 gen_net_boot_params
|
|
|
|
Description:
|
|
This subroutine is used to generate all possible kernel parameters for network boot (rh/sles/ubuntu + diskfull/diskless)
|
|
The supported network boot parameters:
|
|
ksdevice - Specify network device for Anaconda. For rh6 and earlier. Format: 'ksdevice={$mac|$nicname}'
|
|
BOOTIF - Specify network device for Anaconda. The boot device which set by pxe. xCAT also set it if the bootload is not pxe. Format 'BOOTIF={$mac}'
|
|
ifname - Specify a interfacename<->mac pair, it will set the interfacename to the interface which has the <mac>. Format 'ifname=$ifname:$mac'
|
|
# This will only be generated when linuximage.nodebootif is set.
|
|
bootdev - Specify the boot device. Mostly it's used with <ip> parameter and when there are multiple <ip> params. Format 'bootdev={$mac|$ifname}
|
|
ip - Specify the network configuration for an interface. Format: 'ip=dhcp', 'ip=$ifname:dhcp'
|
|
|
|
netdevice - Specify network device for Linuxrc (Suse bootloader). Format: 'netdevice={$mac|$nicname}'
|
|
|
|
netdev - Specify the interfacename which is used by xCAT diskless boot script to select the network interface. Format: 'netdev=$nicname'
|
|
|
|
Reference:
|
|
Redhat anaconda doc: https://github.com/rhinstaller/anaconda/blob/master/docs/boot-options.txt
|
|
Suse Linuxrc do: https://en.opensuse.org/SDB:Linuxrc
|
|
|
|
Arguments:
|
|
$installnic <- node.installnic
|
|
$primarynic <- node.primarynic
|
|
$macmac <- node.mac
|
|
$nodebootif <- linuximage.nodebootif
|
|
|
|
Returns:
|
|
$net_params - The key will be the parameter name, the value for the key will be the parameter value.
|
|
Valid Parameter Name:
|
|
ksdevice
|
|
netdev
|
|
netdevice
|
|
ip
|
|
ifname
|
|
BOOTIF
|
|
|
|
And following two keys also will be returned for reference
|
|
mac
|
|
nicname
|
|
|
|
Example:
|
|
my $netparams = xCAT::NetworkUtils->gen_net_boot_params($installnic, $primmarynic, $macmac, $nodebootif);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
sub gen_net_boot_params
|
|
{
|
|
my $class = shift;
|
|
my $installnic = shift;
|
|
my $primarynic = shift;
|
|
my $macmac = shift;
|
|
my $nodebootif = shift;
|
|
|
|
my $net_params;
|
|
|
|
# arbitrary use primarynic if installnic is not set
|
|
unless ($installnic) {
|
|
$installnic = $primarynic;
|
|
}
|
|
|
|
# just use the installnic to generate the nic related kernel parameters
|
|
my $mac;
|
|
my $nicname;
|
|
|
|
if ((! defined ($installnic)) || ($installnic eq "") || ($installnic =~ /^mac$/i)) {
|
|
$mac = $macmac;
|
|
$net_params->{mac} = $mac;
|
|
} elsif ($installnic =~ /^[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}$/) {
|
|
$mac = $installnic;
|
|
$net_params->{mac} = $mac;
|
|
$net_params->{setmac} = $mac;
|
|
} else {
|
|
$mac = $macmac;
|
|
$nicname = $installnic;
|
|
$net_params->{nicname} = $nicname;
|
|
$net_params->{mac} = $mac;
|
|
}
|
|
if ($nicname) {
|
|
$net_params->{ksdevice} = "ksdevice=$nicname";
|
|
$net_params->{ip} = "ip=$nicname:dhcp";
|
|
$net_params->{netdev} = "netdev=$nicname";
|
|
$net_params->{netdevice} = "netdevice=$nicname";
|
|
$net_params->{ifname} = "ifname=$nicname:$mac";
|
|
} elsif ($mac) {
|
|
$net_params->{ksdevice} = "ksdevice=$mac";
|
|
$net_params->{BOOTIF} = "BOOTIF=$mac";
|
|
$net_params->{bootdev} = "bootdev=$mac";
|
|
$net_params->{ip} = "ip=dhcp";
|
|
if ($nodebootif) {
|
|
$net_params->{ifname} = "ifname=$nodebootif:$mac";
|
|
}
|
|
$net_params->{netdevice} = "netdevice=$mac";
|
|
}
|
|
|
|
return $net_params;
|
|
}
|
|
|
|
1;
|