Solstice Enterprise Manager 4.1 Developing C++ Applications Doc Set ContentsPreviousNextIndex


Chapter 11

Writing Management Protocol Adaptors (MPAs)

The Solstice EM MIS (Management Information Server) is responsible for maintaining the MIT (Management Information Tree) and ensuring that all activity within the MIT is transparent to an application. This transparency allows applications to make requests for information in a normalized fashion without regard for object location or communications protocol. The MIS resolves the request and routes it to an appropriate entity that is capable of making the correct protocol request. These entities are called protocol adaptors. Adaptors exist to map information into the MIT maintained by the MIS. The Management Protocol Adaptors (MPAs) shipped with Solstice EM exist as separate processes from the MIS. Three such adaptors are shipped with Solstice EM: the SNMP MPA, the RPC MPA, the CMIP MPA, and the JDMK MPA. These adaptors provide the protocol translation into the SNMP, RPC, CMIP, and JDMK domains respectively.

This chapter explains how to write MPAs.

11.1 Review of MIS Architecture

The MIS has a modular architecture. Modules are connected by Service Access Points (SAPs). These SAPs provide an asynchronous bi-directional message pipe interface. The core of MIS is the Message Routing Module (MRM) which routes messages to the appropriate modules. New modules can be added to the MIS by attaching a SAP from the new module to the MRM. Each SAP has a unique address which is registered with the MRM when it is attached.

New adaptors are introduced to the system by creating a new SAP to the MRM. (For MPA, no new SAP needs to be created. All MPAs are routed by the same MPA SAP.)

The figure bellow illustrates some of the modules within the MIS.

FIGURE 11-1   MIS Architecture

The shaded components in FIGURE 11-1 illustrate how users can add new adaptors to communicate to a proprietary device X. The two choices are clearly indicated, MPA or PDM.

All requests are initially sent to the Message Routing Module (MRM). The MRM uses configuration information maintained in the MIT to determine where to satisfy the request. Local requests are sent to the OAM. Remote requests are directed to the appropriate adaptor that has registered to handle that remote portion of the MIT.


Note – Both the MPA and the PDM use SAP to communicate to the MRM. There is very little difference between a MPA and a PDM once the SAP has been created. They both receive identical messages through the same interface.

11.2 Initializing Management Protocol Adaptors and Protocol Driver Modules

This section describes how Management Protocol Adaptors and Protocol Driver Modules are initialized.

11.2.1 Services Access Points (SAPs)

SAPs provide an asynchronous message passing service. The message set is based on the set of CMIP Protocol Data Units (PDUs). The complete set of messages that can be passed over a SAP is defined in message.hh.

All SAP's are C++ class instances derived from the C++ MessageSAP class defined in message.hh. This class defines the interfaces that allow messages to be sent and received over SAP pairs. An initialized SAP consists of a coupled pair of MessageSAP instances.


Note – SAP will now be used to refer to an initialized SAP pair.

Once a SAP has been initialized, the following functions may be performed:

SendResult      send(MessagePtr mp, MTime block_time = INFINITY);
SendResult send(MessagePtr mp, const Callback &cb,
MTime block_time = INFINITY);
Result receive_request(MessagePtr &mp);
Result receive_response(MessId m_id, MessagePtr &mp);
Result receive_response(ResponseHandle rh, MessagePtr &mp);
void cancel_callback(MessId m_id);
void cancel_callback(Callback &cb);

This set of functions provides the following message services:

TABLE 11-1   Message Services
Function Service Provided
Send
Send and expect no Response
Send
Send and schedule to Receive a Response
Receive
Receive a message of a particular id
Receive
Receive the first Message on the incoming queue
Cancel
Cancel callbacks for a particular Message
Cancel
Cancel callbacks for a particular Callback


The interface is defined to be asynchronous. This is achieved using callbacks. Callbacks are a C++ class that consist of a static function pointer and user data. The user data is passed as a parameter to the callback function when the function is invoked.

Example 1

The following example from the fdn_register function in samp_utils.cc illustrates a CONFIRMED request message.

	 // Need source so responses can come back.
areq->source.aclass = AC_PRIMITIVE;
areq->source.atag = my_sap_no;
Callback recv_cb((CallbackHandler)pdm_receive_resp, sap);
// Send off the request to add.
TRYRES(sap->send(areq,recv_cb,0));


Note – A callback is created with a static function called pdm_receive_resp as the callback function pointer. The callback data is the SAP instance pointer. The send function includes the callback recv_cb in the send arguments.

When the MIS completes the request, the pdm_receive_resp function is called with two parameters. The first parameter is the SAP and the second is a response handle which is used to receive the message response.

Example 2

The following example excerpt is from the msgio.cc module and illustrates the pdm_receive_resp function.

	 pdm_receive_resp(Ptr cbh, Ptr rh)
{
Message *mp;
MessageSAP *p_sap = (MessageSAP *) cbh;
	 	 Vtry {
TTRYPROC(p_sap->receive_response(rh, mp));
// At this point mp points to the received response
Message:: delete_message(mp);
}

SAPs are initialized by creating SAP pairs. When a SAP pair is created, the init_kernel_msg_sap function is used. The init_kernel_msg_sap function is a utility function which couples two SAPs. Once the SAPs have been coupled, the local SAP must have two callback functions initialized: the receive request callback and the detached callback.

The receive request callback handler is the handler which is invoked when message requests are sent to the SAP. The detach callback handler is invoked when the remote SAP is deleted.

11.2.2 Initializing a Management Protocol Adaptor

Initializing a Management Protocol Adaptor involves:

11.2.2.1 Creating the Listen Port and Request SAP

The MIS to MPA communication is a form of CMIP over TCP/IP. The MIS creates and manages associations to an MPA on a per request basis. If an association is not used for a period of time the association is released. If an association is already established it will be reused for subsequent requests. Each request has a request identifier which allows for multiple requests to be outstanding at any one time. To facilitate demand based association establishment, the MPA must allocate an IP listen port. An IP listen port is where the MPA listens for association requests from the MIS.

The utility function init_mpa creates both a SAP and a listen port.

init_mpa(portnum, &p_sap);

where portnumber is a port number for an IP socket, and p_sap is the address of a pointer to a MessageSAP data type.

11.2.2.2 Connecting to the MIS and Using get_raw_sap

Because the underlying transport mechanism for this SAP might not be active (that is, an underlying association is not established), another SAP must be created to send event reports to the MIS. This other SAP is allocated by creating a platform instance which is connected to the MIS. This platform instance gives access to an ApplMessageSAP. This SAP is based on another MessageSAP implementation. Because the implementation is derived from MessageSAP, the ApplMessageSAP can be used as a MessageSAP. This is possible through C++ inheritance and virtual function mechanisms.

Example

The following code example illustrates how to create a SAP that sends event reports to the MIS and initialize the resultant SAP to receive requests and disconnects.

	 host = getenv("EM_MIS_DEFAULT_HOST");
if (host!=NULL) {
host = def_host;
}
	 if (emPlatform.connect(host, "SAMPLE_MPA") == OK) 
{
emPlatform.when("DISCONNECTED",
Callback(pdm_test_handle_detach, 0));
mis_connected = TRUE ;
	 } else
mis_connected = FALSE ;
ev_sap = (MessageSAP *) emPlatform.get_raw_sap();
pdm_test_sap->receive_request_cb.handler =
	 	 	 	 	 	 	  
pdm_receive_request_msgs;
pdm_test_sap->receive_request_cb.data = (Ptr) pdm_test_sap;
pdm_test_sap->detach_cb.handler = pdm_test_handle_detach;
pdm_test_sap->detach_cb.data = (Ptr) pdm_test_sap;

Once the platform instance has been created, the get_raw_sap method returns the SAP which can be used for sending event reports to the MIS.

11.2.2.3 Locking the Application Discriminator

This step must be completed to allow for proper operation of the MPA. It is most important, as locking the application discriminator has direct impact on system performance. Every platform instance creates an application object instance within the MIS as long as the platform instance is instantiated. Each application object instance contains a discriminator which forwards all platform notifications to the connected application. The MPA typically does not require this feature.

To disable event forwarding, the application instance discriminator must be locked.

Example

The following example excerpt from the samp_main.cc module in the samples directory illustrates this locking mechanism.

	 DU appinst = 
emPlatform.get_prop(duAPPLICATION_OBJNAME) ; 
Image app_image(appinst);
if( app_image.get_error_type()!=PMI_SUCCESS ||
	 	 !app_image.boot() ||
!app_image.set_str("administrativeState","locked") ||
!app_image.store() ) {
	 	 	 printf("Error starting MPA 
%s\n",
app_image.get_error_string());
exit(1);
	 	 }

11.2.3 Initializing a Protocol Driver Module

Protocol Driver Modules are shared libraries that are loaded at MIS start-up time. The MIS looks in the $EM_HOME/config/EM_shared_libs file for a list of libraries to load. Once it finds an entry in that file, it uses the dlopen() system call to load that library. Once the library is loaded, the MIS looks for an instance of the DynLoader class that matches the name of the loaded library. Once the Dynloader instance has been located, the entry point is invoked with a D_LOAD command.


Note – The second parameter of the instance of the declared DynLoader must match the name of the shared library. See dyn_lib.cc for an example.

Initializing a Protocol Driver Module involves:

11.2.3.1 Creating a Kernel Message SAP

A kernel message SAP pair is created using the init_kern_msg_sap function.

	 extern Result init_kernel_msg_sap ( Address , 
MessageSAP ** );

This utility function creates a pair of coupled kernel message SAPs. It returns to the caller a pointer to a local MessageSAP and initializes the remote SAP to be attached to the MRM at the SAP Address supplied. This Address must be the same as the Address supplied in the FDN table configuration step. See the section on "Example of Timer Initialization" for more information on Address Format.

Each request (message) contains a destination address field dest. The MRM searches in its list of attached SAPs for an address match. When the destination address of a request matches a registered SAP, the request is routed over that SAP.


Note – The destination field component is completed by the lookup code within the MIS.

11.2.3.2 Registering an FDN Table Entry

The utility function fdn_register in samp_utils.cc illustrates how to add an entry to the FDN table.

Result fdn_register(MessageSAP *, int, Asn1Value &);

The fdn_register function creates a table entry which specifies a mapping between a fully distinguished name (FDN) and a specific address. It takes three parameters to create a table entry:

Example

The following example from dyn_libs.cc illustrates the creation of a table entry:

// Check in em_config for TEST SAP number.
// GETENV is a front end MACRO to EM-config file
// Using EM-config forces SAP numbers to be unique
// if not there use default of defined VAL (64)
const char *p_sap_no;
if ( (p_sap_no = GETENV("TEST_PDM_SAP") ) ) {
pdm_test_addr.atag = atoi(p_sap_no);
} else
pdm_test_addr.atag = MY_PDM_SAP;
pdm_test_addr.aclass = AC_PRIMITIVE;
pdm_test_sap = (MessageSAP *) 0;
// Create a kernel message SAP, this binds us to the
// MRM at SAP class AC_PRIMITIVE and SAP number MY_PDM_SAP
// Whenever a request's DN matches a DN in the FDN table
// that request is forwarded to the SAP that matches
// the Address portion of the FDN Table Entry. In this case
// our Address is AC_PRIMITIVE, MY_PDM_SAP.
if ( init_kernel_msg_sap ( pdm_test_addr, 
&pdm_test_sap ) != OK )
Return(NOT_OK);
// Here is where we set up our request handlers.
pdm_test_sap->receive_request_cb.handler =
pdm_receive_request_msgs;
pdm_test_sap->receive_request_cb.data = (Ptr) pdm_test_sap;
pdm_test_sap->detach_cb.handler =
pdm_test_handle_detach;
pdm_test_sap->detach_cb.data = (Ptr) pdm_test_sap;
ev_sap = pdm_test_sap;
// This is where we register the PDM DN with the
// fdn table. We register an entry with
// DN = /systemId="pdm" and an address of
// of AC_PRIMITIVE and SAP number MY_PDM_SAP
Asn1Value pdm_dn = my_dn(my_name);
// Lets delete first in case we did not unload
// gracefully.
TRYRES(fdn_unregister(pdm_test_sap, MY_PDM_SAP,pdm_dn));
// Now register should work
TRYRES(fdn_register(pdm_test_sap, MY_PDM_SAP,pdm_dn));

See Section11.3.2 MPA and PDM Addresses" for information on using EM_config. See Section11.3.1.1 Address Classes" for more information on the AC_PRIMITIVE class.

11.3 Routing Messages

11.3.1 How Messages are Routed to the Adaptors

The MIS contains a table which is analogous to the NFS mount table that the UNIX kernel maintains. The table is a complete mapping of the remote MIT. The MRM searches this table for complete or partial matches of the Distinguished Name (DN) for every request. If there is a match, the MRM stores the address information found in the FDN table entry in the destination field of the message and forwards the message to the SAP that matches that address.

To route a message to an adaptor the FDN table must previously have been updated with the DN or DNs that the adaptor is responsible for and an address for the adaptor's SAP.

The FDN table is updated by two action requests: emAddFdnEntry and emRemoveFdnEntry. These action requests are defined in the em.gdmo document. The fdn_register function uses these actions to update the FDN table. The CMIP Configuration utility (em_cmipconfig) uses the same actions to achieve the same purpose.

The FDN table entry has two components: the DN and the Address. The address component is based on the address C++ class defined in address.hh. An address has three components:

11.3.1.1 Address Classes

Four address classes are defined:

11.3.1.2 AC_PRIMITIVE Address Tags (SAP number)

Each Address class uses the tag value to uniquely identify SAP instances. For the purposes of developing PDMs or MPAs, familiarity with AC_PRIMITIVE tags is critical.

The following is a list of the well known AC_PRIMITIVE tags:

#define AT_PRIM_OAM             0
#define AT_PRIM_EMM 1
#define AT_PRIM_CMIP_PRES_ADDR 2
#define AT_PRIM_SNMP_ADDR 3
#define AT_PRIM_AET_ADDR        4     // ASN1: 
AE-title
#define AT_PRIM_MPA_ADDR 5
#define AT_PRIM_AGENT_DN        6     // ASN1: FDN
#define AT_PRIM_RPC_ADDR 7
#define AT_PRIM_CMIP_CONFIG 8 // String:{psel,ssel,tsel,nsap}


Note – The tags listed above are the well known AC_PRIMITIVE tags that are in use by the MIS system. Providers of new PDMs must choose a value outside this range.

11.3.1.3 Address Data (aval)

The data field of an address can be used for any purpose. It is a DataUnit which is of variable length. Of particular interest is the aval syntax for the AT_PRIM_CMIP_PRES_ADDR tagged AC_PRIMITIVE class. This contains a complete Presentation Address using the following syntax:

length byte, Presentation Selector, 
length byte Session Selector,
length byte, Transport Selector,
count byte (number of Network Selectors),
length byte, Network Selector.....

This is a series of octets, one octet of length followed by value octets. A length value of -1 (255) indicates a null selector.

11.3.2 MPA and PDM Addresses

11.3.2.1 PDM Addresses

A PDM Address is defined to have the following values

Example

The following example from dyn_lib.cc serves as an illustration:

// Check in em_config for TEST SAP number.
// Using EM-config forces SAP numbers to be unique
// if not there use default of defined VAL (64)
const char *p_sap_no;
if ( (p_sap_no = GETENV("TEST_PDM_SAP") ) ) {
pdm_test_addr.atag = atoi(p_sap_no);
} else
pdm_test_addr.atag = MY_PDM_SAP;
pdm_test_addr.aclass = AC_PRIMITIVE;
pdm_test_sap = (MessageSAP *) 0;


Note – A convention exists to ensure that user-supplied PDMs use conflicting PDM SAP numbers. This convention is illustrated above. The convention consists of specifying the PDM number in the $RUNTIME/conf/EM-config file which can be extracted using the GETENV macro.

11.3.2.2 MPA Addresses

MPAs have one more level of indirection than PDMs. The additional level allows the MPA to be a separate process that can be run anywhere in the TCP/IP domain. The MPA addresses are defined as:

The developer need not worry about configuring an MPA Address programmatically since the Address for an MPA is configured using the em_cmipconfig utility. The em_cmipconfig utility creates an address where the aval portion contains all the relevant configuration information. The MIS extracts this information and presents it to the MPA using the remote_oi and remote fields of the message request sent to the MPA request routine.

The following fields need to be configured for a custom MPA:

The example MPA supplied used the following configuration:

Entity Name 	 : { 1 2 3 4 5 1 }
Custom MPA port : 5597
Custom MPA host : "carla"
Session Selector 	 : "Test"
Network SAP : carla:5597
FDN : /pdmId=string:"testMPA"

Once the em_cmipconfig configuration has been completed, the MRM attempts to match entries against what has been configured in the FDN table using em_cmipconfig.

Requests for multiple entities can be directed to a custom MPA. The sample source supplied only supports one entity /pdmId="testMPA". A custom MPA can be created to support multiple entities.

The CMIP MPA provided with the MIS is an example of an MPA that is capable of supporting multiple entities. Each CMIP agent in the MIS' management domain is viewed as an entity. For each CMIP agent to be managed, the user must run em_cmipconfig specifying the agent parameters, in particular, the agent's presentation address.

11.3.2.3 Message remote_oi and remote Fields

The values in the remote_oi and remote fields are one of the specific differences between an MPA and a PDM.

The MPA can make explicit use of these fields. The remote_oi contains the DN of the CMIP table entry that was used to route the request to the MPA. The last RDN of this DN can be used to find the AE-Title (Application Entity Table). The remote field contains whatever was configured for that entity's presentation address. This information is what the CMIP MPA uses to establish an association with a remote entity. The aval portion of the remote field contains a string of the format:

"{ Pres, Sess, Tsel, Net }"

This is an ASCII representation of the remote entities presentation address as configured using em_cmipconfig. See Section 11.3.1.3 Address Data (aval) for more information.


Note – A PDM can not make use of the remote_oi or the remote field.

Multiple FDN table entries can be stored which point to a single MPA or PDM. This storage mechanism can be used as a persistent configuration store for each entity supported by the MPA/PDM. This mechanism, in conjunction with the remote_oi and remote fields, allows for easy multiplexing to the real object information.

11.3.3 FDN Table Configuration Options

There are multiple ways to configure the MIS to route messages to adaptors. In deciding which configuration to use, it is important to implement a model view that is appropriate for the problem being solved. Common sense can be a good start. For example, it would not be appropriate to add thousands of entries to the FDN table when the MPA could easily implement an efficient proprietary lookup based on the DN.

To help clarify the process, the following options are examined:

These examples are used to indicate the various options open to the developer.


Note – These examples are not the only options and are used for illustrative purposes only.

11.3.3.1 MPA Supporting Two Remote Objects

Two possible strategies for adding entries to the FDN table are:

The second case illustrates how em_cmipconfig allows one entity to support multiple objects. It is assumed that the remote entity that supports these objects is identically addressed, that is, the objects live at the same presentation address.

11.3.3.2 PDM Supporting Two Remote Objects

Two possible strategies for adding entries to the FDN table are:

The first case assumes that the DN is decoded in the request and that the request is routed to the appropriate agent entity.

The second case allows the data that is configured in the value (aval) portion of the dest field of the message to be used for achieving multiplexing to the remote agent entity.

11.3.4 Source and Destination Fields in the Message

All messages contain src and dest fields. These fields are C++ instances of Address and are very important for message routing.


Note – The src field must be completed for all CONFIRMED requests.

The MPA/PDM developer must complete the src address if responses are expected. The src field is the same address used when creating the SAP and when specifying the address component of the FDN table registry entry.

The dest field is only important if you wish to explicitly route the message.


Caution – Because explicit routing is used for passing messages between applications, it should be used carefully.

11.4 MPA/PDM Request Management

The MIS has been designed to be a multi-user server and can handle multiple requests transparently and asynchronously. The SAP interface has been designed to make this asynchronous style of programming easier.

In FIGURE 11-2, a scenario is illustrated that is typical of a real world environment.

FIGURE 11-2   Potential Real World Configuration

Application1 makes continuous requests to the local MIT. These requests can be satisfied immediately.

Application2 makes requests to A1 and A2. These agents are at the remote end of very slow links. The architecture must support the scheduling of responses to requests that could take a long time to complete. The design and implementation should also handle cases where requests overlap. If appropriate, multiple overlapping requests should be queued and serviced with a single response.

The MPA/PDM module serving A1 and A2 schedules its responses. It achieves this by using the underlying PMI scheduling services.

The transport mechanism used by the MPA/PDM is normally hidden behind a UNIX file descriptor. The MPA/PDM developer needs to use the underlying scheduling services to interface to the file descriptor. This scheduling service makes use of the underlying poll (select) system call to determine the following:

To satisfy remote requests, the MPA/PDM code typically opens a file descriptor to the agent. As requests are made to the agent, they are written to the file descriptor. The MPA/PDM code then schedules a callback for whenever data becomes available at the file descriptor. When the data is completely transferred, the MPA/PDM sends a response back to the MIS.

At a high level, the steps can be broken down as shown in TABLE 11-2.:

TABLE 11-2   MIS and MPA/PDM Connections
MIS MPA/PDM
Request for MIS




Create a connection to remote agent.


Schedule a callback to indicate connect complete.


Send request with unique identifier.


Schedule a callback for response.


When data callback, check for data complete.


If data complete, send response to MIS.
MIS receives Response




Note – Because all requests have unique identifiers, it is easy to match responses to requests.

11.4.1 Asynchronous Request Code Specifics

When managing asynchronous requests, familiarity with some of the underlying C++ classes that facilitate asynchronous request management is critical. The most important C++ class is the Callback class. This is used by all of the asynchronous interfaces. There is also a C++ programming style that must be understood. The proposed C++ model is that a C++ class must be built with a class implementation with the following characteristics:

These characteristics determine what can be called a pending request class. This type of class encompasses the functionality required for responding to requests asynchronously.

Example

The following example excerpt from a class called pdm_pend_req in samp_inc.hh illustrates some key elements associated with asynchronous requests:

class pdm_pend_req : public QueueElem {
ObjReqMess *orig_msg;
MessId req_id;
public:
	 // hash of all pending requests based on request 
id.
Hashdeclare(MessId, pdm_pend_req, hash_MessId, MessIdcmp,0,0)
static Hash(MessId, pdm_pend_req) *p_pdm_req_hash;
I32 cbs_pending;
I32 num_in_scope;
	 ReqStatus 	 status;
Result start_req(Callback &req_done);
// Used in cases where atomic operation requested.
Queue(RespQElement) resp_q;
}

The pdm_pend_req class has the following characteristics:

The function of this class is to remember original request information, to start requests, and to ensure that a final response is sent if required. Requests are completed when there are no more callbacks pending, that is, cbs_pending == 0.

The req_mngt.cc module supplied in the samples directory illustrates all of these key concepts. The req_mngt.cc starts requests, counts the callbacks, and releases resources that are no longer required.

11.4.2 Validating Requests

Each request can be validated. The extent of the validation is dependent on the implementor and the specifics of the implementation. In some cases, it will make no sense to validate requests since much of the intelligence to validate is on the remote agent. The CMIP MPA supplied does little more than store request identifiers and forward the requests to the CMIP agent. The sample source, which is supplied, does some validation for illustrative purposes.

The typical items that can be validated up front are object class and operation types. For illustrations of typical items than can be validated, see the code in msgio.cc particularly pdm_verify_oc and pdm_verify_dn.

11.4.3 Matching Requests to Responses

Every request is identified with an identifier. To send a response to a particular request, set the response message id to the request Id. For completeness the src and dest fields must be completed also.

Example

The following example excerpt from msgio.cc send_resp. rmp is a pointer to a response message. msg is a pointer to the original request.

	 rmp->id = msg->id;
rmp->source = msg->dest;
rmp->dest = msg->source;
rmp->qos = msg->qos;

11.5 Timer Management

The following timer management services are available to the developer:

Timers are very useful in the MPA/PDM environment. In particular, they are needed to implement time out strategies. Every request requires a response. In the real world, there are occasions when devices do not respond. The timer facilities are useful to set a timeout callback which can send an TIMED_OUT response to the MIS in these types of situations.


Note – MPAs cannot use TIMED_OUT, DEST_UNREACH or NO_SUCH_DEST messages. PDMs may use these message to signify errors. For error conditions like these, the MPA should return a PROC_FALL message with a Probable Cause specific error which is defined by the implementor.

Timers can also be used to check on device status. If the device status has changed, the MPA/PDM can emit an attribute change notification. Applications can then be written to wait for these notifications and to operate on an event driven basis. Asynchronous applications (applications that do not POLL or that are event driven) have a positive impact on overall system performance.

The MPA/PDM developer should always attempt to use a notification based mechanism to communicate with applications. Timers can be used to schedule these specific notifications. Using GDMO, any type of notification can be designed. Once the GDMO syntax has been loaded into the metadata repository (MDR), the MPA/PDM can emit the notification based on the behavior defined in the GDMO.

11.5.1 Timer Management Interface

The timer interface consist of a set of functions which allow the scheduling of callback handlers based on criteria specified in instances of a timer C++ class. These timer instances specify the following:

The class definition for timer is defined in sched.hh and is listed below as well as the interface functions to the scheduler.

class Timer {
public:
MTime time; // expiration time in milliseconds
MTime reload; // reload time after expiration
Callback cb; // callback to post when expired
	 Timer() {
time = 0;
reload = 0;
	 }
Timer(MTime t, MTime re, CallbackHandler hand, Ptr d) {
time = t;
reload = re;
cb.handler = hand;
cb.data = d;
}
	 friend int operator==(const Timer &t1, const 
Timer &t2) {
return t1.cb == t2.cb;
}
};
void    post_timer(const Timer &);
// Post a timer into the scheduler queue
void    purge_timer(const Timer &);     
// Purge any matching timers from the scheduler queue
void    purge_timer_handler(CallbackHandler 
handler);
// Purge any timers with matching handler
void    purge_timer_data(Ptr data);
// Purge any timers with matching data

The four functions detailed above provide the interface to the scheduler for enabling and disabling callbacks based on time. The user can choose a purge interface suitable for the implementation.

11.5.1.1 Example of Timer Initialization

The following example excerpt start_timer from rusagobj.cc uses the post_timer scheduling function to start a timer. The timer that is passed to post_timer is an instance of the C++ class timer.

	 void start_timer() {
// Timer Input is in milli secs
// parms are: timer interval, timer reload value
// Handler and parm passed to handler
	 	 post_timer(Timer(timerval * 1000, timerval * 
1000,
(CallbackHandler) pdmrusage_timer, (Ptr) this));
timer_posted = TRUE;
}

The timer constructor takes three parameters

All interval values are specified in milliseconds. The timer instance created above is based on a variable, timerval, stored in the rusageobj instance. This value is in seconds and is converted to milliseconds by multiplying by 1000. The implementation requires that the timer be continuous so a reload value identical to the initial interval is passed for the reload parameter. The callback parameter is passed containing pdmrusage_timer as the function to be called and the rusageobj instance pointer is passed as the Callback user data.


Note – The implementation of post_timer makes a copy of the timer and Callback parameters passed. It is okay to use timers and Callbacks that get destructed.

11.5.2 Stopping a Timer

Timers are stopped or purged using the purge_timer, purge_timer_handler or purge_timer_data utility functions. The stop_timer method in rusageobj.cc, listed below uses the purge_timer_handler function to cancel the pdmrusage_timer callback when it is no longer needed, that is, when the runtime attribute is set to 0.

	 void stop_timer() {
purge_timer_handler((CallbackHandler) pdmrusage_timer);
timer_posted = FALSE;
}

purge_timer_handler searches the list of active timers for any timer that has a callback handler equal to the value passed. It then purges any timers matching from the timer queue.


Note – It is important to remember if timers have been posted. A common error is that users forget to purge timers. The callback then tries to use data that has been deallocated.

11.6 File Descriptor Management

The normal mechanism of communicating outside of a UNIX process is through a UNIX file descriptor. The services provided by the scheduler to interface to file descriptors are important to understand because most MPA/PDMs use file descriptors to communicate with remote devices.

11.6.1 Asynchronous File I/O

It is important that the MPA/PDM never blocks (makes a system call that does not return immediately). The underlying UNIX File I/O system allows file descriptors to be opened or created in NON-BLOCKING modes. It is most important that any file descriptors be opened in a non-blocking mode.

The most important aspect of non-blocking file I/O is that some operations may not complete. The code must handle properly partial reads/writes. By using the underlying operating poll system call (select on BSD systems), the scheduler facilitates non-blocking I/O by providing a set of utility functions to allow for callbacks when particular events happen at a file descriptor. These are based on the standard UNIX set:

Whenever a user expects to read from a file descriptor the user should use post_fd_read_callback. If data needs to be scheduled to be written, the user should use post_fd_write_callback. To handle error cases there should be a handler for exceptions. This handler can be set using post_fd_except_callback.

Callback handlers as discussed above are static functions that are invoked when the event they have been scheduled to service occurs. The file management functions are passed the file descriptor they are managing as parameter two. Parameter one is the data specified when the CallBack was created. Oftentimes parameter one is a pointer to a C++ instance that contains the file descriptor and any status associated with it.

The complete set of function prototypes as defined in sched.hh are listed below:

void    post_fd_read_callback(int fd, const Callback 
&cb);
void post_fd_write_callback(int fd, const Callback &cb);
void post_fd_except_callback(int fd, const Callback &cb);
void purge_fd_read_callback(int fd);
void purge_fd_write_callback(int fd);
void purge_fd_except_callback(int fd);
void purge_fd_callbacks(int fd);


Note – File descriptor callbacks should be purged if the instance associated with the callback is deleted.

11.6.2 Example of a Read Callback Implementation

The example below is taken from the unixobj.cc sample source code. There are two items of importance:

11.6.2.1 Scheduling the Callback

The following example is taken from the unxobj.cc start_get_req routine. Once the pipe has been successfully opened, the code creates a callback and schedules the callback function execution when there is data available from the pipe. The read callback handler is scheduled using the post_fd_read_callback routine.

The following should be noted:

The routine sh_fetch_input is invoked wherever there is data available at the file descriptor fileno(fp).

11.6.2.2 Callback Execution

The code below is excerpted from unixobj.cc sh_fetch_input.

The sh_fetch_input routine does the following:

Example

static void sh_fetch_input(pdmunixOi *p_obj, int)
{
int rv;
DataUnit tmp(RSIZ);
	 // Read the data
if ( !(rv = fread((char *)(const Octet *) tmp,1,
RSIZ,p_obj->fp))) {
	 	 // End of pipe, need to encode, save for 
Persistence
// and then call the requestor get_complete routine.
pclose(p_obj->fp);
p_obj->fp = 0;
p_obj->get_complete();
return;
	 }
// Store it into the sh_data Dataunit, just the correct amount
DataUnit rdata(rv);
memcpy((void *)(const Octet *) rdata, (const Octet *) tmp, rv);
	 // Need to get rid of old data, so we do not keep 
growing 
sh_data
if ( p_obj->firstdata == TRUE ) {
p_obj->firstdata = FALSE;
p_obj->sh_data = DataUnit();
}
p_obj->sh_data = catenate(p_obj->sh_data,rdata);
	 // Need to get Called Back again so reschedule
post_fd_read_callback(fileno(p_obj->fp),
Callback((CallbackHandler)sh_fetch_input, p_obj));
}

This is a very complete example of a read callback handler since it remembers state information (data just read) and reschedules itself.


Note – The callback must be rescheduled if more data is to be read. A common error is the omissions of reposting the callback when the data transfer has not been completed.

11.7 Notifications

Notifications are based on the OSI Management Event Reporting function. All notifications are instances of the CMIP Event Report Request. They contain:

The ASN.1 syntax for a notification is defined in x711.asn and is listed below:

EventReportArgument ::= SEQUENCE {
managedObjectClass ObjectClass,
managedObjectInstance ObjectInstance,
	 eventTime               [5] IMPLICIT GeneralizedTime 
OPTIONAL,
eventType EventTypeId,
eventInfo [8] ANY DEFINED BY eventType OPTIONAL
}


Note – The event information field is an ASN.1 any defined by value, which is defined by the Event Type field. To generate a notification, the eventInfo must first be constructed according to the syntax defined for that specific notification.

Notifications can be confirmed or unconfirmed. Typically notifications are unconfirmed.

Notifications are generated based on the behavior of the object class being modeled. The standard notification set includes ObjectCreation, ObjectDeletion, and attributeValueChange notifications. New notification types can be defined that are specific to the model being presented to the applications. These new notification types and syntaxes must be loaded into the MDR using the em_gdmo and em_asn1 utilities.

11.7.1 Creating a Notification

Notifications are created by:

These steps are illustrated in the pdm_issue_notif routine in msgio.cc. Excerpts from that routine are used in the following subsections.

11.7.1.1 Allocating an Event Report Message

Messages are allocated using the new_message function. An example of how they are allocated follows:

// Allocate Event Report Message
if ((mp = (EventReq *)Message::new_message(EVENT_REPORT_REQ))
== NULL)
{
pdm_test_error.print("pdm_issue_notif:
Not enough memory for "
"M-Event-Report message\n");
Return(NOT_OK);
}

11.7.1.2 Filling in the Event Report Message Fields

The time and info fields are optional and only need to be competed if the syntax demands that they be completed. All other fields must be filled in. Each of the fields require an encoded Asn1Value:

mp->mode = UNCONFIRMED;
mp->oc = oc;
mp->oi = oi;
TRYRES(event.encode_oid(TAG_CONT(6), event_type));
mp->event_type = event;
mp->event_info = info;
getGeneralizedTime(mp->event_time);

Each field has a specific encoding. This must be adhered to as defined by the definition of an EventReport. See the "Notifications" section for information on syntax. The object class field needs to be encoded TAG CONTEXT 0. The OI needs to be defined according to the specific encoding rules for ObjectInstance. See the x711.asn1 documentation for more information about ObjectInstance.

11.7.1.3 Sending a Notification

All messages are sent to the MIS over an initialized SAP.

// Send the Message to the MIS
if (ev_sap->send(mp) != SENT)
{
// Major System Error
Message::delete_message(mp);
	 pdm_test_error.print("pdm_issue_notif: Could not 
send "
"M-Event-Report message\n");
Return(NOT_OK);
}

Unconfirmed event report request messages are sent using the send function. Confirmed event report requests also use the send function, however, it needs the asynchronous version.

SendResult send(MessagePtr mp, const Callback &cb, 
MTime cd 
block_time)

The MIS forwards all event report requests to the Event Distribution System (EDS) where it is discriminated (filtered). The notification is then forwarded to applications that have registered for it.

This routine accepts an already encoded Info parameter. For a complex example of encoding an eventInfo structure, see pdm_make_attr_chginfo in samp_utils.cc.

11.8 Sample MPA/PDM Source Code

The source code example provided is meant for illustrative and educational purposes. Much of the example code would not be used by a standard MPA/PDM. The sample source provides additional Logical Object Services that would normally be provided in the remote agent. To avoid dependencies on a specific remote agent, simple Logical Object Services are included in the sample source.


Note – All of the sample source code should be studied in detail.

11.8.1 Files and Configuration

The sample source and the GDMO and ASN.1 files are included in the mpa_samples directory. There is also a set of netperl scripts which can be used to illustrate the functionality of the MPA/PDM.


Note – The GDMO and ASN.1 files must be loaded before any of the example code is used.

The MPA/PDM sample source consists of the files listed in TABLE 11-3.

TABLE 11-3   MPA Example Files 
Filename Description
Makefile
contains rules
dyn_lib.cc
Portion of Code to create dyn lib entry point and initialization
samp_main.cc
Generates a main for the testmpa program. Attaches to MIS and initializes the MPA event sap.
dynload.hh
Needed by for DynLoader Instance
msgio.cc
Handles message IO from the MIS.
req_mngt.cc
Manages the Requests
samp_inc.hh
Includes and definitions
samp_utils.cc
Utility functions
lroot.cc
Sample logical Root Object
rusageobj.cc
Sample object which reads /proc and generates rusage info. Can be configured to send Attribute Change notifications.


unixobj.cc
Sample that uses the unix popen command to execute unix commands. Illustrates Asyc File IO and Object Create Notifications.


The makefile can be used to generate two files, testmpa and testpdm.so. The testmpa file is an executable and testpdm.so is a shared library.

11.8.1.1 Sample MPA Configuration: testmpa

Testmpa is an executable that binds to 5597 on whatever machine it is run on. It manages a logical MIT that begins at /pdmId="testMPA". em_cmipconfig must be run to address this MPA. The MPA has a DN of /pdmId="testMPA"; it is a CUSTOM MPA that lives at a default port of 5597. You can choose whatever machine name that is needed. Be sure to include a session selector of "test" when using em_cmipconfg.


Note – The port number can be overridden by using the environment variable TEST_MPA_DEFAULT_PORT. Make sure that this port is entered in em_cmipconfig when configuring the MPA.

11.8.1.2 Sample PDM Configuration: testpdm.so

Testpdm.so is a shared library that can be loaded at platform start-up time. To load testpdm.so, edit $EM_HOME/config/EM_shared_libs. There are two methods for loading testpdm.so:

To do so, include the complete pathname of the shared library in EM_shared_libs, e.g. "/opt/ger/pdmsrc/testpdm.so".
To do so, include the libname and place the shared library in $EM_HOME/lib.

The PDM manages a logical MIT that begins at /pdmId="testPDM", it configures itself to be attached to the MRM at an AC_PRIMITIVE SAP type with a SAP number of 64.


Note – PDM SAP numbers can be chosen by the implementor.

To allow for multiple PDMs to exist, this SAP number should be configurable and readable from a file. By convention and default, SAP tag numbers are stored in /var/opt/SUNWconn/em/conf/EM-config. The format is Name : Value. For example:

TEST_PDM_SAP :  64

could be added to the file. This entry can be read using GETENV("TEST_PDM_SAP"). See the source example in dyn_lib.cc.

11.9 Developing an Adaptor

Developing an adaptor involves:

11.9.1 Defining the Management Information Model

The information model presented to the MIS must be defined in GDMO. If the
existing agent already has some GDMO definitions, the task may be easier. In some cases, the existing GDMO definitions may not be adequately abstracted and therefore, will not be suitable. If the existing GDMO model does not provide a sufficient level of abstraction, new definitions should be defined. The GDMO model defined should make every attempt to fully abstract the management problem being solved.

For example, in a case where a device has 5000 ports, the following activities could be defined:

The model chosen is dependent on the problem being solved. In most cases, the more abstract models can provide for less complex development and better performance for the most common operations. Models can also be optimized to enhance the solution.

The preferred solution in the above scenario would be the single object view. This view would be less complex to implement and require less code. Since there is only one logical object to manage, the overhead in maintaining a logical tree would be minimal and the performance may be better. If the object was defined properly, the applications using the model would also be simpler. They would not have to incur the overhead of managing thousands of objects.

There are no specific rules that can be applied here. Common sense and a clear understanding of the real problem and specific solution required by the customer are the best guides.

11.9.2 The Request Management Interface

As outlined in the sample source, the interface to the MIS must be completely asynchronous. The interface code must be capable of managing multiple outstanding requests. In addition, it must have minimal impact on the overall system performance. This is critical in the case of the PDM. The request interface can be modeled on the sample source and the msgio.cc and req_mngt.cc modules can provide the basis for any adaptor.

11.9.3 The Protocol Code

Each device or remote entity must support some type of remote access. Often there are existing libraries that have already implemented a suitable protocol interface to the devices which are to be managed. These interfaces should be reused as much as possible. The most important consideration when reusing existing protocol stack code is that there be no underlying interface element that could block. All code must be asynchronous. When only synchronous interfaces are provided, a layer needs to be built that provides the asynchronous interface.


Sun Microsystems, Inc.
Copyright information. All rights reserved.
Doc Set  |   Contents   |   Previous   |   Next   |   Index