Operational data is representing in YANG as a data node that has a "config" property of "false".

The netconfd-pro server has 3 ways of supporting operational data


NameCallback TypeDescription
Static NodeNoneData node is a static value stored in the system. It can be used by SIL code only.
Virtual NodeGET1Data node is a placeholder stored in the system. There is a GET1 callback installed to retrieve the value as needed. There is one node for each instance of a list or leaf-list. It can be used by SIL code only. 
Object NodeGET2There are no data nodes stored in the system. There is 1 GET2 callback for each complex object. The GET2 callback is called to retrieve one or more values as needed. It can be used by SIL or SIL-SA code



This example uses code for the yuma-system YANG module.

Note: This module is being replaced by the ietf-system module from RFC 7317 in the near future.


Static Nodes vs. Virtual Nodes



1) Install the system container and leafs during the "init2" phase at boot-time.


/********************************************************************
* FUNCTION agt_sys_init2
*
* INIT 2:
*   Initialize the monitoring data structures
*   This must be done after the <running> config is loaded
*
* INPUTS:
*   none
* RETURNS:
*   status
*********************************************************************/
status_t
    agt_sys_init2 (void)
{
    if (!agt_sys_init_done) {
        return SET_ERROR(ERR_INTERNAL_INIT_SEQ);
    }

    /* get the running config to add some static data into */
    cfg_template_t *runningcfg = cfg_get_config_id(NCX_CFGID_RUNNING);
    if (!runningcfg || !runningcfg->root) {
        return SET_ERROR(ERR_INTERNAL_VAL);
    }

    /* add /system */
    val_value_t *topval = val_new_value();
    if (!topval) {
        return ERR_INTERNAL_MEM;
    }
    val_init_from_template(topval, systemobj);

    /* handing off the malloced memory here */
    val_add_child_sorted(topval, runningcfg->root);

    /* add /system/sysName */
    const xmlChar *myhostname = (const xmlChar *)getenv("HOSTNAME");
    if (!myhostname) {
        myhostname = (const xmlChar *)"localhost";
    }

    status_t res = NO_ERR;
    val_value_t  *childval =
        agt_make_leaf(systemobj, system_N_sysName, myhostname, &res);
    if (childval) {
        val_add_child(childval, topval);
    } else {
        return res;
    }

    /* add /system/sysCurrentDateTime */
    childval = agt_make_virtual_leaf(systemobj,
                                     system_N_sysCurrentDateTime,
                                     get_currentDateTime, &res);
    if (childval) {
        val_add_child(childval, topval);
    } else {
        return res;
    }

    /* add /system/sysBootDateTime */
    xmlChar tstampbuff[TSTAMP_MIN_SIZE];
    tstamp_datetime(tstampbuff);
    childval = agt_make_leaf(systemobj,
                             system_N_sysBootDateTime,
                             tstampbuff, &res);
    if (childval) {
        val_add_child(childval, topval);
    } else {
        return res;
    }


2) Example GET1 Callback


/********************************************************************
* FUNCTION get_currentDateTime
*
* <get> operation handler for the sysCurrentDateTime leaf
*
* INPUTS:
*    see ncx/getcb.h getcb_fn_t for details
*
* RETURNS:
*    status
*********************************************************************/
static status_t
    get_currentDateTime (ses_cb_t *scb,
                         getcb_mode_t cbmode,
                         const val_value_t *virval,
                         val_value_t  *dstval)
{
    (void)scb;
    (void)virval;

    if (cbmode == GETCB_GET_VALUE) {
        xmlChar *buff = (xmlChar *)m__getMem(TSTAMP_MIN_SIZE);
        if (!buff) {
            return ERR_INTERNAL_MEM;
        }
        tstamp_datetime(buff);
        VAL_STR(dstval) = buff;
        return NO_ERR;
    } else {
        return ERR_NCX_OPERATION_NOT_SUPPORTED;
    }

} /* get_currentDateTime */