VxWorks Reference Manual : Libraries
masterIoLib - default IO routines for the SNMP master agent
masterIoInit( ) - create the IPC mechanism at the SNMP master agent
snmpMonitorSpawn( ) - spawn tMonQue to run snmpQueMonitor( )
masterIpcComp( ) - transmit a completion of transmission message
masterIoWrite( ) - send the encoded buffer to the subagent
masterIpcSend( ) - send a message to a subagent
masterIpcRcv( ) - wait for a reply from the subagent
masterIpcAyt( ) - check the status of the IPC link
masterIpcFree( ) - free the IPC resources allocated by the SNMP master agent
masterQueCleanup( ) - free resources allocated for SNMP master agent
This module implements the I/O routines used by the SNMP master agent. As shipped, the WindNet SNMP code uses message queues to communicate between the master agent and its subagents. The SNMP master agent also uses a message queue to handle communication between its two component tasks, tSnmpd and tMonQue. The tSnmpd task handles communication with the SNMP manager. The tMonQue task is a secondary task spawned from tSnmpd to receive messages from subagents.
When tSnmpd spawns tMonQue, it assigns snmpQueMonitor( ) to manage the process. This function waits on the message queue that subagents use to send messages to the master agent. The snmpQueMonitor( ) function interprets messages on its queue using an SA_MESSAGE_T structure, which is defined in ipcLib.h as:
typedef struct SA_MESSAGE_S { int msgType; MSG_Q_ID saId; EBUFFER_T mesg; } SA_MESSAGE_T;A switch internal to snmpQueMonitor( ) handles the message according to the value of the msgType member.If the message type is CALL_QUERY_HANDLER, the message is a response to a query from the master agent. The buffer referenced in the mesg is then transferred to the local message queue monitored by tSnmpd, which is waiting for a query response from a subagent.
If the message type is CALL_REG_HANDLER, the message is either a registration request, a deregistration request, or some other control message (such as a trap). To respond to such requests, snmpQueMonitor( ) passes the buffer in mesg to snmpMasterHandlerWR( ).
If the message submitted to snmpMasterHandlerWR( ) is a registration request, it includes information on a set of leaves representing the objects that the subagent wants to add to the master agent's MIB tree. If the message passes all checks, the objects are added to the master agent's MIB tree and snmpMasterHandlerWR( ) returns success. All objects registered in one message become part of a group. They share the same IPC information, and, if the IPC link to their subagent is broken, they are deactivated as a group.
If snmpMasterHandlerWR( ) returns a function value indicating success, it also returns a message for the subagent containing the group ID for the variables just added. The snmpQueMonitor( ) takes responsibility for forwarding this message to the subagent. The subagent uses the group ID contained in this message when it comes time to deregister, as well as when it must register instances of an already registered object.
The returned function value of snmpMasterHandlerWR( ) could indicate failure or an opcode. You might want to rewrite this code to do something different. For example, if the subagent had sent a trap up to the master agent, the returned value of snmpMasterHandlerWR( ) would be SA_TRAP_REQUEST, and the vblist parameter would contain a varbind list from the subagent. In this case, you would want to modify snmpQueMonitor( ) to pass the trap on to the SNMP manager.
These MIB variables that the subagent adds to the master agent's MIB tree look transparent to the SNMP manager that is in communication with the master agent. However, the method routines associated with these MIB variables in the master agent are not standard MIB routines. Instead, they are special routines that know how to queue test, get, and set work on the subagent that registered the MIB variables with the master agent. From the point of view of the PDU processing code, these special method routines look like any other method routines. However, when tSnmpd executes one of these routines, the special method routine actually passes the work on to a subagent while tSnmpd waits on a local message queue.
Because the subagent does not know about this local message queue, its response to the master agent is somewhat indirect. The only master agent message queue known to the subagent is the message queue managed by tMonQue, so the subagent puts its response on that queue. When the snmpQueMonitor( ) function that tMonQue runs to monitor the message queue sees that the message is a query response, it then transfers the message to the local queue upon which tSnmpd is awaiting a response. When tSnmpd sees the response, it parses it and merges the message into the PDU processing system.
In the shipped implementation, communication between the master agent and its subagents is handled serially. For example, if the SNMP manager made a request concerning three MIB variables managed by three different subagents, the master agent would query each subagent in turn. After gathering all three responses, the master agent would then pack them up and ship the information back to the SNMP manager.
With some modifications to the code, you could rewrite the SNMP master agent to query all three subagents simultaneously (see the description of the snmpMasterHandlerAsync( ) function defined in subagentLib.c). That is, the master agent would query all three subagents one after the other without waiting for a response after making each request. If the subagents reside on different targets (each with its own processor), this asynchronous query method of multiple subagents lets you take advantage of the capacity for parallel processing.
However, if the subagents reside on different targets, you will also need to replace the code that implements the IPC mechanism used between the master agent and its subagents. In the shipped code, message queues serve as the IPC mechanism. To support agents that reside on different machines, you must replace this IPC mechanism with something such as sockets. To make this possible, the functions that implement the IPC mechanism are isolated to masterIoLib.c and saIoLib.c. These files ship as source code that you should feel free to edit as needed.
masterIoInit( ) - create the IPC mechanism at the SNMP master agent
STATUS masterIoInit ( void )
This routine, called from snmpIoInit( ), creates the SNMP master agent side of the inter-process communication (IPC) mechanism used to carry messages between subagents and the master agent. In this implementation, masterIoInit( ) creates a single message queue. The identity of this message queue is hard coded into every subagent. The subagent puts a message on this queue when it needs to send a message to the master agent.
The message queue created by masterIoInit( ) is monitored by tMonQue. The tMonQue task is one of the two tasks used to implement the SNMP master agent. The purpose of tMonQue is to note which messages in its queue are registration requests and which are responses to queries. If the message is a subagent registration request, tMonQue handles the request and sends a message back to the subagent telling it whether the registration was successful or not.
If the message is a response to a query, tMonQue transfers the message to the message queue monitored by tSnmpd. The tSnmpd task then encodes the response in an SNMP packet and transmits the packet over a socket to the SNMP manager.
Although the shipped version of this function uses message queues as the IPC between the master agent and its subagents, the IPC mechanism is isolated to the relatively small number functions defined in masterIoLib. Thus, if necessary, you should have little trouble porting the code to use an IPC more suitable to your transport needs.
For example, you could use sockets instead of message queues. However, if you decide to change the IPC mechanism, you must do so both in the master agent and in its subagents. This means that you must also modify the functions defined in saIoLib, the library that defines the agent side of the IPC mechanism.
OK or ERROR.
snmpMonitorSpawn( ) - spawn tMonQue to run snmpQueMonitor( )
void snmpMonitorSpawn (void)
This function spawns the tMonQue task to run snmpQueMonitor( ) a function that waits on the message queue that subagents use to leave messages for the master agent. The snmpQueMonitor( ) waits forever on the master agent's message queue. When message comes in, it is interpreted using an SA_MESSAGE_T structure, which is defined in ipcLib.h as:
typedef struct SA_MESSAGE_S { int msgType; MSG_Q_ID saId; EBUFFER_T mesg; } SA_MESSAGE_T;A switch internal to snmpQueMonitor( ) handles the message according to the value of the msgType member.If the message type is CALL_QUERY_HANDLER, the message is a response to a query from the master agent. The buffer referenced in the mesg is then transferred to the local message queue monitored by tSnmpd, where a masterIpcRcv( ) routine is waiting for a query response from a subagent.
If the message type is CALL_REG_HANDLER, the message is a control message such as a registration request, a deregistration request, or a trap. To respond to such requests, snmpQueMonitor( ) passes the buffer in mesg on to snmpMasterHandlerWR( ).
If the message in the buffer passed to snmpMasterHandlerWR( ) is not correctly formed, the returned function value indicates failure and snmpQueMonitor( ) drops the packet.
If the buffer passed to snmpMasterHandlerWR( ) is a correctly formed registration request, snmpMasterHandlerWR( ) adds the specified objects to the master agent's MIB tree. If the buffer contains a correctly formed deregistration request, snmpMasterHandlerWR( ) removes the specified objects from the master agent's MIB tree. In both cases the returned value of snmpMasterHandlerWR( ) indicates success and its rbuf parameter contains a message that snmpQueMonitor( ) forwards to the subagent that sent the message.
In the case of a successful registration request, the message sent to the subagent contains a group ID for the objects just added to the master agent's MIB tree. When the subagent deregisters itself, it includes this ID in its deregistration message to the master agent. It also uses this group ID when it must register instances of the object just registered.
If the buffer passed to snmpMasterHandlerWR( ) contains a trap, the returned function value is SA_TRAP_REQUEST, the value extracted from the opcode2 member of the header associated with the message. The message itself (minus the header) is a varbind list. It is returned using the vbl parameter. The current implementation of snmpQueMonitor( ) just drops this message. However, you can rewrite snmpQueMonitor( ) to make a snmpIoTrapSend( ) that forwards the varbind list to the SNMP manager. Likewise, you can implement appropriate responses to other opcode2 values. Currently, subagent.h defines symbolic constants for opcodes 1 through 12 (with opcode 11, SA_TRAP_REQUEST, reserved for trap requests). If necessary you are free to use the remaining opcodes for message types specific to your implementation.
If your transport needs require that you rewrite masterIoLib to use an IPC other than message queues, you might need to modify this function, which is called from snmpIoMain( ) just before a call to snmpIoBody( ). For example, if you use sockets as your IPC between the SNMP master agent and its subagents, tSnmpd could monitor the socket connection with the SNMP manager as well as the socket connections with the SNMP subagents.
The shipped version of snmpQueMonitor( ) uses snmpMasterHandlerWR( ) and thus processes messages asynchronously. However, if necessary, you can rewrite snmpQueMonitor( ) to call snmpMasterHandlerAsync( ) instead. For more information on snmpMasterHandlerAsync( ), see its reference entry.
N/A
masterIpcComp( ) - transmit a completion of transmission message
void masterIpcComp ( OCTET_T opcode, /* this specifies what needs to be done */ EBUFFER_T * ebuf, /* reply message to be sent */ VBL_T * vblist, /* list of varbinds that the message contained */ PTR_T ipchandle /* subagent address */ )
If the SNMP master agent uses snmpMasterHandlerAsync( ) to process a subagent's unsolicited control message (such as a registration request), it uses masterIpcComp( ) to complete processing for the message. In the current implementation, this means telling the subagent the completion status of a registration or deregistration request. However, you can rewrite this function to implement a broader range of responses (such as forwarding traps to the SNMP manager).
When the master agent calls this routine, it uses opcode to indicate the processing status of the message. If the status indicates an error, masterIpcComp( ) drops the packet. If the status indicates success, the master agent uses the ebuf parameter to pass in a message for the subagent at ipchandle. Internally, masterIpcComp( ) calls masterIoWrite( ) to forward the message to the specified subagent. If this message is the response to a successful registration request, it contains the group ID for the MIB variables just added to the master agent's MIB tree. The subagent needs this group ID for any deregistration request it might send later. It also uses this ID to register instances of the object just registered.
If the opcode is a value of 1 or greater (up to and including 127), the master agent uses the vblist parameter to pass in a varbind list that it extracted from the control message. In the current implementation, the masterIpcComp( ) routine does nothing with the message and returns. However, you could modify masterIpcComp( ) to process the message according to the value specified by opcode. For example, if opcode indicates a trap, you could forward the information at vblist to the SNMP manager.
Currently, subagent.h defines symbolic constants for opcodes 1 through 12 (with opcode 11, SA_TRAP_REQUEST, reserved for trap requests). You are free to use the remaining opcodes for message types specific to your implementation.
N/A
masterIoWrite( ) - send the encoded buffer to the subagent
STATUS masterIoWrite ( EBUFFER_T * pBuf, /* reply message to be sent */ PTR_T saId, /* subagent address */ INT_32_T flg /* type of message */ )
This routine transmits the byte array at pBuf to the subagent at saId. This routine is called from a wide variety of functions in the master agent. For example, masterIpcSend( ) calls this routine when it needs to query the subagent about one of the MIB variables it manages. Likewise, the masterIpcAyt( ) function calls this routine when needs to check the IPC link status. Similarly, snmpQueMonitor( ) calls this routine to tell the agent the results of a registration or deregistration request.
The master agent uses the value flg to specify the general nature of the message it is writing to the subagent, which partially determines how the subagent responds. For example, when the master agent is responding to the subagent after successfully handling its registration request, the master agent uses a flg value of REG_COMPLETE. When the master agent does an "are you there" check, it specifies a flg value of IPC_AYT. REG_COMPLETE and IPC_AYT are the only currently valid flg values.
OK or ERROR.
masterIpcSend( ) - send a message to a subagent
INT_32_T masterIpcSend ( EBUFFER_T * pBuf, /* message to be sent */ PTR_T ipchandle /* address of subagent */ )
The SNMP master agent calls when it needs to send a query in buf to the subagent at the ipchandle address. If this routine is used with snmpMasterHandlerAsync( ), you must rewrite the function according to the prototype of IPCSEND_AS_T (see subagent.h). The additional parameter reqid in this prototype is the request ID of the message being sent. Use reqid to call snmpMasterCleanup( ) if the IPC layer times out.
Internally, this function calls masterIoWrite( ) to put a message on the subagent's message queue. If you have rewritten masterIoWrite( ) to use different IPC mechanism, such as sockets, you should take care that your rewrite of masterIoWrite( ) is compatible with its use in masterIpcSend( ).
0, if the packet has been sent successfully; 1, if and error has
been detected that caused the objects to be marked inactive and
possibly removed; 2, if the processing of the current packet is
allowed to continue without freeing up objects.
masterIpcRcv( ) - wait for a reply from the subagent
INT_32_T masterIpcRcv ( EBUFFER_T * pBuf, /* buffer to be filled */ PTR_T ipchandle /* pointer to the IPC handle */ )
This routine waits for a response after query has been sent to the subagent. In the shipped implementation of the WindNet SNMP master agent, this function waits on a message queue that is local to the master agent. This message queue is used to facilitate communication between tSnmpd, the task that manages communication with the SNMP manager, and tMonQue, the task that manages communication between the SNMP master agent and its subagents.
In the shipped master agent code, subagents communicate with the master agent by putting messages on the message queue monitored by tMonQue. If the message is a control message, it is processed by snmpMasterHandlerWR( ). If the message is a query response, it is transferred to the local message queue on which masterIpcRcv( ) is waiting. All of this is handled synchronously. Thus, while the master agent is waiting for a response from the subagent, it is blocked. Normally, the amount of time spent blocked is quite short and is not a problem.
However, it is an imperfect world, so it is possible that a response for a query never makes it back to the subagent. To handle this possibility, the shipped version of the WindNet SNMP master agent puts a timeout on its wait for a query response. If you should rewrite the SNMP master agent for any reason, make sure that you preserve this timeout.
0, if the packet was received successfully; 1, if an error or a
timeout has caused the objects to be marked inactive and
subsequently removed; 2, if the master agent will allow the
current packet to be processed without freeing objects.
masterIpcAyt( ) - check the status of the IPC link
INT_32_T masterIpcAyt ( PTR_T ipchandle /* pointer to IPC handle */ )
This is an "are you there" routine. The SNMP master agent calls this routine whenever it needs to do a status check on the IPC link to the address ipchandle. This routine puts a null-buffer message of type IPC_AYT on the subagent's message queue. If the subagent replies with a message of the same type, the link is considered active.
0, if the link is inactive; 1, if the link is inactive
masterIpcFree( ) - free the IPC resources allocated by the SNMP master agent
void masterIpcFree ( PTR_T ipchandle /* pointer to IPC handle */ )
The SNMP master agent calls this routine to free a pointer to an IPC handle. This is part of the deregistration process for an SNMP agent.
N/A
masterQueCleanup( ) - free resources allocated for SNMP master agent
void masterQueCleanup (void)
This routine is called from the cleanup routine in snmpIoLib if the agent fails to allocate resources. This routine deletes the message queue and all other resources that have been allocated for the master agent.
N/A