I’ve written a lot of Perl scripts to help make managing the network easier and more efficient. One of the scripts I’ve written allows me to dump the IP ARP table of the Nortel Ethernet Routing Switch 8600 to a file for later/additional processing. While the script was original written for the ERS 8600 switch it will also work on just about any router (Layer 3 device) that supports the RFC1213 (ipNetToMediaNetAddress).
The script has been tested and works on Nortel’s BayRS routers (ARN, ASN, BLN, BCN). You just obviously need to be careful of how the script interprets the ipNetToMediaIfIndex value depending on the device you are polling.
The script get8600arp.pl is a very straight forward script. It simply polls various SNMP OIDs and then stores the results in a file. It does this for every switch (FQDN/IP Address) that is listed in the input file.
#!/usr/bin/perl # # Filename: /root/get8600arp.pl # # Purpose: Query Nortel Ethernet Routing Switch 8600 for the IP ARP # table via SNMP. This script will poll a list of devices # (input file) and dump the contents of the IP ARP table to # and outputfile. # # Author: Michael McNamara # # Date: December 5, 2002 # # Support Switches: # - Nortel ERS 8600 # - Nortel ERS 1600 # - Nortel ERS 5500 # - Nortel BayRS Routers # # Requirements: # - Net-SNMP # - Net-SNMP Perl Module # - SNMP-MIBS # # Changes: # # - May 5, 2007 (M.McNamara) # clean up code and documentation for release to public # - Oct 10, 2006 (M.McNamara) # went back to SNMP v1 to support BayRS legacy routers # - Sep 04, 2003 (M.McNamara) # migrated from vendor specific MIB to RFC1213 (ipNetToMediaNetAddress) # # Load Modules use strict; use SNMP; use Net::Ping; # Declare constants #use constant DEBUG => 0; # DEBUG settings use constant RETRIES => 3; # SNMP retries use constant TIMEOUT => 1000000; # SNMP timeout, in microseconds use constant SNMPVER => 1; # SNMP version # SNMP Settings $SNMP::verbose = 0; $SNMP::use_enums = 1; $SNMP::use_sprint_value = 0; &SNMP::initMib(); &SNMP::loadModules('RAPID-CITY'); # Declaration Variables my ($sess, @vals); my @devices; my ($card, $port); my $snmphost; my $comm = "public"; # SNMP ReadOnly Community String my %array; my $switchfile; my $datafile; our $DEBUG; # DEBUG flag undef @devices; # Program and help information my $program = "get8600arp.pl"; my $version = "v1.3"; my $author = "Michael McNamara"; my $purpose = "This Perl script is retreieve the IP ARP table from the ERS8600 Layer 3 switch/router and store it in file for later use."; my $usage = "Usage: $program \[input\] \[output\] \[-help\] \[debug\]\n <input> = filename listing each switch to poll\n <output> = filename where to store output\n"; if (($#ARGV +1) <= 2) { print "Program: $program \nVersion: $version \nWritten by: $author \n$purpose\n\n$usage\n"; print "DEBUG: ARGV = $#ARGV\n"; print "DEBUG: ARGV = $ARGV[0] $ARGV[1] $ARGV[2] $ARGV[3]\n"; exit; } my $arg1 = shift @ARGV; my $arg2 = shift @ARGV; my $arg3 = shift @ARGV; if ($arg1 =~ /help/) { print "Program: $program \nVersion: $version \nWritten by: $author \n$purpose\n\n$usage\n"; print "DEBUG: ARGV = @ARGV\n"; print "DEBUG: ARGV = $ARGV[0] $ARGV[1] $ARGV[2] $ARGV[3]\n"; exit; } $switchfile = $arg1; $datafile = $arg2; $DEBUG = $arg3; # Test to see if inputifle exists if (!-e $switchfile) { die "ERROR: Unable to locate and/or open inputfile $switchfile..."; } ############################################################################ ##### B E G I N M A I N ################################################## ############################################################################ &load_switches; &collect_arp; exit 0; ############################################################################ #### E N D M A I N ####################################################### ############################################################################ ############################################################################ # Subroutine collect_arp # # Purpose: collect ARP information from layer 3 switches/routers ############################################################################ sub collect_arp { # Open output datafile for appending open(DATAFILE, ">>$datafile"); # Loop over each Passport 8600 switch foreach $snmphost (@devices) { my $packet = Net::Ping->new('icmp'); $snmphost =~ s/\n//g; # remove CRLF if ($packet->ping($snmphost)) { $sess = new SNMP::Session ( DestHost => $snmphost, Community => $comm, Retry => RETRIES, Timeout => TIMEOUT, Version => SNMPVER ); my $vars = new SNMP::VarList( ['ipNetToMediaIfIndex', 0], ['ipNetToMediaPhysAddress', 0], ['ipNetToMediaNetAddress', 0], ['ipNetToMediaType', 0] ); while (1) { @vals = $sess->getnext($vars); # retreive SNMP information last unless ($vars->[0]->tag eq 'ipNetToMediaIfIndex'); $vals[1] = unpack('H12', $vals[1]); $vals[1] =~ tr/a-z/A-Z/; $card = (($vals[0] & 62914560) / 4194304); $port = (($vals[0] & 4128768) / 65536) + 1; print "$snmphost, $vals[0], ($card/$port), $vals[1], $vals[2], $vals[3]\n" if ($DEBUG); print DATAFILE "$snmphost, $vals[0], $card, $port, $vals[1], $vals[2]\n"; $array{$snmphost}[$card][$port] = $vals[2]; } # end while } else { print ("ERROR: $snmphost not responding to ICMP ping skipping...\n"); } #end if $packet } #end foreach close(DATAFILE); } #end sub collect_arp ############################################################################ # Subroutine load_switches # # Purpose: load list of switches ############################################################################ sub load_switches { open(SWITCHLIST, "<$switchfile"); # Walk through data file while (<SWITCHLIST>) { # Skip blank lines next if (/^\n$/); # Skip comments next if (/^#/); #print "DEBUG: adding $_ to our list of devices \n" if ($DEBUG); push (@devices, $_); } close(SWITCHLIST); return 1; } # end sub load_switches ############################################################################
The real magic that folks have always been searching for is the binary formula to turn the ipNetToMediaIfIndex into a location that denotes the card and port where that specific device is connected to.
$card = (($vals[0] & 62914560) / 4194304); $port = (($vals[0] & 4128768) / 65536) + 1;
While I still use flat files you could certainly adopt this code to dump the output into a database. I just haven’t had the time although I’ve been playing with MySQL quite a bit lately.
Cheers!
GlenP says
More often than not we have SysAdmins come to us asking about a certain host, and when asked where it is located, they give a blank look. While this could be rectified with relevant documentation we often have to resort to the FDB tables to trace its MAC to the source to identify the physical port the server is connected to.
On occasion we have also had Nortel switches reporting FDB entries incorrectly, and this would be great to identify without manually hitting each device with JDM!
Do you have any script that can correlate the ARP tables to the FDB and report the endpoints?
Still a Nortel/Avaya customer… so far.
Glen.
Michael McNamara says
Hi Glen,
I actually have a few scripts that build and ARP/FDB report for every switch in the network. I then make reports available via a web server for our field engineers. I also make the ability to actively search the ARP/FDB tables for a specific MAC/IP address if an engineer is looking for a device at that exact time (as opposed to a report run 3 hours ago or last night even).
There’s a thread over in the forums regarding your exact question. I haven’t released all the scripts because they’re not properly sanitized. I’ll see if I can find some time to prepare a sanitized version and make it available.
Cheers!
Dan Frazier says
Found your website when doing a Nortel VoIP deployment a while back. Great stuff! I just recently saw this post with your script. I’ve attempted to email you in the past but I don’t think I have the right email address…
1. Not sure if you’re familiar with the project, but Netdisco can do your switch port mapping and report generation for you. I’m using it with some Nortel ERS5510’s, 4548s, BES50 and the older 470s. It also works with every Cisco device I’ve thrown at it as well as some HP and Netgear switches. It’s pretty easy to setup and it’s saved me a TON of time when trying to locate devices on the network.
2. I found another project called NetDot which is being developed out of the University of Oregon. It’s shaping up to be an amazing tool to document EVERYTHING from switch port mapping, vlan config, IPAM, cable plant, etc. I can get it to work with every device I have out there except for our ERS5510 stack. I can’t get the arp collection working. The developer says it’s due to a “broken” snmp implementation of ipAdEntIfIndex.Thats how I found this post.
I tried your script against my 5510 stack (also does our inter vlan routing) but it doesn’t appear accurate. The ports are being listed incorrectly and I can’t figure out why. Have you tested this script with 5510s?
Michael McNamara says
Hi Dan,
What version of software are you running on your 5510s?
I ask because I discovered today that 6.1.x software on the ERS 5500 series switches handles the generation of the IfIndex numbers differently than previously releases.
Switch 1/ Port 1 = IfIndex 1
Siwtch 2 / Port 1 = IfIndex 129
Switch 3 / Port 1 = IfIndex 257
etc
etc
This is very different than previous behavior.
In any event back to your question… the code may need to be tweaked. Do you have a stack of 5510s or just a standalone switch?
You are trying to map ARP/IP to port correct?
Let me do some testing and let you know, shouldn’t be hard to fix if it’s broken.
Thanks for the information on the other projects… good stuff!
Cheers!
Dan Frazier says
I have a stack of 3 5510s. They are running 5.1.4.02. I could provide a snmpwalk of them if you’re interested. However, I’m getting ready to replace them in the VERY near future with a brand new stack of 5510s due to some horrible stack instability problems.
I suppose it’d be best to start a discussion in the forums or email. I’ve taken a class in Perl but I’m not that great at it. I can take code and adapt it when needed but I’m not that great at starting from scratch. Both of the programs I’ve mentioned are written in Perl. Hopefully I can get Netdot to work properly with the 5500s. I’ve tracked down the problem and think I have a fix for it if I can just figure out the odd ifindexing.
Let me know what you think of those two projects. They both have an active development community and I’ve been hoping to give back to the projects. I personally think the Netdot project is going to be amazing when it’s complete. However, it’s mostly geared toward an Open Source shop. Mine is a mix of just about everything. From your site, it does look like we both use a lot of the same gear.
dz says
Hi, may I know how to execute the script with the input file. Should i create the input file? Please advise further
perl get8600arp.pl
Please assist. Thanks
Michael McNamara says
Yes, the input file needs to include every switch, either DNS or IP on a single line.
Good Luck!