How to Work with Leafref Data Type
The leafref type is restricted to the value space of a leaf or leaf-list node in the schema tree, and optionally further constrained by corresponding instance nodes in the data tree. The "path" sub-statement identifies the referred node. The value space of the referring leafref node matches exactly that of the target node.
If the "require-instance" property is "true", the target node must exist in the data tree with the value matching the leafref for the configuration to be valid.
Consider the following example YANG module:
module example {
namespace "http://yumaworks.com/ns/example";
prefix "example";
revision 2019-07-30 {
description "Initial example module for leafref type";
}
leaf yang-boolean-example {
type boolean;
}
leaf yang-leafref-example-1 {
type leafref {
path "../yang-boolean-example";
require-instance "false";
}
}
leaf yang-leafref-example-2 {
type leafref {
path "../yang-boolean-example";
require-instance "true";
}
}
}
Accessing Leafref Nodes
There are multiple ways to access or modify a leafref node:
Using RESTCONF/HTTP
Create a new "yang-leafref-example-1" node using RESTCONF:
POST /restconf/data/ HTTP/1.1
Host: example-server
Content-Type: application/yang-data+json
{ "yang-leafref-example-1": "false" }
If created successfully, the server response is:
HTTP/1.1 201 Created
Server: example-server
Location: https://example-server/restconf/data/yang-leafref-example-1
If the node already exists, the server returns a "409 Conflict".
Retrieve the created node:
GET /restconf/data/yang-leafref-example-1 HTTP/1.1
Host: example-server
Accept: application/yang-data+xml
Server response:
HTTP/1.1 200 OK
Server: example-server
Content-Type: application/yang-data+xml
<yang-leafref-example-1 xmlns="http://yumaworks.com/ns/example">false</yang-leafref-example-1>
Attempting to create "yang-leafref-example-2" without an existing instance of "yang-boolean-example":
POST /restconf/data/ HTTP/1.1
Host: example-server
Content-Type: application/yang-data+json
{ "yang-leafref-example-2": "false" }
Server response with error:
{
"ietf-restconf:errors": {
"error": [{
"error-type": "application",
"error-tag": "data-missing",
"error-app-tag": "instance-required",
"error-path": "/example:yang-leafref-example-2",
"error-message": "required value instance not found",
"error-info": {
"bad-value": "yang-leafref-example-2",
"error-number": 310
}
}]
}
}
Using yangcli-pro
To create a new "yang-leafref-example-1" node using yangcli-pro client, the client might send the following commands:
user@server> create /yang-leafref-example-1 value=false
user@server> commit
To retrieve the created leafref leaf, the following request might be sent:
user@server> sget /yang-leafref-example-1
The server might respond with rpc-reply, containing below information:
<rpc-reply>
<data>
<yang-leafref-example-1
xmlns="http://yumaworks.com/ns/example">false
</yang-leafref-example-1>
</data>
</rpc-reply>
The following example illustrates how the leafref leaf can be set by using inline JSON file:
edit-config target=candidate config="""
{
"config": {
"yang-leafref-example-1": "false"
}
}
"""
The following example illustrates how the leafref leaf can be set by using inline XML file:
edit-config target=candidate config="""
<config>
<yang-leafref-example-1>false</yang-leafref-example-1>
</config>
"""
To retrieve the newly created leafref leaf, the following request might be sent:
user@server> sget /yang-leafref-example-1
The server might respond with rpc-reply, containing below information:
<rpc-reply>
<data>
<yang-leafref-example-1
xmlns="http://yumaworks.com/ns/example">false
</yang-leafref-example-1>
</data>
</rpc-reply>
yangcli-pro might parse the above message as:
rpc-reply {
data {
yang-leafref-example-1 false
}
}
Using DB-API
Example of setting a leafref leaf value using DB-API:
/********************************************************************
* FUNCTION send_test_edit
*
* This is an example send edit function for leafref node.
**********************************************************************/
static void
send_test_edit (void)
{
const xmlChar *path_str = (const xmlChar *)"/";
const xmlChar *operation_str = (const xmlChar *)"merge";
const xmlChar *value_str = (const xmlChar *)
"<config>"
"<yang-leafref-example-1 xmlns='http://yumaworks.com/ns/example'>false</yang-leafref-example-1>"
"</config>";
const xmlChar *patch_id_str = NULL;
boolean system_edit = FALSE;
status_t res = db_api_send_edit_ex(path_str,
operation_str,
value_str,
patch_id_str,
system_edit);
if (res != NO_ERR) {
log_error("\nSend test edit for leafref node failed %s %s = %s (%s)\n",
operation_str, path_str, value_str,
get_error_string(res));
} else if (LOGDEBUG) {
log_debug("\nSend test edit for leafref node OK %s %s = %s\n",
operation_str, path_str, value_str);
}
} /* send_test_edit */
Leafref Node Creation Using SIL
The following APIs and macros can be used with a leafref val value node. Refer to val.h:
val_make_simval_obj(): creates a val node.
val_get_leafref_typdef(): retrieves the base type.
VAL_STR(): retrieves the string value.
Following code example creates the value of leafref node and outputs it to the standard log output using val_make_simval_obj().
This is just an example of how the following API can be used:
...
/* create a new leafref type node */
val_value_t *return_val =
val_make_simval_obj(obj, (const xmlChar *)"false", &res);
if (return_val) {
typ_def_t *typdef = NULL;
/* As an example, get the value's type:
* If the value has LEAFREF base type, to get its actual type
* definition would required to call val_get_leafref_typdef()
* API that will return leafref actual type that it points at.
* Otherwise, regular macros could be used VAL_TYPDEF()
*/
if (VAL_BTYPE(return_val) == NCX_BT_LEAFREF) {
typdef = val_get_leafref_typdef(return_val);
} else {
typdef = VAL_TYPDEF(return_val);
}
/* Output the value to the standard output log */
log_info("\nCreated leafref node; type: %s; value: %s",
typdef->typenamestr,
VAL_STR(return_val));
}
...
Server logging example:
...
Created leafref node; type: boolean; value: false
...