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
...