#!/usr/bin/env perl # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html package xCAT_plugin::switchdiscover; BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; } use lib "$::XCATROOT/lib/perl"; use Getopt::Long; use xCAT::Usage; use xCAT::NodeRange; use xCAT::NetworkUtils; use xCAT::Utils; use XML::Simple; no strict; use Data::Dumper; use Socket; #global variables for this module my %globalopt; my @filternodes; my @iprange; my %global_scan_type = ( nmap => "nmap_scan", lldp => "lldp_scan", snmp => "snmp_scan" ); my %global_switch_type = ( Juniper => "Juniper", Cisco => "Cisco", BNT => "BNT", Mellanox => "Mellanox" ); #------------------------------------------------------------------------------- =head1 xCAT_plugin:switchdiscover =head2 Package Description Handles switch discovery functions. It uses lldp, nmap or snmap to scan the network to find out the switches attached to the network. =cut #------------------------------------------------------------------------------- #-------------------------------------------------------------------------------- =head3 send_msg Invokes the callback with the specified message Arguments: request: request structure for plguin calls ecode: error code. 0 for succeful. msg: messages to be displayed. Returns: none =cut #-------------------------------------------------------------------------------- sub send_msg { my $request = shift; my $ecode = shift; my $msg = shift; my %output; ################################################# # Called from child process - send to parent ################################################# if ( exists( $request->{pipe} )) { my $out = $request->{pipe}; $output{errorcode} = $ecode; $output{data} = \@_; print $out freeze( [\%output] ); print $out "\nENDOFFREEZE6sK4ci\n"; } ################################################# # Called from parent - invoke callback directly ################################################# elsif ( exists( $request->{callback} )) { my $callback = $request->{callback}; $output{errorcode} = $ecode; $output{data} = $msg; $callback->( \%output ); } } #-------------------------------------------------------------------------------- =head3 handled_commands It returns a list of commands handled by this plugin. Arguments: none Returns: a list of commands. =cut #-------------------------------------------------------------------------------- sub handled_commands { return( {switchdiscover=>"switchdiscover"} ); } #-------------------------------------------------------------------------------- =head3 parse_args Parse the command line options and operands. Arguments: request: the request structure for plugin Returns: Usage string or error message. 0 if no user promp needed. =cut #-------------------------------------------------------------------------------- sub parse_args { my $request = shift; my $args = $request->{arg}; my $cmd = $request->{command}; my %opt; ############################################# # Responds with usage statement ############################################# local *usage = sub { my $usage_string = xCAT::Usage->getUsage($cmd); return( [$_[0], $usage_string] ); }; ############################################# # No command-line arguments - use defaults ############################################# if ( !defined( $args )) { return(0); } ############################################# # Checks case in GetOptions, allows opts # to be grouped (e.g. -vx), and terminates # at the first unrecognized option. ############################################# @ARGV = @$args; $Getopt::Long::ignorecase = 0; Getopt::Long::Configure( "bundling" ); ############################################# # Process command-line flags ############################################# if (!GetOptions( \%opt, qw(h|help V|Verbose v|version x z w r n range=s s=s))) { return( usage() ); } ############################################# # Check for node range ############################################# if ( scalar(@ARGV) eq 1 ) { my @nodes = xCAT::NodeRange::noderange( @ARGV ); if (nodesmissed) { return (usage( "The following nodes are not defined in xCAT DB:\n " . join(',', nodesmissed))); } foreach (@nodes) { push @filternodes, $_; } unless (@filternodes) { return(usage( "Invalid Argument: $ARGV[0]" )); } if ( exists( $opt{range} )) { return(usage( "--range flag cannot be used with noderange." )); } } elsif ( scalar(@ARGV) > 1 ) { return(usage( "Invalid flag, please check and retry." )); } ############################################# # Option -V for verbose output ############################################# if ( exists( $opt{V} )) { $globalopt{verbose} = 1; } ############################################# # Check for mutually-exclusive formatting ############################################# if ( (exists($opt{r}) + exists($opt{x}) + exists($opt{z}) ) > 1 ) { return( usage() ); } ############################################# # Check for unsupported scan types ############################################# if ( exists( $opt{s} )) { my @stypes = split ',', $opt{s}; my $error; foreach my $st (@stypes) { if (! exists($global_scan_type{$st})) { $error = $error . "Invalide scan type: $st\n"; } } if ($error) { return usage($error); } $globalopt{scan_types} = \@stypes; } ############################################# # Check the --range ip range option ############################################# if ( exists( $opt{range} )) { $globalopt{range} = $opt{range}; my @ips = split /,/, $opt{range}; foreach my $ip (@ips) { if (($ip =~ /^(\d{1,3})(-\d{1,3})?\.(\d{1,3})(-\d{1,3})?\.(\d{1,3})(-\d{1,3})?\.(\d{1,3})(-\d{1,3})?$/) || ($ip =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d+)$/)) { push @iprange, $ip; } else { return usage("Invalid ip or ip range specified: $ip."); } } } ############################################# # write to the database ############################################# if ( exists( $opt{w} )) { $globalopt{w} = 1; } ############################################# # list the raw information ############################################# if ( exists( $opt{r} )) { $globalopt{r} = 1; } ############################################# # list the xml formate data ############################################# if ( exists( $opt{x} )) { $globalopt{x} = 1; } ############################################# # list the stanza formate data ############################################# if ( exists( $opt{z} )) { $globalopt{z} = 1; } ######################################################### # only list the nodes that discovered for the first time ######################################################### if ( exists( $opt{n} )) { $globalopt{n} = 1; } return; } #-------------------------------------------------------------------------------- =head3 preprocess_request Parse the arguments and display the usage or the version string. =cut #-------------------------------------------------------------------------------- sub preprocess_request { my $req = shift; if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; } my $callback=shift; my $command = $req->{command}->[0]; my $extrargs = $req->{arg}; my @exargs=($req->{arg}); if (ref($extrargs)) { @exargs=@$extrargs; } my $usage_string=xCAT::Usage->parseCommand($command, @exargs); if ($usage_string) { $callback->({data=>[$usage_string]}); $req = {}; return; } my @result = (); my $mncopy = {%$req}; push @result, $mncopy; return \@result; } #-------------------------------------------------------------------------------- =head3 process_request Pasrse the arguments and call the correspondent functions to do switch discovery. =cut #-------------------------------------------------------------------------------- sub process_request { my $req = shift; my $callback = shift; my $sub_req = shift; ########################################### # Build hash to pass around ########################################### my %request; $request{arg} = $req->{arg}; $request{callback} = $callback; $request{command} = $req->{command}->[0]; #################################### # Process command-specific options #################################### my $result = parse_args( \%request ); #################################### # Return error #################################### if ( ref($result) eq 'ARRAY' ) { send_msg( \%request, 1, @$result ); return(1); } # call the relavant functions to start the scan my @scan_types = ("nmap"); if (exists($globalopt{scan_types})) { @scan_types = @{$globalopt{scan_types}}; } my $all_result; foreach my $st (@scan_types) { no strict; my $fn = $global_scan_type{$st}; my $tmp_result = &$fn(\%request, $callback); if (ref($tmp_result) eq 'HASH') { $all_result->{$st} = $tmp_result; } } #consolidate the results by merging the swithes with the same ip or same mac #or same hostname my $result; my $merged; my $counter=0; foreach my $st (keys %$all_result) { my $tmp_result = $all_result->{$st}; #send_msg( \%request, 1, Dumper($tmp_result)); foreach my $old_mac (keys %$tmp_result) { $same = 0; foreach my $new_mac (keys %$result) { my $old_ip = $tmp_result->{$old_mac}->{ip}; my $old_name = $tmp_result->{$old_mac}->{name}; my $old_vendor = $tmp_result->{$old_mac}->{vendor}; my $new_ip = $result->{$new_mac}->{ip}; my $new_name = $result->{$new_mac}->{name}; my $new_vendor = $result->{$new_mac}->{vendor}; if (($old_mac eq $new_mac) || ($old_ip && ($old_ip eq $new_ip)) || ($old_name && ($old_name eq $new_name))) { $same = 1; my $key =$new_mac; if ($new_mac =~ /nomac/) { if ($old_mac =~ /nomac/) { $key = "nomac_$counter"; $counter++; } else { $key = $old_mac; } } if ($old_name) { $result->{$key}->{name} = $old_name; } if ($old_ip) { $result->{$key}->{ip} = $old_ip; } $result->{$key}->{vendor} = $new_vendor; if ($old_vendor) { if ($old_vendor ne $new_vendor) { $result->{$key}->{vendor} .= " " . $old_vendor; } else { $result->{$key}->{vendor} = $old_vendor; } } if ($key ne $new_mac) { delete $result->{$new_mac}; } } } if (!$same) { $result->{$old_mac} = $tmp_result->{$old_mac}; } } } if (!($result)) { send_msg( \%request, 0, " No switch found "); return; } my $display_done = 0; if (exists($globalopt{r})) { #do nothing since is done by the scan functions. $display_done = 1; } if (exists($globalopt{x})) { send_msg( \%request, 0, format_xml( $result )); $display_done = 1; } if (exists($globalopt{z})) { my $stanza_output = format_stanza( $result ); send_msg( \%request, 0, $stanza_output ); $display_done = 1; } if (!$display_done) { #display header $format = "%-12s\t%-18s\t%-20.20s\t%-12s"; $header = sprintf $format, "ip", "name","vendor", "mac"; send_msg(\%request, 0, $header); my $sep = "------------"; send_msg(\%request, 0, sprintf($format, $sep, $sep, $sep, $sep )); #display switches one by one foreach my $key (keys(%$result)) { my $ip = " "; my $vendor = " "; my $mac = " "; if (exists($result->{$key}->{ip})) { $ip = $result->{$key}->{ip}; } my $name = get_hostname($result->{$key}->{name}, $ip); if (exists($result->{$key}->{vendor})) { $vendor = $result->{$key}->{vendor}; } if ($key != /nomac/) { $mac = $key; } my $msg = sprintf $format, $ip, $name, $vendor, $key; send_msg(\%request, 0, $msg); } } # writes the data into xCAT db if (exists($globalopt{w})) { send_msg(\%request, 0, "Writing the data into xCAT DB...."); xCATdB($result, \%request, $sub_req); } return; } #-------------------------------------------------------------------------------- =head3 lldp_scan Use lldpd to scan the subnets to do switch discovery. Arguments: request: request structure with callback pointer. Returns: A hash containing the swithes discovered. Each element is a hash of switch attributes. For examples: { "AABBCCDDEEFA" =>{name=>"switch1", vendor=>"ibm", ip=>"10.1.2.3"}, "112233445566" =>{name=>"switch2", vendor=>"cisco", ip=>"11.4.5.6"} } returns 1 if there are errors occurred. =cut #-------------------------------------------------------------------------------- sub lldp_scan { my $request = shift; send_msg($request, 0, "Discovering switches using lldp..."); # get the PID of the currently running lldpd if it is running. if (exists($globalopt{verbose})) { send_msg($request, 0, "...Checking if lldpd is up and running:\n ps -ef | grep lldpd | grep -v grep | awk '{print \$2}'\n"); } my $pid; chomp($pid= `ps -ef | grep lldpd | grep -v grep | awk '{print \$2}'`); unless($pid){ my $dcmd = "lldpd -c -s -e -f"; #my $outref = xCAT::Utils->runcmd($dcmd, 0); #if ($::RUNCMD_RC != 0) #{ # send_msg($request, 1, "Could not start lldpd process. The command was: $dcmd" #); # return 1; #} #xCAT::Utils->runcmd("sleep 30"); send_msg($request, 1, "Warning: lldpd is not running. Please start it with the following flags:\n $dcmd\nThen wait a few minutes before running switchdiscover command again.\n"); return 1; } #now run the lldpcli to collect the data my $ccmd = "lldpcli show neighbors -f xml"; if (exists($globalopt{verbose})) { send_msg($request, 0, "...Discovering switches using lldpd:\n $ccmd\n"); } my $result = xCAT::Utils->runcmd($ccmd, 0); if ($::RUNCMD_RC != 0) { send_msg($request, 1, "Could not start lldpd process. The command was: $ccmd" ); return 1; } if (exists($globalopt{verbose})) { send_msg($request, 0, "$result\n"); } #display the raw output if (exists($globalopt{r})) { my $ccmd = "lldpcli show neighbors"; my $raw_result = xCAT::Utils->runcmd($ccmd, 0); if ($::RUNCMD_RC == 0) { send_msg($request, 0, "$raw_result\n\n"); } } if (exists($globalopt{verbose})) { send_msg($request, 0, "...Converting XML output to hash.\n"); } my $result_ref = XMLin($result, KeyAttr => 'interface', ForceArray => 1); my $switches; my $counter=0; if ($result_ref) { if (exists($result_ref->{interface})) { my $ref1 = $result_ref->{interface}; foreach my $interface (@$ref1) { if (exists($interface->{chassis})) { my $chassis = $interface->{chassis}->[0]; my $name = $chassis->{name}->[0]->{content}; my $ip = $chassis->{'mgmt-ip'}->[0]->{content}; # resolve the ip from name if (!$ip) { if ($name) { $ip = xCAT::NetworkUtils->getipaddr($name); } } my $id = $chassis->{id}->[0]->{content}; if (!$id) { $id="nomac_lldp_$counter"; $counter++; } my $desc = $chassis->{descr}->[0]->{content}; if ($desc) { $desc =~ s/\n/ /g; $desc =~ s/\"//g; } if ($id) { $switches->{$id}->{name} = $name; $switches->{$id}->{ip} = $ip; $switches->{$id}->{vendor} = $desc; } } } } } # filter out the uwanted entries if noderange or ip range is specified. if ((@filternodes> 0) || (@iprange>0)) { my $ranges = get_ip_ranges($request); if (exists($globalopt{verbose})) { send_msg($request, 0, "...Removing the switches that are not within the following ranges:\n @$ranges\n"); } foreach my $mac (keys %$switches) { my $ip_r = $switches->{$mac}->{ip}; $match = 0; foreach my $ip_f (@$ranges) { my ($net, $mask) = split '/', $ip_f; if ($mask) { #this is a subnet $mask = xCAT::NetworkUtils::formatNetmask($mask, 1, 0); if (xCAT::NetworkUtils->ishostinsubnet($ip_r, $mask, $net)) { $match = 1; last; } } else { #this is an ip if ($ip_r eq $net) { $match = 1; last; } #TODO: handles the case where the range is something like 10.2-3.4.5-6 } } if (!$match) { delete $switches->{$mac}; } } } return $switches } #-------------------------------------------------------------------------------- =head3 nmap_scan Use nmap to scan the subnets to do switch discovery. Arguments: request: request structure with callback pointer. Returns: A hash containing the swithes discovered. Each element is a hash of switch attributes. For examples: { "AABBCCDDEEFA" =>{name=>"switch1", vendor=>"ibm", ip=>"10.1.2.3"}, "112233445566" =>{name=>"switch2", vendor=>"cisco", ip=>"11.4.5.6"} } returns 1 if there are errors occurred. =cut #-------------------------------------------------------------------------------- sub nmap_scan { my $request = shift; my $ccmd; ################################################# # If --range options, take iprange, if noderange is defined # us the ip addresses of the nodes. If none is define, use the # subnets for all the interfaces. ################################################## my $ranges = get_ip_ranges($request); send_msg($request, 0, "Discovering switches using nmap for @$ranges. It may take long time..."); #warning the user if the range is too big foreach my $r (@$ranges) { if ($r =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d+)$/) { if ($5 < 24) { send_msg($request, 0, "You can modify the --range parameters to cut down the time.\n" ); last; } } } # handle ctrl-c $SIG{TERM} = $SIG{INT} = sub { #clean up the nmap processes my $nmap_pid = `ps -ef | grep nmap | grep -v grep | awk '{print \$2}'`; if ($nmap_pid) { system("kill -9 $nmap_pid >/dev/null 2>&1"); exit 0; } }; $ccmd = "/usr/bin/nmap -sP -oX - @$ranges"; if (exists($globalopt{verbose})) { send_msg($request, 0, "Process command: $ccmd\n"); } my $result = xCAT::Utils->runcmd($ccmd, 0); if ($::RUNCMD_RC != 0) { send_msg($request, 1, "Could not process this command: $ccmd" ); return 1; } ################################################# #display the raw output ################################################# if (exists($globalopt{r})) { send_msg($request, 0, "$result\n" ); } else { if (exists($globalopt{verbose})) { send_msg($request, 0, "$result\n" ); } } ################################################# #compose the switch hash ################################################# my $result_ref = XMLin($result, ForceArray => 1); my $switches; my $found; my $counter=0; if ($result_ref) { if (exists($result_ref->{host})) { my $host_ref = $result_ref->{host}; foreach my $host ( @$host_ref ) { my $ip; my $mac; if (exists($host->{address})) { my $addr_ref = $host->{address}; foreach my $addr ( @$addr_ref ) { my $type = $addr->{addrtype}; if ( $type ne "mac" ) { $ip = $addr->{addr}; $found = 0; } else { $mac = $addr->{addr}; } if (!$mac) { $mac="nomac_nmap_$counter"; $counter++; } if ($addr->{vendor}) { my $search_string = join '|', keys(%global_switch_type); if ($addr->{vendor} =~ /($search_string)/) { $switches->{$mac}->{ip} = $ip; $switches->{$mac}->{vendor} = $addr->{vendor}; $switches->{$mac}->{name} = $host->{hostname}; $found = 1; if (exists($globalopt{verbose})) { send_msg($request, 0, "FOUND Switch: ip=$ip, mac=$mac, vendor=$addr->{vendor}\n"); } } } ########################################################## # If there is no vendor or other than %global_switch_type, # issue the nmap again to do more aggresively discovery # Choose best guess from osscan # only search port 22 and 23 for fast performance ########################################################### if ( ($found == 0) && ($type eq "mac") ) { if (exists($globalopt{verbose})) { send_msg($request, 0, "*********************************"); send_msg($request, 0, "Couldn't find vendor info, use nmap osscan command to choose best guess"); } $ccmd = "/usr/bin/nmap -O --osscan-guess -A -p 22,23 -oX - $ip | grep osclass | grep -v embedded "; if (exists($globalopt{verbose})) { send_msg($request, 0, "Process command: $ccmd"); } my $os_result = xCAT::Utils->runcmd($ccmd, 0); if ($::RUNCMD_RC == 0) { if (exists($globalopt{verbose})) { send_msg($request, 0, "$os_result\n"); } my $os_vendor; my @lines = split /\n/ => $os_result; foreach my $line (@lines) { # pick the first one if found osclass type = switch if ($line =~ /switch/) { if ($line =~ /vendor=\"(\S*)\"/) { $os_vendor = $1; last; } } # if didn't find switch type, choose router as switch if ($line =~ /router/) { if ($line =~ /vendor=\"(\S*)\"/) { if (!($os_vendor)) { $os_vendor = $1; } } } } if ($os_vendor) { $switches->{$mac}->{ip} = $ip; $switches->{$mac}->{vendor} = $os_vendor; $switches->{$mac}->{name} = $host->{hostname}; $found = 1; if (exists($globalopt{verbose})) { send_msg($request, 0, "Choose best guess: ip=$ip, mac=$mac, vendor=$os_vendor"); send_msg($request, 0, "*********************************\n"); } } else { if (exists($globalopt{verbose})) { send_msg($request, 0, "ip=$ip, mac=$mac is not switch"); send_msg($request, 0, "*********************************\n"); } } } else { if (exists($globalopt{verbose})) { send_msg($request, 0, "ip=$ip, mac=$mac is not switch"); send_msg($request, 0, "*********************************\n"); } } } # end nmap osscan command } #end for each address } } #end for each host } } return $switches } #-------------------------------------------------------------------------------- =head3 snmp_scan Use lldpd to scan the subnets to do switch discovery. Arguments: request: request structure with callback pointer. Returns: A hash containing the swithes discovered. Each element is a hash of switch attributes. For examples: { "AABBCCDDEEFA" =>{name=>"switch1", vendor=>"ibm", ip=>"10.1.2.3"}, "112233445566" =>{name=>"switch2", vendor=>"cisco", ip=>"11.4.5.6"} } returns 1 if there are errors occurred. =cut #-------------------------------------------------------------------------------- sub snmp_scan { my $request = shift; send_msg($request, 0, "Discovering switches using snmp is not supported yet."); my $switches = { "AABBCCDDEEFA" =>{name=>"switch1", vendor=>"ibm", ip=>"10.1.2.3"}, "112233445566" =>{name=>"switch2", vendor=>"cisco", ip=>"11.4.5.6"} }; return 1; } #-------------------------------------------------------------------------------- =head3 get_hostname return hostname for the switch discovered Arguments: host: hostname passed by the switch after scan ip : IP address passed by the switch after scan Returns: hose: hostname of the switch if host is empty, try to lookup use ip address, otherwise format hostname as switch and ip combination. ex: switch_9_114_5_6 =cut #-------------------------------------------------------------------------------- sub get_hostname { my $host = shift; my $ip = shift; if ( !$host ) { $host = gethostbyaddr( inet_aton($ip), AF_INET ); if ( !$host ) { my $ip_str = $ip; $ip_str =~ s/\./\_/g; $host = "switch_$ip_str"; } } return $host; } #-------------------------------------------------------------------------------- =head3 get_switchtype determine the switch type based on the switch vendor Arguments: vendor: switch vendor Returns: stype: type of switch, supports Juniper, Cisco, BNT and Mellanox =cut #-------------------------------------------------------------------------------- sub get_switchtype { my $vendor = shift; my $key; my $search_string = join '|', keys(%global_switch_type); if ($vendor =~ /($search_string)/) { $key = $1; return $global_switch_type{$key}; } else { return $vendor; } } #-------------------------------------------------------------------------------- =head3 xCATdB Write discovered switch information to xCAT database. Arguments: outhash: A hash containing the swithes discovered. request: The request structure for plugin. sub_req: The request structure for runxcmd. Returns: none =cut #-------------------------------------------------------------------------------- sub xCATdB { my $outhash = shift; my $request = shift; my $sub_req = shift; my $ret; ################################################# # write each switch to xcat database ################################################## foreach my $mac ( keys %$outhash ) { my $ip = $outhash->{$mac}->{ip}; my $vendor = $outhash->{$mac}->{vendor}; #Get hostname and switch type my $host = get_hostname($outhash->{$mac}->{name}, $ip); my $stype = get_switchtype($vendor); if ($mac =~ /nomac/) { $mac=" "; } ################################################# # use lsdef command to check if this switch is # already in the switch table # if it is, use chdef to update it's attribute # otherwise, use mkdef to add this switch to # switch table ################################################## $ret = xCAT::Utils->runxcmd( { command => ['lsdef'], arg => ['-t','node','-o',$host] }, $sub_req, 0, 1); if ($::RUNCMD_RC == 0) { $ret = xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$host,"ip=$ip",'nodetype=switch','mgt=switch',"switchtype=$stype","usercomment=$vendor"] }, $sub_req, 0, 1); $ret = xCAT::Utils->runxcmd({ command => ['chdef'], arg => ['-t','node','-o',$host,'-p','groups=switch'] }, $sub_req, 0, 1); } else { $ret = xCAT::Utils->runxcmd( { command => ['mkdef'], arg => ['-t','node','-o',$host,'groups=switch',"ip=$ip",'nodetype=switch','mgt=switch',"switchtype=$stype","usercomment=$vendor"] }, $sub_req, 0, 1); } if ($::RUNCMD_RC != 0) { send_msg($request, 0, "$$ret[0]"); } } } #-------------------------------------------------------------------------------- =head3 get_ip_ranges Return the an array of ip ranges. If --range is specified, use it. If noderange is specified, use the ip address of the nodes. Otherwise, use the subnets for all the live nics on the xCAT mn. Arguments: request: request structure with callback pointer. Returns: A pointer of an array of ip ranges. =cut #-------------------------------------------------------------------------------- sub get_ip_ranges { $request = shift; # if --range is defined, just return the ranges specified by the user if (@iprange > 0) { return \@iprange; } # if noderange is defined, then put the ip addresses of the nodes in if (@filternodes > 0) { my @ipranges=(); foreach my $node (@filternodes) { my $ip = xCAT::NetworkUtils->getipaddr($node); push(@ipranges, $ip); } return \@ipranges; } # for default, use the subnets for all the live nics on the mn my $nets = xCAT::NetworkUtils->my_nets(); my $ranges=[]; foreach my $net (keys %$nets) { if ($net !~ /127\.0\.0\.0/) { push(@$ranges, $net); } } return $ranges; } #------------------------------------------------------------------------------- =head3 format_stanza list the stanza format for swithes Arguments: outhash: a hash containing the switches discovered Returns: result: return lists as stanza format for swithes =cut #-------------------------------------------------------------------------------- sub format_stanza { my $outhash = shift; my $result; ##################################### # Write attributes ##################################### foreach my $mac ( keys %$outhash ) { my $ip = $outhash->{$mac}->{ip}; my $vendor = $outhash->{$mac}->{vendor}; #Get hostname and switch type my $host = get_hostname($outhash->{$mac}->{name}, $ip); my $stype = get_switchtype($vendor); if ($mac =~ /nomac/) { $mac = " "; } $result .= "$host:\n\tobjtype=node\n"; $result .= "\tgroups=switch\n"; $result .= "\tip=$ip\n"; $result .= "\tmac=$mac\n"; $result .= "\tmgt=switch\n"; $result .= "\tnodetype=switch\n"; $result .= "\tswitchtype=$stype\n"; } return ($result); } #-------------------------------------------------------------------------------- =head3 format_xml list the xml format for swithes Arguments: outhash: a hash containing the switches discovered Returns: result: return lists as xml format for swithes =cut #-------------------------------------------------------------------------------- sub format_xml { my $outhash = shift; my $xml; ##################################### # Write attributes ##################################### foreach my $mac ( keys %$outhash ) { my $result; my $ip = $outhash->{$mac}->{ip}; my $vendor = $outhash->{$mac}->{vendor}; #Get hostname and switch type my $host = get_hostname($outhash->{$mac}->{name}, $ip); my $stype = get_switchtype($vendor); if ($mac =~ /nomac/) { $mac = " "; } $result .= "hostname=$host\n"; $result .= "objtype=node\n"; $result .= "groups=switch\n"; $result .= "ip=$ip\n"; $result .= "mac=$mac\n"; $result .= "mgt=switch\n"; $result .= "nodetype=switch\n"; $result .= "switchtype=$stype\n"; my $href = { Switch => { } }; my @attr = split '\\n', $result; for (my $i = 0; $i < scalar(@attr); $i++ ){ if( $attr[$i] =~ /(\w+)\=(.*)/){ $href->{Switch}->{$1} = $2; } } $xml.= XMLout($href, NoAttr => 1, KeyAttr => [], RootName => undef ); } return ($xml); } 1;