summaryrefslogtreecommitdiff
path: root/perl/agent/Support/Support.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl/agent/Support/Support.pm')
-rw-r--r--perl/agent/Support/Support.pm461
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;