2010-05-07 01:58:02 +00:00
#!/usr/bin/env perl
# IBM(c) 2010 EPL license http://www.eclipse.org/legal/epl-v10.html
2010-05-07 01:59:49 +00:00
package xCAT::NetworkUtils ;
2010-05-07 01:58:02 +00:00
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 ) {
2012-08-08 17:27:50 +00:00
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 ) ) ;
2010-05-07 01:58:02 +00:00
}
use lib "$::XCATROOT/lib/perl" ;
use POSIX qw( ceil ) ;
use File::Path ;
2011-01-17 19:17:38 +00:00
use Math::BigInt ;
2010-05-07 01:58:02 +00:00
use Socket ;
2012-08-23 04:21:28 +00:00
use xCAT::GlobalDef ;
2010-05-07 01:58:02 +00:00
use strict ;
use warnings "all" ;
2010-08-26 15:46:11 +00:00
my $ socket6support = eval { require Socket6 } ;
2010-05-07 01:58:02 +00:00
our @ ISA = qw( Exporter ) ;
2011-01-17 19:17:38 +00:00
our @ EXPORT_OK = qw( getipaddr ) ;
2012-08-09 03:48:50 +00:00
my $ utildata ; #data to persist locally
2010-05-07 01:58:02 +00:00
#--------------------------------------------------------------------------------
= head1 xCAT:: NetworkUtils
= head2 Package Description
This program module file , is a set of network utilities used by xCAT commands .
= cut
#-------------------------------------------------------------
2012-08-23 16:56:08 +00:00
#-------------------------------------------------------------------------------
= 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 $ callback = shift ;
my @ nodelist = @$ nodes ;
my % nodedomains ;
# Get the network info for each node
my % nethash = xCAT::DBobjUtils - > getNetwkInfo ( \ @ nodelist , $ callback ) ;
if ( ! ( % nethash ) && $ ::VERBOSE )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Could not get xCAT network definitions for one or more nodes.\n" ;
xCAT::MsgUtils - > message ( "W" , $ rsp , $ callback ) ;
}
# get the site domain value
my @ domains = xCAT::TableUtils - > get_site_attribute ( "domain" ) ;
my $ sitedomain = $ domains [ 0 ] ;
if ( ! $ sitedomain && $ ::VERBOSE )
{
my $ rsp ;
push @ { $ rsp - > { data } } , "Cannot get a domain value from the cluster site definition.\n" ;
xCAT::MsgUtils - > message ( "W" , $ rsp , $ callback ) ;
}
# for each node - set hash value to network domain or default
# to site domain
foreach my $ node ( @ nodelist ) {
if ( $ nethash { $ node } { domain } ) {
$ nodedomains { $ node } = $ nethash { $ node } { domain } ;
} else {
$ nodedomains { $ node } = $ sitedomain ;
}
}
return \ % nodedomains ;
}
2010-05-07 01:58:02 +00:00
#-------------------------------------------------------------------------------
= 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:
2010-05-13 11:59:49 +00:00
my ( $ host , $ ip ) = xCAT::NetworkUtils - > gethostnameandip ( $ iporhost ) ;
2010-05-07 01:58:02 +00:00
Comments:
none
= cut
#-------------------------------------------------------------------------------
sub gethostnameandip ()
{
my ( $ class , $ iporhost ) = @ _ ;
if ( ( $ iporhost =~ /\d+\.\d+\.\d+\.\d+/ ) || ( $ iporhost =~ /:/ ) ) #ip address
{
2010-05-07 02:53:44 +00:00
return ( xCAT::NetworkUtils - > gethostname ( $ iporhost ) , $ iporhost ) ;
2010-05-07 01:58:02 +00:00
}
else #hostname
{
2010-05-07 02:53:44 +00:00
return ( $ iporhost , xCAT::NetworkUtils - > getipaddr ( $ iporhost ) ) ;
2010-05-07 01:58:02 +00:00
}
}
#-------------------------------------------------------------------------------
= 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:
2010-05-07 02:53:44 +00:00
my $ host = xCAT::NetworkUtils - > gethostname ( $ ip ) ;
2010-05-07 01:58:02 +00:00
Comments:
none
= cut
#-------------------------------------------------------------------------------
sub gethostname ()
{
my ( $ class , $ iporhost ) = @ _ ;
2010-09-29 21:12:51 +00:00
if ( ! defined ( $ iporhost ) )
{
return undef ;
}
2010-09-25 03:08:46 +00:00
2010-09-29 21:12:51 +00:00
if ( ref ( $ iporhost ) eq 'ARRAY' )
{
2010-05-11 14:03:58 +00:00
$ iporhost = @ { $ iporhost } [ 0 ] ;
if ( ! $ iporhost )
{
return undef ;
}
2010-09-29 21:12:51 +00:00
}
2010-05-11 14:03:58 +00:00
2010-05-07 01:58:02 +00:00
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
{
2011-01-26 15:43:26 +00:00
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
2010-05-07 09:56:01 +00:00
my $ host = ( Socket6:: getnameinfo ( $ ip ) ) [ 0 ] ;
2010-05-07 01:58:02 +00:00
if ( $ host eq $ iporhost ) # can not resolve
{
return undef ;
}
if ( $ host )
{
$ host =~ s/\..*// ; #short hostname
}
return $ host ;
}
else
{
2010-05-14 01:36:40 +00:00
#it is possible that no Socket6 available,
#but passing in IPv6 address, such as ::1 on loopback
if ( $ iporhost =~ /:/ )
{
return undef ;
}
2010-05-07 01:58:02 +00:00
my $ hostname = gethostbyaddr ( inet_aton ( $ iporhost ) , AF_INET ) ;
2010-12-14 13:34:10 +00:00
if ( $ hostname ) {
$ hostname =~ s/\..*// ; #short hostname
}
2010-05-07 01:58:02 +00:00
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
2011-01-17 19:17:38 +00:00
Optional:
GetNumber = > 1 ( return the address as a BigInt instead of readable string )
2010-05-07 01:58:02 +00:00
Returns: ip address
Globals:
cache: % ::hostiphash
Error:
none
Example:
2010-05-07 02:53:44 +00:00
my $ ip = xCAT::NetworkUtils - > getipaddr ( $ hostname ) ;
2010-05-07 01:58:02 +00:00
Comments:
none
= cut
#-------------------------------------------------------------------------------
2011-01-17 19:17:38 +00:00
sub getipaddr
2010-05-07 01:58:02 +00:00
{
2011-01-17 19:17:38 +00:00
my $ iporhost = shift ;
if ( $ iporhost eq 'xCAT::NetworkUtils' ) { #was called with -> syntax
$ iporhost = shift ;
}
my % extraarguments = @ _ ;
2010-05-07 01:58:02 +00:00
2010-09-25 03:08:46 +00:00
if ( ! defined ( $ iporhost ) )
{
return undef ;
}
2010-05-11 14:03:58 +00:00
if ( ref ( $ iporhost ) eq 'ARRAY' )
{
$ iporhost = @ { $ iporhost } [ 0 ] ;
if ( ! $ iporhost )
{
return undef ;
}
}
2010-05-07 01:58:02 +00:00
2011-01-17 19:17:38 +00:00
#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;
#}
2010-05-07 01:58:02 +00:00
#cache, do not lookup DNS each time
2010-09-29 21:12:51 +00:00
if ( $ ::hostiphash and defined ( $ ::hostiphash { $ iporhost } ) && $ ::hostiphash { $ iporhost } )
2010-05-07 01:58:02 +00:00
{
return $ ::hostiphash { $ iporhost } ;
}
else
{
if ( $ socket6support ) # the getaddrinfo and getnameinfo supports both IPv4 and IPv6
{
2011-01-26 15:43:26 +00:00
my @ returns ;
2011-01-26 15:44:42 +00:00
my $ reqfamily = AF_UNSPEC ;
2011-01-26 15:43:26 +00:00
if ( $ extraarguments { OnlyV6 } ) {
2011-01-26 15:44:42 +00:00
$ reqfamily = AF_INET6 ;
2011-01-26 15:43:26 +00:00
} elsif ( $ extraarguments { OnlyV4 } ) {
2011-01-26 15:44:42 +00:00
$ reqfamily = AF_INET ;
2011-01-26 15:43:26 +00:00
}
2011-01-26 15:44:42 +00:00
my @ addrinfo = Socket6:: getaddrinfo ( $ iporhost , 0 , $ reqfamily , SOCK_STREAM , 6 ) ;
2011-01-26 15:43:26 +00:00
my ( $ family , $ socket , $ protocol , $ ip , $ name ) = splice ( @ addrinfo , 0 , 5 ) ;
while ( $ ip )
2010-05-07 01:58:02 +00:00
{
2011-01-17 19:17:38 +00:00
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 ( $ _ ) ;
}
2011-01-26 15:43:26 +00:00
push ( @ returns , $ bignumber ) ;
} else {
push @ returns , ( Socket6:: getnameinfo ( $ ip , Socket6:: NI_NUMERICHOST ( ) ) ) [ 0 ] ;
}
2011-01-26 15:44:42 +00:00
if ( scalar @ addrinfo and $ extraarguments { GetAllAddresses } ) {
2011-01-26 15:43:26 +00:00
( $ family , $ socket , $ protocol , $ ip , $ name ) = splice ( @ addrinfo , 0 , 5 ) ;
2011-01-17 19:17:38 +00:00
} else {
2011-01-26 15:43:26 +00:00
$ ip = 0 ;
2011-01-17 19:17:38 +00:00
}
2010-05-07 01:58:02 +00:00
}
2011-01-26 16:07:01 +00:00
unless ( $ extraarguments { GetAllAddresses } ) {
return $ returns [ 0 ] ;
}
2011-01-26 15:43:26 +00:00
return @ returns ;
2010-05-07 01:58:02 +00:00
}
else
{
2010-05-11 14:03:58 +00:00
#return inet_ntoa(inet_aton($iporhost))
2010-05-14 01:36:40 +00:00
#TODO, what if no scoket6 support, but passing in a IPv6 hostname?
2011-07-28 17:09:24 +00:00
if ( $ iporhost =~ /:/ ) { #ipv6
2011-08-11 14:13:46 +00:00
return undef ;
#die "Attempt to process IPv6 address, but system does not have requisite IPv6 perl support";
2011-07-28 17:09:24 +00:00
}
2010-09-29 21:12:51 +00:00
my $ packed_ip ;
$ iporhost and $ packed_ip = inet_aton ( $ iporhost ) ;
2010-05-11 14:03:58 +00:00
if ( ! $ packed_ip )
{
return undef ;
}
2011-01-17 19:17:38 +00:00
if ( $ extraarguments { GetNumber } ) { #only 32 bits, no for loop needed.
return Math::BigInt - > new ( unpack ( "N*" , $ packed_ip ) ) ;
}
2010-05-11 14:03:58 +00:00
return inet_ntoa ( $ packed_ip ) ;
2010-05-07 01:58:02 +00:00
}
}
}
#-------------------------------------------------------------------------------
= 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:
2010-05-07 02:53:44 +00:00
my $ linklocaladdr = xCAT::NetworkUtils - > linklocaladdr ( $ mac ) ;
2010-05-07 01:58:02 +00:00
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" ) ;
2010-05-27 07:40:10 +00:00
#my $bit = (int $m1) & 2;
#if ($bit) {
# $m1 = $m1 - 2;
#} else {
# $m1 = $m1 + 2;
#}
$ m1 = hex ( $ m1 ) ;
$ m1 = $ m1 ^ 2 ;
$ m1 = sprintf ( "%x" , $ m1 ) ;
2010-05-07 01:58:02 +00:00
$ 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 ;
}
2010-05-07 03:49:05 +00:00
2010-05-07 01:58:02 +00:00
#-------------------------------------------------------------------------------
= 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:
2010-05-07 02:53:44 +00:00
if ( xCAT::NetworkUtils - > ishostinsubnet ( $ ip , $ netmask , $ subnet ) ;
2010-05-07 01:58:02 +00:00
Comments:
none
= cut
#-------------------------------------------------------------------------------
sub ishostinsubnet {
2010-05-07 03:49:05 +00:00
my ( $ class , $ ip , $ mask , $ subnet ) = @ _ ;
2011-01-17 19:54:25 +00:00
my $ numbits = 32 ;
if ( $ ip =~ /:/ ) { #ipv6
$ numbits = 128 ;
}
if ( $ mask ) {
2012-04-14 16:09:38 +00:00
if ( $ mask =~ /\// ) {
$ mask =~ s/^\/// ;
$ mask = Math::BigInt - > new ( "0b" . ( "1" x $ mask ) . ( "0" x ( $ numbits - $ mask ) ) ) ;
} else {
$ mask = getipaddr ( $ mask , GetNumber = > 1 ) ;
}
2011-01-17 19:54:25 +00:00
} else { #CIDR notation supported
2011-01-17 20:24:28 +00:00
if ( $ subnet =~ /\// ) {
( $ subnet , $ mask ) = split /\// , $ subnet , 2 ;
2011-01-17 19:54:25 +00:00
$ 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" ;
}
}
$ ip = getipaddr ( $ ip , GetNumber = > 1 ) ;
2011-01-17 20:24:28 +00:00
$ subnet = getipaddr ( $ subnet , GetNumber = > 1 ) ;
2011-01-17 19:54:25 +00:00
$ ip & = $ mask ;
2012-02-21 03:09:35 +00:00
if ( $ ip && $ subnet && ( $ ip == $ subnet ) ) {
2011-01-17 19:54:25 +00:00
return 1 ;
} else {
return 0 ;
2010-05-07 01:58:02 +00:00
}
}
2010-05-27 15:13:26 +00:00
#-----------------------------------------------------------------------------
= 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` ;
} else {
`echo "net.ipv4.ip_forward = $enable" >> $conf_file` ;
}
2012-02-09 11:36:25 +00:00
`sysctl -e -p $conf_file` ; # workaround for redhat bug 639821
2010-05-27 15:13:26 +00:00
}
else
2010-06-01 14:27:13 +00:00
{
`no -o ipforwarding=$enable` ;
2010-05-27 15:13:26 +00:00
}
return 0 ;
}
2010-06-17 07:18:00 +00:00
#-------------------------------------------------------------------------------
= 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 ;
}
2011-01-17 19:54:25 +00:00
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 ;
2010-06-17 07:18:00 +00:00
return $ mask ;
}
2011-02-24 03:15:01 +00:00
#-------------------------------------------------------------------------------
= 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 ;
}
2012-08-09 03:48:50 +00:00
my $ fmask = xCAT::NetworkUtils:: formatNetmask ( $ mask , 0 , 1 ) ;
2011-02-24 03:15:01 +00:00
2012-08-09 03:48:50 +00:00
my $ localnets = xCAT::NetworkUtils - > my_nets ( ) ;
2011-02-24 03:15:01 +00:00
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 ;
}
2011-10-18 06:30:26 +00:00
#-------------------------------------------------------------------------------
= 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
#-------------------------------------------------------------------------------
2011-02-24 03:15:01 +00:00
2011-09-18 15:30:41 +00:00
sub get_nic_ip
{
my $ nic ;
my % iphash ;
my $ cmd = "ifconfig -a" ;
my $ result = `$cmd` ;
my $ mode = "MULTICAST" ;
#############################################
# Error running command
#############################################
if ( ! $ result ) {
return undef ;
}
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: ...
#
##############################################################
2011-10-19 09:08:01 +00:00
my @ adapter = split /(\w+\d+):\s+flags=/ , $ result ;
2011-09-18 15:30:41 +00:00
foreach ( @ adapter ) {
2011-10-19 09:08:01 +00:00
if ( $ _ =~ /^(en\d)/ ) {
$ nic = $ 1 ;
next ;
}
2011-09-18 15:30:41 +00:00
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 {
##############################################################
# Should look like this for Linux:
# eth0 Link encap:Ethernet HWaddr 00:02:55:7B:06:30
# inet addr:9.114.154.193 Bcast:9.114.154.223
# inet6 addr: fe80::202:55ff:fe7b:630/64 Scope:Link
# UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
# RX packets:1280982 errors:0 dropped:0 overruns:0 frame:0
# TX packets:3535776 errors:0 dropped:0 overruns:0 carrier:0
# collisions:0 txqueuelen:1000
# RX bytes:343489371 (327.5 MiB) TX bytes:870969610 (830.6 MiB)
# Base address:0x2600 Memory:fbfe0000-fc0000080
#
# eth1 ...
#
##############################################################
my @ adapter = split /\n{2,}/ , $ result ;
foreach ( @ adapter ) {
if ( ! ( $ _ =~ /LOOPBACK / ) and
$ _ =~ /UP / and
$ _ =~ /$mode / ) {
my @ ip = split /\n/ ;
for my $ ent ( @ ip ) {
2012-02-07 13:02:53 +00:00
if ( $ ent =~ /^(eth\d|ib\d|hf\d)\s+/ ) {
2011-09-18 15:30:41 +00:00
$ nic = $ 1 ;
}
if ( $ ent =~ /^\s*inet addr:\s*(\d+\.\d+\.\d+\.\d+)/ ) {
$ iphash { $ nic } = $ 1 ;
next ;
}
}
}
}
}
return \ % iphash ;
}
2012-08-09 03:48:50 +00:00
#-------------------------------------------------------------------------------
= 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:
2012-08-16 07:03:02 +00:00
xCAT::NetworkUtils - > my_hexnets
2012-08-09 03:48:50 +00:00
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:
2012-08-16 07:03:02 +00:00
xCAT::NetworkUtils - > my_ip_facing
2012-08-09 03:48:50 +00:00
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` ;
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 ) )
{
return $ curnet ;
}
}
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:
2012-08-16 07:03:02 +00:00
xCAT::NetworkUtils - > nodeonmynet
2012-08-09 03:48:50 +00:00
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:
2012-08-16 07:03:02 +00:00
xCAT::NetworkUtils - > thishostisnot
2012-08-09 03:48:50 +00:00
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_ips
{
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 ] ;
}
}
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 ;
}
#-------------------------------------------------------------------------------
= 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 getFacingIP
Gets the ip address of the adapter of the localhost that is facing the
the given node .
Assume it is the same as my_ip_facing ...
Arguments:
The name of the node that is facing the localhost .
Returns:
The ip address of the adapter that faces the node .
= cut
#-------------------------------------------------------------------------------
sub getFacingIP
{
my ( $ class , $ node ) = @ _ ;
my $ ip ;
my $ cmd ;
my @ ipaddress ;
my $ nodeip = inet_ntoa ( inet_aton ( $ node ) ) ;
unless ( $ nodeip =~ /\d+\.\d+\.\d+\.\d+/ )
{
return 0 ; #Not supporting IPv6 here IPV6TODO
}
$ 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 ;
}
# split node address
my ( $ n1 , $ n2 , $ n3 , $ n4 ) = split ( '\.' , $ nodeip ) ;
foreach my $ addr ( @ result )
{
my $ ip ;
my $ mask ;
if ( xCAT::Utils - > isLinux ( ) )
{
my ( $ inet , $ addr1 , $ Bcast , $ Mask ) = split ( " " , $ addr ) ;
if ( ( ! $ addr1 ) || ( ! $ Mask ) ) { next ; }
my @ ips = split ( ":" , $ addr1 ) ;
my @ masks = split ( ":" , $ Mask ) ;
$ ip = $ ips [ 1 ] ;
$ mask = $ masks [ 1 ] ;
}
else
{ #AIX
my ( $ inet , $ addr1 , $ netmask , $ mask1 , $ Bcast , $ bcastaddr ) =
split ( " " , $ addr ) ;
if ( ( ! $ addr1 ) && ( ! $ mask1 ) ) { next ; }
$ ip = $ addr1 ;
$ mask1 =~ s/0x// ;
$ mask =
`printf "%d.%d.%d.%d" \$(echo "$mask1" | sed 's/../0x& /g')` ;
}
if ( $ ip && $ mask )
{
# split interface IP
my ( $ h1 , $ h2 , $ h3 , $ h4 ) = split ( '\.' , $ ip ) ;
# split mask
my ( $ m1 , $ m2 , $ m3 , $ m4 ) = split ( '\.' , $ mask ) ;
# AND this interface IP with the netmask of the network
my $ a1 = ( ( int $ h1 ) & ( int $ m1 ) ) ;
my $ a2 = ( ( int $ h2 ) & ( int $ m2 ) ) ;
my $ a3 = ( ( int $ h3 ) & ( int $ m3 ) ) ;
my $ a4 = ( ( int $ h4 ) & ( int $ m4 ) ) ;
# AND node IP with the netmask of the network
my $ b1 = ( ( int $ n1 ) & ( int $ m1 ) ) ;
my $ b2 = ( ( int $ n2 ) & ( int $ m2 ) ) ;
my $ b3 = ( ( int $ n3 ) & ( int $ m3 ) ) ;
my $ b4 = ( ( int $ n4 ) & ( int $ m4 ) ) ;
if ( ( $ b1 == $ a1 ) && ( $ b2 == $ a2 ) && ( $ b3 == $ a3 ) && ( $ b4 == $ a4 ) )
{
return $ ip ;
}
}
}
xCAT::MsgUtils - > message ( "S" , "Cannot find master for the node $node\n" ) ;
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 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 ;
my $ nets = xCAT::NetworkUtils:: my_nets ( ) ;
my $ ip = xCAT::NetworkUtils - > getipaddr ( $ node ) ;
my $ mask = undef ;
for my $ net ( keys %$ nets )
{
my $ netname ;
( $ netname , $ mask ) = split /\// , $ net ;
last if ( xCAT::NetworkUtils:: isInSameSubnet ( $ netname , $ ip , $ mask , 1 ) ) ;
}
return ( $ ip , $ node , undef , xCAT::NetworkUtils:: formatNetmask ( $ mask , 1 , 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 ;
}
2012-08-23 04:21:28 +00:00
#--------------------------------------------------------------------------------
= head3 pingNodeStatus
This function takes an array of nodes and returns their status using 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 = ( ) ;
if ( ( @ mon_nodes ) && ( @ mon_nodes > 0 ) ) {
#get all the active nodes
my $ nodes = join ( ' ' , @ mon_nodes ) ;
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 ;
return % status ;
}
2010-05-07 01:58:02 +00:00
1 ;