YANG Extension Handlers

The YANG compiler supports user callbacks to handle specific extension statements. There are two types of callbacks:

Top-level extensions:

  • These extensions have the module statement itself as its parent.

  • These extensions may be wrappers for additional statements, such as the reserved extension “yang-data”.

  • The callback for these extensions is invoked during the module parsing phase (E.g,., 'consume_extension').

  • The callback is responsible for completing the parsing phase and consume all tokens for the external statement, including the final semi-colon or right brace.

Nested extensions:

  • These extensions are contained within nested statements, which are not at the top-level.

  • They are expected to be simple statements and not wrappers for YANG statements.

  • The callback for these extensions is invoked during the module validation phase (E.g., 'resolve_extension').

  • This callback is not responsible for parsing any module token input.

  • All parsing has already been completed.

YANG Extension Handler Callback

The following callback API is defined in ncx/ext.h:

typedef status_t (*ext_cbfn_t)(void *rawpcb, ncx_module_t *mod, tk_chain_t *tkc, struct ext_template_t_ *ext, void *cookie, const xmlChar *arg, ncx_node_t node_type, void *node)

One YANG Extension Handler Callback.

ext_cbfn_t

Handle the parsing and processing of an external statement using the associated YANG extension statement

This callback is invoked when the external statement is first encountered. The current token is the argument string if any or the identifier token if none. The next token is expected to be a semi-colon or a left brace The callback is expected to parse the closing semi-colon or entire sub-section including starting brace

Param rawpcb:

parser control block in progress (cast as void *)

Param mod:

module being processed

Param tkc:

token chain of module tokens parse in progress

Param ext:

extension definition record (allows a handler to process multiple extension types)

Param cookie:

cbfn_cookie from the extension 'ext'

Param arg:

argument string used in the external statement (if any)

Param node_type:

type of node being processed; direct parent statement of the external statement using the extension If NULL, then the parent statement is the module itself, and 'mod' should be used as the 'node' pointer

Param node:

pointer to node indicated by node_type

Return:

status of processing

The registration function is defined in ncx/etc.h. This API should be registered in the yp-system initialization phase, before YANG modules are parsed.

status_t ext_register_cbfn(const xmlChar *modname, const xmlChar *extname, ext_cbfn_t cbfn, void *cbfn_cookie)

Register a callback function for the specified extension If multiple callbacks for same extension, then last one wins.

Parameters:
  • modname -- module name defining the extension

  • extname -- extension name

  • cbfn -- pointer to callback function to register

  • cbfn_cookie -- optional cookie to register; will not be freed when the extension is freed Use macro EXT_CBFN_COOKIE(ext) to access from callback; (may be NULL if not used)

Returns:

status

Example registration inside yp_system_init1:

#include “ext.h”

status_t yp_system_init1 (boolean pre_cli)
{
    status_t res = NO_ERR;
    log_debug("\nyp_system init1\n");

    if (pre_cli) {
        ;
    } else {

        /* example -- Register a Extension Handler Callback */
        res = ext_register_cbfn((const xmlChar *)"acme-ext",
                                (const xmlChar *)"acme1",
                                example_ext_cbfn,
                                NULL);   // cookie

    }
    return res;

}  /* yp_system_init1 */

YANG Extension Usage Example

This example callback function checks for a proprietary YANG extension within a YANG object.

It uses the same YANG module as the YANG Object Template Callback.

/*
 * Callback is invoked to check a specific extension in an
 * obj_template_t, typ_template_t, typ_def_t
 *
 * Assume the same YANG module foo exists with extension acme1
 *
 * The example callback does the same task as the
 * example_obj_template_cbfn, using the per-callback approach
 */

/* One YANG Extension Handler Callback
 *
 * example_ext_cbfn
 *
 * Handle the parsing and processing of an external statement
 * using the associated YANG extension statement
 *
 * This callback is invoked when the external statement is
 * first encountered. The current token is the argument string
 * if any or the identifier token if none.
 * The next token is expected to be a semi-colon or a left brace
 * The callback is expected to parse the closing semi-colon or
 * entire sub-section including starting brace
 *
 * INPUTS:
 *   rawpcb == parser control block in progress (cast as void *)
 *   mod == module being processed
 *   tkc == token chain of module tokens parse in progress
 *   ext == extension definition record (allows a handler to
 *         process multiple extension types)
 *   cookie == cbfn_cookie from the extension 'ext'
 *   arg == argument string used in the external statement (if any)
 *   node_type == type of node being processed; direct parent
 *         statement of the external statement using the extension
 *         If NULL, then the parent statement is the module itself,
 *         and 'mod' should be used as the 'node' pointer
 *   node == pointer to node indicated by node_type
 * OUTPUTS:
 *
 * RETURNS:
 *   status of processing
 */
static status_t
     example_ext_cbfn (void *rawpcb,  // struct yang_pcb_t_ *pcb
                       ncx_module_t *mod,
                       tk_chain_t *tkc,
                       struct ext_template_t_ *ext,
                       void *cookie,
                       const xmlChar *arg,
                       ncx_node_t node_type,
                       void *node)
{
    (void)rawpcb;
    (void)mod;
    (void)tkc;
    (void)ext;
    (void)cookie;
    (void)arg;

    /* ignore this extension in all contexts except object template */
    if (node_type != NCX_NT_OBJ) {
        return NO_ERR;
    }

    /* get the object template */
    obj_template_t *obj = (obj_template_t *)node;

    /* set the acme1 bit */
    OBJ_USER_FLAGS(obj) |= FL_ACME_1;

    return NO_ERR;
}