8  RPC Operation Callbacks

All RPC operations are data-driven within the server, using the YANG RPC statement for the operation and SIL callback functions.

Any new protocol operation can be added by defining a new YANG RPC statement in a module, and providing the proper SIL code.

The agt_rpc_method_t function in agt/agt_rpc.h is used as the callback template for all RPC callback phases.

The following function template definition is used for RPC callback function:

 

 

/* Template for RPC server callbacks

 * The same template is used for all RPC callback phases

 */

typedef status_t

    (*agt_rpc_method_t) (ses_cb_t *scb,

    rpc_msg_t *msg,

    xml_node_t *methnode);

 

 

Callback Template

 

Where, scb pointer represents a session control block structure that is defined in the netconf/src/ncx/ses.h. This control block is primarily used for error reporting, as described in the example section later. However, can be used for more advanced actions. It provides access to the session specific information, such as current message input/output encoding, current session ID information, current protocol information, user name information, peer address information, etc. Note, almost all the fields in this structure should NOT be changed and accessed directly. This control block ideally should be used only for getting more information about the current session, not for alteration of any of its fields.

The msg pointer represents the NETCONF Server and Client RPC Request/Reply Message Handler control block that is defined in the netconf/src/ncx/rpc.h. Similarly to SCB, this control block is primarily used for error reporting, as described in the example section later. However, this control block also provides the RPC input value, as described later in the examples.

The methnode pointer represents the XML node being parsed if this is available. This can used for error reporting if no 'val' or 'obj' parameters are available (from the request message). This pointer is defined in the netconf/src/ncx/xml_util.h.

 

8.1  RPC Callback Initialization and Cleanup

The agt_rpc_register_method function in agt/agt_rpc.h is used to provide a callback function for a specific callback phase.  The same function can be used for multiple phases if desired.

The registration is done during the Initialization Phase 1 before the startup configuration is loaded into the running configuration database and before running configurations are loaded.

Initialization function with the RPC callbacks registration for the Validate Phase may look as follows.

 

 

/********************************************************************

* FUNCTION interfaces_init

*

* initialize the server instrumentation library.

* Initialization Phase 1

*

*********************************************************************/

static status_t

     interfaces_init (void)

{

  ...

 

  res =

    agt_rpc_register_method (EXAMPLE_MODNAME,

                             (const xmlChar *)"do-example",

                             AGT_RPC_PH_VALIDATE,

                             rpc_example_validate);

  ...

}

 

 

Initialization function with the RPC callbacks registration for the Invoke Phase may look as follows.

 

 

/********************************************************************

* FUNCTION interfaces_init

*

* initialize the server instrumentation library.

* Initialization Phase 1

*

*********************************************************************/

static status_t

     interfaces_init (void)

{

  ...

 

  res =

    agt_rpc_register_method (EXAMPLE_MODNAME,

                             (const xmlChar *)"do-example",

                             AGT_RPC_PH_INVOKE,

                             rpc_example_validate);

 

  ...

}

 

 

agt_rpc_register_method

 

Parameter

Description

module

The name of the module that contains the rpc statement

method_name

The identifier for the rpc statement

phase

AGT_PH_VALIDATE(0): validate phase
AGT_PH_INVOKE(1): invoke phase
AGT_PH_POST_REPLY(2): post-reply phase

method

The address of the callback function to register

 

If you register a callback for a specific object, your SIL code must unregister it during the cleanup phase, that is being called any time the server is shutting down. Also, it is getting called during restart and reload procedure.

The following example code illustrates how the RPC callback can be cleaned up. The callbacks cleanup is getting done during module Cleanup Phase. This unregister function will clean up callbacks for all the phases and should be called only once per object.

 

 

/********************************************************************

* FUNCTION  interfaces_cleanup

*    cleanup the server instrumentation library

*

********************************************************************/

void interfaces_cleanup (void)

{

  ...

 

   /* Unregister all the RPC SIL callbacks */

    agt_rpc_unregister_method(EXAMPLE_MODNAME, (const xmlChar *)"do-example");

 

  ...

}

 

 

agt_rpc_unregister_method

 

Parameter

Description

module

The name of the module that contains the rpc statement

method_name

The identifier for the rpc statement

 

 

8.2  RPC Callback Function Examples

8.2.1  RPC Validate Callback Function

The RPC Validate callback function is optional to use. Its purpose is to validate any aspects of an RPC operation, beyond the constraints checked by the server engine. Only 1 validate function can register for each YANG RPC statement. The standard NETCONF operations are reserved by the server engine.  There is usually zero or one of these callback functions for every 'rpc' statement in the YANG module associated with the SIL code.

The yangdump-sdk code generator will create the SIL callback function by default.  There will be C comments in the code to indicate where your additional C code should be added.

The val_find_child function is commonly used to retrieve particular parameters within the RPC input section, which is encoded as a val_value_t tree.  The rpc_user1 and rpc_user2 cache pointers in the rpc_msg_t structure can also be used to store data in the Validation phase, so it can be immediately available in the Invoke phase.

The agt_record_error function is commonly used to record any parameter or other errors.

In the following example the callback function validates “session id” value and if it is higher then allowed the operation will report an error and terminate:

 

 

/********************************************************************

* FUNCTION rpc_example_validate

*

* RPC validation phase

* All YANG constraints have passed at this point.

*

* INPUTS:

*     see agt/agt_rpc.h for details

*

* RETURNS:

*     error status

********************************************************************/

static status_t

    rpc_example_validate (ses_cb_t *scb,

                          rpc_msg_t *msg,

                          xml_node_t *methnode)

{

    status_t res = NO_ERR;

    val_value_t *errorval = NULL;

 

    if (LOGDEBUG) {

        log_debug("\nStart SIL validate rpc <do-example> ");

    }

 

    val_value_t *session_id_val = NULL;

    uint32 session_id = 0;

 

    val_value_t *inputval = msg->rpc_input;

 

 

    /* find a session-id child in the RPC input */

    session_id_val = val_find_child(inputval,

                                    EXAMPLE_MODNAME,

                                    (const xmlChar *)"session-id");

 

    if (session_id_val != NULL && session_id_val->res == NO_ERR) {

        session_id = VAL_UINT(session_id_val);

    }

 

    if (session_id) {

if (LOGDEBUG) {

   log_debug("\nSesion ID %u is not acceptable ", session_id);

}

 

/* validate the session ID value */

if (session_id > 10) {

   res = ERR_NCX_OPERATION_NOT_SUPPORTED;

}

    }

 

    if (res != NO_ERR) {

        agt_record_error(scb,

                         &msg->mhdr,

                         NCX_LAYER_OPERATION,

                         res,

                         methnode,

                         (errorval) ? NCX_NT_VAL : NCX_NT_NONE,

                         errorval,

                         (errorval) ? NCX_NT_VAL : NCX_NT_NONE,

                         errorval);

    }

 

    return res;

 

} /* rpc_test_augm_validate */

 

 

 

Now, let us go through the most eminent parts of the above example.

In the following part of the above code example we are trying to retrieve the RPC input value, that is stored in the msg->rpc_input and then obtain a needed “session-id” node from the RPC input in order to validate it later:

 

 

    ...

 

    val_value_t *inputval = msg->rpc_input;

 

    /* find a session-id child in the RPC input */

    session_id_val = val_find_child(inputval,

                                    EXAMPLE_MODNAME,

                                    (const xmlChar *)"session-id");

 

    if (session_id_val != NULL && session_id_val->res == NO_ERR) {

        session_id = VAL_UINT(session_id_val);

    }

 

    ...

 

 

In the following part of the above code example we are trying to validate previously retrieved “session-id” value. If the provided in the input value is not acceptable as specified below, then the status_t res pointer will be set to ERR_NCX_OPERATION_NOT_SUPPORTED enumeration value, that would signal to record an error and rterminate the operation.

 

 

...

 

    if (session_id) {

if (LOGDEBUG) {

   log_debug("\nSesion ID %u is not acceptable ", session_id);

}

 

/* validate the session ID value */

if (session_id > 10) {

   res = ERR_NCX_OPERATION_NOT_SUPPORTED;

}

    }

 

    if (res != NO_ERR) {

        agt_record_error(scb,

                         &msg->mhdr,

                         NCX_LAYER_OPERATION,

                         res,

                         methnode,

                         (errorval) ? NCX_NT_VAL : NCX_NT_NONE,

                         errorval,

                         (errorval) ? NCX_NT_VAL : NCX_NT_NONE,

                         errorval);

    }

...

 

 

 

8.2.2  RPC Invoke Callback Function

The RPC Invoke callback function is used to perform the operation requested by the client session. Only 1 invoke function can register for each YANG rpc statement. The standard NETCONF operations are reserved by the server engine.  There is usually one of these callback functions for every 'rpc' statement in the YANG module associated with the SIL code.

The RPC Invoke callback function is optional to use, although if no invoke callback is provided, then the operation will have no affect. Normally, this is only the case if the module is tested by an application developer, using netconfd-pro as a server simulator.

The yangdump-sdk code generator will create this SIL callback function by default.  There will be C comments in the code to indicate where your additional C code should be added.

The val_find_child function is commonly used to retrieve particular parameters within the RPC input section, which is encoded as a val_value_t tree.  The rpc_user1 and rpc_user2 cache pointers in the rpc_msg_t structure can also be used to store data in the Validation phase, so it can be immediately available in the Invoke phase.

The agt_record_error function is commonly used to record any internal or platform-specific errors.

For RPC operations that return either an <ok> or <rpc-error> response, there is nothing more required of the RPC Invoke callback function.

For operations which return some data or <rpc-error>, the SIL code must do 1 of 2 additional tasks:

 

 

/********************************************************************

* FUNCTION rpc_test_augm_invoke

*

* RPC invocation phase

* All constraints have passed at this point.

* Call device instrumentation code in this function.

*

* INPUTS:

*     see agt/agt_rpc.h for details

*

* RETURNS:

*     error status

********************************************************************/

static status_t

    rpc_test_augm_invoke (ses_cb_t *scb,

                         rpc_msg_t *msg,

                         xml_node_t *methnode)

{

    status_t res = NO_ERR;

 

    if (LOGDEBUG) {

        log_debug("\nStart SIL invoke rpc <do-example>");

    }

 

    val_value_t *session_id_val = NULL;

   val_value_t *inputval = msg->rpc_input;

 

    session_id_val = val_find_child(inputval,

                                    RPC_TEST_MOD,

                                    (const xmlChar *)"session-id");

 

    if (session_id_val != NULL && session_id_val->res == NO_ERR) {

        ;

    }

 

    /* remove the next line if scb is used */

    (void)scb;

 

    /* remove the next line if methnode is used */

    (void)methnode;

 

    /* invoke your device instrumentation code here */

 

    return res;

 

} /* rpc_test_augm_invoke */