diff options
Diffstat (limited to 'perl/agent/Support/Support.pm')
-rw-r--r-- | perl/agent/Support/Support.pm | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/perl/agent/Support/Support.pm b/perl/agent/Support/Support.pm new file mode 100644 index 0000000..41cf694 --- /dev/null +++ b/perl/agent/Support/Support.pm @@ -0,0 +1,461 @@ +#################################################################### +# +# SnmpAgent module for use with the code generated by mib2c with the +# embedded perl configuration file mib2c.perl.conf +# +# Copyright Tripleplay Services Limited 2005 +# All rights reserved. +# +# Use is subject to license terms specified in the COPYING file +# distributed with the Net-SNMP package. +# +#################################################################### + +package NetSNMP::agent::Support; +require Exporter; + +use NetSNMP::OID (':all'); +use NetSNMP::agent (':all'); +use NetSNMP::ASN (':all'); +use NetSNMP::default_store (':all'); +use Data::Dumper; + + +use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION); + +@ISA = qw(Exporter getLeaf); +@EXPORT = qw(registerAgent getOidElement setOidElement); +@EXPORT_OK = qw(); +$VERSION = '5.0702'; + +use strict; +use warnings; + +BEGIN { + print STDERR "Module SnmpAgent.pm loaded ok\n"; +} + +# set to 1 to get extra debugging information +my $debugging = 0; + +# if we're not embedded, this will get auto-set below to 1 +my $subagent = 0; + +################################################################ +# The oidtable is used for rapid random access to elements with known +# oids, such as when doing gets/sets. It is not so good for +# ordered access. For that we build a tree (see below) and setup +# next links in the oidtable to aid in evaluating where to go next +# for GETNEXT requests. +################################################################ +my $oidtable; +my $oidtree; + +# oidroot holds the top most oid record in the table. +my $oidroot = ""; + +################################################################ +# Build a tree for handling getnext requests +# Some parts borrowed from the perl cookbook +################################################################ +sub buildTree { + my ($new_oidtable) = @_; + foreach my $key (keys %$new_oidtable) { + insert($oidtree, $key); + } +} + +sub printTree { + my ($tree) = @_; + return unless $tree; + printTree($tree->{LEFT}); + print $tree->{VALUE}. "\n"; + printTree($tree->{RIGHT}); +} + +my $prev=""; +############################################################## +# Walk the sorted oid tree and set the 'next' links in the +# oidtable. +############################################################## +sub doLinks { + my ($tree) = @_; + return unless $tree; + doLinks($tree->{LEFT}); + if($oidroot eq "") { + $oidroot = $tree->{VALUE}; +# print "Setting oidroot to $oidroot\n"; + } + if($prev ne "") { + $oidtable->{$prev}->{next} = $tree->{VALUE}; + } + $prev = $tree->{VALUE}; + my $node = $oidtable->{$tree->{VALUE}}; + doLinks($tree->{RIGHT}); +} + +################################################################ +# Insert a node into the tree +################################################################ +sub insert { + my ($tree, $value) = @_; + unless ($tree) { + $tree = {}; # Allocate memory + $tree->{VALUE} = $value; + $tree->{LEFT} = undef; + $tree->{RIGHT} = undef; + $_[0] = $tree; + return ; + } + my $tv = new NetSNMP::OID($tree->{VALUE}); + my $mv = new NetSNMP::OID($value); + if ($tv > $mv) { + insert($tree->{LEFT}, $value); + } elsif ($tv < $mv) { + insert($tree->{RIGHT}, $value); + } else { + print "ERR: Duplicate insert of $value\n"; + } +} + +################################################################# +## Main interface. +## registerAgent(oid); +################################################################# +sub registerAgent { + my $agent = shift; + my $regat = shift; + my $new_oidtable = shift; + + foreach (keys %$new_oidtable) { $oidtable->{$_} = $new_oidtable->{$_}; } + + # This is necessary to avoid problems traversing trees where the + # IID index is range-limited to not include .0, which is used as a + # placeholder in the oidtable. + netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_DONT_CHECK_RANGE, 1); + + print STDERR "Building OID tree\n"; + buildTree($new_oidtable); + doLinks($oidtree); + +# print Dumper($oidtable); + + # Debug. Print the list of oids in their next ordering + my $node = $oidroot; + while($node) { +# print $node . "\n"; + $node = $oidtable->{$node}->{next}; + } + +# where we are going to hook onto + my $regoid = new NetSNMP::OID($regat); + print "registering at ",$regoid,"\n" if ($debugging); + +# If we're not running embedded within the agent, then try to start +# our own subagent instead. + if (! $agent) { + $agent = new NetSNMP::agent('Name' => 'test', # reads test.conf + 'AgentX' => 1); # make us a subagent + $subagent = 1; + print STDERR "started us as a subagent ($agent)\n" + } + +# we register ourselves with the master agent we're embedded in. The +# global $agent variable is how we do this: + print Dumper($agent) if ($debugging); + $agent->register('myname',$regoid, \&my_snmp_handler); +} + + +###################################################################### +# The subroutine to handle the incoming requests to our +# part of the OID tree. This subroutine will get called for all +# requests within the OID space under the registration oid made above. +###################################################################### +sub my_snmp_handler { + my ($handler, $registration_info, $request_info, $requests) = @_; + + my $request; + my $reqnum=1; + +# print STDERR "refs: ",join(", ", ref($handler), ref($registration_info), + # ref($request_info), ref($requests)),"\n"; + + print "==============================================\n" if ($debugging); + + print STDERR "processing a request of type " . + $request_info->getMode() . "\n" if ($debugging) ; + # + # Process each varbind in teh list of requests + # + for($request = $requests; $request; $request = $request->next()) { + my $oid = $request->getOID(); + print STDERR "-- processing request of $oid (request $reqnum) \n" if ($debugging); + + # + # Handle the different request types + # + my $mode = $request_info->getMode(); + if ($mode == MODE_GET) { + getLeaf($oid, $request, $request_info); + } elsif ($mode == MODE_GETNEXT) { + getNextOid($oid, $request, $request_info); + } else { + print STDERR "Request type $mode not supported\n"; + } + + $reqnum++; + } + + print STDERR " finished processing\n" + if ($debugging); +} + +########################################################## +# Given an oid see if there is an entry in the oidtable +# and get the record if there is. +# +# Passed the oid as a NetSNMP oid +# +# Returns the record if found +# +########################################################## +sub findOid { + my $oid = shift; + + # Convert the OID to a string + # The index items are temporarily set to zero to cater for tables + my @indexes = $oid->to_array(); + + my $idxoffset = $oid->length() - 1; + + # Locate the record in the table if it exists + # If no match then try setting index values to zero until + # we have a match of we exhaust the oid + while($idxoffset) { + my $oidstr="." . join ".", @indexes; + my $rec = $oidtable->{$oidstr}; + + # Return the record if found and the repaired index array + if($rec) { + print "Found OID $oid ($oidstr) in the table\n" if ($debugging); + return ($rec); + } else { + # Not found. Set the next potential index to zero and + # try again + $indexes[$idxoffset] = 0; + $idxoffset--; + } + } + return (0); +} + + +########################################################## +# Sub to return an element of an OID +# This is commonly used to get an index item from +# an OID for table accesses. +########################################################## +sub getOidElement { + my ($oid, $idx) = @_; + + my @idx = $oid->to_array(); + my $len = $oid->length(); + my $val = $idx[$idx]; + return $val; +} +########################################################## +# Sub to set an element of an OID +# Returns a new NetSNMP::OID object +########################################################## +sub setOidElement { + my ($oid, $offset, $val) = @_; + + my @idx = $oid->to_array(); + $idx[$offset] = $val; + my $str = "." . join ".", @idx; + return new NetSNMP::OID($str);; +} + + +########################################################## +# Given scalar record in the oidtable get the value. +# Passed the record and the request. +########################################################## +sub getScalar { + my ($rec, $request) = @_; + + # Got a scalar node from the table + my $type = $rec->{type}; + + # Call the GET function + my $val = $rec->{func}(); + + $request->setValue($type, $val); +} + +############################################################ +# Given a record in the OID table that is a columnar object +# locate any objects that have the required index. +# +# Passed the record, the oid object and the request +############################################################ +sub getColumnar { + my ($rec, $oid, $request) = @_; + + print "Get Columnar $oid\n" if ($debugging); + + my $type = $rec->{type}; + my $args = $rec->{args}; + + # Check the index is in range and exists + if($rec->{check}($oid)) { + + # Call the handler function with the oid + my $val = $rec->{func}($oid); + + # Set the value found in the request + $request->setValue($type, $val); + } +} + +###################################################################### +# +# If the oid is in range then set the data in the supplied request +# object. +# +# Tries to get a scalar first then checks the coumnar second +# +# Return 1 if successful or 0 if not +# +####################################################################### +sub getLeaf { + my $oid = shift; + my $request = shift; + my $request_info = shift; + + print "getLeaf: $oid\n" if ($debugging); + + # Find an oid entry in the table + my ($rec) = findOid($oid); + if($rec) { + + # Record found. Use the istable flag to pass control to the + # scalar or coulmnar handler + if($rec->{istable} == 1) { + return getColumnar($rec, $oid, $request); + } else { + return getScalar($rec, $request); + } + } +} + +##################################################### +# +# getNextOid +# +# The workhorse for GETNEXT. +# Given an OID, locates the next oid and if valid does +# a getLeaf on that OID. It does this by walking the list of +# OIDs. We try to otimise the walk by first looking for an oid +# in the list as follows: +# +# 1. Try to locate an oid match in the table. +# If that succeeds then look for the next object in the table +# using the next attribute and get that object. +# +# 2. If the OID found is a table element then use the table +# specific index handler to see if there is an item with the +# next index.This will retutn either an oid which we get, or 0. +# If there is not then we continue our walk along the tree +# +# 3.If the supplied oid is not found, but is in the range of our oids +# then we start at the root oid and walk the list until we either +# drop of the end, or we fnd an OID that is greater than the OID supplied. +# In all cases if we sucessfully find an OID to retrieve, +# then we set the next OID in the resposnse. +# +###################################################### +sub getNextOid { + my $oid = shift; + my $request = shift; + my $request_info = shift; + + my $curoid = new NetSNMP::OID($oidroot); # Current OID in the walk + + # Find the starting position if we can + my $current = findOid($oid); +# print Dumper($current); + if($current) { + # Found the start in the table + $curoid = new NetSNMP::OID($oid); + + # If the node we found is not a table then start at the + # next oid in the table + unless($current->{istable}) { + + my $nextoid = $current->{next}; + $curoid = new NetSNMP::OID($nextoid); +# print "Not a table so using the next $nextoid\n"; + $current = $oidtable->{$nextoid}; + } + } + + # If we cannot find the starting point in the table, then start + # at the top and + # walk along the list until we drop off the end + # or we get to an oid that is >= to the one we want. + else { + +# print "Not found so using the top ($oidroot)\n"; + $current = $oidtable->{$oidroot}; + + while($current && $curoid <= $oid) { + my $nextoid = $current->{next}; + print "Trying $nextoid\n" if ($debugging); + $current = $oidtable->{$nextoid}; + $curoid = $current ? new NetSNMP::OID($nextoid) : undef; + } + } + + ## + ## Got a starting point + ## $current points to the node in the table + ## $curoid is a NetSNMP::OID object with the oid we are trying + ## + print "Got a startng point of " . Dumper($current) if ($debugging); + while($current) { + if($current->{istable}) { + + # Got a table oid. See if the next is valid for the table +# print "Trying table\n"; + + my $nextoid = $current->{nextoid}($curoid); + +# print Dumper($nextoid); + if($nextoid) { + getColumnar($current, $nextoid, $request); + $request->setOID($nextoid); + return; + } + + # No not this one so try the next + $nextoid = $current->{next}; + $current = $oidtable->{$nextoid}; + $curoid = $current ? new NetSNMP::OID($nextoid) : undef; + print "Trying next $curoid $nextoid\n" if ($debugging); + } else { + + # Must be the current node + if(getScalar($current, $request)) { + $request->setOID($curoid); + return 1; + } + } + } +} + + +# Return true from this module +1; |