Attached is my first try at an OSPF monitoring script meant for use in Mon.
It's loosely based on bgp.monitor.

The script walks through your OSPF interface table, and lists all enabled
OSPF interfaces and whether you have adjacencies on them.  It complains
if it finds any interfaces that OSPF has enabled but hasn't been able
to form an adjacency.

Usage is as follows:

  ospf.monitor [--exclude regexp] [--community blah] router1 router2 ...

Where "router1", "router2", etc. are the routers you are polling, "blah"
is the SNMP community, and "regexp" is either a single IP address of
an interface to ignore, or a regexp in the form "ip1|ip2|ip3" if you
want to ignore multiple interfaces.

I was rather surprised when I ran this script on my routers - a few of
my routers were trying to start adjacencies on dead interfaces or in
other places that they shouldn't have been.  Here's a sample output:

$ ./ospf.monitor router1
router1

router1 (ID 10.99.99.99)
router1:   Interface 10.99.37.8.0     state : down             [NO ADJACENCY]
router1:   Interface 10.99.37.9.0     state : pointToPoint   
router1:   Interface 10.99.37.10.0    state : pointToPoint   
router1:   Interface 10.99.37.11.0    state : pointToPoint   
router1:   Interface 10.99.37.12.0    state : down             [NO ADJACENCY]
router1:   Interface 10.99.38.88.0    state : designatedRouter
router1:   Interface 10.99.38.89.0    state : loopback         [NO ADJACENCY]
router1:   Interface 10.99.38.90.0    state : designatedRouter
router1:   Interface 10.99.38.91.0    state : designatedRouter

For this router, the two "down" links are lines that have been disconnected
and I forgot to tell OSPF not to listen on them anymore, and the "loopback"
line is a loopback interface that I've incorrectly told OSFP to listen on.

The script will also tell you about addressless interfaces that have
OSPF enabled - I need to put a bit more code in the script to identify
them (currently you just see an ifIndex without explanation).

This script is fresh out of the oven, so consider it beta quality or
worse - but I'd be pleased if folks with the right environment (Perl and
the SNMP_Session module from http://www.switch.ch/misc/leinen/snmp/perl)
could give it a spin and let me know what they think of it.  It sticks
to the RFC1253 OSPF MIB, so it should work on any router, not just
Cisco.

        -- Ed
#!/usr/bin/perl
#
# Router ospf (Open Shortest Path First) monitor
# Look at each router and get the status of all OSPF neighbors.
# Issue alarm if any interfaces configured for neighbors do not
#   have a full adjacencies
# Detail log shows status of all enabled OSPF interfaces.

# Usage:
#     ospf.monitor [--exclude pattern] [--community str] router1 [...]
#
# --exclude - don't alarm for IP addresses that match <pattern>.  Periods
# in the IP address will be escaped so that they only match periods.  Use
# [0-9] or the like if you need character class matching.  Use 'ip|ip|ip'
# to exclude multiple peers.
#
# --community - SNMPv1 community name to use.  But it's more secure
# to pass the community in via the environment variable COMMUNITY.


#
# Edit history below
# Version 0.1
# 
# By Ed Ravin <[EMAIL PROTECTED]>  This code is made available courtesy of
# PANIX http://www.panix.com.
# Copyright 2005, by Ed Ravin
#
# License: GNU GPL v2, see http://www.gnu.org/copyleft/gpl.html
#
# Loosely based on bgp.monitor which is:
#   Copyright 2002, by Marc Hauswirth, Safe Host SA <[EMAIL PROTECTED]>
#
# Some inspiration is taked from others mon monitors and from
# routerinfo.pl by Ben Buxton ([EMAIL PROTECTED]), also under GPL, see 
http://www.zipworld.com.au/~bb/linux/
# and from routerint.monitor by P. Strauss ([EMAIL PROTECTED]) and me self 
([EMAIL PROTECTED]).
#

# This script need the SNMP Session module from Simon Leinen <[EMAIL PROTECTED]>
#   Wich you could found under http://www.switch.ch/misc/leinen/snmp/perl/
#   It is also part of MRTG (http://people.ee.ethz.ch/~oetiker/webtools/mrtg/)

use SNMP;
use SNMP_Session;
use Getopt::Long;
use strict;

my %opt;

$opt{'community'}= undef;
$opt{'exclude'}= "";
$opt{'debug'}= undef;
my $usage="Usage: [COMMUNITY=str] ospf.monitor [--exclude regexp] [--community 
str] router [...]\n";
GetOptions(\%opt, "exclude=s", "community=s", "debug") or die $usage;

# It's highly unlikely someone wants dots in an IP address to be treated
# as a regexp pattern, so we'll escape them to make behavior more predictable.
# If you really want to use pattern matching, use a character class like
# [0-9] instead.
$opt{'exclude'} =~ s/\./\\./g;
$opt{'exclude'}= '^(' . $opt{exclude} . ')';


## --
my $community = $opt{'community'} || $ENV{'COMMUNITY'} || "public";

## --

my @failures;
my @details;

$ENV{'MIBS'}= ""; # all OIDs needed are specified in script

# OID's to the SNMP elements that I want to show...
# From Cisco's MIB and RFC's
# http://sunsite.cnlab-switch.ch/ftp/doc/standard/rfc/16xx/1657
# http://www.telecomm.uh.edu/stats/rfc/BGP4-MIB.html

my %oids = ( 
        "SysUptime"                     =>      "1.3.6.1.2.1.1.3.0",
        "ospfRouterId"                  =>      "1.3.6.1.2.1.14.1.1" ,
        "ospfIfIpAddress"               =>      "1.3.6.1.2.1.14.7.1.1" ,
        "ospfAddressLessIf"             =>      "1.3.6.1.2.1.14.7.1.2" ,
        "ospfIfAdminStat"               =>      "1.3.6.1.2.1.14.7.1.5" ,
        "ospfIfState"                   =>      "1.3.6.1.2.1.14.7.1.12" ,
        );


my %ospfIfStates = (
        1 => "down",
        2 => "loopback",
        3 => "waiting",
        4 => "pointToPoint",
        5 => "designatedRouter",
        6 => "backupDesignatedRouter",
        7 => "otherDesignatedRouter",
        );

my %ospfAdminStatus = (
        1 => "enabled",
        2 => "disabled",
        );


my %state;
my $router;

sub snmpget1 # session, oid-hashstr, instance
{
        my $session= shift;
        my $oidstr= shift;
        my $instance = shift;
        my $result= $session->get(".$oids{$oidstr}.$instance");

        if ($session->{ErrorNum})
        {
                push @failures, $router;
                push @details, "$router: error on SNMP get of $oidstr: 
$session->{ErrorStr}";
                return 0;
        }
        return $result;
}
foreach $router (@ARGV) {
        # Get some infos about this router
        my $sess = new SNMP::Session ( DestHost => $router, Community => 
$community );
        if (!defined($sess))
        {
                push @failures, $router;
                push @details, "$router: cannot create SNMP session";
                next;
        }
        
        my $ospfRouterID = snmpget1($sess, "ospfRouterId", "0") || next;
        
        push @details, "$router (ID $ospfRouterID)";

        # Find the indexes of the interfaces with OSPF enabled
        my @ospfinterfaces;

        my $vars  = new SNMP::VarList([$oids{ospfIfAdminStat}]);
        for (my @vals = $sess->getnext($vars);
                        $vars->[0]->tag =~ /1\.3\.6\.1\.2\.1\.14\.7\.1\.5/      
 # still in table (Did you have a cleaner solutions ?)
                        and 
                        not $sess->{ErrorStr};          # and not end of mib or 
other error
                        @vals = $sess->getnext($vars))
                {
                        
                        my $textIfAdminStatus = $ospfAdminStatus{$vals[0]};
                        push  @ospfinterfaces, $vars->[0]->tag
                                if $textIfAdminStatus eq "enabled";
                }
        # trim down OID to keep just the interface part, which we will use
        # shortly as an instance ID
        map {s/^\.$oids{ospfIfAdminStat}\.//} @ospfinterfaces;

        foreach my $int (@ospfinterfaces)
        {
        my $ifstate = snmpget1($sess, "ospfIfState", "$int");
                push @details, sprintf("$router:   Interface %-16s  state : 
%-15s",$int, $ospfIfStates{$ifstate}); 

                # if ospfIfState not in [4..7] (OSPF full adjacency states)
                if ($ifstate < 4 or $ifstate > 7) {
                        push @failures, $router unless $int =~ $opt{exclude} or 
grep(/$router/, @failures);
                        $details[$#details] .= "  [NO ADJACENCY]";
                }
        }
}

if (@failures) {
        print join(' ', @failures), "\n";
};
if (@details) {
        print "\n";
        print join("\n", @details), "\n";
}

if (@failures) {
        # Error state exit
        exit 1;
} else {
        # Correct exit
        exit 0;
};

_______________________________________________
mon mailing list
mon@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/mon

Reply via email to