YANG 1.1 Action Interface

A YANG action is like an RPC operation in many ways except it is associated with the data node where the action is defined. The SIL code for an action callback is a combination of the RPC callbacks and the EDIT callbacks. The call flow is the same as for RPC operations. The parameters are similar as well, except the ancestor keys for the instance are provided, so the SIL callback knows which instance to apply the action.

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

Any new data-specific actions can be added by defining a new YANG action statement within a container or list, and providing the proper SIL code.

> make_sil_dir_pro ex-action

Example YANG Action

module ex-action {
  yang-version 1.1;
  namespace "http://netconfcentral.org/ns/ex-action";
  prefix exa;
  import ietf-yang-types { prefix yang; }
  revision 2020-03-06;

  list server {
    key name;
    leaf name {
      type string;
      description "Server name";
    }
    action reset {
      input {
        leaf reset-msg {
          type string;
          description "Log message to print before server reset";
        }
      }
      output {
        leaf reset-finished-at {
          type yang:date-and-time;
          description "Time the reset was done on the server";
        }
      }
    }
  }
}

Example YANG Action Request:

<?xml version="1.0" encoding="UTF-8"?>
<rpc message-id="1"
 xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
 <action xmlns="urn:ietf:params:xml:ns:yang:1">
   <server xmlns="http://netconfcentral.org/ns/ex-action">
     <name>test1</name>
     <reset>
       <reset-msg>diagnostic mode 1</reset-msg>
     </reset>
   </server>
 </action>
</rpc>

Example YANG Action Reply:

<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply message-id="1" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <reset-finished-at xmlns="http://netconfcentral.org/ns/ex-action">2020-03-08T19:01:22Z</reset-finished-at>
</rpc-reply>

Action Callbacks

Action Callback Template

The 'agt_action_cb_t' typedef is used for SIL and SIL-SA action callback functions.

typedef status_t (*agt_action_cb_t)(ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode, val_value_t *actionval)

Template for Action server callbacks.

The same template is used for all Action callback phases The callback is expected to validate if needed and then invoke if needed.

The entire input hierarchy for an action is contained in the msg->rpc_input node. The 'actionval' node passed to the callback points at the action node nested in the input (like <ping> in the example below)

      <action xmlns="urn:ietf:params:xml:ns:yang:1">
        <interfaces xmlns="http://netconfcentral.org/ns/t200">
          <interface>
            <name>eth1</name>
            <ping>
              <destination>192.0.2.1</destination>
            </ping>
          </interface>
        </interfaces>
      </action>

Param scb:

The session control block for the session handling the action request.

Param msg:

message in progress for this <rpc> request, containing the input parameters (if any).

Param methnode:

The XML-specific node being parsed if available. This can used for error reporting if no 'val' or 'obj' parameters are available (from the request message).

Param actionval:

The input node represents the start of the specific action being invoked. The auto-generated SIL code can derive all the ancestor keys from this data structure.

Return:

status return status for the phase; an error in validate phase will cancel invoke phase; an rpc-error will be added if an error is returned and the msg error Q is empty

Action Callback Initialization

The 'agt_action_register_action' function in agt/agt_action.h is used to provide a callback function for a specific callback phase.

  • It is expected within the phase 1 initialization callback function.

  • The same function can be used for multiple phases if desired.

  • Only one validate or invoke function can be registered for each YANG action statement.

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

  • The registration for the action will also be generated automatically by yangdump-pro.

  • Separate callbacks and initialization/cleanup call are automatically generated by yangdump-pro for each action statement.

status_t agt_action_register_action(const xmlChar *defpath, agt_rpc_phase_t phase, agt_action_cb_t action_cb)

add callback for 1 phase of action processing

Parameters:
  • defpath -- Xpath with default (or no) prefixes defining the object that will get the callbacks

  • phase -- action server callback phase for this callback

    • AGT_PH_VALIDATE(0): validate phase

    • AGT_PH_INVOKE(1): invoke phase

    • AGT_PH_POST_REPLY(2): post-reply phase

  • action_cb -- pointer to callback function to register

Returns:

status of the operation

Example SIL Function Registration (found in y_ex-action.c)

res = agt_action_register_action(
    (const xmlChar *)"/exa:server/exa:reset",
    AGT_RPC_PH_VALIDATE,
    ex_action_server_reset_action_val);
if (res != NO_ERR) {
    return res;
}

res = agt_action_register_action(
    (const xmlChar *)"/exa:server/exa:reset",
    AGT_RPC_PH_INVOKE,
    ex_action_server_reset_action_inv);
if (res != NO_ERR) {
    return res;
}

Action Callback Cleanup

The 'agt_action_unregister_action' function in agt/agt_action.h is used to cleanup a callback function for a specific callback phase. The same function can be used for multiple phases if desired.

void agt_action_unregister_action(const xmlChar *defpath)

remove a callback for all phases of action processing

Parameters:

defpath -- Xpath with default (or no) prefixes defining the object that will have the callbacks removed

Action Message Header

The NETCONF server will parse the incoming XML message and construct an RPC message header, which is used to maintain state and any other message-specific data during the processing of an incoming <rpc> request.

The rpc_msg_t data structure in ncx/rpc.h is used for this purpose. This is exactly the same as for an RPC operation.

Action Validate Callback Function

The action validate callback function is optional to use. Its purpose is to validate any aspects of an action request, beyond the constraints checked by the server engine.

  • The validate callback is optional to use.

  • Validation could be done in the validate or invoke phase with the same result.

Example User SIL Function:

(Note that the input parameters include the list key 'k_server_name' for the YANG list /server)

/********************************************************************
* FUNCTION u_ex_action_server_reset_action_val
*
* YANG 1.1 action validate callback
* Path: /server/reset
*
* INPUTS:
*     see agt/agt_action.h for details
*     k_ parameters are ancestor list key values.
*
* RETURNS:
*     error status
********************************************************************/
status_t u_ex_action_server_reset_action_val (
    ses_cb_t *scb,
    rpc_msg_t *msg,
    xml_node_t *methnode,
    val_value_t *actionval,
    const xmlChar *k_server_name)
{
    status_t res = NO_ERR;
    val_value_t *errorval = NULL;

    if (LOGDEBUG) {
        log_debug("\nEnter u_ex_action_server_reset_action_val for action <reset>");
    }

    val_value_t *v_reset_msg_val = NULL;
    const xmlChar *v_reset_msg;

    if (actionval) {
        v_reset_msg_val = val_find_child(
            actionval,
            y_ex_action_M_ex_action,
            y_ex_action_N_reset_msg);
        if (v_reset_msg_val) {
            v_reset_msg = VAL_STRING(v_reset_msg_val);
        }
    }

    /* the validate function would check here if it is OK to
     * reset the server right now; if not an error would be
     * returned by setting res to the correct error status.
     * If the input parameter is the problem then set errorval
     * otherwise leave errorval NULL
     */

    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;

} /* u_ex_action_server_reset_action_val */

Action Invoke Callback Function

The action invoke callback function is used to perform the data-specific action requested by the client session.

  • The action invoke callback function is optional to use, although if no invoke callback is provided, then the action will have no affect.

Example SIL Action Invoke Function:


/********************************************************************
* FUNCTION u_ex_action_server_reset_action_inv
*
* YANG 1.1 action invoke callback
* Path: /server/reset
*
* INPUTS:
*     see agt/agt_action.h for details
*     k_ parameters are ancestor list key values.
*
* RETURNS:
*     error status
********************************************************************/
status_t u_ex_action_server_reset_action_inv (
    ses_cb_t *scb,
    rpc_msg_t *msg,
    xml_node_t *methnode,
    val_value_t *actionval,
    const xmlChar *k_server_name)
{
    status_t res = NO_ERR;

    if (LOGDEBUG) {
        log_debug("\nEnter u_ex_action_server_reset_action_inv for action <reset>");
    }

    val_value_t *v_reset_msg_val = NULL;
    const xmlChar *v_reset_msg = NULL;

    if (actionval) {
        v_reset_msg_val = val_find_child(
            actionval,
            y_ex_action_M_ex_action,
            y_ex_action_N_reset_msg);
        if (v_reset_msg_val) {
            v_reset_msg = VAL_STRING(v_reset_msg_val);
        }
    }

    /* display the reset logging message */
    log_info("\nex-action: Resetting server %s\n", k_server_name);
    if (v_reset_msg) {
        log_info_append("%s\n", v_reset_msg);
    }

    /* the invoke function would schedule or execute the server reset here */

    /* 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 */

    /* Following output nodes expected:
     * leaf reset-finished-at
     */
    if (actionval == NULL) {
        return ERR_NCX_OPERATION_FAILED;  // should not happen
    }

    obj_template_t *obj =
        obj_find_child(VAL_OBJ(actionval),
                       NULL,
                       NCX_EL_OUTPUT);
    if (obj == NULL) {
        return ERR_NCX_DEF_NOT_FOUND;  // should not happen
    }

    /* return the current time */
    xmlChar buff[TSTAMP_MIN_SIZE+1];
    tstamp_datetime(buff);

    val_value_t *val =
        agt_make_leaf(obj,
                      y_ex_action_N_reset_finished_at,
                      buff,
                      &res);
    if (retval) {
        agt_rpc_add_return_val(val, msg);
    } // else res set to error

    return res;

} /* u_ex_action_server_reset_action_inv */

Action Data Output Handling

YANG actions can return data to the client if the operation succeeds. The YANG “output” statement defines the return data for each YANG action. Constructing YANG data is covered in detail elsewhere. This section shows a simple example SIL action invoke function that returns data.

This procedure is not the same for YANG Actions as it is for RPC Operations. The 'rpc_method' parameter will contain the <action> operation, not the YANG action object.

Example: Get the 'output' object for the invoked YANG action

obj_template_t *obj =
    obj_find_child(VAL_OBJ(actionval),
                   NULL,
                   NCX_EL_OUTPUT);
if (obj == NULL) {
    return ERR_NCX_DEF_NOT_FOUND;  // should not happen
}

The 'obj' variable now contains the proper parent for the output parameters. API functions such as 'agt_make_leaf' can be used to create an output return value and add it to the message control block.

/* return the current time */
xmlChar buff[TSTAMP_MIN_SIZE+1];
tstamp_datetime(buff);
status_t res = NO_ERR;

val_value_t *val =
    agt_make_leaf(obj,
                  y_ex_action_N_reset_finished_at,
                  buff,
                  &res);
if (retval) {
    agt_rpc_add_return_val(val, msg);
} // else res set to error