Edit Transaction Examples

Edit transactions are used to modify configuration datastores. The Database Operations section explains the callback functions that are used to implement an edit transaction. This section provides guidelines and examples for handling various editing procedures.

There are several operations that cause an edit transaction to be executed. The Database Deployment Variants section describes the different internal database deployment options. The Databases variant used on the server will determine which operations are available.

Newval, Curval and Update Parameters

The newval and curval parameters that are passed to SIL and SIL-SA callback functions can be used to implement YANG instrumentation for configuration data nodes.

The properties and usage of these parameters are explained in this section.

  • newval: edit callback input parameter

    • non-NULL: the new value that will be set if the edit succeeds.

    • NULL: no new value if the edit is a delete operation

  • curval: edit callback input parameter

    • non-NULL: the current value that will be replaced if the edit succeeds.

    • NULL: there is no current value for the node.

The advent of the EDIT3 Callback marks a significant shift in YANG instrumentation for configuration data nodes, pivoting primarily on the utilization of the update value.

The update value streamlines the update process by providing a composite Update value, that incorporates latest changes proposed by the user (newval) along with relevant current values from the datastore (curval).

  • update: a merged value of all new and current values from the datastore,

    streamlining the update process.

    • non-NULL: replace the existing data with this composite update value

    • NULL: operation is delete - Delete all data from the device

A data node can either be created by YANG default or created by a client edit operation. The edit transaction processing details for YANG defaults depend on the --default-style parameter value used on the server and the YANG data model being processed.

The following example use-cases will be examined:

  • Leaf with a Default

  • Leaf without a Default

  • Non-Presence Container with a Default

  • Non-Presence Container without a Default

  • Presence Container with a Default

  • Presence Container without a Default

The default processing is handled during an edit operation before the SIL or SIL-SA callbacks are invoked. This section contains the following examples:

  • the details for a first edit to a node by a client operation

  • the details for an edit to an existing node by a client operation

  • the details for a delete edit to an existing node by a client operation

The actual edit operations can change in different scenarios. For example, a 'delete' operation followed by a 'create' operation on the <candidate> datastore can be changed to a 'replace' operation on the <running> datastore.

Printing the Value Path String from a SIL Edit Callback

It is very common to print a debug trace when entering a SIL callback function. There is such a debug trace in the auto-generated code by yangdump-pro.

The 'val_gen_instance_id' function is used to get the string value for the path string of the object node for the callback.

status_t val_gen_instance_id(xml_msg_hdr_t *mhdr, const val_value_t *val, ncx_instfmt_t format, xmlChar **buff)

Malloc and Generate the instance ID string for this value node,.

Parameters:
  • mhdr -- [inout] message hdr w/ prefix map or NULL to just use the internal prefix mappings

    • mhdr.pmap may have entries added if prefixes used in the instance identifier which are not already in the pmap

  • val -- node to generate the instance ID for

  • format -- desired output format (NCX or Xpath)

  • buff -- [out] pointer to address of buffer to use

    • *buff malloced buffer with the instance ID

Returns:

status

The following example uses this small YANG module to show path strings for the 'test3' list node:

container test1 {
  list test2 {
     key "a b";
     leaf a { type int32; }
     leaf b { type string; }

     list test3 {
       key "c d";
       leaf c { type string; }
       leaf d { type string; }
     }
  }
}

The following code snippet shows how this function can be used.

if (LOGDEBUG) {
    log_debug("\nEnter u_tlist_test3_edit callback for %s phase",
        agt_cbtype_name(cbtyp));

    /* print the edit operation */
    log_debug_append(" op=%s", op_editop_name(editop));

    /* print the path string */
    val_value_t *useval = newval;
    if (useval == NULL) {
        useval = curval;
    }
    if (useval != NULL) {
        ncx_instfmt_t format = NCX_IFMT_XPATH2;
        xmlChar *buff = NULL;
        res = val_gen_instance_id(RPC_MHDR(msg),
                                  useval,
                                  format,
                                  &buff);
        if ((res == NO_ERR) && (buff != NULL)) {
            log_debug_append("\nPath: %s", buff);
        }
        m__free(buff);
    }
}

The following log trace shows an example list entry being created:

Enter test3_edit callback for commit phase
Enter u_tlist_test3_edit callback for commit phase op=create
Path: /tlist:test1/tlist:test2[tlist:a="100"][tlist:b="test-b"]/tlist:test3[tlist:c="test-c"][tlist:d="test-d"]

Example YANG Module: testdef2

The YANG module modules/test/pass/testdef2.yang is used as an example for default handling.

module testdef2 {
  yang-version 1.1;
  namespace "urn:yumaworks:params:xml:ns:yang:testdef2";
  prefix "tdef2";
  revision 2023-04-07;

  leaf defleaf {
    type uint32;
    default 42;
  }

  leaf nodefleaf {
    type uint32;
  }

  container npcon {
    leaf defleaf2 {
      type uint32;
      default 142;
    }
    leaf nodefleaf2 {
      type uint32;
    }
  }

  container pcon {
    presence "enabled";
    leaf defleaf3 {
      type uint32;
      default 242;
    }
    leaf nodefleaf3 {
      type uint32;
    }
  }

}

Each example shows the value and source of the newval, curval, and update parameters that are passed to the edit callback function.

Note

Update value is used only in EDIT3 Callback

A simple debug trace function was added to the edit functions:

static void dump_edit_vals (val_value_t *newval,
                            val_value_t *curval,
                            val_value_t *update)
{
    if (!LOGDEBUG) {
        return;
    }
    log_debug("\nEdit values:");
    if (newval) {
        log_debug_append("\nnewval set %s",
                         val_set_by_default(newval) ?
                         "by default" : "by client");
        val_dump_value(newval, 2, DBG);
    } else {
        log_debug_append("\nnewval NULL");
    }
    if (curval) {
        log_debug_append("\ncurval set %s",
                         val_set_by_default(curval) ?
                         "by default" : "by client");
        val_dump_value(curval, 2, DBG);
    } else {
        log_debug_append("\ncurval NULL");
    }
    if (update) {
        log_debug_append("\nupdate set %s",
                         val_set_by_default(update) ?
                         "by default" : "by client");
        val_dump_value(update, 2, DBG);
    } else {
        log_debug_append("\nupdate NULL");
    }

}  /* dump_edit_vals */

Default Nodes Created During Load Config

The server will usually create default leafs and NP containers during the system <load-config> operation. The defaults are added to an empty datastore or to a datastore with the previous contents from non-volatile storage.

A val_value_t data structure is created for both default and non-default nodes leafs:

  • The newval, curval, or update parameters could be set by default

  • Use function val_set_by_default to check if the value was added by the system

  • Use function val_is_default to check if the value is equal to the YANG default value

For this example it is assumed the initial datastore is empty. This is possible many ways, included by use of the --no-startup parameter.

  • The curval is NULL during a load since the datastore is initially empty.

  • The newval is set by default.

  • The update is the same as newval in EDIT3 callbacks.

  • The editop will be OP_EDITOP_LOAD

  • The --default-style parameter is ignored during processing.

  • The newval will be set-by-default in all 3 default styles

  • The datastore will be <running>.

In this example, there will be SIL callbacks for the 2 nodes that are created by default.

  • Leaf /defleaf = 42

    Start invoking validate SIL callback for load on testdef2:defleaf
    Enter defleaf_edit callback for validate phase
    Enter u_tdef2_defleaf_edit callback for validate phase
    Edit values:
    newval set by default
      tdef2:defleaf 42
    curval NULL
    update NULL
    Finished invoking user callback on testdef2:defleaf
    
  • Container /npcon (contains defleaf2 = 142)

    Enter npcon_edit callback for validate phase
    Enter u_tdef2_npcon_edit callback for validate phase
    Edit values:
    newval set by default
      tdef2:npcon {
        defleaf2 142
      }
    curval NULL
    update set by default
      tdef2:npcon {
        defleaf2 142
      }
    Finished invoking user callback on testdef2:defleaf
    

Edit Processing For Leafs

The callback details for a leaf are is the simplest of all YANG objects. There is only one instance possible of a leaf.

Note

Top level leafy nodes cannot have EDIT2 nor EDIT3 callbacks. In this case there will be an EDIT1 callback, thus no update value.

For non-delete operations:

  • The newval is non-NULL and is set by a client.

  • The curval is non-NULL is there is an existing value for the leaf.

  • The edit operation is a 'set' operation if the editop is one of:

    • OP_EDITOP_CREATE

    • OP_EDITOP_MERGE

    • OP_EDITOP_REPLACE

  • These operations mean the same thing for leafs and should be treated the same.

For delete operations:

  • The newval is NULL

  • The curval is set-by-default or NULL

  • The edit operation is a 'delete' operation if the editop is one of:

    • OP_EDITOP_DELETE

    • OP_EDITOP_REMOVE

  • For SIL or SIL-SA callback purposes the value of editop will always be OP_EDITOP_DELETE for any form of delete operation used by the client.

Leaf with a Default Value

  • create /defleaf value=100

    Enter u_tdef2_defleaf_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:defleaf 100
    curval set by default
      tdef2:defleaf 42
    update NULL
    Finished invoking user callback on testdef2:defleaf
    

    There is always a current value for a leaf with a YANG default, even if it is deleted.

  • replace /defleaf value=101

    Enter defleaf_edit callback for validate phase
    Enter u_tdef2_defleaf_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:defleaf 101
    curval set by client
      tdef2:defleaf 100
    update NULL
    Finished invoking user callback on testdef2:defleaf
    
  • delete /defleaf

    Enter u_tdef2_defleaf_edit callback for validate phase
    Edit values:
    newval set by default
      tdef2:defleaf 42
    curval set by client
      tdef2:defleaf 101
    update NULL
    Finished invoking user callback on testdef2:defleaf
    

Leaf Without a Default Value

  • create /nodefleaf value=200

    Enter u_tdef2_nodefleaf_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:nodefleaf 200
    curval NULL
    update NULL
    Finished invoking user callback on testdef2:nodefleaf
    
  • replace /nodefleaf value=201

    Enter u_tdef2_nodefleaf_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:nodefleaf 201
    curval set by client
      tdef2:nodefleaf 200
    update NULL
    Finished invoking user callback on testdef2:nodefleaf
    
  • delete /nodefleaf

    Enter u_tdef2_nodefleaf_edit callback for commit phase
    Edit values:
    newval NULL
    curval set by client
      tdef2:nodefleaf 201
    update NULL
    Finished invoking user callback on testdef2:nodefleaf
    

Edit Processing For Containers and Lists

There are 2 types of YANG data nodes that can have child nodes:

  • non-presence container:

    • These nodes are created automatically.

    • The --create-empty-npcontainers parameter controls this behavior during edit operations.

    • The value can either be set-by-default or set-by-client

  • presence container or list:

    • These nodes are not created automatically.

    • The value is always set-by-client

For non-delete operations:

  • The newval is non-NULL and is set by a client.

  • The curval is non-NULL is there is an existing value for the node.

  • The update is non-NULL and is a merged value of new and current values.

  • The edit operation is a 'set' operation if the editop is one of:

    • OP_EDITOP_CREATE

    • OP_EDITOP_MERGE

    • OP_EDITOP_REPLACE

  • These operations mean the same thing only if the current value is set-by-default or NULL.

For delete operations:

  • The newval is NULL

  • The curval is set-by-default or NULL

  • The update is NULL

  • The edit operation is a 'delete' operation if the editop is one of:

    • OP_EDITOP_DELETE

    • OP_EDITOP_REMOVE

  • For SIL or SIL-SA callback purposes the value of editop will always be OP_EDITOP_DELETE for any form of delete operation used by the client.

  • If the --allow-list-delete-all parameter is 'true' then the following edit operations can be in the edit request. - OP_EDITOP_DELETE_ALL - OP_EDITOP_REMOVE_ALL

    • The server will set editop to OP_EDITOP_DELETE for each individual list instance.

Non Presence Container with a Default Value

  • create /npcon (defleaf2 = 242, nodefleaf2 = 243)

    Enter u_tdef2_npcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:npcon {
        defleaf2 242
        nodefleaf2 243
      }
    curval set by default
      tdef2:npcon {
        defleaf2 142
      }
    update set by client
      tdef2:npcon {
        defleaf2 242
        nodefleaf2 243
      }
    Finished invoking user callback on testdef2:npcon
    

    Update value is the same as newval for CREATE operation.

  • replace /npcon (defleaf2 = 143, nodefleaf2 NOT SET)

    Enter u_tdef2_npcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:npcon {
        defleaf2 143
      }
    curval set by client
      tdef2:npcon {
        defleaf2 242
        nodefleaf2 243
      }
    update set by client
      tdef2:npcon {
        defleaf2 143
        nodefleaf2 243
      }
    Finished invoking user callback on testdef2:npcon
    

    There is no instance of the 'nodefleaf2' node in 'newval'. The SIL callback for 'npcon' must remove any internal value held for this leaf if its configuration instance is removed.

    Update value can be used to update internal values. The technique here is to replace the existing data with this composite Update value.

  • replace /npcon (defleaf2 NOT SET, nodefleaf2 = 256)

    Enter u_tdef2_npcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:npcon {
        nodefleaf2 256
      }
    curval set by client
      tdef2:npcon {
        defleaf2 143
        nodefleaf2 243
      }
    update set by client
      tdef2:npcon {
        defleaf2 143
        nodefleaf2 256
      }
    Finished invoking user callback on testdef2:npcon
    

    Update value can be used to update internal values. The technique here is to replace the existing data with this composite Update value.

  • delete /npcon

    Enter u_tdef2_npcon_edit callback for validate phase
    Edit values:
    newval set by default
      tdef2:npcon {
        defleaf2 142
      }
    curval set by client
      tdef2:npcon {
        defleaf2 143
        nodefleaf2 256
      }
    update NULL
    Finished invoking user callback on testdef2:npcon
    

    Update value is NULL during DELETE operation. Newval contains only defaults.

Presence Containers and Lists

An example for a presence container pcon is shown. The callbacks would be quite similar for lists, except additional key leaf parameters are used.

  • create /pcon (defleaf3 = 300, nodefleaf3 = 400)

    Enter u_tdef2_pcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:pcon {
        defleaf3 300
        nodefleaf3 400
      }
    curval NULL
    update set by client
      tdef2:pcon {
        defleaf3 300
        nodefleaf3 400
      }
    Finished invoking user callback on testdef2:pcon
    

    Update value is the same as newval for CREATE operation.

  • replace /pcon (defleaf3 = 243, nodefleaf3 NOT SET)

    Enter u_tdef2_pcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:pcon {
        defleaf3 243
      }
    curval set by client
      tdef2:pcon {
        defleaf3 300
        nodefleaf3 400
      }
    update set by client
      tdef2:pcon {
        defleaf3 243
        nodefleaf3 400
      }
    Finished invoking user callback on testdef2:pcon
    

    Update value can be used to update internal values. The technique here is to replace the existing data with this composite Update value.

  • replace /npcon (defleaf3 NOT SET, nodefleaf3 = 256)

    Enter u_tdef2_pcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:pcon {
        nodefleaf3 256
      }
    curval set by client
      tdef2:pcon {
        defleaf3 243
        nodefleaf3 400
      }
    update set by client
      tdef2:pcon {
        defleaf3 243
        nodefleaf3 256
      }
    Finished invoking user callback on testdef2:pcon
    

    Update value can be used to update internal values. The technique here is to replace the existing data with this composite Update value.

  • delete /pcon

    Enter u_tdef2_pcon_edit callback for validate phase
    Edit values:
    newval NULL
    curval set by client
      tdef2:pcon {
        defleaf3 242
        nodefleaf3 256
      }
    update NULL
    Finished invoking user callback on testdef2:pcon
    

    Update value is NULL during DELETE operation. Newval does not contain any defaults and is also NULL.