From 6e86c7aecc7f169b2944d41a786a9210cdeafb43 Mon Sep 17 00:00:00 2001 From: Casandra Qiu Date: Thu, 17 Mar 2016 13:20:07 -0400 Subject: [PATCH 1/7] Find switch vendor using snmpwalk command --- .../lib/xcat/plugins/switchdiscover.pm | 119 ++++++++++++++++-- 1 file changed, 110 insertions(+), 9 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/switchdiscover.pm b/xCAT-server/lib/xcat/plugins/switchdiscover.pm index ac775b949..3eed2e213 100644 --- a/xCAT-server/lib/xcat/plugins/switchdiscover.pm +++ b/xCAT-server/lib/xcat/plugins/switchdiscover.pm @@ -35,6 +35,20 @@ my %global_switch_type = ( Mellanox => "Mellanox" ); +my %global_OID_model_metrix = ( + "enterprises.2636.1.1.1.2.54" => "Juniper", + "enterprises.2636" => "Juniper", + "enterprises.20301.1.18.13" => "(BNT)IBM Flex System Fabric EN4093/EN2092 Scalable Switch", + "enterprises.26543.1.7.1" => "(BNT)IBM Networking Operating System RackSwitch G8000-RS", + "enterprises.26543.1.7.4" => "(BNT)IBM Networking Operating System RackSwitch G8124", + "enterprises.26543.1.7.6" => "(BNT)IBM Networking Operating System RackSwitch G8264", + "enterprises.26543.1.7.7" => "(BNT)IBM Networking Operating System RackSwitch G8052", + "enterprises.33049.1.1.1.6036" => "IBM Mellanox Switch SX6036", + "enterprises.33049.1.1.1.6512" => "IBM Mellanox Switch SX6512", + "enterprises.33049.2.1" => "IBM Mellanox Switch IB6131" +); + + #------------------------------------------------------------------------------- =head1 xCAT_plugin:switchdiscover =head2 Package Description @@ -695,15 +709,20 @@ sub nmap_scan { $mac="nomac_nmap_$counter"; $counter++; } - if ($addr->{vendor}) { + my $vendor = $addr->{vendor}; + # run snmpwalk command to find vendor + if (!$vendor) { + $vendor = get_vendorinfo($request, $ip); + } + if ($vendor) { my $search_string = join '|', keys(%global_switch_type); - if ($addr->{vendor} =~ /($search_string)/) { + if ($vendor =~ /($search_string)/) { $switches->{$mac}->{ip} = $ip; - $switches->{$mac}->{vendor} = $addr->{vendor}; + $switches->{$mac}->{vendor} = $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"); + send_msg($request, 0, "FOUND Switch: ip=$ip, mac=$mac, vendor=$vendor\n"); } } } @@ -782,7 +801,7 @@ sub nmap_scan { #-------------------------------------------------------------------------------- =head3 snmp_scan - Use lldpd to scan the subnets to do switch discovery. + Use snmp to scan the subnets to do switch discovery. Arguments: request: request structure with callback pointer. Returns: @@ -806,6 +825,68 @@ sub snmp_scan { return 1; } +#-------------------------------------------------------------------------------- +=head3 get_vendorinfo + return vendor info from snmpwalk command + Arguments: + ip : IP address passed by the switch after scan + Returns: + vendor: vendor info of the switch +=cut +#-------------------------------------------------------------------------------- +sub get_vendorinfo { + my $request = shift; + my $ip = shift; + my $snmpwalk_vendor; + + + if (-x "/usr/bin/snmpwalk" ){ + if (exists($globalopt{verbose})) { + send_msg($request, 0, "Discovering switch vendor using snmpwalk....."); + } + } else { + if (exists($globalopt{verbose})) { + send_msg($request, 0, "snmpwalk is not available, please install snmpwalk command for better results"); + } + return $snmpwalk_vendor; + } + + my $ccmd = "snmpwalk -Os -v1 -c public $ip system | grep enterprises"; + if (exists($globalopt{verbose})) { + send_msg($request, 0, "Process command: $ccmd\n"); + } + + my $result = xCAT::Utils->runcmd($ccmd, 0); + if ($::RUNCMD_RC != 0) + { + if (exists($globalopt{verbose})) { + send_msg($request, 1, "Could not process this command: $ccmd" ); + } + return $snmpwalk_vendor; + } + + my ($desc,$oid) = split /: /, $result; + my $key; + + if (exists($globalopt{verbose})) { + send_msg($request, 0, "oid = $oid\n" ); + } + my $search_string = join '|', keys(%global_OID_model_metrix); + if ($oid =~ /($search_string)/) { + $key = $1; + $snmpwalk_vendor = $global_OID_model_metrix{$key}; + if (exists($globalopt{verbose})) { + send_msg($request, 0, "find vendor = $snmpwalk_vendor from snmpwalk command\n"); + } + } else { + if (exists($globalopt{verbose})) { + send_msg($request, 0, "Couldn't find vendor from snmpwalk command\n"); + } + } + + return $snmpwalk_vendor; +} + #-------------------------------------------------------------------------------- =head3 get_hostname return hostname for the switch discovered @@ -814,14 +895,34 @@ sub snmp_scan { ip : IP address passed by the switch after scan Returns: host: 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 + if host is empty, try to lookup use snmpwalk command or 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) { + return $host; + } + + # run snmpwalk to get hostname + my $ccmd = "snmpwalk -Os -v1 -c public $ip system | grep sysName"; + if (exists($globalopt{verbose})) { + send_msg($request, 0, "Process command: $ccmd\n"); + } + + my $result = xCAT::Utils->runcmd($ccmd, 0); + if ($::RUNCMD_RC != 0) + { + if (exists($globalopt{verbose})) { + send_msg($request, 1, "Could not process this command: $ccmd" ); + } + } + + my ($desc,$host) = split /: /, $result; + if ( !$host ) { $host = gethostbyaddr( inet_aton($ip), AF_INET ); if ( !$host ) { @@ -897,10 +998,10 @@ sub xCATdB { $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,"ip=$ip","mac=$mac",'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); + $ret = xCAT::Utils->runxcmd( { command => ['mkdef'], arg => ['-t','node','-o',$host,'groups=switch',"ip=$ip","mac=$mac",'nodetype=switch','mgt=switch',"switchtype=$stype","usercomment=$vendor"] }, $sub_req, 0, 1); } if ($::RUNCMD_RC != 0) { From 74d35a6b3dfea949ba5f2128431ce53718644bac Mon Sep 17 00:00:00 2001 From: Casandra Qiu Date: Thu, 17 Mar 2016 14:20:14 -0400 Subject: [PATCH 2/7] Add OID matrix --- xCAT-server/lib/xcat/plugins/switchdiscover.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xCAT-server/lib/xcat/plugins/switchdiscover.pm b/xCAT-server/lib/xcat/plugins/switchdiscover.pm index 3eed2e213..972df433b 100644 --- a/xCAT-server/lib/xcat/plugins/switchdiscover.pm +++ b/xCAT-server/lib/xcat/plugins/switchdiscover.pm @@ -43,9 +43,11 @@ my %global_OID_model_metrix = ( "enterprises.26543.1.7.4" => "(BNT)IBM Networking Operating System RackSwitch G8124", "enterprises.26543.1.7.6" => "(BNT)IBM Networking Operating System RackSwitch G8264", "enterprises.26543.1.7.7" => "(BNT)IBM Networking Operating System RackSwitch G8052", + "enterprises.26543" => "BNT", "enterprises.33049.1.1.1.6036" => "IBM Mellanox Switch SX6036", "enterprises.33049.1.1.1.6512" => "IBM Mellanox Switch SX6512", - "enterprises.33049.2.1" => "IBM Mellanox Switch IB6131" + "enterprises.33049.2.1" => "IBM Mellanox Switch IB6131", + "enterprises.33049" => "IBM Mellanox Switch" ); From 4488c24a300001dc7f9abbc476474a581982595a Mon Sep 17 00:00:00 2001 From: Casandra Qiu Date: Thu, 24 Mar 2016 21:22:58 -0400 Subject: [PATCH 3/7] Add snmp_scan method for switchdiscover command --- .../switchdiscover/switches_discovery.rst | 2 +- .../references/man1/switchdiscover.1.rst | 6 +- xCAT-client/pods/man1/switchdiscover.1.pod | 10 +- .../lib/xcat/plugins/switchdiscover.pm | 257 ++++++++++++------ 4 files changed, 191 insertions(+), 84 deletions(-) diff --git a/docs/source/advanced/networks/switchdiscover/switches_discovery.rst b/docs/source/advanced/networks/switchdiscover/switches_discovery.rst index c1dabd527..3163db74b 100644 --- a/docs/source/advanced/networks/switchdiscover/switches_discovery.rst +++ b/docs/source/advanced/networks/switchdiscover/switches_discovery.rst @@ -5,7 +5,7 @@ Use switchdiscover command to discover the switches that are attached to the nei switchdiscover [noderange|--range ip_ranges][-s scan_methods][-r|-x|-z][-w] -where the scan_methods can be **nmap** . The default is **nmap**. (**nmap** comes from most os distribution.) +where the scan_methods can be **nmap**, **snmp", or **lldp** . The default is **nmap**. (**nmap** comes from most os distribution.) To discover switches over the IP range 10.4.25.0/24 and 192.168.0.0/24, use the following command: :: diff --git a/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst b/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst index de604d36a..6c594d4cb 100644 --- a/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst +++ b/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst @@ -29,6 +29,8 @@ To view all the switches defined in the xCAT databasee use \ **lsdef -w "nodetyp For lldp method, please make sure that lldpd package is installed and lldpd is running on the xCAT management node. lldpd comes from xcat-dep packge or you can get it from http://vincentbernat.github.io/lldpd/installation.html. +For snmp method, please make sure that snmpwalk command is installed and snmp is enabled for switches. To install snmpwalk, "yum install net-snmp-utils" for redhat and sles, "apt-get install snmp" for Ubuntu. + ******* OPTIONS @@ -60,6 +62,8 @@ OPTIONS Specify one or more IP ranges. Each can be an ip address (10.1.2.3) or an ip range (10.1.2.0/24). If the range is huge, for example, 192.168.1.1/8, the switch discover may take a very long time to scan. So the range should be exactly specified. For nmap scan method, it accepts multiple formats. For example, 192.168.1.1/24, 40-41.1-2.3-4.1-100. + +For snmp scan method, it accepts multiple formats. For example: 192.168.1.1/24, 1.2-3.4.5, 1.2.3-4.5, 1.2.3.4-5 If the range is not specified, the command scans all the subnets that the active network interfaces (eth0, eth1) are on where this command is issued. @@ -74,7 +78,7 @@ OPTIONS \ **-s**\ It is a comma separated list of methods for switch discovery. - The possible switch scan methods are: lldp and nmap. The default is nmap. + The possible switch scan methods are: lldp, nmap or snmp. The default is nmap. diff --git a/xCAT-client/pods/man1/switchdiscover.1.pod b/xCAT-client/pods/man1/switchdiscover.1.pod index ffca87876..bc7b121d8 100755 --- a/xCAT-client/pods/man1/switchdiscover.1.pod +++ b/xCAT-client/pods/man1/switchdiscover.1.pod @@ -16,12 +16,14 @@ B [I | B<--range> I] B<[-V] [-w][-r|-x|-z] =head1 DESCRIPTION -The switchdiscover command scans the subnets and discovers all the swithches on the subnets. The command takes a list of subnets as input. The default subnets are the ones that the xCAT management node is on. It uses nmap command to discover the switches. However, you can specify other discovery methods such as lldp with B<-s> flag. You can write the discovered switches into xCAT database with B<-w> flag. This command supports may output formats such as xml(B<-x>), raw(B<-r>) and stanza(B<-z>) in addition to the default format. +The switchdiscover command scans the subnets and discovers all the swithches on the subnets. The command takes a list of subnets as input. The default subnets are the ones that the xCAT management node is on. It uses nmap command as default to discover the switches. However, you can specify other discovery methods such as lldp or snmp with B<-s> flag. You can write the discovered switches into xCAT database with B<-w> flag. This command supports may output formats such as xml(B<-x>), raw(B<-r>) and stanza(B<-z>) in addition to the default format. To view all the switches defined in the xCAT databasee use B command. For lldp method, please make sure that lldpd package is installed and lldpd is running on the xCAT management node. lldpd comes from xcat-dep packge or you can get it from http://vincentbernat.github.io/lldpd/installation.html. +For snmp method, please make sure that snmpwalk command is installed and snmp is enabled for switches. To install snmpwalk, "yum install net-snmp-utils" for redhat and sles, "apt-get install snmp" for Ubuntu. + =head1 OPTIONS @@ -46,7 +48,9 @@ Display usage message. Specify one or more IP ranges. Each can be an ip address (10.1.2.3) or an ip range (10.1.2.0/24). If the range is huge, for example, 192.168.1.1/8, the switch discover may take a very long time to scan. So the range should be exactly specified. -For nmap scan method, it accepts multiple formats. For example, 192.168.1.1/24, 40-41.1-2.3-4.1-100. +For nmap scan method, it accepts multiple formats. For example: 192.168.1.1/24, 40-41.1-2.3-4.1-100. + +For snmp scan method, it accepts multiple formats. For example: 192.168.1.1/24, 1.2-3.4.5, 1.2.3-4.5, 1.2.3.4-5 If the range is not specified, the command scans all the subnets that the active network interfaces (eth0, eth1) are on where this command is issued. @@ -57,7 +61,7 @@ Display Raw responses. =item B<-s> It is a comma separated list of methods for switch discovery. -The possible switch scan methods are: lldp and nmap. The default is nmap. +The possible switch scan methods are: lldp, nmap or snmp. The default is nmap. =item B<-v|--version> diff --git a/xCAT-server/lib/xcat/plugins/switchdiscover.pm b/xCAT-server/lib/xcat/plugins/switchdiscover.pm index 972df433b..e8e7b6e2f 100644 --- a/xCAT-server/lib/xcat/plugins/switchdiscover.pm +++ b/xCAT-server/lib/xcat/plugins/switchdiscover.pm @@ -30,24 +30,14 @@ my %global_scan_type = ( my %global_switch_type = ( Juniper => "Juniper", + juniper => "Juniper", Cisco => "Cisco", BNT => "BNT", - Mellanox => "Mellanox" -); - -my %global_OID_model_metrix = ( - "enterprises.2636.1.1.1.2.54" => "Juniper", - "enterprises.2636" => "Juniper", - "enterprises.20301.1.18.13" => "(BNT)IBM Flex System Fabric EN4093/EN2092 Scalable Switch", - "enterprises.26543.1.7.1" => "(BNT)IBM Networking Operating System RackSwitch G8000-RS", - "enterprises.26543.1.7.4" => "(BNT)IBM Networking Operating System RackSwitch G8124", - "enterprises.26543.1.7.6" => "(BNT)IBM Networking Operating System RackSwitch G8264", - "enterprises.26543.1.7.7" => "(BNT)IBM Networking Operating System RackSwitch G8052", - "enterprises.26543" => "BNT", - "enterprises.33049.1.1.1.6036" => "IBM Mellanox Switch SX6036", - "enterprises.33049.1.1.1.6512" => "IBM Mellanox Switch SX6512", - "enterprises.33049.2.1" => "IBM Mellanox Switch IB6131", - "enterprises.33049" => "IBM Mellanox Switch" + Mellanox => "Mellanox", + mellanox => "Mellanox", + MLNX => "Mellanox", + MELLAN => "Mellanox", + IBM => "BNT", ); @@ -433,7 +423,7 @@ sub process_request { if (!$display_done) { #display header - $format = "%-12s\t%-18s\t%-20.20s\t%-12s"; + $format = "%-12s\t%-15s\t%-40.50s\t%-12s"; $header = sprintf $format, "ip", "name","vendor", "mac"; send_msg(\%request, 0, $header); my $sep = "------------"; @@ -712,10 +702,6 @@ sub nmap_scan { $counter++; } my $vendor = $addr->{vendor}; - # run snmpwalk command to find vendor - if (!$vendor) { - $vendor = get_vendorinfo($request, $ip); - } if ($vendor) { my $search_string = join '|', keys(%global_switch_type); if ($vendor =~ /($search_string)/) { @@ -818,17 +804,98 @@ sub nmap_scan { #-------------------------------------------------------------------------------- sub snmp_scan { my $request = shift; + my $ccmd; + my $switches; + my $counter = 0; + my @iplists = (); - 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; + + if (-x "/usr/bin/snmpwalk" ){ + send_msg($request, 0, "Discovering switches using snmpwalk....."); + } else { + send_msg($request, 0, "snmpwalk is not available, please install snmpwalk command first"); + return 1; + } + + ################################################# + # 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); + + #push each ip to ip list (need better code?) + foreach my $ips (@$ranges) { + #process ip address 1.2.3.4-5 format + if ($ips =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\-(\d+)$/) { + my $startip = "$1.$2.$3.$4"; + my $endip = "$1.$2.$3.$5"; + my $iplist = xCAT::NetworkUtils->get_allips_in_range($startip, $endip, 1); + foreach (@$iplist) { + push (@iplists, $_); + } + } + #process ip address 1.2.3-4.5 format + if ($ips =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\-(\d{1,3})\.(\d{1,3})$/) { + my $beginip = $3; + my $endip = $4; + while ( $beginip <= $endip ) { + my $tip = "$1.$2.$beginip.$5"; + push (@iplists, $tip); + $beginip++; + } + } + #process ip address 1.2-3.4.5 format + if ($ips =~ /^(\d{1,3})\.(\d{1,3})\-(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) { + my $beginip = $2; + my $endip = $3; + while ( $beginip <= $endip ) { + my $tip = "$1.$beginip.$4.$5"; + push (@iplists, $tip); + $beginip++; + } + } + #process ip address 1.2.3.4/24 format + if ($ips =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d+)$/) { + my ($startip, $mask) = split '/', $ips; + $mask = xCAT::NetworkUtils::formatNetmask($mask, 1, 0); + my $endip = xCAT::NetworkUtils->getBroadcast($startip, $mask); + my $iplist = xCAT::NetworkUtils->get_allips_in_range($startip, $endip, 1); + foreach (@$iplist) { + push (@iplists, $_); + } + } + #process single ip address 1.2.3.4 + if ($ips =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) { + push (@iplists, $ips); + } + } + + foreach my $ip (@iplists) { + my $vendor = get_snmpvendorinfo($request, $ip); + if ($vendor) { + my $hostname; + my $mac = get_snmpmac($request, $ip); + if (!$mac) { + $mac="nomac_nmap_$counter"; + $counter++; + } + $hostname = get_snmphostname($hostname, $ip); + my $stype = get_switchtype($vendor); + $switches->{$mac}->{ip} = $ip; + $switches->{$mac}->{vendor} = $vendor; + $switches->{$mac}->{name} = $hostname; + if (exists($globalopt{verbose})) { + send_msg($request, 0, "found switch: $hostname, $ip, $stype, $vendor"); + } + } + } + + return $switches; } #-------------------------------------------------------------------------------- -=head3 get_vendorinfo +=head3 get_snmpvendorinfo return vendor info from snmpwalk command Arguments: ip : IP address passed by the switch after scan @@ -836,24 +903,13 @@ sub snmp_scan { vendor: vendor info of the switch =cut #-------------------------------------------------------------------------------- -sub get_vendorinfo { +sub get_snmpvendorinfo { my $request = shift; my $ip = shift; my $snmpwalk_vendor; - if (-x "/usr/bin/snmpwalk" ){ - if (exists($globalopt{verbose})) { - send_msg($request, 0, "Discovering switch vendor using snmpwalk....."); - } - } else { - if (exists($globalopt{verbose})) { - send_msg($request, 0, "snmpwalk is not available, please install snmpwalk command for better results"); - } - return $snmpwalk_vendor; - } - - my $ccmd = "snmpwalk -Os -v1 -c public $ip system | grep enterprises"; + my $ccmd = "snmpwalk -Os -v1 -c public $ip sysDescr.0"; if (exists($globalopt{verbose})) { send_msg($request, 0, "Process command: $ccmd\n"); } @@ -867,28 +923,91 @@ sub get_vendorinfo { return $snmpwalk_vendor; } - my ($desc,$oid) = split /: /, $result; - my $key; + my ($desc,$model) = split /: /, $result; if (exists($globalopt{verbose})) { - send_msg($request, 0, "oid = $oid\n" ); - } - my $search_string = join '|', keys(%global_OID_model_metrix); - if ($oid =~ /($search_string)/) { - $key = $1; - $snmpwalk_vendor = $global_OID_model_metrix{$key}; - if (exists($globalopt{verbose})) { - send_msg($request, 0, "find vendor = $snmpwalk_vendor from snmpwalk command\n"); - } - } else { - if (exists($globalopt{verbose})) { - send_msg($request, 0, "Couldn't find vendor from snmpwalk command\n"); - } + send_msg($request, 0, "switch model = $model\n" ); } - return $snmpwalk_vendor; + return $model; } +#-------------------------------------------------------------------------------- +=head3 get_snmpmac + return mac address from snmpwalk command + Arguments: + ip : IP address passed by the switch after scan + Returns: + mac: mac address of the switch +=cut +#-------------------------------------------------------------------------------- +sub get_snmpmac { + my $request = shift; + my $ip = shift; + my $mac; + + my $ccmd = "snmpwalk -Os -v1 -c public $ip ipNetToMediaPhysAddress | grep $ip"; + if (exists($globalopt{verbose})) { + send_msg($request, 0, "Process command: $ccmd\n"); + } + + my $result = xCAT::Utils->runcmd($ccmd, 0); + if ($::RUNCMD_RC != 0) + { + if (exists($globalopt{verbose})) { + send_msg($request, 1, "Could not process this command: $ccmd" ); + } + return $mac; + } + + my ($desc,$mac) = split /: /, $result; + + if (exists($globalopt{verbose})) { + send_msg($request, 0, "switch mac = $mac\n" ); + } + + return $mac; +} + +#-------------------------------------------------------------------------------- +=head3 get_snmphostname + return hostname from snmpwalk command + Arguments: + ip : IP address passed by the switch after scan + Returns: + mac: hostname of the switch +=cut +#-------------------------------------------------------------------------------- +sub get_snmphostname { + my $request = shift; + my $ip = shift; + my $hostname; + + my $ccmd = "snmpwalk -Os -v1 -c public $ip sysName"; + if (exists($globalopt{verbose})) { + send_msg($request, 0, "Process command: $ccmd\n"); + } + + my $result = xCAT::Utils->runcmd($ccmd, 0); + if ($::RUNCMD_RC != 0) + { + if (exists($globalopt{verbose})) { + send_msg($request, 1, "Could not process this command: $ccmd" ); + } + return $hostname; + } + + my ($desc,$hostname) = split /: /, $result; + + if (exists($globalopt{verbose})) { + send_msg($request, 0, "switch hostname = $hostname\n" ); + } + + return $hostname; + +} + + #-------------------------------------------------------------------------------- =head3 get_hostname return hostname for the switch discovered @@ -897,34 +1016,14 @@ sub get_vendorinfo { ip : IP address passed by the switch after scan Returns: host: hostname of the switch - if host is empty, try to lookup use snmpwalk command or ip address, - otherwise format hostname as switch and ip combination. ex: switch-9-114-5-6 + 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) { - return $host; - } - - # run snmpwalk to get hostname - my $ccmd = "snmpwalk -Os -v1 -c public $ip system | grep sysName"; - if (exists($globalopt{verbose})) { - send_msg($request, 0, "Process command: $ccmd\n"); - } - - my $result = xCAT::Utils->runcmd($ccmd, 0); - if ($::RUNCMD_RC != 0) - { - if (exists($globalopt{verbose})) { - send_msg($request, 1, "Could not process this command: $ccmd" ); - } - } - - my ($desc,$host) = split /: /, $result; - if ( !$host ) { $host = gethostbyaddr( inet_aton($ip), AF_INET ); if ( !$host ) { From 7f9b5e8b57cc16ad40bee4c33af1d8e69c9014e6 Mon Sep 17 00:00:00 2001 From: Casandra Qiu Date: Mon, 28 Mar 2016 21:44:19 -0400 Subject: [PATCH 4/7] use nmap command to find if snmp port is enabled --- .../lib/xcat/plugins/switchdiscover.pm | 86 ++++++++----------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/switchdiscover.pm b/xCAT-server/lib/xcat/plugins/switchdiscover.pm index e8e7b6e2f..fbc7507ee 100644 --- a/xCAT-server/lib/xcat/plugins/switchdiscover.pm +++ b/xCAT-server/lib/xcat/plugins/switchdiscover.pm @@ -807,9 +807,8 @@ sub snmp_scan { my $ccmd; my $switches; my $counter = 0; - my @iplists = (); - + # snmpwalk command has to be available for snmp_scan if (-x "/usr/bin/snmpwalk" ){ send_msg($request, 0, "Discovering switches using snmpwalk....."); } else { @@ -824,63 +823,46 @@ sub snmp_scan { ################################################## my $ranges = get_ip_ranges($request); - #push each ip to ip list (need better code?) - foreach my $ips (@$ranges) { - #process ip address 1.2.3.4-5 format - if ($ips =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\-(\d+)$/) { - my $startip = "$1.$2.$3.$4"; - my $endip = "$1.$2.$3.$5"; - my $iplist = xCAT::NetworkUtils->get_allips_in_range($startip, $endip, 1); - foreach (@$iplist) { - push (@iplists, $_); - } - } - #process ip address 1.2.3-4.5 format - if ($ips =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\-(\d{1,3})\.(\d{1,3})$/) { - my $beginip = $3; - my $endip = $4; - while ( $beginip <= $endip ) { - my $tip = "$1.$2.$beginip.$5"; - push (@iplists, $tip); - $beginip++; - } - } - #process ip address 1.2-3.4.5 format - if ($ips =~ /^(\d{1,3})\.(\d{1,3})\-(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) { - my $beginip = $2; - my $endip = $3; - while ( $beginip <= $endip ) { - my $tip = "$1.$beginip.$4.$5"; - push (@iplists, $tip); - $beginip++; - } - } - #process ip address 1.2.3.4/24 format - if ($ips =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d+)$/) { - my ($startip, $mask) = split '/', $ips; - $mask = xCAT::NetworkUtils::formatNetmask($mask, 1, 0); - my $endip = xCAT::NetworkUtils->getBroadcast($startip, $mask); - my $iplist = xCAT::NetworkUtils->get_allips_in_range($startip, $endip, 1); - foreach (@$iplist) { - push (@iplists, $_); - } - } - #process single ip address 1.2.3.4 - if ($ips =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) { - push (@iplists, $ips); - } + #use nmap to find if snmp port is enabled + $ccmd = "/usr/bin/nmap -P0 -v -sU -p 161 -oA snmp_scan @$ranges | grep 'open port 161' "; + if (exists($globalopt{verbose})) { + send_msg($request, 0, "Process command: $ccmd\n"); } - foreach my $ip (@iplists) { + 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" ); + } + } + my @lines = split /\n/, $result; + + # only open port will be scan + foreach my $line (@lines) { + my $ip = `echo "$line\n" |awk '{printf \$6}'`; + if (exists($globalopt{verbose})) { + send_msg($request, 0, "Run snmpwalk command to get information for $ip"); + } + my $vendor = get_snmpvendorinfo($request, $ip); if ($vendor) { - my $hostname; my $mac = get_snmpmac($request, $ip); if (!$mac) { $mac="nomac_nmap_$counter"; $counter++; } - $hostname = get_snmphostname($hostname, $ip); + my $hostname = get_snmphostname($request, $ip); my $stype = get_switchtype($vendor); $switches->{$mac}->{ip} = $ip; $switches->{$mac}->{vendor} = $vendor; @@ -1024,6 +1006,10 @@ sub get_hostname { my $host = shift; my $ip = shift; + if ($host) { + return $host; + } + if ( !$host ) { $host = gethostbyaddr( inet_aton($ip), AF_INET ); if ( !$host ) { From 6754e3902c3c1ee41408ab6f780e1dcac954a00b Mon Sep 17 00:00:00 2001 From: Casandra Qiu Date: Wed, 30 Mar 2016 10:19:31 -0400 Subject: [PATCH 5/7] Modify split code as per XiaoPeng's comments --- xCAT-server/lib/xcat/plugins/switchdiscover.pm | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/switchdiscover.pm b/xCAT-server/lib/xcat/plugins/switchdiscover.pm index fbc7507ee..cde703e9d 100644 --- a/xCAT-server/lib/xcat/plugins/switchdiscover.pm +++ b/xCAT-server/lib/xcat/plugins/switchdiscover.pm @@ -666,12 +666,8 @@ sub nmap_scan { ################################################# #display the raw output ################################################# - if (exists($globalopt{r})) { + if (defined($globalopt{r}) || defined($globalopt{verbose})) { send_msg($request, 0, "$result\n" ); - } else { - if (exists($globalopt{verbose})) { - send_msg($request, 0, "$result\n" ); - } } ################################################# @@ -839,18 +835,16 @@ sub snmp_scan { ################################################# #display the raw output ################################################# - if (exists($globalopt{r})) { + if (defined($globalopt{r}) || defined($globalopt{verbose})) { send_msg($request, 0, "$result\n" ); - } else { - if (exists($globalopt{verbose})) { - send_msg($request, 0, "$result\n" ); - } } my @lines = split /\n/, $result; + # each line like this: "Discovered open port 161/udp on 10.4.25.1" # only open port will be scan foreach my $line (@lines) { - my $ip = `echo "$line\n" |awk '{printf \$6}'`; + my @array = split / /, $line; + my $ip = $array[5]; if (exists($globalopt{verbose})) { send_msg($request, 0, "Run snmpwalk command to get information for $ip"); } From 2584be6e11817be39bd1bd5bb4878d6530e84a1d Mon Sep 17 00:00:00 2001 From: Casandra Qiu Date: Wed, 30 Mar 2016 10:26:34 -0400 Subject: [PATCH 6/7] modify switchdiscover command man page --- .../guides/admin-guides/references/man1/switchdiscover.1.rst | 3 +-- xCAT-client/pods/man1/switchdiscover.1.pod | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst b/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst index 6c594d4cb..8cc4b3336 100644 --- a/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst +++ b/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst @@ -61,9 +61,8 @@ OPTIONS Specify one or more IP ranges. Each can be an ip address (10.1.2.3) or an ip range (10.1.2.0/24). If the range is huge, for example, 192.168.1.1/8, the switch discover may take a very long time to scan. So the range should be exactly specified. - For nmap scan method, it accepts multiple formats. For example, 192.168.1.1/24, 40-41.1-2.3-4.1-100. + For nmap and snmp scan method, it accepts multiple formats. For example, 192.168.1.1/24, 40-41.1-2.3-4.1-100. -For snmp scan method, it accepts multiple formats. For example: 192.168.1.1/24, 1.2-3.4.5, 1.2.3-4.5, 1.2.3.4-5 If the range is not specified, the command scans all the subnets that the active network interfaces (eth0, eth1) are on where this command is issued. diff --git a/xCAT-client/pods/man1/switchdiscover.1.pod b/xCAT-client/pods/man1/switchdiscover.1.pod index bc7b121d8..21aff4e43 100755 --- a/xCAT-client/pods/man1/switchdiscover.1.pod +++ b/xCAT-client/pods/man1/switchdiscover.1.pod @@ -48,9 +48,7 @@ Display usage message. Specify one or more IP ranges. Each can be an ip address (10.1.2.3) or an ip range (10.1.2.0/24). If the range is huge, for example, 192.168.1.1/8, the switch discover may take a very long time to scan. So the range should be exactly specified. -For nmap scan method, it accepts multiple formats. For example: 192.168.1.1/24, 40-41.1-2.3-4.1-100. - -For snmp scan method, it accepts multiple formats. For example: 192.168.1.1/24, 1.2-3.4.5, 1.2.3-4.5, 1.2.3.4-5 +For nmap and snmp scan method, it accepts multiple formats. For example: 192.168.1.1/24, 40-41.1-2.3-4.1-100. If the range is not specified, the command scans all the subnets that the active network interfaces (eth0, eth1) are on where this command is issued. From 8ff7c029a5f81f49a85fbaac92983bcee7ce7b4b Mon Sep 17 00:00:00 2001 From: Casandra Qiu Date: Wed, 30 Mar 2016 10:44:22 -0400 Subject: [PATCH 7/7] recheckin switchdiscover.1.rst after ran create_man_page.py command --- .../guides/admin-guides/references/man1/switchdiscover.1.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst b/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst index 8cc4b3336..0c2ed8cce 100644 --- a/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst +++ b/docs/source/guides/admin-guides/references/man1/switchdiscover.1.rst @@ -23,7 +23,7 @@ DESCRIPTION *********** -The switchdiscover command scans the subnets and discovers all the swithches on the subnets. The command takes a list of subnets as input. The default subnets are the ones that the xCAT management node is on. It uses nmap command to discover the switches. However, you can specify other discovery methods such as lldp with \ **-s**\ flag. You can write the discovered switches into xCAT database with \ **-w**\ flag. This command supports may output formats such as xml(\ **-x**\ ), raw(\ **-r**\ ) and stanza(\ **-z**\ ) in addition to the default format. +The switchdiscover command scans the subnets and discovers all the swithches on the subnets. The command takes a list of subnets as input. The default subnets are the ones that the xCAT management node is on. It uses nmap command as default to discover the switches. However, you can specify other discovery methods such as lldp or snmp with \ **-s**\ flag. You can write the discovered switches into xCAT database with \ **-w**\ flag. This command supports may output formats such as xml(\ **-x**\ ), raw(\ **-r**\ ) and stanza(\ **-z**\ ) in addition to the default format. To view all the switches defined in the xCAT databasee use \ **lsdef -w "nodetype=switch"**\ command. @@ -61,8 +61,7 @@ OPTIONS Specify one or more IP ranges. Each can be an ip address (10.1.2.3) or an ip range (10.1.2.0/24). If the range is huge, for example, 192.168.1.1/8, the switch discover may take a very long time to scan. So the range should be exactly specified. - For nmap and snmp scan method, it accepts multiple formats. For example, 192.168.1.1/24, 40-41.1-2.3-4.1-100. - + For nmap and snmp scan method, it accepts multiple formats. For example: 192.168.1.1/24, 40-41.1-2.3-4.1-100. If the range is not specified, the command scans all the subnets that the active network interfaces (eth0, eth1) are on where this command is issued.