Java Dynamic Management Kit 5.0 Tutorial

SNMP Protocol Adaptor

Once your MIBs are implemented as MBeans, your agent application needs an SNMP protocol adaptor to function as an SNMP agent. Because the SNMP adaptor is also an MBean, it can be created and started dynamically in your agent by a connected manager, or through the HTML adaptor.

Since Java DMK 5.0, the performance of the SNMP protocol adaptor has been improved by the addition of multithread support.

The following SNMPv1/v2 Agent example launches the protocol adaptor for SNMPv1/v2 agents, through the code of the agent application.


Example 18–1 SNMPv1/v2 Agent Application

public class Agent {

    static SnmpAdaptorServer snmpAdaptor = null;

    public static void main(String args[]) {
        
        MBeanServer server;
        ObjectName htmlObjName;
        ObjectName snmpObjName;
        ObjectName mibObjName;
        ObjectName trapGeneratorObjName;
        int htmlPort = 8082;
        int snmpPort = 8085; // non-standard

        [...]    
        try {
            server = MBeanServerFactory.createMBeanServer();
            String domain = server.getDefaultDomain();

            // Create and start the HTML adaptor.
            //
            htmlObjName = new ObjectName( domain +
				":class=HtmlAdaptorServer,protocol=html,port=" 
					 + htmlPort);
            HtmlAdaptorServer htmlAdaptor = new HtmlAdaptorServer(htmlPort);
            server.registerMBean(htmlAdaptor, htmlObjName);
            htmlAdaptor.start();

            // Create and start the SNMP adaptor.
            //
            snmpObjName = new ObjectName(domain +
                ":class=SnmpAdaptorServer,protocol=snmp,port=" + snmpPort);
            snmpAdaptor = new SnmpAdaptorServer(snmpPort);
            server.registerMBean(snmpAdaptor, snmpObjName);
            snmpAdaptor.start();

            // The rest of the code is specific to our SNMP agent

            // Send a coldStart SNMP Trap (use port = snmpPort+1)
            // Trap communities are defined in the ACL file
            //
            snmpAdaptor.setTrapPort(new Integer(snmpPort+1));
            snmpAdaptor.sendV1Trap(0, 0, null);

            // Create the MIB-II (RFC 1213) and add it to the MBean server.
            //
            mibObjName = new ObjectName("snmp:class=RFC1213_MIB");
            RFC1213_MIB mib2 = new RFC1213_MIB();
            // The MBean will register all group and table entry MBeans
            // during its pre-registration
            server.registerMBean(mib2, mibObjName);

            // Bind the SNMP adaptor to the MIB
            mib2.setSnmpAdaptorName(snmpObjName);

            [...]

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Needed to get a reference on the SNMP adaptor object
    static public SnmpAdaptorServer getSnmpAdaptor() {
        return snmpAdaptor;
    }
}

The following SNMPv3 AgentV3 example launches the protocol adaptor for SNMPv3 agents, in the same way as in the SNMPv1/v2 Agent example. This example creates a simple SNMPv3 agent, without encryption. See "Security Mechanisms in the SNMP Toolkit" for details of how to implement SNMPv3 agents with encryption.


Example 18–2 SNMPv3 AgentV3 Application

public class AgentV3 {

    static SnmpV3AdaptorServer snmpAdaptor = null;
    
    /**
     * This variable defines the number of traps this agent have to send.
     * If not specified in the command line arguments, the traps will be 
     * sent continuously.
     */
    public static void main(String args[]) {
        
        final MBeanServer server;
        final ObjectName htmlObjName;
        final ObjectName snmpObjName;
        final ObjectName mibObjName;
        final ObjectName trapGeneratorObjName;
        int htmlPort = 8082;
        int snmpPort = 161;

       
        try {
            server = MBeanServerFactory.createMBeanServer();
            String domain = server.getDefaultDomain();

            // Create and start the HTML adaptor.
            //
            htmlObjName = new ObjectName(domain + 
				":class=HtmlAdaptorServer,protocol=html,port=" + htmlPort);
            Trace.send(Trace.LEVEL_TRACE, Trace.INFO_MISC, "Agent", "main", 
                       "Adding HTML adaptor to MBean server with name \n\t"+
		       htmlObjName);
            println("NOTE: HTML adaptor is bound on TCP port " + htmlPort);
            HtmlAdaptorServer htmlAdaptor = new HtmlAdaptorServer(htmlPort);
            server.registerMBean(htmlAdaptor, htmlObjName);
            htmlAdaptor.start();
                  
            // Create and start the SNMP adaptor.
            //     snmpPort = 8085;
            //
            snmpPort = 8085;
            snmpObjName = new ObjectName(domain + 
                 ":class=SnmpAdaptorServer,protocol=snmp,port=" + snmpPort);
            snmpAdaptor = new SnmpV3AdaptorServer(snmpPort);
            server.registerMBean(snmpAdaptor, snmpObjName);
	           snmpAdaptor.registerUsmMib(server, null);
            snmpAdaptor.start();

            // Send a coldStart SNMP Trap. 
            // Use port = snmpPort+1.
            //
            snmpAdaptor.setTrapPort(new Integer(snmpPort+1));
            snmpAdaptor.snmpV1Trap(0, 0, null);
            println("Done.");
      
            // Create the MIB II (RFC 1213) and add it to the MBean server.
            //
            mibObjName= new ObjectName("snmp:class=RFC1213_MIB");
            RFC1213_MIB mib2 = new RFC1213_MIB_IMPL();
            server.registerMBean(mib2, mibObjName);
      
            // Bind the SNMP adaptor to the MIB 
         	mib2.setSnmpAdaptorName(snmpObjName, "TEST-CONTEXT");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static SnmpAdaptorServer getSnmpAdaptor() {
       return snmpAdaptor;
    }

Starting the SNMP Adaptor

We start the SNMP adaptor in the same way that we start the HTML adaptor. First we create a meaningful object name for its MBean, then we instantiate the class with a constructor enabling us to specify a non-default port, we register the MBean with the MBean server, and we start the adaptor to make it active.

By default, the SNMP protocol adaptor uses the standard SNMP port 161. Because other applications might be using this port on a host, our simple agent uses port 8085. When we connect to this agent, our SNMP manager must specify this non-standard port number.


Note –

On certain platforms, applications also require superuser privileges to assign the default SNMP port 161. If your SNMP adaptor uses this port, its agent application must be started with superuser privileges.


Creating MIB MBeans

Our agent application creates and manages one MIB, our subset of MIB-II. To do so, it instantiates the corresponding RFC1213_MIB MBean that was generated by the mibgen tool (see MIB Development Process). We give it a meaningful object name and then we register it in the MBean server.

The registration process enables the MBean to instantiate and register other MBeans that represent the groups of the MIB and the entries of its tables. The set of all these MBeans at the end of registration makes up the MBean representation of the MIB. If an SNMP manager later adds entries to a table, the MIB implementation registers the new entry MBean into the MBean server as well.

If you do not want to expose a MIB through the MBean server, you do not have to register it. However, you still need to create all of its other MBean objects so that the SNMP adaptor can access all of its groups and table entries. The generated code provides the init method in the main MBean of the MIB. Calling this method creates all necessary MBean objects without registering them in the MBean server.

Binding the MIB MBeans

The SNMP adaptors do not interact with MBeans in the same way as the other connectors and adaptors. Because the SNMP data model relies on MIBs, only MBeans representing MIBs can be managed through SNMP. The SNMP adaptor does not interact with MBeans of a MIB through the MBean server, they must be explicitly bound to the instance of the SNMP adaptor.

After a MIB is instantiated, you must set the SnmpAdaptorName attribute of its main MBean to bind it to the SNMP adaptor. You can either call its setSnmpAdaptorName method directly or, if the MIB's MBean was registered in the MBean server, another management application can set the attribute through the MBean's exposed interface.

In the binding process, the SNMP adaptor obtains the root OID of the MIB. The adaptor uses this OID to determine which variables are implemented in the MIB's corresponding MBeans.

Even though the SNMP adaptors can be registered in the MBean server, the adaptor only makes MIBs visible to SNMP managers. Other MBeans in the agent cannot be accessed or even represented in the SNMP protocol. The SNMP manager is limited by its protocol: it cannot take full advantage of a Java dynamic management agent through the basic MIBs, and it does not have access to any other MBeans. In an advanced management solution, you could write a special MIB and implement it so that operations on its variables actually interact with the MBean server. This is left as an exercise for the reader.

MIB Scoping

In the SnmpV3AdaptorServer, it is possible to specify a scope, or context name, when registering a MIB. Conceptually, there is one instance of the global OID tree per scope. If you do not specify a context name when registering a MIB, the MIB is registered in the default scope. You can thus register SnmpProxy objects in any default or specific scope. Routing and MIB overlapping is handled in the same way in any scope.

When an incoming request is received, the SnmpV3AdaptorServer first determines the scope of that request. Only the SNMP agents that have been registered in that scope are triggered by that request.

If the incoming request is an SNM v3 request, the scope is identified by the context name specified in the request protocol data unit (PDU). If no context name is specified, the scope of that request is the default scope. If the incoming request is an SNM v1 or v2 request, the scope of the request is the default scope, unless mapping community strings to context names is enabled in the adaptor.

To register a MIB in a specific context, call the following method:

myMib.setSnmpAdaptorName(myAdaptorName, "myContext")

This method only works for adaptors that have been registered with an MBean server.

Accessing a MIB MBean

Once the MBean representing a MIB has been instantiated and bound to one of the two SNMP adaptors, it is accessible through that SNMP adaptor. SNMP managers can send requests to operate on the contents of the MIB. The SNMP adaptor interprets the SNMP management requests, performs the operation on the corresponding MBean and returns the SNMP response to the manager. One SNMP protocol adaptor is compatible with SNMPv1 and SNMPv2c, and the other is compatible with these two protocols as well as SNMPv3.

The advantage of having an SNMP agent “inside” a Java dynamic management agent is that you can use the other communications protocols to interact with MIBs and manage the SNMP adaptor. Because both the registered MIBs and the adaptor are MBeans, they are exposed for management. In our simple agent, the MIB was registered, and you can view its MBeans in a web browser through the HTML protocol adaptor.

If our agent were to include other connectors, management applications could connect to the agent and also manage the MIB and the SNMP adaptor. A non-SNMP manager could instantiate new MIB objects, bind them to the SNMP adaptor and operate on the exposed attributes and operations of the MIB.

Non-SNMP managers can operate on the variables of a MIB, getting and setting values, regardless of any SNMP manager that might also be accessing them through the SNMP adaptor. When dealing with a table, however, they cannot create new table entry MBeans without adding them to the table. For example, in the InterfacesImpl.java class, we called the addEntry method of the IfTable object before registering the entry MBeans with the MBean server. This ensures that the new entries are visible when an SNMP manager accesses the table.

In order for a non-SNMP manager to create a table entry, you must customize the table's group MBean to expose this functionality. Briefly, you would need to write a new method that instantiates and initializes the entry's MBean, adds the MBean to the table object, and registers the entry MBean in the MBean server. Advanced customization such as this is not covered in our examples. In general, the designer of the agent and management applications is responsible for all coherency issues when accessing MIBs concurrently through different protocols and when adding table entries.

Managing the SNMP Adaptors

Non-SNMP managers can also control the SNMP agent through the MBean of the SNMP adaptors. Like the other communications MBeans, the port and other attributes can be modified when the SNMP adaptor is stopped. You can also get information about its state, and stop or restart it to control when it is online. These administrative attributes and operations are defined in the CommunicatorServerMBean interface.

The SNMPv1v/2 adaptor server implements the SnmpAdaptorServerMBean interface to define its operating information. The SNMPv3 adaptor server implements a similar interface called SnmpV3AdaptorServerMBean. The SNMP protocols define certain variables that SNMP agents must expose about their current state. For example, the SNMP adaptor provides methods for getSnmpInPkts and getSnmpOutBadValues. Non-SNMP managers can read these variables as attributes of the SNMP adaptor MBean.

The SNMP adaptors also expose other operating information that is unavailable to SNMP managers. For example, the ActiveClientCount and ServedClientCount read-only attributes report on SNMP manager connections to this agent. The read-write BufferSize attribute enables you to change the size of the message buffer, but only when the adaptor is not online. The adaptor MBean also exposes operations for sending traps or implementing your own security (see Enabling User-Based Access Control).

To Run the SNMPv1/v2 Agent Example
  1. After building the example as described in MIB Development Process, start the simple SNMPv1/v2 agent with the following command:


    $ java -classpath classpath:. Agent nbTraps
    

    Set nbTraps to zero.

    You should see some initialization messages, including our notification listener giving information about the two table entries that are created. Access this agent's HTML adaptor by pointing a web browser to the following URL: http://localhost:8082/.

  2. Through the HTML adaptor, you can see the MBeans representing the MIB:

    • The class=RFC1213_MIB MBean in the snmp domain is the MBean representing the MIB; it contains a name and information about the SNMP adaptor to which the MIB is bound

    • The RFC1213_MIB domain contains the MBeans for each group; both name=Snmp and name=System contain variables with values provided by our customizations

    • The ifTable domain contains the entries of the Interfaces table

    • The trapGenerator domain contains the class that sends traps periodically, as part of our sample MIB implementation

  3. In any of these MBeans, you can write new values into the text fields of exposed attributes and click the Apply button.

    This sets the corresponding SNMP variable, and thereafter, SNMP managers see the new value. This is an example of managing a MIB through a protocol other than SNMP.

    For any SNMP agent application, you can turn on trace messages for the SNMP adaptor by specifying the -DINFO_ADAPTOR_SNMP property on the command line. The tracing mechanism is described in the Java Dynamic Management Kit 5.0 Tools Reference and in the Javadoc API of the com.sun.jdmk.TraceManager class (for receiving traces) and the com.sun.jdmk.trace.Trace class (for producing traces).

  4. Press Control-C when you have finished viewing the agent.

Configuring SNMPv3 Security for Agents

Before you run the SNMPv3 agent examples, you require some information about how SNMPv3 security is configured. Below are brief descriptions of the SNMPv3 security files that provide you with the information you need to run the SNMPv3 examples in this chapter. Full descriptions of the SNMPv3 security mechanisms are given in SNMPv3 User-Based Security Model.

The SNMPv3 security mechanisms are defined in two text files:

The files used by the SNMPv3 agent examples are provided in the examplesDir/Snmp/Agent directory. These files are used by the examples in the subsequent sections of this chapter.


Example 18–3 A jdmk.security File for an SNMPv3 Agent

The jdmk.security identifies the SNMP engine, authorized user and the security settings for the SNMPv3 session:

#Local engine ID
localEngineID=0x8000002a05819dcb6e00001f95
#Number of boots
localEngineBoots=0

#User and security configuration
userEntry=localEngineID,defaultUser,,usmHMACMD5AuthProtocol,mypasswd

The local engine ID and the number of times that engine will boot are read by the agent when it is created.

The authorized users and the security levels for the SNMP session are defined by the userEntry. This particular jdmk.security file defines a user that implements authentication, but not privacy. Consequently, the settings are as follows:

localEngineID

The identifier of the local engine, as specified earlier in the file

defaultUser

The name of the authorized user

usmHMACMD5AuthProtocol

The authentication algorithm; in this case, HMAC MD5

myPasswd

The authentication password


Note –

User-based access control is not used by the examples in this chapter, so we do not examine the jdmk.uacl file here. See Chapter 20, Security Mechanisms in the SNMP Toolkit to find out how to implement user-based access control.


To Run the SMNPv3 AgentV3 Example
  1. After building the example as described in MIB Development Process, start the simple SNMPv3 agent with the following command:

    You have to direct the AgentV3 example to its security file to run it.


    $ java -classpath classpath -Djdmk.security.file=./jdmk.security 
    AgentV3 nbTraps
    

    Set nbTraps to zero.

    You should see some initialization messages, including our notification listener giving information about the two table entries that are created. Access this agent's HTML adaptor by pointing a web browser to the following URL: http://localhost:8082/.

  2. Through the HTML adaptor, you can see the MBeans representing the MIB:

    • The SNMP_USER_BASED_SM_MIB domain contains information pertaining to the user-based security model implemented; see "Security Mechanisms in the SNMP Toolkit" for details of how to implement SNMPv3 user-based security.

    • The class=RFC1213_MIB MBean in the snmp domain is the MBean representing the MIB; it contains a name and information about the SNMP adaptor to which the MIB is bound

    • The RFC1213_MIB domain contains the MBeans for each group; both name=Snmp and name=System contain variables with values provided by our customizations

    • The ifTable domain contains the entries of the Interfaces table

    • The trapGenerator domain contains the class that sends traps periodically, as part of our sample MIB implementation

  3. In any of these MBeans, you can write new values into the text fields of exposed attributes and click the “Apply” button.

    This sets the corresponding SNMP variable, and thereafter, SNMP managers see the new value. This is an example of managing a MIB through a protocol other than SNMP.

    For any SNMP agent application, you can turn on trace messages for the SNMP adaptor by specifying the -DINFO_ADAPTOR_SNMP property on the command line. The tracing mechanism is covered in the Java Dynamic Management Kit 5.0 Tools Reference guide and in the Javadoc API of the com.sun.jdmk.TraceManager class (for receiving traces) and the com.sun.jdmk.trace.Trace class (for producing traces).

  4. Press Control-C when you have finished viewing the agent.