Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

RFC: Who wants to design a better SNMP API?

by Hercynium (Hermit)
on Nov 28, 2007 at 17:28 UTC ( #653590=perlmeditation: print w/replies, xml ) Need Help??

I have what I hope is an interesting proposition for whomever's reading this node!

I am trying to design a distribution for working with SNMP, that I will eventually upload to CPAN. I've been disappointed in one way or another by the API of every SNMP module I've tried, but I haven't given up hope that there can be something better.

Smarter hackers than I have put their hands to this task before, but I still believe there's a better way and I need your help to find it!

Everything in this RFC is up for debate and constructive criticism, and if anyone wishes to collaborate further on this project, I welcome you!

To begin, I have laid out the following terminology:
SNMP MIB Terminology: MIB - A Management Information Base. It's a database, essentially, j +ust not a familiar RDBMS. Every device that supports SNMP has one, whi +ch you can query and update, if you know it's schema. The schema of a MIB + is defined in a set of MIB files where each file contains modular + portions of the schema. Since each device may implement a different ove +rall schema, a module-based approach allows for that sort of flexib +ility MIB File - An ASCII text file written according to the SMI format, w +hich is based on and defined using ASN.1. The MIB file is used to + define and describe the schema of an SNMP MIB, or a portion of o +ne. MIB Object - A queriable entity from an SNMP MIB. In a MIB browser, +this is often described as a leaf or column. Each MIB Object is + defined in a MIB file using the OBJECT-TYPE syntax. A MIB Objec +t would define the following properties: object_type: The name of this object in the SMI OBJECT-TYPE def +inition in the MIB File. type_oid: The OID of the object_type, as defined in the MIB. index_name[n]: The name of the n-th index of this object-type, as + defined in the MIB. (only valid for tables, table entries, an +d columns) Object Instance - To borrow terminology from Object Oriented Program +ming, if a MIB Object is a class definition, an Object Instan +ce is an instance of an object of a class. In addition to t +he properties of a MIB Object, it has the following w +hich establish it's identity and value: value: The actual value, as returned from a query to a dev +ice. instance_id: The specific identity of this object instance in a +device in relation to it's object_type. It is a portion of an + OID string that is composed by the concatenation of one + or more indices. index_val[n]: The value of the n-th index of this object's instan +ce full_oid: The full identifier for this particular object inst +ance in a device's MIB. It's the same as concatenating the ty +pe_oid and instance_id
Some additional notes:

An OID is a way of identifying objects in a MIB. an OID is composed of an array of Octets, represented by integers with a \. between each element. Each object in a MIB has a unique OID, and instances of objects have additional octets on the end that define their identity in relation to their object-type.

There are several types of objects, but only a few can be queried. The queriable object types are scalars and columns, but for the purposes of this we only will consider columns, because scalars are *much* simpler.

Column objects are assembled into groupings called Tables, and tables contain a Table Entry object which defines what indexes are used to construct the instance_id of available Object Instances of the column objects within the table.

These concepts are what SNMP is built on. SNMP is essentially object-oriented, but uses mechanisms and concepts that are (academically) supposed to be straight-forward to implement in C. (they usually aren't) It's both elegantly simple and frustratingly complex, depending on the implementation, much like some programming languages. ;)

With this terminology in mind, I have the following scenarios as 'use cases'for which I am trying to develop a clean, clear, flexible general API.

Objects that I am presenting in these use cases will be specified not using their Numeric OIDs (. but rather their Symbolic OIDs (textual names defined in the MIB Files)

First, a simple one:
ifTable.ifEntry.ifType - value is an integer representing the type of interface - index_val[0] is an integer value known as an ifIndex ifTable.ifEntry.ifAdminStatus - value is an integer that represents an interface's administrative +state (1=up,2=down,3=testing) - index_val[0] is an integer value known as an ifIndex ifTable.ifEntry.ifInOctets - value is the number of bytes that have passed through the interfac +e since being turned up. - index_val[0] is an integer value known as an ifIndex
We want to retrieve the full_oid of any ifInOctets objects whose instance_id matches (the instance_ids of all ifType objects whose value is 18) and (the instance_ids of all ifAdminStatus objects whose value is 1)

Second, a more complex one:
adMX2820M13PrvSlotTable.adMX2820M13PrvSlotEntry.adMX2820M13PrvCardPair +ID - value is the name of the protection pair - index_val[0] is the slot number of this card in the pair adGenPortSlotMapTable.adGenPortSlotMapEntry.adGenSlotAddress - value is the slot number an interface is provisioned on (many interfaces per slot) - index_val[0] is the ifIndex value that corresponds to an interface + adMX2820M13StatDS3Table.adMX2820M13StatDS3Entry.adMX2820M13NetFuncServ +State - value is a bitmask with the status of a DS3 circuit - index_val[0] is the ifIndex value that corresponds to this interfa +ce
We want to retrieve the values of the adMX2820M13NetFuncServState objects that are only provisioned in slots whose adMX2820M13PrvCardPairID value is not blank and does not match '/not in use/i'

If you could write code to implement any of these use cases any way you wished, what would it look like? Pseudo-code is just as welcome as Perl.

Replies are listed 'Best First'.
Re: RFC: Who wants to design a better SNMP API?
by Hercynium (Hermit) on Nov 29, 2007 at 16:54 UTC
    Here's a pseudo-SQL-style example for the second one:
    SELECT adMX2820M13PrvSlotTable.adMX2820M13NetFuncServState.value FROM adMX2820M13PrvSlotTable WHERE adMX2820M13PrvSlotTable.adMX2820M13NetFuncServState.index_val[ +0] IN ( SELECT adGenPortSlotMapTable.adGenSlotAddress.index_val[0] FROM adGenPortSlotMapTable WHERE adGenPortSlotMapTable.adGenSlotAddress.value IN ( SELECT adMX2820M13StatDS3Table.adMX2820M13PrvCardPairID.index_ +val[0] FROM adMX2820M13StatDS3Table WHERE adMX2820M13StatDS3Table.adMX2820M13PrvCardPairID.value + !~ /not in use/i AND adMX2820M13StatDS3Table.adMX2820M13PrvCardPairID.value ! += '' ) )
    This query string could be parsed and 'compiled' into a set of SNMP queries and then a set of lookup operations on the SNMP query results to return the specific data being requested.

    So, the SNMP queries generated by parsing this would probably be something like this:
    my $snmp1 = $sess->gettable( adMX2820M13StatDS3Table, columns => ['adMX2820M13PrvCardPairID',], ); my $snmp2 = $sess->gettable( adGenPortSlotMapTable, columns => ['adGenSlotAddress',], ); my $snmp3 = $sess->gettable( adMX2820M13PrvSlotTable, columns => ['adMX2820M13NetFuncServState',], ); # Code to correlate indices and values and such... # I could do this in larger, combined steps, or in a more # functional fashion, but I want this code to be as clear # and linear as possible # Inner-most sub-select: my $res1 = match_by_value( $snmp1, sub { $_ !~ /not in use/i } ); my $res2 = match_by_value( $snmp1, sub { $_ != '' } ); my $res3 = and( $res1, $res2 ); my $res4 = extract_index_val( 0, $res3 ); # Next sub-select: my $res5 = match_by_value( $snmp2, sub { $_ in( @$res4 ) } ); my $res6 = extract_index_val( 0, $res5 ); # Main select: my $res7 = match_by_value( $snmp3, sub { $_ in( @$res6 ) } ); my $res8 = extract_value( $res7 ); my $result = $res8
    Somehow, it didn't come out as clear as I had hoped.
      Posting anonymously so people don't think I'm begging for XP

      Just for fun, Here's what the above code would look like if I eliminated all the temporary variables...
      my $snmp1 = $sess->gettable( adMX2820M13StatDS3Table, columns => ['adMX2820M13PrvCardPairID',], ); my $snmp2 = $sess->gettable( adGenPortSlotMapTable, columns => ['adGenSlotAddress',], ); my $snmp3 = $sess->gettable( adMX2820M13PrvSlotTable, columns => ['adMX2820M13NetFuncServState',], ); # wheeeeee! my $result = extract_value( match_by_value( $snmp3, sub { $_ in( extract_index_val( 0, match_by_value( $snmp2, sub { $_ in( extract_index_val( 0, and( match_by_value( $snmp1, sub { $_ !~ /not in use/i } ), match_by_value( $snmp1, sub { $_ != '' } ) ) ) ) } ) ) ) } ) );

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://653590]
Approved by TStanley
marto must set time aside for cpan things, life is just too crazy at the moment

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (6)
As of 2017-01-23 09:59 GMT
Find Nodes?
    Voting Booth?
    Do you watch meteor showers?

    Results (192 votes). Check out past polls.