Perl script checking route table via snmp against routes in a database

  • Script is based on Cisco MPLS-VPN-MIB, this MIB gives route table information for L3 MPLS VPN instances other wise, ipRouteTable OID can be used.
  • There may be two approach while checking route table. Get the whole route table with snmp walk and cross check with the ones in the database or check the routes in the database one by one in the route table via snmpget. Second method is used in the script.
  • For L3 MPLS VPN, you can get the MPLS VPN name from the database like category, or it can be embedded. Script expects route and MPLS VPN name from the database (although this can be easily change.
  • Also MPLS VPN index is used in the OIDs which is get from a snmpwalk, (explained in the script)

This is not the final script, just a quick testing one.

1 – Adding route next hop to OID section should be added to options menu or it can be defined in the database along with the route.

2 – Complex error handling should be added.

3 – Next hop of the route can be get from the database, its embedded in the script.



use Log::Handler;
use Time::Local;
use DBI;
use Mail::Sendmail;
use Getopt::Simple qw($switch);
use Net::SNMP;
use Net::SNMP 6.0 qw( :snmp DEBUG_ALL ENDOFMIBVIEW );
my($options) = {
help =>
type => ”,
env => ‘-‘,
default => ‘works with snmpv2c not for a generic use’,
order => 1,
loglevel =>
type => ‘=s’,
env => ‘-‘,
default => ’emergency’,
verbose => ‘Specify the log level debug,info,notice,warning,error,critical,alert,emergency’,
order => 2,
logfile =>
type => ‘=s’,
env => ‘-‘,
default => ‘/var/log/ipv4control.log’,
verbose => ‘Specify the log file’,
order => 3,
snmpvcomm =>
type => ‘=s’,
env => ‘-‘,
default => ‘test’,
verbose => ‘Specify the snmpcommunity for connecting the remote devices’,
order => 4,
routeserver =>
type => ‘=s’,
env => ‘-‘,
default => ‘’,
verbose => ‘IPv4 Address of the routeserver for snmp query’,
order => 5,
dsnname =>
type => ‘=s’,
env => ‘-‘,
default => ‘test’,
verbose => ‘Specify dsn name for route database like dbi:ODBC:TEST’,
order => 6,
databaseusername =>
type => ‘=s’,
env => ‘-‘,
default => ‘test’,
verbose => ‘Specify the username for the database, ‘,
order => 7,
databasepassword =>
type => ‘=s’,
env => ‘-‘,
default => ‘test’,
verbose => ‘Specify the password for the database’,
order => 8,
mailfrom =>
type => ‘=s’,
env => ‘-‘,
default => ‘’,
verbose => ‘Specify the from for sending errors via e-mail’,
order => 10,
mailto =>
type => ‘=s’,
env => ‘-‘,
default => ‘’,
verbose => ‘Specify the to for sending errors via e-mail’,
order => 11,
mailsubject =>
type => ‘=s’,
env => ‘-‘,
default => ‘test subject’,
verbose => ‘add description’,
order => 12,
my($option) = Getopt::Simple -> new();
if (! $option -> getOptions($options, “Usage: Option Error [options]”)) {
exit(-1);# Failure.
my ($sec, $min, $hours, $mday, $month, $year, $wday, $yday, $is_summer_time) = localtime();
my $routetable = “test”;
$query=”SELECT route,\’:\’,category,\’:\’,id,\’:\’,routeid,\’:\’,uname FROM $routetable order by id asc”;
$log = Log::Handler->new();
$log->add( file =>{maxlevel => $$switch{‘loglevel’},minlevel => “emergency”,filename => “$$switch{‘logfile’}”});
$log->debug(“Getting route list from database”);
$log->debug(“Tring to connect database:$$switch{‘dsnname’}”);
$connect = DBI->connect($$switch{‘dsnname’}, $$switch{‘databaseusername’}, $$switch{‘databasepassword’});
if ($connect) {
$log->debug(“Connect to the database:$$switch{‘dsnname’}”);
$log->debug(“running query is $query”);
$query_handle = $connect->prepare($query);
$query_handle->execute() or $log->error(“Sql statement error”), goto MAIL;
$array_ref = $query_handle->fetchall_arrayref();
$log->debug(“Retrived information and disconnected from database $$switch{‘dsnname’}”);
$log->debug(“Tring to connect $$switch{‘routeserver’} via snmpv3”);
my ($session, $error) = Net::SNMP->session (
-hostname => $$switch{‘routeserver’},
-community => $$switch{‘snmpvcomm’},
-translate => [-octetstring => 0],
-version => ‘snmpv2c’,
-timeout => 1,
if (!defined $session) {
$log->error(“Snmp session creation error $error”);
### vrf names cannot directly be used to construct snmp oids for searching a route.
### vrf indexes are used in the MPLS-VPN-MIB along with the vrf name (which is same as category of the route) and route.
### to get the vrf index initial snmpwalk is used to get all vrf names and their indexes and then mapped to a hash which is later used for constructing the final oid of the route.
### it can be done on the oid construction of each oid of each route but this should be performance intesive solution.
### So initial snmpwalk is done to the target to get all index values of the vrf’s
$log->debug(“Getting L3 MPLS VPN name to index mapping,vrf names are in decimal format”);

my $baseoid=’′;#mplsVpnVrfDescription used for vrf description to index mapping

my %vrfnametoindex;

my @ARGV;
push @ARGV, “$baseoid”;
my @args = (
-varbindlist => [($ARGV[0] eq q{.}) ? ‘0’ : $ARGV[0]],
my $last_oid = $ARGV[0];
push @args, -maxrepetitions => 25;
GET_BULK: while (defined $session->get_bulk_request(@args)) {
my @oids = $session->var_bind_names();
if (!scalar @oids) {
for my $oid (@oids) {
# Make sure we have not hit the end of the MIB.
if (!oid_base_match($ARGV[0], $oid)) {
last GET_BULK;
my $valuetype=$session->var_bind_types()->{$oid};
my $value=$session->var_bind_list()->{$oid};
my $index=$oid;
my $vrfname=$oid;
### vrf name is inserted wih initial dot
$last_oid = $oid;
$vrfnametoindex{ $vrfname } = $index;
$log->debug(“Adding vrfname:$vrfname and index:$index to the hash”);

@args = (-maxrepetitions => 25, -varbindlist => [$last_oid]);
if ($session->error()) {
print “NET::SNMP snmpwalk Error\n”;
exit 0;

foreach $row (@$array_ref) {
$log->debug(“New route”);
$line =”@$row”;
$log->debug(“Parinsg $line”);
$log->debug(“$route, $category, $id, $routeid, $uname”);
$log->debug(“Parsing route for snmp oid construction it should be formatted as \’ipv4predix.4.netmask.0.4.nexthop\’, route is $route”);
my $tmproute=$route;
$log->debug(“adding blacked hole next hop, $route”);
$log->debug(“route is $route”);
$category =~ s/^\s+//;
$category =~ s/\s+$//;
$log->debug(“category is $category”);
# Category names which are strings must be converted to decimal values (ascii to decimal convertion) to be used in oid construction. These category names define L3 MPLS VPN name which the route resides.

my @decimalcategory = unpack(“C*”, $category);
my $decimalcategoryname;
foreach my $asciivalue (@decimalcategory)
### ceonverting ascii name to descimal with initial dot

if (!defined($vrfnametoindex{ $decimalcategoryname }))
$log->error(“route $tmproute, category $category decimalname:$decimalcategoryname , $category is not defined on the device, NOK”);
$mailbody=”$mailbody”.”\nroute $tmproute, category $category is not defined on the device,”;
$decimalcategoryname=$vrfnametoindex{ $decimalcategoryname }.$decimalcategoryname;
$log->debug(“adding vrf index:$decimalcategoryname to the route oid “);
$log->debug(“$category decimal value $decimalcategoryname”);
my $OID_route=’’.$decimalcategoryname.’.4.’.$route;
$log->debug(“sending snmpget request with oid $OID_route”);
my $trynumber=0;
my $result = $session->get_request(-varbindlist => [ $OID_route ],);
if (!defined $result) {
$mailbody=”$mailbody”.’Script error ‘.$session->error();
goto MAIL if ($trynumber > 3);
sleep 1;
$log->debug(“snmpget result $result->{$OID_route}”);
if ($result->{$OID_route} ne ‘1’) {
$log->info(“route $tmproute, category $category, id $id is not defined on the device, NOK”);
$mailbody=”$mailbody”.”\nroute $tmproute, category $category, id $id table $routetable is not defined on the device”;
else {
$log->info(“route $tmproute, category $category, id $id table $routetable is defined on the device, OK”);
else {
$log->error(“Cannot connect to database:$$switch{‘dsnname’} with user:$$switch{‘databaseusername’} error:$DBI::errstr”);
$mailbody=”Cannot connect to database:$$switch{‘dsnname’} with user:$$switch{‘databaseusername’} error:$DBI::errstr”;
if (defined($mailbody)) {
$mailbody=”$mailbody”.”\n\n\nThis mail is sent by script\n”;
open MAIL, “|/usr/sbin/sendmail -t” or do
$log->error(“Mail::Sendmail while sending mail”);
print MAIL “From: $$switch{‘mailfrom’}\n”;
print MAIL “To: $$switch{‘mailto’}\n”;
print MAIL “Subject: $$switch{‘mailsubject’}\n”;
print MAIL $mailbody;
close(MAIL) or do
$log->error(“error while closing mail”);
$log->debug(“Error mail $$switch{‘mailsubject’} send from $$switch{‘mailfrom’} to $$switch{‘mailto’}\n\t$mailbody”);