Understanding the Structure of Management Information (SMI)

... or the Hitchhiker's Guide to SNMP, Part-II.

Before I can launch into a blog about understanding the JVM-MANAGEMENT-MIB, I will need to say a few words about SNMP MIBs in general, and more particularly, about how SNMP data is structured. These will be the miscellaneous stops we will make in our hitchhiking journey:


[Introduction] [The Global OID Tree] [SNMP and OBJECT IDENTIFIERS] [SNMP is Simple] [Scalar Objects and Columnar Objects] [Defining Tables in SNMP] [Conceptual Rows] [Definition of Index and Non-Index Columnar Objects] [TEXTUAL-CONVENTIONS] [The End Is Close!] [Hurrah!] [Getting an Instance of a Columnar Object] [The End!]

Introduction

In previous entries, I have briefly talked about SNMP itself, and introduced the Tiger (and Mustang) JVM SNMP agent.
In this blog, I'm going to elaborate a little more on the structure of SNMP MIBs - and the syntax used to describe those MIBs. As I have already explained in Simple Is Not Easy there are two versions of this syntax: SMIv1 and SMIv2. In this blog I will only speak of SMIv2.

For those advanced readers who wish to acquire more background, RFC 3584 - Coexistence between Version 1, Version 2, and Version 3 of the Internet-standard Network Management Framework, explains all the fine points of why and how SMIv2 MIBs can be implemented by agents supporting any of the existing SNMP protocol versions - therefore obsoleting SMIv1.
For those advanced readers who wish to get first hand information about designing SNMP MIBs, then Understanding SNMP MIBs, by Perkins and McGinnis, published by Prentice Hall, is probably the best reference.
And for those of you who really wish to know the ultimate answer to the great question of SNMP, the Universe, and the Structure of Management Information version 2, then fity-eight, two-thousand-five-hundred-and-seventy-eight is the answer. You will note that it is a somewhat more complex answer than that to the great question of Life, the Universe, and Everything ;-)...

At this point, it is not in my intention to launch in a full-fledged tutorial about MIBs and SNMP - and were I to do so, I wouldn't probably have the requisite editorial skills. My ambitions are more humbly to get you started on understanding how SNMP (the protocol) and MIBs (the data accessed by the protocol) work, so that you may practice with our little JVM agent.

The Global OID Tree

At the root of the structure of SNMP data - is the concept of OBJECT IDENTIFIER, or OID. In my previous blog I have briefly explained the concept of OBJECT-IDENTIFIER. In particular, I have explained that all SNMP definitions - MIBs, objects, etc... are identified by their OID in the global OID tree. I have also shown how enterprises can obtain a sub-node in the enterprises sub-branch of this OID tree. More to the point, I have explained that Sun Microsystems owns the subnode 42 in that enterprises sub-branch and is therefore responsible for the allocation of any node below:

sun OBJECT IDENTIFIER ::= { iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) 42 }

There, a whole sub-tree has been reserved for the JVM-MANAGEMENT-MIB, whose root is defined at:

sun 2 jmgt(145) standard(3) jsr163(163) 1

From now on, I will therefore use the label jvmMgtMIB to represent the OID at the root of the JVM-MANAGEMENT-MIB which is - in dot notation:

1.3.6.1.4.1.42.2.145.3.163.1

SNMP and OBJECT IDENTIFIERS

An important thing to note is that OIDs are not only used to register global definitions, but also to identify the corresponding pieces of data that can be retrieved from an SNMP Agent implementing these definitions. Let me take an example. In the JVM-MANAGEMENT-MIB, we have defined a scalar variable that represents the current count of living threads. This variable is defined by the following OBJECT-TYPE definition, extracted from the JVM-MANAGEMENT-MIB:

[...]
jvmMgtMIBObjects OBJECT IDENTIFIER ::= { jvmMgtMIB 1 }
[...]
jvmThreading     OBJECT IDENTIFIER ::= { jvmMgtMIBObjects 3 }

-- The following objects are mapped from the ThreadMXBean interface.
-----------------------------------------------------------------------

jvmThreadCount OBJECT-TYPE
    SYNTAX      Gauge32
    MAX-ACCESS  read-only
    STATUS      current
    DESCRIPTION
	"The current number of live threads.

	 See java.lang.management.ThreadMXBean.getThreadCount()
        "
    REFERENCE "J2SE 5.0 API Specification,
              java.lang.management.ThreadMXBean"
    ::= { jvmThreading 1 }

This means that to get the jvmThreadCount from an SNMP agent that implements the JVM-MANAGEMENT-MIB, we will simply send an SNMP GET request containing the OID:

1.3.6.1.4.1.42.2.145.3.163.1.1.3.1.0
\^---sun-----\^              \^     \^ \^
\^--------jvmMgtMIB---------\^     \^ \^
\^-----------jvmThreadCount-------\^ \^
\^------value of jvmThreadCount-----\^

It is also important to note that only terminal values (leaves of the tree) can be accessed through the SNMP protocol. This is why scalar variables are accessed with a trailing .0 in their OID, which distinguishes the value (jvmThreadCount.0) from the definition (jvmThreadCount). Another way to put it would be to say that the MIB contains the definitions (jvmThreadCount), while the agent contains only the actual associated values (jvmThreadCount.0).

SNMP is Simple

Now one of the reasons why we say that SNMP is simple, is because SNMP and SMIv2 will only allow you to define, expose, get, and set values of simple types. The types supported by the SNMP protocol and SMIv2 are defined in STD 58, RFC 2578. I will not go and describe all these types, and the interested reader is invited to go directly at the source in RFC 2578. To sketch it, we can say that SNMP allows you only to expose:

  • INTEGER based types (Counters, Gauges, Integers, Named-Integers)
  • OCTET-STRING based types (Displayable Strings, hexadecimal strings, bit maps, DateAndTime, etc...)
  • and OBJECT IDENTIFIERS
Some of these types have ASN.1 specific tags (like Counters and Gauges), some others are only defined by TEXTUAL CONVENTIONS, which means that they can only be correctly interpreted by looking at the corresponding MIB definition, because in that case only the base type is encoded over the wire.

Scalar Objects and Columnar Objects

In SMI, we will find two kinds of objects that you can GET and SET: scalar objects, of which jvmThreadCount is an instance, and columnar objects, which allow us to represent tables. Tables are probably the most complex things that you will encounter in SNMP. This is because a) all the data in SNMP is registered in a tree structure, which does not map quite naturally to two-dimensional [column/row] tables, and b) the protocol itself has no verb for CREATE/INSERT/DELETE, so all creation/deletion of rows in tables has to be performed by means of SET requests.

Defining Tables in SNMP

In SMIv2, tables are defined in this way:

-----------------------------------------------------------------------
--
-- The JVM Input Argument Table
--
-- The jvmRTInputArgsTable contains one row per input argument given on
-- the Java command line.
--
-- See J2SE 5.0 API Specification,
--     java.lang.management.RuntimeMXBean.getInputArguments()
--     for more information.
-----------------------------------------------------------------------

jvmRTInputArgsTable OBJECT-TYPE
    SYNTAX      SEQUENCE OF JvmRTInputArgsEntry
    MAX-ACCESS  not-accessible
    STATUS      current
    DESCRIPTION
	"The Input Argument Table lists the input arguments passed
	 to the Java Virtual Machine. 

	 The jvmRTInputArgsIndex is the index of the argument in 
	 the array returned by RuntimeMXBean.getInputArguments().
	 
	 See java.lang.management.RuntimeMXBean.getInputArguments()
        "
    REFERENCE "J2SE 5.0 API Specification,
              java.lang.management.RuntimeMXBean"
    ::= { jvmRuntime 20 }

This defines a table called jvmRTInputArgsTable whose rows are modeled as instances of JvmRTInputArgsEntry.

Conceptual Rows

In fact, in SNMP, we do not speak of rows, but rather of conceptual rows. This is because there doesn't exists such a thing as a row in an OID tree: there doesn't exist such a thing as an instance of JvmRTInputArgsEntry, that you could identify by a single OID, and that you could get and set. What we have in the OID tree, and what you can get and set with SNMP, are individual table cells, identified by the OID of the column you're looking at, and the index of the conceptual row that intersects with that column. So here is how you define a conceptual row:

jvmRTInputArgsEntry OBJECT-TYPE
    SYNTAX      JvmRTInputArgsEntry
    MAX-ACCESS  not-accessible
    STATUS      current
    DESCRIPTION
	"Represent an input argument passed to the Java Virtual Machine.

	 See java.lang.management.RuntimeMXBean.getInputArguments()
        "
    REFERENCE "J2SE 5.0 API Specification,
              java.lang.management.RuntimeMXBean"
    INDEX { jvmRTInputArgsIndex }
    ::= { jvmRTInputArgsTable 1 }

JvmRTInputArgsEntry ::= SEQUENCE {
        jvmRTInputArgsIndex JvmPositive32TC,
	jvmRTInputArgsItem  JvmArgValueTC
}

The first construct (jvmRTInputArgsEntry is an OBJECT-TYPE that identifies the definition of the conceptual row itself. You will notice that this OBJECT-TYPE, like the OBJECT-TYPE that declares the table itself, is said to be not-accessible. This is because, as I have stated earlier, these objects are not value leaves of the OID tree, and therefore cannot be returned.
The jvmRTInputArgsEntry has mostly two clauses that interests us: the SYNTAX clause identifies the pseudo-type of the conceptual row. Just like the pseudo-type of the jvmRTInputArgsTable was declared to be a SEQUENCE OF JvmRTInputArgsEntry, the pseudo-type of jvmRTInputArgsEntry is declared to be JvmRTInputArgsEntry. Notice how the name of the conceptual row definition and the name of its pseudo-type differ only in the case of their first letter.
The second clause that interests us is the INDEX clause. The INDEX clause identifies the columns whose values will serve to uniquely identify a row in the table (they compose a primary key). In our case, we have only one column in the primary key - named jvmRTInputArgsIndex. We will see later the definition of this columnar object.

The second construct is not an OBJECT-TYPE, but is the ASN.1 definition of the pseudo-type of the conceptual row. This pseudo-type is declared to be a SEQUENCE of fields whose name and types correspond to the table's columnar objects. In this small example, we have only two columns, which are, the column index itself jvmRTInputArgsIndex and the value of the JVM input argument at that index, jvmRTInputArgsItem.

Now let's me state it again: jvmRTInputArgsTable, jvmRTInputArgsEntry, or JvmRTInputArgsEntry, are not things that can be returned by SNMP agents. The only things that will be returned by the SNMP agent - and only if it is asked politely, are the instances of jvmRTInputArgsItem.
Let's see how this works...

Definition of Index and Non-Index Columnar Objects

To complete the definition of our small input argument table, we must now define its two columns:

jvmRTInputArgsIndex OBJECT-TYPE
    SYNTAX      JvmPositive32TC
    MAX-ACCESS  not-accessible
    STATUS      current
    DESCRIPTION
	"The index of the input argument, as in the array returned 
	 by RuntimeMXBean.getInputArguments().

	 See java.lang.management.RuntimeMXBean.getInputArguments()
        "
    REFERENCE "J2SE 5.0 API Specification,
              java.lang.management.RuntimeMXBean"
    ::= { jvmRTInputArgsEntry 1 }

defines the jvmRTInputArgsIndex index column. There are two things that are noticeable about this definition. First, this index object is declared to be not-accessible. Why? because of The Chicken, and because of The Egg. Namely, to GET the value of the index, you would have to know the value of the index in the first place: asking for "hey, I want the value of the index where the value of the index is Z" would simply get you Z. This would be completely irrelevant and SMIv2 thus mandates that all indexes be declared as not-accessible - there is one exception, which I'm not going to detail - when the table contains only indexes - e.g. when it simply defines relationships between indexes in other tables. However, this is for 2nd year in SNMP, so let's forget about this for now - readers etc... STD 58, RFC 2578 etc... ;-)

TEXTUAL-CONVENTIONS

The second thing that is noticeable about this definition is the value of the SYNTAX clause, which is defined to be JvmPositive32TC.
JvmPositive32TC is a TEXTUAL-CONVENTION which is defined in the JVM-MANAGEMENT-MIB as follows:

JvmPositive32TC ::= TEXTUAL-CONVENTION
    STATUS       current
    DESCRIPTION
          "A positive Integer32. In Java that would be a number 
           in [0..Integer.MAX_VALUE].
	  "  
    -- We use Integer32 (0..2147483647) rather than Unsigned32 because
    -- Unsigned32 (0..2147483647) because Unsigned32 is based on 
    -- Gauge32 - which has a specific ASN.1 tag and a specific semantics. 
    -- In principle you cannot use a Gauge32 as base type for an index 
    -- in a table.
    -- Note also that Unsigned32 is (0..2\^32-1) 
    --          while Positive32 is (0..2\^31-1)
    -- 
    SYNTAX Integer32 (0..2147483647)

TEXTUAL-CONVENTIONS are in fact a means to assign some specific semantics to to a generic base type used in a specific context - here as value of an index. When the value of jvmRTInputArgsIndex will be encoded and sent over the wire, it will be encoded as a simple Integer32, just as if the JvmPositive32TC had never existed. Only by reading the MIB definitions for the corresponding object can you know that jvmRTInputArgsIndex in fact follows the JvmPositive32TC TEXTUAL-CONVENTION.

The End Is Close!

Finally, and to complete our table, we still need to define the only piece of data that we will be able to access, the real content of the table, its unique non index column (unique in this case: tables can have multiple indexes and multiple non index columns), the jvmRTInputArgsItem:

jvmRTInputArgsItem OBJECT-TYPE
    SYNTAX      JvmArgValueTC
    MAX-ACCESS  read-only
    STATUS      current
    DESCRIPTION
	"An input argument at index jvmRTInputArgsIndex, as in the array 
	 returned by RuntimeMXBean.getInputArguments().

	 Note that the SNMP agent may have to truncate the string returned
         by the underlying API if it does not fit in the JvmArgValueTC 
         (1023 bytes max).

	 See java.lang.management.RuntimeMXBean.getInputArguments()
        "
    REFERENCE "J2SE 5.0 API Specification,
              java.lang.management.RuntimeMXBean"
    ::= { jvmRTInputArgsEntry 2 }

This, dear reader who has been patient enough to follow me this far, is the actual data that is contained in this table - which makes it possible to retrieve, using the SNMP protocol, each of the args[i] input passed to the JVM public static void main(String[] args) method...
Hurrah!

Getting an Instance of a Columnar Object

So to get the value of args[i], and according to all these definitions we've been examining so far, you will simply need to send a GET request for the following OID: jvmRTInputArgsItem.<i> or in dot notation, and assuming that i=5:

1.3.6.1.4.1.42.2.145.3.163.1.1.4.20.1.2.5
\^---sun-----\^              \^     \^  \^ \^ \^
\^------jvmMgtMIB-----------\^     \^  \^ \^ \^
\^--------jvmRTInputArgsTable-----\^  \^ \^ \^
\^--------jvmRTInputArgsEntry--------\^ \^ \^ 
\^----------jvmRTInputArgsItem---------\^ \^
\^------value of jvmRTInputArgsItem------\^
         at jvmRTInputArgsIndex=5 

The End! Don't miss the next episode in our SNMP series!

In some next entries, I'll do a follow-up to explain how you can discover the content of a table by sending GET-NEXT request, how you can compose the index part of an OBJECT-IDENTIFIER when the index value is a string, and how to work with tables which have multiple indexes. But I think you will agree with me, this would be definitely too much for tonight...


Sleep Well!
Grenoble, France, one night at 12pm...
Comments:

Your blog was extremely useful for us to understand the basics of SNMP. Espesically the mystery behind "NOT-ACCESIBLE" was crisply explained. Cool Stuff, keep on blogging.

Posted by C. Sridhar on June 08, 2006 at 03:14 AM CEST #

Thanks for the praise! It is always gratifying to know when readers find an article useful!
Thanks for reading!

-- daniel

Posted by daniel on June 08, 2006 at 07:21 AM CEST #

Hi Daniel:

Excellent blogs! Your info on SNMP is concise and to the point. When can I expect the entry you promised about GET-NEXT? ("In some next entries, I'll do a follow-up to explain how you can discover the content of a table by sending GET-NEXT request")

Kind regards,

Frank Kieviet

Posted by Frank Kieviet on November 29, 2006 at 09:18 PM CET #

Hi Frank,
Your interest is noted. But I have an entry about multi-indexed tables in preparation first.

Cheers and thanks for reading,
-- daniel

Posted by daniel on December 10, 2006 at 01:20 PM CET #

Hi Daniel, It takes a master to explain someinformation so adequetly and I like to bow infront of you about the snmp table and table INDEX. I have been searching and searching besides many hours of reading books about snmp tables. Finally God send me your way and I really thank you. I am very interested in your type of explaining and blogging. Please inform me for any upcoming topic in your snmp domain of expertise. Thank you, thank you.

Posted by Reza Amiri on January 12, 2007 at 12:33 AM CET #

Hi Reza,
I'm glad you found my blog useful!
Thanks a lot for letting me know with such enthousiasm :-)
-- daniel

Posted by daniel on January 12, 2007 at 04:11 AM CET #

Hi, great blog, I'm a snmp beginner , and the article helped me to understand a little bit of Columnar Object.

I do have one question:
If you have conceptual table with several rows, will you have to define a different entries for each row?

Thanks again.

Posted by Edo on August 12, 2008 at 03:27 AM CEST #

can some one plz post a simple snmp program.. a get requset to some OID..

Posted by guest on November 12, 2008 at 03:47 AM CET #

in which folder should the jvm-management.mib should be kept??

Posted by ravi on November 12, 2008 at 03:49 AM CET #

Hi Ravi,

The jvm-management.mib is a specification - if you will, it's like javadoc.

If you want to write a Java program that gets an SNMP OID you can use for instance OpenDMK
http://opendmk.dev.java.net/

If you want to do it from a shell script you can use for instance NET-SNMP (on UNIX try: man snmpget).

hope this helps,
-- daniel

Posted by daniel on November 12, 2008 at 04:22 AM CET #

hey daniel,
thanks a lot for the reply,and one more question..

i tried to retrieve the value of the snmp variable corresponding to the oid=" 1.3.6.1.4.1.42.2.145.3.163.1.1.2.11" (jvmmemoryheapusage) by a simple snmp get request..but not getting any result.

Is it because i have not installed any java dynamic management kit?is dmk a must for any snmp operations with the java virtual machine?

Posted by ravi on November 12, 2008 at 11:03 PM CET #

Hi,

1) You need to start the Java app you want to monitor with the appropriate flag - in order to start the SNMP daemon:
http://java.sun.com/javase/6/docs/technotes/guides/management/snmp.html

2) If you are using snmpget to get the OID make sure that you are using the correct community string configured for the agent (see http://java.sun.com/javase/6/docs/technotes/guides/management/snmp.html)

3) When you get a scalar object you need to append .0 to the OID, so what you need to get is in fact jvmMemoryHeapUsed.0, which is 1.3.6.1.4.1.42.2.145.3.163.1.1.2.11.0, as explained here:
http://blogs.sun.com/jmxetc/entry/understanding_the_structure_of_management#OIDs

-- daniel

Posted by daniel on November 13, 2008 at 04:45 AM CET #

thanx a lot daniel , it worked.. thank you

Posted by ravi on November 14, 2008 at 03:28 AM CET #

hi daniel,

the above explanation worked,

i could find values for the oids of "jvmthreadcount","jvmdeamonthreadcount" n some others which returned Gauge32 or a Counter32 but when i looked for the value of any snmpvariable that returned Counter64,i dint get any response..

i did both of them with snmp.get() method..

what can be the problem?

thank you

Posted by ravi on November 14, 2008 at 05:23 AM CET #

Hi ravi,

To get 64 bits values you need to use the version 2 (SNMPv2c) of the SNMP protocol. 64 bits are not supported by SNMP v1. For instance if you're using snmpget you need to call it with the flag -v 2c

-- daniel

Posted by daniel on November 14, 2008 at 05:41 AM CET #

hi daniel,

your suggestions were really helpful,I learnt most of what i know about snmp from your blogs.. keep blogging

thanks a lot

Posted by ravi on November 16, 2008 at 10:36 PM CET #

Hi Daniel,

your suggestions were really helpful and I want to know whether snmpgetnext() method will work fine even for scalar objects?

snmpget() method is not working fine for tabular objects..y?..could u plzzz explain me these things in details...am very confused...

Thanks in Advance...

Malar

Posted by Malar on November 25, 2008 at 01:11 AM CET #

Hi Daniel
Thanks very much for this exceptionally clear explanation. I'm putting together some background for one of our J2EE teams who are just getting into SNMP - is it allowable for me to copy and paste some of this content (with complete attribution to you, of course) to use in an internal guide?
Regards
Scott

Posted by Scott on July 01, 2009 at 04:33 PM CEST #

Very clear and concise explanations, Daniel.
Thanks for shedding light on the intricacies of MIB objects.

Cheers,
Evan

Posted by Evan Gamblin on March 18, 2010 at 10:43 AM CET #

Excellent description.

Posted by Benix samuel on May 16, 2010 at 04:03 AM CEST #

Great Blog!

Thank you very much for great post!

Posted by Shankar on June 22, 2012 at 12:57 AM CEST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Daniel Fuchs blogs on Scene Builder, JMX, SNMP, Java, etc...

The views expressed on this blog are those of the author and do not necessarily reflect the views of Oracle.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today