It is easier to manage a large number of simple network management protocol (SNMP) agents when they have a hierarchical structure of master agents and subagents. Master agents concentrate and relay the information in their subagents and can provide their own specific information as well. Managers only communicate with the master agents and access the subagents transparently, as if the information actually resided in the master agent.
This chapter covers the following topics:
20.1 SNMP Master Agent and the SNMPv3 Proxy Forwarder explains the differences between the Java Dynamic Management Kit (Java DMK) 5.1 SNMP master agent and the SNMPv3 proxy forwarder
20.2 Overview of the SNMP Master Agent provides a description of the different Java DMK 5.1 functions that make up the SNMP master agent
20.3 Routing Overlapping MIBs explains the concept of overlapping MIBs
20.4 MIB Scoping in Master Agents details how scoped MIBs are used by the master agent
20.5 Trap Forwarding describes how master agents listen for traps and forward them to managers
20.6 Protocol Translation describes how the master agent translates requests between different versions of the SNMP protocol
20.7 SNMP Master Agent Examples explains how to run the SNMP master agent example provided with Java DMK 5.1
The Java DMK 5.1 SNMP master agent is clearly distinct from the SNMPv3 proxy forwarder application as described in RFC 2573 SNMPv3 Applications, and must not be confused with it. The distinction is as follows:
An SNMP master agent makes it possible to route parts of an SNMP request to a number of subagents. The subagents are completely hidden from the manager. The manager sees a single SNMP entity, the master agent. In an SNMPv3 framework, the manager knows only one SNMP engine ID, namely that of the master agent. A single SNMP request might trigger the retrieval of information from several subagents. How the information is dispatched and retrieved from the subagents is completely controlled by the master agent and is hidden from the manager.
On the contrary, in a proxy forwarder application, the manager needs to be aware of all the proxied agents. It needs to build a request targeted to a single specific subagent, and it needs to include in the request some information that enables the proxy forwarder application to determine which subagent is the target of the request. In SNMPv3, this is the subagent's SNMP engine ID. In SNMPv1 and SNMPv2, it is a specific community string, for example public@bridge2, where bridge2 identifies the subagent to which the request is forwarded.
The SNMP master agent functionality is thus particularly dedicated to the integration of legacy SNMP agents, in cases where the manager must see only a single entity. An example of such an SNMP master agent is snmpdx on the Solaris operating environment. The proxy forwarder application is more generally used as a firewall, to route information from a public node to agents running in a private network, or to add an additional security layer (for example, SNMPv3 security) to unsecured agents.
Both applications, master agent and proxy forwarder, share a common set of functions, for example, transferring information from one version of the SNMP protocol to another. However, their scope of application is different, and the problems they address are distinct. Java DMK 5.1 supports only the master agent, and does not support the proxy forwarder.
The SNMP master agent function is available on the SnmpV3AdaptorServer. As the SnmpV3AdaptorServer is trilingual, a master agent can answer requests in SNMPv1, SNMPv2 or SNMPv3. The master agent function is based on the functional blocks of the Java DMK 5.1 SNMP toolkit, particularly:
The SnmpV3AdaptorServer makes it possible to register an SnmpMibAgent that handles all varbinds whose OIDs are contained below a given node of the global OID tree. For each SNMP request, all varbinds that are relevant to the part of the OID tree handled by the SnmpMibAgent are grouped into an SnmpMibRequest and passed to the SnmpMibAgent. The concrete SnmpMibAgent implementation can be either a local MIB generated by the mibgen tool, or a remote MIB, configured with an SnmpProxy object.
The SnmpV3AdaptorServer enables you to register overlapping MIBs. The actual value returned to the manager is the value implemented by the deepest MIB registered for that value. This makes it possible to register, for example, a default SnmpMibAgent to which all unhandled OIDs are forwarded. An example of such a default subagent can be the Solaris subagent snmpdx, all the OIDs of which are neither handled locally nor handled by known subagents. This makes it possible to forward them to an SnmpProxy object that forwards to snmpdx and is registered at the root of the OID tree. This only requires registering such an SnmpProxy object at the root of the OID tree.
The SnmpV3AdaptorServer supports MIB scoping, namely, context names, and makes it possible to register a MIB within a given scope, that is, for a given context name. The SnmpV3AdaptorServer also makes it possible to extract context names from an SNMPv1 or SNMPv2 community string. The master agent function can thus be spawned over several context names. A specific context name can be dedicated to a specific subagent, enabling you to register a single SnmpProxy object at the root of the OID tree for a given context name. The context name can also be shared between several subagents, and possibly local MIBs, as described above.
The SnmpProxy object makes it possible to get the actual values requested by the manager from a MIB implemented in a remote SNMP subagent. The SnmpProxy objects are able to get values from SNMP agents implementing either of the SNMPv1 or SNMPv2 protocols. This makes it possible to get values from legacy SNMP agents in a way that is transparent to the manager.
The SnmpProxy object extends the SnmpMibAgent abstract class, and as such can be registered in the SnmpV3AdaptorServer just like a local MIB generated by the mibgen tool. In a master agent application, one SnmpProxy must be created per subagent. When creating the SnmpProxy object, you must provide it with the following parameters to enable it to access the underlying subagent:
Subagent's IP address
Subagent's port number
Security parameters, namely community strings, used for communicating with the subagent
Version of SNMP that must be used to access the subagent, namely either SNMPv1 or SNMPv2
Then you must register that proxy with the SnmpV3AdaptorServer, once for each MIB implemented by the subagent that you want to mirror in the master agent. This is demonstrated in Example 20–1.
A subagent implements the following three MIBs:
mib#1 (root OID=x.y.z.1)
mib#2 (root OID=x.y.z.2)
mib#3 (root OID=x.y.z.3)
If you want mib#1 and mib#3 to be accessible from the master agent managers, then you need to register your SnmpProxy object for both mib#1 and mib#3:
SnmpV3AdaptorServer snmpAdaptor = ....; SnmpProxy mySubAgentProxy = new SnmpProxy(....); SnmpOid oids[] = new SnmpOid(2); oids[0] = new SnmpOid("x.y.z.1"); oids[1] = new SnmpOid("x.y.z.3"); snmpAdaptor.addMib(mySubAgentProxy,oids); |
Once you have done this, all varbinds contained in an SNMP request whose OIDs appear to be below x.y.z.1 or x.y.z.3 are passed to the registered mySubAgentProxy. The mySubAgentProxy proxy gets the actual values from the remote agent it is proxying. OIDs that appear to be contained below x.y.z.2 are not forwarded, and where applicable, are handled locally, because the SnmpProxy is not registered for those OIDs.
The SnmpUsmProxy object performs the same function as the SnmpProxy, except that it gets values from SNMP agents implementing the SNMPv3 protocol.
The SnmpUsmProxy object extends the SnmpUsmMibAgent abstract class, and as such can be registered in the SnmpV3AdaptorServer just like a local MIB generated by the mibgen tool. In a master agent application, one SnmpUsmProxy must be created per subagent. When creating the SnmpUsmProxy object, you must provide it with the following parameters to enable it to access the underlying subagent:
Subagent's IP address
Subagent's port number
Security parameters, namely context names, the user name and the security level, used for communicating with the subagent
Request context, namely the context engine ID and the context name
The SnmpUsmProxy receives requests in any version of SNMP, and always forwards them as SNMPv3 requests.
An SnmpTrapForwarder object makes it possible to listen to traps emitted by a subagent, convert them into the master agent's manager's protocol or protocols, and forward them to the manager or managers as if they originated from the master agent itself. One or more SnmpTrapForwarder objects must be instantiated, and the subagents must be configured to send their traps to these objects. This is the responsibility of the main application code. This is explained in detail in 20.5 Trap Forwarding.
In a master agent application, routing is performed depending on the OIDs requested. SNMP MIB agents are registered for branches of the global OID tree, and varbinds are dispatched to subagents according to the requested OIDs. The SnmpV3AdaptorServer supports registration of overlapping MIBs. Overlapping MIBs are MIBs that are registered below the OID of a previously registered MIB. The actual value returned to the manager is the value implemented by the deepest MIB registered for that value. When a get or set request is received, for each varbind in the request, the SnmpV3AdaptorServer identifies the deepest MIB responsible for handling the OID contained in the varbind. All varbinds targeted to that MIB are grouped in an SnmpMibRequest, and that request is passed to the identified SnmpMibAgent.
MIB overlapping enables you to shadow MIBs that are implemented in subagents. For instance, you might want to implement the system group and snmp from MIB-II locally in your master agent, and delegate all other requests concerning MIB-II to a legacy SNMP agent implementing MIB-II. You do this as described in To Shadow Overlapping MIBs.
Run the mibgen tool to generate an implementation of MIB-II
Instrument the system group and snmp group as shown in the basic SNMP agent example in “Creating an SNMP Agent”
Register your generated MIB with the OIDs of both the system group, 1.3.6.1.2.1, and snmp group, 1.3.6.1.2.1.1.1
Create an SnmpProxy object proxying your legacy MIB-II agent, and register that proxy for the root OID of MIB-II
MIB overlapping also enables you to delegate all unhandled OIDs to a legacy master agent, such as the Solaris agent snmpdx. If you register an SnmpProxy at the root of the OID tree, then all varbinds for whose OIDs no SnmpMibAgent was registered are passed to that SnmpProxy.
In addition, MIB overlapping enables you to give precedence to a specific agent for a part of a MIB, by registering it deeper in the OID tree.
For a get-next or get-bulk request, the incoming OID does not make it possible to identify directly the subagent that will contain the next OID. Indeed, the next OID might not be a sub-OID of the requested OID, but might be in a different part of the global OID tree. The get-next and get-bulk requests are thus forwarded to all subagents, and sorted a posteriori to identify the deepest matching subagent.
MIB scoping is a special case in which the SNMP proxy forwarder application can be emulated by a master agent application. If a subagent is dedicated completely to handling a specific MIB scope, you register a single SnmpProxy for that subagent at the root of the OID tree for that scope. Because there can be only one context per request, then all or none of the varbinds in the incoming request are passed to the SnmpProxy. In this case, the master agent application behaves similarly to a proxy forwarder application. The only difference is that it identifies the target agent with the context name contained in the request.
Another function of an SNMP master agent is to listen to SNMP traps and notifications emitted by its subagents, and to forward them to its managers. The Java DMK 5.1 SNMP toolkit provides an SnmpTrapForwarder for that purpose.
How to configure the trap forwarding mechanism is entirely the responsibility of your main application code. The following are three possibilities for ways to configure your trap forwarding mechanism, but the list is by no means exhaustive.
Create a single SnmpTrapForwarder and make all subagents to send traps to that forwarder
Create one forwarder per subagent, each listening to a different port for each subagent
Create one SnmpTrapForwarder per manager, each one forwarding traps to a specific manager
The SnmpTrapForwarder handles protocol conversion. It is able to convert any of an SNMPv1 trap, or an SNMPv2 or SNMPv3 notification into any of an SNMPv1 trap or an SNMPv2 or SNMPv3 notification following the protocol conversion rules specified in RFC 2576.
You can pass specific manager addresses when forwarding for a specific protocol. By default the InetAddressAcl is also parsed. So the set of actual manager addresses is the trap blocks located in the acl file and the set of added targets. You can disable the InetAddressAcl parsing by calling the method setInetAddressAclUsed(false).
To enable trap forwarding you must start the trap forwarder.
If you have manager addresses in your set of targets that are also present in InetAddressAcl, or you have no InetAddressAcl activated but are targeting the local host, your manager will receive the trap twice. To prevent this, configure the SnmpTrapForwarder carefully. You can, for example, disable the setInetAddressAcl parsing by calling isInetAddressAclUsed(false).
By default a trap is sent as a notification originator. The difference between acting as a notification originator or acting as a proxy when forwarding the trap is detailed in RFC 2576 “Coexistence Between SNMP versions”
Proxy forwarding is activated by calling the forwardAsProxy() method.
When translating SNMPv1 traps into SNMPv2 traps, the varbind received is reused. Three additional varbinds are appended, if these three additional varbinds do not already exist in the SNMPv1 varbinds:
The name portion of the first additional varbind contains snmpTrapAddress.0, and the value contains the SNMPv1 agent-addr parameter.
The name portion of the second additional varbind contains snmpTrapCommunity.0, and the value contains the value of the community string field from the received SNMPv1 message which contained the SNMPv1 trap PDU.
The name portion of the third additional variable binding contains snmpTrapEnterprise.0, and the value is the SNMPv1 enterprise parameter.
The SNMPv1 agent-addr parameter is determined by the proxy extracting the original source of the notification from the varbinds, If the SNMPv2 varbinds contain a varbind whose name is snmpTrapAddress.0, the agent-addr parameter is set to the value of that varbind. Otherwise, the SNMPv1 agent-addr parameter is set to 0.0.0.0.
Traps are forwarded as notification originators by calling the forwardAsNotificationOriginator() method.
When translating from SNMPv1 to SNMPv2, the SNMPv2 varbinds are the same as the SNMPv1 varbinds.
When translating from SNMPv2 to SNMPv1, the SNMPv1 agent-addr parameter is determined as follow:
If the notification is sent over IP, the SNMPv1 agent-addr parameter is set to the IP address of the SNMP entity in which the notification originator resides.
If the notification is sent over some other transport protocol, the SNMPv1 agent-addr parameter is set to 0.0.0.0.
As explained in the previous section, both the SnmpProxy and SnmpTrapForwarder are compliant with RFC 2576. However, RFC 2576 does not simply describe protocol conversion, but rather describes how protocol conversion is performed in the scope of a proxy forwarding application. In a master agent application, the question is more complex because we want the master agent to behave as a single agent responding with the same protocol as is used by the manager. We also want to hide the presence of subagents from the manager.
When looking from an end-to-end perspective, the master agent does not strictly behave as described in RFC 2576. This is because the protocol translation applied by the SnmpProxy is post-processed and aggregated in the master agent with results coming from other SnmpMibAgents, such as SnmpProxy objects and mibgen generated local MIBs, each possibly translating from different protocol versions.
The main differences, when looking from an end to end perspective, between protocol translation in the SNMP master agent and RFC 2576 are the following:
When the incoming request is an SNMPv2 or SNMPv3 request, the error codes returned are SNMPv2 error codes, when applicable, even if the subagent from which the error originally came is a SNMPv1 agent.
When the incoming request is an SNMPv2 or SNMPv3 request, get, get-next and get-bulk always transform global SNMPv1 errors into a varbind value of noSuchInstance, noSuchObject, or endOfMibView, and skip to the next varbind; this is the same behavior as for an SNMPv2/v3 agent.
If an exception is raised or an error is returned by a subagent during the set() phase of a set request, then the error returned is always undoFailed. In fact, there is no way to apply a two-phased check()/set() action to a remote SNMP agent because the SNMP protocol does not have any CHECK primitive. Consequently, the atomicity of a set request is only guaranteed when all the OIDs in the request are processed by the same SNMP entity. See 20.6.3 Atomicity and Error Handling for details.
When creating an SnmpProxy object, the application must decide whether the remote request is sent during the check() phase or the set() phase of the set operation. If the operation is performed during the check() phase, the error returned to the manager is that which is emitted by the subagent. However, the atomicity is no longer guaranteed, because the check() phase can now actually modify some of the sub agent MIBs. According to SNMPv2, the error returned in that case should be undoFailed, but in fact it is whatever error was returned or raised by the SnmpMibAgent. If the operation is performed during the set() phase, the error returned is always undoFailed for SNMPv2 or SNMPv3, or genError for SNMPv1. This will hide the actual error that was returned by the subagent. Whether one method or the other is used is entirely the responsibility of the application code.
The SnmpProxy object implements the following translation:
SnmpProxy forwards the request in the protocol specified by the subagent; a get request makes the SnmpProxy object send a get to the subagent, a set request makes the SnmpProxy object send a set to the subagent, and so on.
If the incoming request is a get-bulk request, and the subagent is an SNMPv1 subagent, SnmpProxy forwards the request as a series of get-next requests.
If the incoming request is an SNMPv2 or SNMPv3 get or get-next request, and the subagent is an SNMPv1 subagent, SnmpProxy subtracts the varbinds for which an error was returned, and resends the request until either a value or an error is obtained for each varbind. The requests are sent to emulate SNMPv2 or SNMPv3 get and get-next behavior.
If the incoming request is a set, then two types of behavior are possible, depending on how the SnmpProxy object is configured:
The set request can be performed during the check phase, in which case nothing is done during the set
The set request can be performed during the set phase, in which case nothing is performed during the check; this is the default behavior
Whichever solution is chosen has different impacts on the atomicity of set requests. See 20.6.3 Atomicity and Error Handling for details.
If the incoming request contains SNMPv1 or SNMPv2 community strings, they must be translated using the translateParameters() method. The translateParameters() method reuses the information contained in the SnmpMibRequest PDU to construct new SnmpParams.
You can overload this method to change its behavior.
When an SNMPv1 or SNMPv2 request is received, the translateParameters() method is called. The received community string is reused in the forwarded request. If an SNMPv3 request is received, the community string is forwarded as public in a get request and as private in a set request.
The SnmpUsmProxy object inherits from SnmpProxy. When a request is received, the translateParameters() method is called.
If the request is an SNMPv1 or SNMPv2 request, the security level is set to noAuthNoPriv. If the received community string is of the form community@context, the context name is set to the received context value. If it is in any other form it is null.
If the request is an SNMPv3 request, the received context, security level, and other values are reused.
As stated in the previous section, the atomicity of set requests is no longer guaranteed when remote MIBs are involved. Although some strategies exist that try to offer a best-effort regarding the atomicity of set requests, there is no generic mechanism that is guaranteed to work in a master agent application. The best that can be done in a generic toolkit is to identify those cases where atomicity might have been broken, and to inform the manager of that situation. Java DMK 5.1 handles this by responding with undoFailed when an error occurs during the set() phase of a set request. In its default configuration, when an SNMPv2 set request is received, Java DMK guarantees that undoFailed is sent when atomicity might have been broken. This no longer holds if the application code configures the SnmpProxy object to send the remote SNMP set request during the check() phase of the set operation.
Some toolkits attempt to implement atomicity by:
Getting the current values of all variables included in the set.
Performing the set.
Reverting to the old values by sending a second set with the values obtained in 1 above, or the values obtained in 2 if no error is returned.
Although this might seem more satisfactory it is not guaranteed to work. Depending on the semantics of the variables involved in the set, several things might happen:
If the transition from value#1 to value#2 is valid, there is no guarantee that the transition from value#2 to value#1 will be accepted by the agent; reverting to the old value might not be possible
Setting an object to a specific value might already have had unrecoverable effects on the agent; for example removing a resource, destroying a row, and so on
Some objects might be of type Test-And-Increment which means that getting their value in 1 above already modifies them. Trying to perform a set on them will probably generate an error as these objects are usually read-only. In the end, the whole process will return an error while still having modified the objects as a side effect
Even if no generic mechanism is supported, the Java DMK can still be customized to implement any specific behavior. The SnmpUserDataFactory makes it possible to allocate and release contextual data about requests, which can be used to implement transactional behavior. By subclassing SnmpProxy, and mibgen–generated metadata classes, any kind of specific transactional behavior can be implemented. However, no generic solution exists, and if transactional behavior can be implemented, it is specific to the semantics of the objects contained in the application and subagent MIBs.
Another special case is when a subagent is entirely responsible for a given context scope. In that case, the atomicity of set requests can still be achieved by performing the remote SNMP set during the check() phase. See 20.4 MIB Scoping in Master Agents for details.
The following tables show the end-to-end error translation performed by a master agent application.
Table 20–1 Error Translation from SNMPv1 Subagents to SNMPv2/v3 Managers
PDU Type |
Error From SNMPv1 Subagents |
Error Sent to SNMPv2/v3 Managers |
---|---|---|
get |
genErr |
genErr |
get |
noSuchName |
noError => noSuchInstance in varbind |
get |
tooBig |
handled by stack =>resend or tooBig |
get |
any other error |
genErr |
set |
any error |
undoFailed(**) |
get-next/get-bulk |
genErr(*) |
genErr |
get-next/get-bulk |
noSuchName |
noError => skip to next SnmpMibAgent or endOfMibView if none |
get-next/get-bulk |
tooBig |
handled by stack resend or tooBig cated response (get-bulk) |
get-next/get-bulk |
any other error(*) |
genErr |
(*) The SnmpProxy objects can be configured to hide such errors. In this case the master agent skips to the next SnmpMibAgent. This behavior can be very useful when dealing with faulty legacy agents.
(**) See Table 20–5.
Table 20–2 Error Translation from SNMPv2/v3 Subagents to v1 Managers
PDU Type |
Error From SNMPv2/v3 Subagents |
Error Sent to SNMPv1 Managers |
---|---|---|
get |
genErr |
genErr |
get |
noError => noSuchInstance in varbind |
noSuchName |
get |
noError => noSuchInstance in varbind |
noSuchName |
get |
tooBig |
handled by stack => resend or tooBig |
get |
any other error |
genErr |
set |
any error |
genErr (**) - undoFailed is translated into genErr |
get-next |
genErr |
genErr |
get-next |
noError => endOfMibView in varbind |
noSuchName |
get-next |
tooBig |
handled by stack => resend or tooBig |
get-next |
any other error |
genErr |
(**) See Table 20–5.
Table 20–3 Error Translation From SNMPv1 Subagents to SNMPv1 Managers
PDU Type |
Error From SNMPv1 Subagents |
Error Sent to SNMPv1 Managers |
---|---|---|
get |
genErr |
genErr |
get |
noSuchName |
noSuchName |
get |
tooBig |
handled by stack => resend or tooBig |
get |
any other error |
genErr |
set |
any error |
genErr (**) - undoFailed is translated into genErr |
get-next |
genErr |
genErr |
get-next |
noSuchName |
noSuchName |
get-next |
tooBig |
handled by stack => resend or tooBig |
get-next |
any other error |
genErr |
(**) See Table 20–5.
Table 20–4 Error Translation from SNMPv2/v3 Subagents to SNMPv2/v3 Managers
PDU Type |
Error From SNMPv2/v3 Subagents |
Error Sent to SNMPv2/v3 Managers |
---|---|---|
get |
noError |
noError |
get |
tooBig |
handled by stack => resend or tooBig |
get |
any other error |
same error (if valid) or genErr |
set |
any error |
undoFailed (**) |
get-next/get-bulk |
noError |
noError |
get-next/get-bulk |
tooBig |
handled by stack => resend or tooBig or truncated response (GET-BULK) |
get-next/get-bulk |
any other error |
same error (if valid) or genErr |
(**) By default SnmpProxy sends the remote set request during the set() phase of the set operation. When an error occurs during the set() phase, undoFailed is returned to the manager because the atomicity is no longer guaranteed. Note that in the special case where an SnmpProxy is configured to perform the remote set request during the check() phase of the set operation, the following translation is applied for errors returned by the remote set request, even if the atomicity of the set request is broken, as shown in the following table.
Table 20–5 Error Translation When SnmpProxy Performs Remote set
Before Translation |
After Translation |
---|---|
v1 errorStatus |
v2/v3 errorStatus |
noError |
noError |
noSuchName |
noSuchName |
genErr |
genErr |
badValue |
wrongValue |
readOnly |
wrongValue |
v2/v3 errorStatus |
v1 errorStatus |
noError |
noError |
genErr |
genErr |
wrongValue, wrongEncoding, wrongLength, wrongType, inconsistentValue |
badValue |
noAccess, notWritable, noCreation, inconsistentName, authorizationError |
noSuchName |
resourceUnavailable, commitFailed, undoFailed, any other error |
genErr |
v1 errorStatus |
v1 errorStatus |
any error |
same error (if valid); genErr otherwise |
v2/v3 errorStatus |
v2/v3 errorStatus |
any error |
same error (if valid); genErr otherwise |
v1 errorStatus |
v2/v3 errorStatus |
noError |
noError |
noSuchName |
noSuchName |
genErr |
genErr |
badValue |
wrongValue |
readOnly |
wrongValue |
v2/v3 errorStatus |
v1 errorStatus |
noError |
noError |
genErr |
genErr |
wrongValue, wrongEncoding, wrongLength, wrongType, inconsistentValue |
badValue |
noAccess, notWritable, noCreation, inconsistentName, authorizationError |
noSuchName |
resourceUnavailable, commitFailed, undoFailed, any other error |
genErr |
v1 errorStatus |
v1 errorStatus |
any error |
same error (if valid); genErr otherwise |
v2/v3 errorStatus |
v2/v3 errorStatus |
any error |
same error (if valid); genErr otherwise |
These examples show you how to register local and remote MIBs within the master agent SNMP adaptor. They demonstrate how to instantiate and use the SnmpProxy and SnmpUsmProxy classes to register the remote MIBs.
In these examples, we demonstrate two different types of SNMP master agent that delegate handling of SNMP requests to subagents:
A master agent, which hides a single subagent and contains a single remote MIB implemented by that subagent
An overlap master agent, which locally implements part of a MIB whose OID space overlaps with the MIB implemented by its subagent
These examples also contain a manager which is used to send requests to the master agent. This manager operates in synchronous mode. Manager requests are sent both in SNMPv2 and SNMPv3.
Before going through this example, you must be familiar with the agent and manager examples described in Chapter 16, Creating an SNMP Agent and Chapter 17, Developing an SNMP Manager.
The following applications are used in these examples:
A manager used to query the master agent. This class is in the examplesDir/current/Snmp/MasterAgent/manager directory. The SimpleManager application makes SNMP requests both in SNMPv3 and in SNMPv2 on a Java DMK master agent, and listens to forwarded traps.
A Java DMK SNMPv1/v2 standalone subagent. This class is in the examplesDir/current/Snmp/MasterAgent/standalone directory. The StandAloneAgent application is a multi-protocol SNMP agent implementing a simple MIB containing four OIDs:
sysDescr1 value "error1"
sysDescr2 value "error2"
sysDescr3 value "sysDescr3"
sysDescr4 value "sysDescr4"
This simple MIB contains a single fake system group registered in the OID space of MIB-II.
A simple SNMPv1/v2 master agent, configured with a single remote MIB implemented by a single subagent. This class is in the examplesDir/current/Snmp/MasterAgent/master directory. The MasterAgent application registers an SnmpProxy to forward requests to the remote MIB implemented by the StandAloneAgent, and forwards SNMPv1 and v2 traps to SNMPv1 and v2 managers.
A simple SNMPv3 master agent, configured with a single remote MIB implemented by a single subagent. This class is in the examplesDir/current/Snmp/MasterAgent/master directory. The MasterAgentV3 application registers an SnmpUsmProxy to forward requests to the remote MIB implemented by the StandAloneAgent and forwards SNMPv1 and SNMPv2 traps to SNMPv3 managers.
A simple master agent that deals with MIBs whose OID spaces overlap. This class is in the examplesDir/current/Snmp/MasterAgent/overlap directory. The MasterAgent application registers an SnmpProxy to forward requests to the remote MIB implemented by the StandAloneAgent subagent. It also locally implements a MIB whose variables sysDescr1 and sysDescr2 with values "sysDescr1", "sysDescr2" overlap with the variables defined in the subagent's MIB.
The SimpleManager is identical to a standard Java DMK SNMP manager. The StandAloneAgent is also identical to a standard Java DMK SNMP standalone agent. It is unaware of the existence of the master agent, unless it is configured to send traps.
There are, however, differences in the way each of the SNMPv1/v2 master agent and the SNMPv3 master agent creates a proxy, as shown in Example 20–2 and Example 20–3. Example 20–4 shows how the MIB overlapping is programmed.
In the SNMPv1/v2 master agent example, proxy registration is identical to standard MIB registration. The proxies are created as shown in the following example.
[...] // First we need to create a peer to the distant sub agent. // final SnmpPeer peer = new SnmpPeer(host, Integer.parseInt(port)); final SnmpParameters p = new SnmpParameters(); // The sub agent is seen as a SNMPv2. // p.setProtocolVersion(SnmpDefinitions.snmpVersionTwo); //Set the parameters to the peer. // peer.setParams(p); // SnmpProxy creation. // final SnmpProxy proxy = new SnmpProxy(snmpAdaptor.getEngine(), peer,"1.3.6.1.2.1"); // A SnmpProxy is also an MBean. Register it in the // MBeanServer. // proxyObjName= new ObjectName("snmp:class=SnmpProxy"); server.registerMBean(proxy, proxyObjName); proxy.setSnmpAdaptor(snmpAdaptor); [...]
To instantiate and register the proxy, the MasterAgent example first of all creates a peer to the subagent using new SnmpPeer(), and creates security parameters p using the SnmpParameters() method. It then sets the subagent as an SMNPv2 agent using setProtocolVersion.
The MasterAgent passes the parameters p to the new peer using peer.setParams. Finally, MasterAgent creates the proxy, passing it the following information:
The adaptor's engine ID, via snmpAdaptor.getEngine()
The peer
The distant MIB's OID, 1.3.6.1.2.1
In the SNMPv3 master agent example, proxy registration is identical to standard MIB registration. The proxies are created as shown in the following example.
[...] // First we need to create a peer to the distant SNMPv3 sub // agent final SnmpUsmPeer peer = new SnmpUsmPeer(snmpAdaptor.getEngine(), host, Integer.parseInt(port)); // Forward the requests. // final SnmpUsmParameters p = new SnmpUsmParameters(snmpAdaptor.getEngine(), "defaultUser"); p.setContextEngineId(peer.getEngineId().getBytes()); p.setSecurityLevel(SnmpDefinitions.authNoPriv); peer.setParams(p); peer.processUsmTimelinessDiscovery(); final SnmpUsmProxy proxy = new SnmpUsmProxy(snmpAdaptor.getEngine(), peer, "1.3.6.1.2.1"); // A SnmpUsmProxy is also an MBean. Register it in the // MBeanServer. // proxyObjName= new ObjectName("snmp:class=SnmpUsmProxy"); server.registerMBean(proxy, proxyObjName); proxy.setSnmpAdaptor(snmpAdaptor); [...]
To instantiate and register the proxy, the MasterAgentV3 example first of all creates a peer to the subagent using new SnmpUsmPeer(), and creates SNMPv3 security parameters p using the SnmpUsmParameters() method. These new security parameters are then passed to the peer using peer.setParams, thus translating all requests that come through the peer into SNMPv3 requests.
Finally, MasterAgent creates the proxy, passing it the following information:
The adaptor's engine ID, via snmpAdaptor.getEngine()
The peer
The distant MIB's OID, 1.3.6.1.2.1
In the overlapping MIB master agent example, proxy registration is identical to standard MIB registration and the proxies are created in the same way as for SNMPv1 and v2 master agents.
// Instantiate a Mib // final MIB1_MIB mib1 = new MIB1_MIB(); // Register the local MIB1 implementation for sysDescr1 // and sysDescr2. // final SnmpOid oid1 = new SnmpOid("1.3.6.1.2.1.1.1"); final SnmpOid oid2 = new SnmpOid("1.3.6.1.2.1.1.2"); // Make an array of these OIDs. // final SnmpOid[] local_oids = {oid1, oid2}; // Add the local MIB1 implementation for each redefined oid // snmpAdaptor.addMib(mib1, local_oids); // Initialize the mib // mib1.init();
The overlapping MIB MasterAgent example creates a new MIB using new MIB1_MIB. It then registers the local MIB1 implementation for sysDescr1 and sysDescr2, which are configured into the StandAloneAgent example as error1 and error2, respectively. The local MIB thus shadows the implementation of sysDescr1 and sysDescr2 instrumented in the remote MIB, because it is registered with deeper OIDs than the remote MIB.
The MIBs are then added to the SNMP adaptor server using snmpAdaptor.addMib and initialized using init().
Before running the example applications, compile all the Java classes in each of the four subdirectories inside examplesDir/current/Snmp/MasterAgent, by typing the following command in each directory.
$ javac -classpath classpath -d . *.java |
The following procedures give instructions to run five different SNMP master agent scenarios:
The manager sends requests to the master agent with an SNMPv2 subagent.
The manager sends requests to the master agent with an SNMPv3 subagent.
The manager sends requests to the master agent, with overlapping.
The manager receives forwarded SNMPv1 and SNMPv2 traps. Both the agent and manager must be running on the same host.
The manager receives forwarded SNMPv3 traps.
Ensure that no agents are already running before you start the examples.
Because there are no MIBs overlapping in this first example, all the variables implemented by the subagent MIB can be seen from the manager. Thus, you can see that some of the OIDs queried return a DisplayString value of error#.
Start the StandAloneAgent subagent.
In examplesDir/current/Snmp/MasterAgent/standalone, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security StandAloneAgent 8085 |
This binds StandAloneAgent to port 8085. Do not send traps when prompted.
Start the SNMPv2 MasterAgent application.
You need to provide MasterAgent with the following information:
The location of its security configuration file, jdmk.security
The port on which it should listen for incoming requests, in this case we choose 8087
The subagent's host, in this case the local host
The subagent's port number, in this case 8085
In examplesDir/current/Snmp/MasterAgent/master, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security MasterAgent 8087 localhost 8085 |
The following output is displayed:
NOTE: HTML adaptor is bound on TCP port 8082 NOTE: SNMP Adaptor is bound on UDP port 8087 The master agent forward traps on port : 8088 >> Press Enter if you want to stop. |
Start the SimpleManager application.
You need to provide SimpleManager with the following information:
The location of its security configuration file, jdmk.security
The master agent's host, in this case the local host
The port on which the master agent is listening for request, in this case 8087
In examplesDir/current/Snmp/MasterAgent/manager, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security SimpleManager localhost 8087 >> Press Enter if you want to send a SNMPv3 request. |
Press Enter to send an SNMPv3 request
The following output is displayed:
SimpleManager::main: Send SNMPv3 get request to SNMPv3 agent on localhost at port 8087 Result: [Object ID : 1.3.6.1.2.1.1.1.0 (Syntax : String) Value : error1, Object ID : 1.3.6.1.2.1.1.2.0 (Syntax : String) Value : error2, Object ID : 1.3.6.1.2.1.1.3.0 (Syntax : String) Value : sysDescr3, Object ID : 1.3.6.1.2.1.1.4.0 (Syntax : String) Value : sysDescr4] >> Press Enter if you want to send a SNMPv2 request. |
Press Enter to send an SNMPv2 request
The following output is displayed:
SimpleManager::main: Send SNMPv2 get request to SNMP agent on localhost at port 8087 Result: [Object ID : 1.3.6.1.2.1.1.1.0 (Syntax : String) Value : error1, Object ID : 1.3.6.1.2.1.1.2.0 (Syntax : String) Value : error2, Object ID : 1.3.6.1.2.1.1.3.0 (Syntax : String) Value : sysDescr3, Object ID : 1.3.6.1.2.1.1.4.0 (Syntax : String) Value : sysDescr4] $ |
The manager has successfully sent the two requests to the subagent, via the master agent.
Because there is no MIB overlapping in this second example, all the variables implemented by the subagent MIB can be seen from the manager. Thus, you see that some of the OIDs queried return a DisplayString value of error#.
Start the StandAloneAgent subagent.
In examplesDir/current/Snmp/MasterAgent/standalone, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security StandAloneAgent 8085 |
This binds StandAloneAgent to port 8085. Do not send traps when prompted.
Start the SNMPv3 MasterAgentV3 application.
You need to provide MasterAgentV3 with the following information:
The location of its security configuration file, jdmk.security
The port on which it should listen for incoming requests, in this case we choose 8087
The subagent's host, in this case the local host
The subagent's port number, in this case 8085
The manager's host, in this case the local host
In examplesDir/current/Snmp/MasterAgent/master, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security MasterAgentV3 8087 localhost 8085 localhost |
The following output is displayed:
NOTE: HTML adaptor is bound on TCP port 8082 NOTE: SNMP Adaptor is bound on UDP port 8087 >> Press Enter if you want to stop. |
Start the SimpleManager application.
You need to provide SimpleManager with the following information:
The location of its security configuration file, jdmk.security
The master agent's host, in this case the local host
The port on which the master agent is listening for requests, in this case 8087
In examplesDir/current/Snmp/MasterAgent/manager, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security SimpleManager localhost 8087 >> Press Enter if you want to send a SNMPv3 request. |
Press Enter to send an SNMPv3 request
The following output is displayed:
SimpleManager::main: Send SNMPv3 get request to SNMPv3 agent on localhost at port 8087 Result: [Object ID : 1.3.6.1.2.1.1.1.0 (Syntax : String) Value : error1, Object ID : 1.3.6.1.2.1.1.2.0 (Syntax : String) Value : error2, Object ID : 1.3.6.1.2.1.1.3.0 (Syntax : String) Value : sysDescr3, Object ID : 1.3.6.1.2.1.1.4.0 (Syntax : String) Value : sysDescr4] >> Press Enter if you want to send a SNMPv2 request. |
Press Enter to send an SNMPv2 request
The following output is displayed:
SimpleManager::main: Send SNMPv2 get request to SNMP agent on localhost at port 8087 Result: [Object ID : 1.3.6.1.2.1.1.1.0 (Syntax : String) Value : error1, Object ID : 1.3.6.1.2.1.1.2.0 (Syntax : String) Value : error2, Object ID : 1.3.6.1.2.1.1.3.0 (Syntax : String) Value : sysDescr3, Object ID : 1.3.6.1.2.1.1.4.0 (Syntax : String) Value : sysDescr4] $ |
The manager has successfully sent the two requests to the subagent, via the SNMPv3 master agent.
This example is very similar to To Send Requests From a Manager to the SNMPv2 Master Agent, except that the master agent now implements a local MIB which partly shadows the MIB implemented remotely by the agent.
Because the local MIB now shadows the variables for which the value was error#, these pseudo error messages no longer appear in the result displayed.
Start the StandAloneAgent subagent.
In examplesDir/current/Snmp/MasterAgent/standalone, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security StandAloneAgent 8085 |
This binds StandAloneAgent to port 8085. Do not send traps when prompted.
Start the overlap MasterAgent application.
You need to provide MasterAgent with the following information:
The location of its security configuration file, jdmk.security
The port on which it should listen for incoming requests, in this case we choose 8087
The subagent's host, in this case the local host
The subagent's port number, in this case 8085
In examplesDir/current/Snmp/MasterAgent/overlap, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security MasterAgent 8087 localhost 8085 |
The following output is displayed:
NOTE: HTML adaptor is bound on TCP port 8082 NOTE: SNMP Adaptor is bound on UDP port 8087 >> Press Enter if you want to stop. |
Start the SimpleManager application.
You need to provide SimpleManager with the following information:
The location of its security configuration file, jdmk.security
The master agent's host, in this case the local host
The port on which the master agent is listening for requests, in this case 8087
In examplesDir/current/Snmp/MasterAgent/manager, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security SimpleManager localhost 8087 >> Press Enter if you want to send a SNMPv3 request. |
Press Enter to send an SNMPv3 request
The following output is displayed:
SimpleManager::main: Send SNMPv3 get request to SNMPv3 agent on localhost at port 8087 Result: [Object ID : 1.3.6.1.2.1.1.1.0 (Syntax : String) Value : sysDescr1, Object ID : 1.3.6.1.2.1.1.2.0 (Syntax : String) Value : sysDescr2, Object ID : 1.3.6.1.2.1.1.3.0 (Syntax : String) Value : sysDescr3, Object ID : 1.3.6.1.2.1.1.4.0 (Syntax : String) Value : sysDescr4] >> Press Enter if you want to send a SNMPv2 request. |
Press Enter to send an SNMPv2 request
The following output is displayed:
SimpleManager::main: Send SNMPv2 get request to SNMP agent on localhost at port 8087 Result: [Object ID : 1.3.6.1.2.1.1.1.0 (Syntax : String) Value : sysDescr1, Object ID : 1.3.6.1.2.1.1.2.0 (Syntax : String) Value : sysDescr2, Object ID : 1.3.6.1.2.1.1.3.0 (Syntax : String) Value : sysDescr3, Object ID : 1.3.6.1.2.1.1.4.0 (Syntax : String) Value : sysDescr4] $ |
The manager has successfully sent the two requests to the subagent, via the overlap master agent. As you can see, the error# values have been replaced by the variables sysDescr1 and sysDescr2, which were configured in the master agent to overlap with the variables in the subagent's MIB.
In this scenario, an SNMPv1 trap or a v2 trap is sent by the subagent. The master agent forwards the trap as is and sends a translated trap. The version translation from v1 to v2, or from v2 to v1 is performed by the master agent. The manager therefore receives two traps, namely, the initial trap and the translated trap.
Start the StandAloneAgent subagent.
In examplesDir/current/Snmp/MasterAgent/standalone, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security StandAloneAgent 8085 |
The following output is displayed:
NOTE: SNMP Adaptor is bound on UDP port 8085 Press Return if you want to send trap |
Press Return to activate stand alone traps
The following output is displayed:
Press crtl-c in order to kill the agent Type 1 in order to launch snmp V1 traps, 2 for snmp V2. |
Do not send any traps yet, but leave the StandAloneAgent active.
Start the SNMPv2 MasterAgent application.
You need to provide MasterAgent with the following information:
The location of its security configuration file, jdmk.security
The port on which it should listen for incoming requests, in this case we choose 8087
The subagent's host, in this case the local host
The subagent's port number, in this case 8085
In examplesDir/current/Snmp/MasterAgent/master, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security MasterAgent 8087 localhost 8085 |
The following output is displayed:
NOTE: HTML adaptor is bound on TCP port 8082 NOTE: SNMP Adaptor is bound on UDP port 8087 The master agent forward traps on port : 8088 >> Press Enter if you want to stop. |
Start the SimpleManager application.
You need to provide SimpleManager with the following information:
The location of its security configuration file, jdmk.security
The master agent's host, which in this example must be the local host
The port on which the master agent is listening for requests, in this case 8087
In examplesDir/current/Snmp/MasterAgent/manager, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security SimpleManager localhost 8087 >> Press Enter if you want to send a SNMPv3 request. |
Do not send a request this time.
Go back to examplesDir/current/Snmp/MasterAgent/standalone
The StandAloneAgent should still be waiting to send traps.
Type either 1 or 2 to send SNMPv1 or SNMPv2 traps
The following output is displayed:
1 V1 TRAP to send Trap V1 sent! Type 1 in order to launch snmp V1 traps, 2 for snmp V2. 2 V2 TRAP to send Trap V2 sent! Type 1 in order to launch snmp V1 traps, 2 for snmp V2. |
Go back to examplesDir/current/Snmp/MasterAgent/manager
Notice that the SimpleManager application has received SNMPv1 and v2 traps from the StandAloneAgent. The following output from SimpleManager is displayed:
NOTE: TrapListenerImpl received SNMPv1 trap : Generic 0 Specific 0 TimeStamp 104549 Agent adress 129.157.203.98 NOTE: TrapListenerImpl received SNMPv2 trap: CommunityString : VarBind list : oid : 1.3.6.1.2.1.1.3.0 val : 0:17:25 oid : 1.3.6.1.6.3.1.1.4.1.0 val : 1.3.6.1.6.3.1.1.5.1 oid : 1.2.3.4.5.6.0.0 val : Test values oid : 1.2.3.4.5.6.1.0 val : NULL oid : 1.2.3.4.5.6.2.0 val : 43 oid : 1.2.3.4.5.6.3.0 val : Test values oid : 1.3.6.1.6.3.18.1.3.0 val : 129.157.203.98 oid : 1.3.6.1.6.3.18.1.3.0 val : 129.157.203.98 oid : 1.3.6.1.6.3.18.1.4.0 val : oid : 1.3.6.1.6.3.1.1.4.3.0 val : 1.3.6.1.4.1.42 |
Stop the StandAloneAgent and the SimpleManager by pressing Control-C, and stop the MasterAgent by pressing Enter.
In this scenario an SNMPv1 or SNMPv2 trap is sent by the subagent. The master agent translates the trap into an SNMP v3 trap and sends it to the manager.
Start the StandAloneAgent subagent.
In examplesDir/current/Snmp/MasterAgent/standalone, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security StandAloneAgent 8085 |
The following output is displayed:
NOTE: SNMP Adaptor is bound on UDP port 8085 Press Return if you want to send trap |
Press Return to activate stand alone traps
The following output is displayed:
Press crtl-c in order to kill the agent Type 1 in order to launch snmp V1 traps, 2 for snmp V2. |
Do not send any traps yet, but leave the StandAloneAgent active.
Start the SNMPv3 MasterAgentV3 application.
You need to provide MasterAgentV3 with the following information:
The location of its security configuration file, jdmk.security
The port on which it should listen for incoming requests, in this case we choose 8087
The subagent's host, in this case the local host
The subagent's port number, in this case 8085
The manager's host, in this case the local host
In examplesDir/current/Snmp/MasterAgent/master, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security MasterAgentV3 8087 localhost 8085 localhost |
The following output is displayed:
NOTE: HTML adaptor is bound on TCP port 8082 NOTE: SNMP Adaptor is bound on UDP port 8087 The master agent forward traps on port : 8088 >> Press Enter if you want to stop. |
Start the SimpleManager application.
You need to provide SimpleManager with the following information:
The location of its security configuration file, jdmk.security
The master agent's host, in this case the local host
The port on which the master agent is listening for requests, in this case 8087
In examplesDir/current/Snmp/MasterAgent/manager, type the following command:
$ java -classpath classpath -Djdmk.security.file=jdmk.security SimpleManager localhost 8087 >> Press Enter if you want to send a SNMPv3 request. |
Do not send a request this time.
Go back to examplesDir/current/Snmp/MasterAgent/standalone
The StandAloneAgent should still be waiting to send traps.
Type either 1 or 2 to send SNMPv1 or SNMPv2 traps
The following output is displayed:
1 V1 TRAP to send Trap V1 sent! Type 1 in order to launch snmp V1 traps, 2 for snmp V2. 2 V2 TRAP to send Trap V2 sent! Type 1 in order to launch snmp V1 traps, 2 for snmp V2. |
Go back to examplesDir/current/Snmp/MasterAgent/manager
Notice that the SimpleManager application has received SNMPv3 traps from the StandAloneAgent, via MasterAgentV3. The following output from SimpleManager is displayed:
NOTE: TrapListenerImpl received trap V3: ContextEngineId : 0x8000002a05819dcb6e00001f95 ContextName : TEST-CONTEXT VarBind list : oid : 1.3.6.1.2.1.1.3.0 val : 0:5:24 oid : 1.3.6.1.6.3.1.1.4.1.0 val : 1.3.6.1.6.3.1.1.5.1 oid : 1.2.3.4.5.6.0.0 val : Test values oid : 1.2.3.4.5.6.1.0 val : NULL oid : 1.2.3.4.5.6.2.0 val : 43 oid : 1.2.3.4.5.6.3.0 val : Test values oid : 1.3.6.1.6.3.18.1.3.0 val : 129.157.203.98 oid : 1.3.6.1.6.3.18.1.3.0 val : 129.157.203.98 oid : 1.3.6.1.6.3.18.1.4.0 val : oid : 1.3.6.1.6.3.1.1.4.3.0 val : 1.3.6.1.4.1.42 |
Stop the StandAloneAgent and the SimpleManager by pressing Control-C, and stop the MasterAgentV3 by pressing Enter