Java Dynamic Management Kit 5.1 Tutorial

16.3 Sending Traps

Agents can send unsolicited event reports to management applications by using traps. The SNMP protocol adaptor can send v1, v2 and v3 traps, the differences being in the format of the corresponding PDU. Traps in the SNMP specification are not acknowledged by the management application, so agents do not know if traps are received. However, under SNMPv2 and v3, acknowledgements can be sent in the form of informs.

Inform requests are acknowledged event reports, they are sent by entities acting in a manager role, according to RFC 1905. In the Java DMK, both the SNMP adaptor and the classes of the SNMP manager API can send inform requests. Manager-to-manager inform requests are described in 17.3 Inform Requests. Agent-to-manager inform requests are demonstrated by the applications in the current/Snmp/Inform/ example directory located in the main examplesDir directory.

In this example, we demonstrate how our simple SNMP agent application can send traps. The class IfEntryImpl in the example directory extends the IfEntry class generated by mibgen to provide a method that switches the IfOperStatus variable and sends a trap. Before sending the trap, the example establishes whether the agent is an SNMPv1/v2 agent or SNMPv3, and sends a trap accordingly. This is an example of customization of the generated code: an agent-side entity switches the operation status, the MIB variable is updated and a trap is sent to SNMP managers.


Example 16–4 Sending a Trap in the IfEntryImpl Class

    public void switchifOperStatus() {
    // Implement the switch and then calls sendTrap indirectly
     [...]
    }

    // Identify the adaptor created by one of the entry-point
    // classes for this example.

    private void initialize() {

			boolean encryption=false;
			SnmpAdaptorServer snmpAdaptor = null;
	
		// Determine wheter we are within the the scope of Agent.java, 
		// StandAloneSnmpAgent.java, AgentV3.java, AgentEncryptV3.java
	
		try {
	    snmpAdaptor = Agent.getSnmpAdaptor();
	    if (snmpAdaptor != null) return;

	    snmpAdaptor = StandAloneSnmpAgent.getSnmpAdaptor();
	    if (snmpAdaptor != null) return;

	    snmpAdaptor = AgentV3.getSnmpAdaptor();
	    if (snmpAdaptor != null) return;

	    snmpAdaptor = AgentEncryptV3.getSnmpAdaptor();
	    if (snmpAdaptor != null) {
		encryption=true;
		return;
	    }

	} finally {
	    // Set the value of this.snmpAdaptor and 
	    // this.securityLevel
	    // 
	    this.snmpAdaptor=snmpAdaptor;
	    this.securityLevel = SnmpDefinitions.noAuthNoPriv;
	    if (snmpAdaptor == null) return;
	    if (snmpAdaptor instanceof SnmpV3AdaptorServer) {
		this.securityLevel = (encryption?SnmpDefinitions.authPriv:
				      SnmpDefinitions.authNoPriv);
	    } 
	}
    }

    	// Send SNMP v1 traps with the generic number of the trap
    	// according to the "IfOperStatus" value.
     //
    	public void sendTrap(int generic) {

        if (snmpAdaptor == null) {
           java.lang.System.err.println("BUG: 
				IfEntryImpl.sendTrap(): 
				snmpAdaptor is null");
           return;
        }

        String generic_string= null;

        switch (generic) {
		case 3:
			generic_string = "linkUp";
			break;
		case 2:
			generic_string = "linkDown";
			break;
		default:
			java.lang.System.err.println("BUG: IfEntryImpl.sendTrap(): 
			bad generic: " + generic);
			return;
        }

        SnmpVarBindList varBindList = new SnmpVarBindList();

        SnmpOid oid1 = new SnmpOid("1.3.6.1.2.1.2.2.1.1." + IfIndex);
        SnmpInt value1 = new SnmpInt(IfIndex);
        SnmpVarBind varBind1 = new SnmpVarBind(oid1, (SnmpValue) value1);

        varBindList.addVarBind(varBind1);

        java.lang.System.out.print("NOTE: Sending a " + generic_string +
                                   " SNMP trap for the Interface " + 
				   IfIndex +
                                   " to each destination defined" +
				   " in the ACL file...");
        try {
	    	//Send SNMPv3 trap if v3 agent only.
	   		 if(snmpAdaptor instanceof SnmpV3AdaptorServer) {
				final SnmpV3AdaptorServer adaptorV3=
		   		 (SnmpV3AdaptorServer)snmpAdaptor;
				adaptorV3.snmpV3UsmTrap("defaultUser",
					securityLevel,
					"TEST-CONTEXT",
					new SnmpOid("1.2.3.4.5.6.7.8.9.0"), 
					varBindList);
	    }
	  	 	 // Send v1 trap in every case.
	    		snmpAdaptor.snmpV1Trap(generic, 0, varBindList);
			} catch (Exception e) {
            e.printStackTrace();
        }
        java.lang.System.out.println("Done.");
    }
}

As the sendTrap method runs in a different thread, it needs to get a reference to the SNMP adaptor instance. Here we call the static methods of our different possible agent implementations. This code is specific to these agents and is only an example of how to retrieve this information.

As shown in the above example, SNMPv1 traps are always sent, regardless of the version of SNMP of the agent. An SNMPv3 trap is sent only when the agent is an SNMPv3 agent.

To simulate a live operation status, we invent the LinkTrapGenerator class that switches the status periodically. It is an MBean that contains a thread that loops endlessly. The interval period between traps and the number of the table entry can be modified through the MBean's attributes.


Example 16–5 Thread of the Link Trap Generator

public void run() {
    int remainingTraps = nbTraps;
    while ((nbTraps == -1) || (remainingTraps > 0)) {
        try {
            sleep(interval);
        } catch (Exception e) {
            e.printStackTrace();
        }
        triggerTrap();
        remainingTraps--;
    }
}

public void triggerTrap() {
    // get the entry whose status we will switch
    IfEntryImpl ifEntryImpl = InterfacesImpl.find(ifIndex);
    if (ifEntryImpl == null) {
        errors++;
        return;
    }
    ifEntryImpl.switchifOperStatus();
    successes++;
}

To run the trap generator, the example application instantiates and registers a LinkTrapGenerator MBean. During its registration, this MBean starts the thread, sending a trap every two seconds by default.


Example 16–6 Starting the Trap Generator Example

// Create a LinkTrapGenerator (specify the ifIndex in the object name)
//
String trapGeneratorClass = "LinkTrapGenerator";
int ifIndex = 1;
trapGeneratorObjName = new ObjectName("trapGenerator" +
    ":class=LinkTrapGenerator,ifIndex=" + ifIndex);
LinkTrapGenerator trapGenerator = new LinkTrapGenerator(nbTraps);
server.registerMBean(trapGenerator, trapGeneratorObjName);

[...] // Press <Enter> to start sending traps

trapGenerator.start();

16.3.1 Specifying the Trap Destination

There are several methods in the SNMP protocol adaptor for sending traps to remote managers. They differ in their method signatures, depending upon whether or not you need to specify the destination host. When no host is specified, the SNMP protocol adaptor relies on the trap group definition in IP-based access control lists (InetAddressAcl), as described below.

In all cases, traps are sent to the port specified by the current value of the TrapPort attribute on the SnmpAdaptorServer or SnmpV3AdaptorServer MBean. In our simple agent, we set the trap port to 8086, but this can be changed at any time by a custom MIB implementation or a management application.

Although SNMPv3 implements user-based access control for other types of requests, traps and informs are always sent using InetAddressAcl, in all versions of SNMP.

16.3.1.1 Using an InetAddressAcl Trap Group

The methods below were used in Example 16–4 to send SNMPv1 and v3 traps. They are presented here with their SNMPv2 equivalent (see the Javadoc API for a description of the parameters).

Using these methods, you must first define the trap group in an InetAddressAcl. See 19.1 IP-Based Access Control Lists for a formal definition of the trap group and instructions for defining the InetAddressAcl file when starting the agent. By default, these lists are file-based, but you can implement other mechanisms, as described in 19.1.3 Custom Access Control.

In this example, we provide the following template file.


Example 16–7 Trap Group of the jdmk.acl File

acl = {
  …
}

trap = {
  {
  trap-community = public
  hosts = yourmanager
  }
}

The trap group lists all the hosts to which the SNMP protocol adaptor sends every trap. A community definition associates a community name with a list of hosts specified either by one of the following identifiers:

Hostname

The name of the host

IP v4 and IPv6 address

For example, 123.456.789.12 for IPv4, and fe80::a00:20ff:fe9b:ea82 for IPv6

IPv4 and IPv6 netmask prefix notation

For example, 123.456.789.12/24 for IPv4, and fe80::a00:20ff:fe9b:ea82/64 for IPv6

All hosts in a community definition receive the trap in a PDU identified by the community name.


Note –

Because access control and trap recipients share the same file, you must fully define the access control when you want to send traps using the InetAddressAcl mechanism.


Given this definition, traps are sent to a host called yourmanager, and the community string of the trap PDU would contain the value public. By adding community definitions to this file, you can specify all hosts that will receive traps along with the community string for each host or group of hosts.


Note –

SNMPv3 does not use the community string to identify destinations. Only use the manager's IP address when creating an SNMPv3 trap group, or the contextName to define the scope of the requests sent.


If the InetAddressAcl file is not defined, or if the trap group is empty, the default behavior of these methods is to send a trap only to the local host.

16.3.1.2 Specifying the Hostname Directly

The other methods of the SNMP protocol adaptor, one for each trap version, enable you to send a trap to a specified recipient:

In the first two cases, these methods take an address and a community string, in addition to the version-specific trap information. The address is an InetAddress object that is usually instantiated by its static methods getLocalHost or getByName. The second method returns a valid InetAddress object when given a string representing a hostname or IP address.

The cs parameter is the community string, a name that the agent and manager exchange to help identify one another. The string given is used as the community when sending the trap PDU.

The SNMPv3 method also takes an InetAddress, but does not use the community string. Only use the manager's IP address when creating an SNMPv3 trap group, or the contextName to define the scope of the requests sent.

Either one of these methods sends a trap to a single manager using a single community string. The InetAddressAcl trap group mechanism is better suited to sending traps to multiple managers, though it requires you to set up a trap group. Note that even if a trap group is in use, the two methods above only send one trap to the specified host address.

16.3.2 Traps in the Agent and AgentV3 Examples

Before starting the SNMP agent again, edit the jdmk.acl file to replace the occurrences of yourmanager with the name of a host running an SNMP manager.

You can start the example SNMPv3 agent by replacing Agent with AgentV3.

Start the agent, specifying the InetAddressAcl file as a property:


$ java -classpath classpath 
-Djdmk.acl.file=examplesDir/current/Snmp/Agent/jdmk.acl \ 
       -classpath classpath:. Agent nbTraps

In these commands, nbTraps is the number of traps that the agent sends. Set it to a small integer to avoid too much output. If you omit this parameter, traps are sent continuously.

If you do not have an SNMP manager or a second host, do not copy the InetAddressAcl file or specify it as a property. In the absence of the trap-community definitions, the traps are addressed to the trap port on the local host. And even if no manager is running, we can still see the agent sending the traps. See 17.1.4 SNMP Trap Handler for details about receiving traps.

To Interact With the Trap Generator
  1. Access this agent's HTML adaptor by pointing a web browser to the following URL: http://localhost:8082/. Click on the class=LinkTrapGenerator,ifIndex=1 MBean in the trapGenerator domain.

    Through the HTML adaptor, you can see the MBean representing the trap generator object. You can modify its attributes to change the table entry that it operates on and to change the interval between traps.

  2. Change the trap interval to 10000 so that traps are sent every 10 seconds.

  3. Go back to the agent view and click on the ifEntry.ifIndex=1 MBean in the ifTable domain. Set the reload period to 10, and click the Reload button.

    You should see the effect of the trap generator is to switch the value of the IfOperStatus variable. It is our implementation of the table entry that sends a trap when this status is changed.

  4. Go back to the agent view and click on the name=Snmp MBean in the RFC1213_MIB domain. Scroll down to see the SnmpOutPkts and SnmpOutTraps variables.

    These variables should be the only nonzero values, if no manager has connected to the SNMP agent. The Snmp group shows information about the SNMP adaptor, and we can see how many traps have been sent since the agent was started.

  5. Press Control-C when you have finished interacting with the agent.

The LinkTrapGenerator MBean is not manageable through the SNMP adaptor because it is not part of any MIB. It is an example of another MBean providing some control of the SNMP agent, and this control can be exercised by other managers connecting through other protocols. This shows that designing an SNMP agent application involves both the implementation of the MIB functionality and, if desired, the implementation of other dynamic controls afforded by the JMX architecture and the services of Java DMK.