git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/branches/2.8@15197 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			2347 lines
		
	
	
		
			62 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2347 lines
		
	
	
		
			62 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 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) {
 | 
						|
		if ($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;
 | 
						|
    }
 | 
						|
    # IPv6 subnet with netmask postfix like /64
 | 
						|
    if ($subnet && ($subnet =~ /\//))
 | 
						|
    {
 | 
						|
        $subnet =~ s/\/.*$//;
 | 
						|
    }
 | 
						|
    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";
 | 
						|
        }
 | 
						|
    }
 | 
						|
    $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 $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: ...
 | 
						|
        #
 | 
						|
        ##############################################################
 | 
						|
        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 {
 | 
						|
        ##############################################################
 | 
						|
        # 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 ) {
 | 
						|
                    if ($ent =~ /^(eth\d|ib\d|hf\d)\s+/) {
 | 
						|
                        $nic = $1;
 | 
						|
                    }    
 | 
						|
                    if ( $ent =~ /^\s*inet addr:\s*(\d+\.\d+\.\d+\.\d+)/ ) {
 | 
						|
                        $iphash{$nic} = $1; 
 | 
						|
                        next;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    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:
 | 
						|
        xCAT::NetworkUtils->my_ip_facing
 | 
						|
    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:
 | 
						|
        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_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;
 | 
						|
}
 | 
						|
 | 
						|
#--------------------------------------------------------------------------------
 | 
						|
=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;
 | 
						|
	    }	 
 | 
						|
	    open (NMAP, "nmap -PE --system-dns --send-ip -sP ". $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 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;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
1;
 |