External Commands

External commands can be supported by yangcli-pro and yp-shell.

This support is limited to the functionality available to existing yangcli-pro commands:

  • Access local data structures

  • Access local files

  • Generate log output

  • Send 1 or 2 commands to the server

  • Override or add to the existing reply output processing

YANG for Command Definitions

The YANG module definition is used for several tasks:

  • process command line input, including command name and input parameters

  • control tab key completion

  • provide help text for commands and input parameters

The YANG syntax is restricted for CLI command purposes:

  • must statement validation is not done

  • unique statement validation is not done

Example Command Definition:

rpc example-cmd {
  description "Example external command";
  input {
    leaf parm1 {
      type string;
      description "The first example parameter";
    }
    leaf parm2 {
      type int32;
      description "The second example parameter";
    }
  }
}

yp-show API Functions

There are a limited number of API functions available to add an external command.

A yangcli-pro or yp-shell command requires at least 3 components:

  1. YANG module “RPC statement” defining the command syntax

  2. Callback function to do the command when requested by user input

  3. Call to the registration function to add the command into the program

External Command Callback Function

The callback function for the external command must use the “yangcli_command_cbfn_t” definition in yangcli.h:

/* Callback template for a local command
 *
 * Handles the command line for the specified command
 *
 * INPUTS:
 *   server_cb == server control block to use
 *   session_cb == session control block to use
 *   rpc == object template for the command
 *   line == input command line to execute
 *   len == offset into the line to start processing
 *          this can be > 0 if the command is the left-hand-side
 *          of an assignment statement
 * RETURNS:
 *    status
 */
typedef status_t
    (*yangcli_command_cbfn_t) (server_cb_t *server_cb,
                               session_cb_t *session_cb,
                               obj_template_t *rpc,
                               const xmlChar *line,
                               uint32 len);

The following example callback can be found in example-fan.cpp

/********************************************************************
 * FUNCTION do_example_cmd (local RPC)
 *
 * Do Example Command
 *
 * INPUTS:
 *    server_cb == server control block to use
 *    session_cb == session control block to use
 *    rpc == RPC method for the example-cmd command
 *    line == CLI input in progress
 *    len == offset into line buffer to start parsing
 *
 * RETURNS:
 *   status
 *********************************************************************/
static status_t
    do_example_cmd (server_cb_t *server_cb,
                    session_cb_t *session_cb,
                    obj_template_t *rpc,
                    const xmlChar *line,
                    uint32 len)
{
    (void)rpc;

    status_t res = NO_ERR;
    val_value_t *valset =
        get_valset(server_cb, session_cb, rpc, &line[len], &res);
    if (valset && (res == NO_ERR)) {
        val_value_t *parm1 =
            val_find_child(valset, MODNAME, (const xmlChar *)"parm1");
        if (parm1) {
            log_debug("\nGot parm1=%s", VAL_STR(parm1));
        }

        val_value_t *parm2 =
            val_find_child(valset, MODNAME, (const xmlChar *)"parm2");
        if (parm2) {
            log_debug("\nGot parm2=%d", VAL_INT32(parm2));
        }

        /* do something with the parameters */
    }

    val_free_value(valset);

    return res;

}  /* do_example_cmd */

Key steps:

  • the input line is parsed. This should be done even if no input parameters to make sure no extra parameters are present.

  • a val_value_t tree is produced representing a container of all the input parameters that were parsed

  • the parameters are checked with “val_find_child”

  • the callback does the work required for the command

  • the val_value_t for the input parameters is freed

Register an External Command

The “register_command” function is called from the yp_show_init function to register an external command:

/********************************************************************
* FUNCTION register_command
*
* INPUTS:
*    server_cb == server control block to use
*    module == module name containing the RPC method
*    ycli_command_name == RPC method name
*    command_fn == pointer to callback function for this command
*    is_top_cmd == TRUE if opt-level command
*    yangcli_ok == TRUE if OK for yangcli to use it
*    ypshell_ok == TRUE if OK for yp-shell to use it
*    ypserver_ok == TRUE if OK for yp-server to use it
*
* RETURNS:
*    status of the operation
*********************************************************************/
extern status_t
    register_command (
              server_cb_t *server_cb,
              const xmlChar *module,
              const xmlChar *ycli_command_name,
              yangcli_command_cbfn_t command_fn,
              boolean is_top_cmd,
              boolean yangcli_ok,
              boolean ypshell_ok,
              boolean ypserver_ok);

Usage Example: (from example-fan.cpp)

server_cb_t *server_cb = get_default_server_cb();
if (server_cb == NULL){
    res = ERR_NCX_NOT_FOUND;
} else {
    res = register_command(server_cb,
                           MODNAME,
                           (const xmlChar *)"example-cmd",
                           do_example_cmd,
                           TRUE,   // is_top_cmd
                           TRUE,   // yangcli_ok
                           TRUE,   // ypshell_ok
                           FALSE); // ypserver_ok (not used)
}

Usage Notes:

  • The YANG module identified by “module” must already be loaded

  • The command name cannot be a duplicate of any command in yangcli-pro.yang

  • The command name cannot be a duplicate of any other external command

  • The “is_top_cmd” field must be set to TRUE

  • The “ypserver_ok field is ignored but should be set to FALSE