#!/usr/bin/perl # vi:syntax=perl # # Name: # mrrogers # Licensed under Don't Worry, Be Happy # see: http://wiki.xdroop.com/space/Software+Licensing # # Synopsis # list LLDP neighbours listed in SNMP # # Options # see &usage # # History: # 2014-07-16 D.Mackintosh # Initial rev # # Usefull Values. use Net::SNMP qw(snmp_dispatcher oid_lex_sort); $BASENAME = $0; $BASENAME =~ s|\\|/|g; if ($BASENAME =~ m|(.*/)(.*)|) { $BASENAME = $2; } # # code here. while ($#ARGV > -1) { $_ = shift @ARGV; if (/^-c$/) { $COMMUNITY = shift @ARGV; next; } if (/^-s$/) { $SHOWLOCALPORTS = 1; next; } if (/^-p$/) { $PORTID = 1; next; } if (/^-l$/) { $SpecificPort = shift @ARGV; next; } if (/^--DEBUG$/) { $DEBUG = 1; &debug("Debugging on"); next; } if (/^--HELP$/) { &usage("__SHOW_HELP"); } if (!$switch) { $switch = $_; next; } &usage("$_"); } # # display the help message. # I find it usefull to leave this subroutine here, next to the parameter # parsing, as it makes it much easer to keep the help and the # actual parsing in sync. sub usage { $gripe = shift @_; print <<"EO_USAGE"; $BASENAME [-c STRING ] [-p] TARGET TARGET query the switch at ip, or named, TARGET -c STRING use STRING as the SNMP community -l PORT show neighbour on PORT only -p display remote PortID strings as well as PortDesc strings -s show local PortID --HELP print this screen EO_USAGE exit 0 if ($gripe eq "__SHOW_HELP"); &die("Don't understand:$gripe"); } $switch = $switch || '192.168.1.1'; $COMMUNITY = $COMMUNITY || 'public'; if ($PORTID) { &loadLLDPPortID(); } &loadLLDPPortDesc(); &loadLLDPSysName(); if ($SpecificPort) { print &showNeighbour($SpecificPort) . "\n"; exit; } foreach $localPort (sort(keys(%RemotePortDesc))) { print &showNeighbour($localPort) . "\n"; } # # Return the ifName for a given ifIndex. sub ifName { my $ifIndex = shift(@_); my $ifName; my $ifNameOID = '1.3.6.1.2.1.31.1.1.1.1'; my $ifNameOIDPort = "$ifNameOID.$ifIndex"; &debug("ifName: ifNameOIDPort -> $ifNameOIDPort"); my ($nameSession, $nameError) = Net::SNMP->session( -hostname => $switch, -community => $COMMUNITY, -port => 161, ); if (!defined($nameSession)) { &die("ifName: no session"); } $ifName = $nameSession->get_request(-varbindlist => [$ifNameOIDPort],); $ifName = $ifName->{$ifNameOIDPort}; return ($ifName); } # # load the LLDPPortDesc column into %RemotePortDesc sub loadLLDPPortDesc { my $LLDPPortDesc = '1.0.8802.1.1.2.1.4.1.1.8'; my ($session, $error) = Net::SNMP->session( -hostname => $switch, -community => $COMMUNITY, -port => 161, -translate => [-octetstring => 0x0] # http://rt.cpan.org/Public/Bug/Display.html?id=1946 ); if (!defined($session)) { printf("ERROR: %s\n", $error); exit 1; } if (defined($result = $session->get_table(-baseoid => $LLDPPortDesc))) { foreach (oid_lex_sort(keys(%{$result}))) { $raw = $_; $value = $result->{$_}; if ($raw =~ /\.(\d+)\.\d+$/) { $raw = $1; } $RemotePortDesc{$raw} = $value; &debug("LLDPPortDesc: [$raw] -> [$value]"); } } else { printf("ERROR: %s\n(load-LLDPPortDesc)\n", $session->error()); } } # # Load the LLDPPortID column into %RemotePortID sub loadLLDPPortID { my $LLDPPortID = '1.0.8802.1.1.2.1.4.1.1.7'; my ($session, $error) = Net::SNMP->session( -hostname => $switch, -community => $COMMUNITY, -port => 161, -translate => [-octetstring => 0x0] # http://rt.cpan.org/Public/Bug/Display.html?id=1946 ); if (!defined($session)) { printf("ERROR: %s\n", $error); exit 1; } if (defined($result = $session->get_table(-baseoid => $LLDPPortID))) { foreach (oid_lex_sort(keys(%{$result}))) { $raw = $_; $value = $result->{$_}; if ($raw =~ /\.(\d+)\.\d+$/) { $raw = $1; } $RemotePortID{$raw} = $value; &debug("LLDPortID: [$raw] -> [$value]"); } } else { printf("ERROR: %s\n(loadLLDPPortID)\n", $session->error()); } } # # Load the LLDPSysName column into %RemoteSysName sub loadLLDPSysName { my $LLDPSysName = '1.0.8802.1.1.2.1.4.1.1.9'; my ($session, $error) = Net::SNMP->session( -hostname => $switch, -community => $COMMUNITY, -port => 161, -translate => [-octetstring => 0x0] # http://rt.cpan.org/Public/Bug/Display.html?id=1946 ); if (!defined($session)) { printf("ERROR: %s\n", $error); exit 1; } if (defined($result = $session->get_table(-baseoid => $LLDPSysName))) { foreach (oid_lex_sort(keys(%{$result}))) { $raw = $_; $value = $result->{$_}; if ($raw =~ /\.(\d+)\.\d+$/) { $raw = $1; } $RemoteSysName{$raw} = $value; &debug("LLDPSysName: [$raw] -> [$value]"); } } else { printf("ERROR: %s\n(loadLLDPSysName)\n", $session->error()); } } # # Return the output string for the given ifIndex sub showNeighbour { my $ifIndex = shift(@_); my $LocalPortName; my $out; $LocalPortName = &ifName($ifIndex); if ($SHOWLOCALPORTS) { $out = "($ifIndex) "; } $out = $out . "$LocalPortName -> $RemoteSysName{$ifIndex} $RemotePortDesc{$ifIndex}"; if ($PORTID) { $out = $out . " ($RemotePortID{$ifIndex})"; } return $out; } # These subroutines come from my Perl template and are used just for # my convenience. # # an easy way to change those back-ticks into # system() calls when we fuck up. sub doThis { local ($result); local ($thing) = pop @_; &debug("doing [$thing]"); # $result=system($thing); $result = `$thing`; &debug("finished shelling; output:\n$result"); &debug("output ends"); return $result; } # # Log something to the local syslog sub logItem { local ($message); $message = pop(@_); setlogsock('unix'); openlog($BASENAME, '', 'user'); syslog('info', $message); closelog; } # # A (braindead) friend for our undertaker. sub warn { local ($gripe); $gripe = pop(@_); print STDERR "$BASENAME:$gripe\n"; &logItem($gripe); } # # A simple debug outputer. sub debug { local ($gripe); $gripe = pop(@_); $DEBUG && print STDERR "DEBUG:$gripe\n"; } # # A (braindead) undertaker. sub die { local ($gripe); $gripe = pop(@_); &warn("fatal:$gripe"); &logItem("fatal:$gripe"); exit 1; }