AVAILABLE SINCE 19.10-4 RELEASE


This section describes All In One (AIO) GET2 mechanism that allows to call a single GET2 callback for the whole Subtree. This article focuses on how to use AIO callback with val value tree that has to be constructed and provided as a return value to the server.


AIO GET2 callbacks follow exactly the same template as regular GET2 callbacks, they use the same registration API and are getting invoked the same way for SIL and SIL-SA as regular GET2 callbacks. The main difference is that there will not be any callback invocations for descendant children and there will not be any callbacks auto generated at all for any of AIO node children.


The yangdump auto-generation code does not auto generate callbacks for children of the top All In One parent. The callbacks will be generated only for the top nodes that have the extension specified. The extension definition looks as follows:


  extension sil-aio-get2 {
    description
      "Used within a data definition statement to define
       the GET2 retrieval mechanism.
       This extension affects the descendant data nodes.

       This extension can be used in a container or list
       to force the server to treat that data subtree as
       a terminal node for GET2.

       The entire subtree would be expected in one retrieval
       in one callback invocation.

       The entire subtree can be specified in the JSON
       or XML buffer that will be used for return values.
       The server will parse and handle the buffer and process
       retrieval based on the provide JSON or XML encoded buffer.

       The 'parmstr' argument can specify the encoding that will
       be used in the callback. Available options are:
         - xml: XML element in a buffer is expected in return value
         - json: JSON object in a buffer is expected in return value
         - val: val_value_t tree is expected in return value
      ";
    argument parmstr;
  }


For more information refer to the following article: 

How do I use All In One (AIO) GET2 callback?


For more example on how to use AIO callbacks with different extension parameters refer to the following articles:

How do I use All In One (AIO) GET2 callback with XML/JSON buffers?



AIO VAL Callback Examples


Let us go through simple examples that will illustrate how to utilize the AIO callbacks for the specific purposes. First we need a YANG module. Consider this simplified, but functional, example. You can download this YANG module from attachments and run make_sil_dir_pro to auto-generate stub SIL code for this module.

Note, the AIO callback is not part of the auto-generated code by default and you will have to add an extension to the desired node that you want to become an AIO callback node. Otherwise, the auto generated code will generate regular GET2 callback for that node.


In this example we are going to use "sil-aio-get2" extension with "val" parameter, meaning we are going to construct our own val value structure to return in the AIO callback.


SIL code Generation command that was used in this example. Please refer to the attached SIL code.


> make_sil_dir_pro aio-test --sil-get2 sil-edit2


As an example, to illustrate how the "sil-aio-get2" extension can be used in a YANG module refer to the following YANG module. It can be found in the attachments in this article. Note, that you have to import "yumaworks-extensions" YANG module:


module aio-test {
  namespace "http://yumaworks.com/ns/aio-test";
  prefix "aiotest";

  import yumaworks-extensions { prefix ywx; }

  revision 2020-02-20 {
    description "Initial Version";
  }


  /* All in One callback within config true and GET2 reg callbacks */
  container get3-config-cont {
    presence "Presence container";

    list config-list {
      key name;
      leaf name { type string; }

      list nonconfig-list {               // Regular GET2 CB
        config false;
        key name;
        leaf name { type string; }

        list nonconfig-list2 {            // All in One GET2 CB
          ywx:sil-aio-get2 "val";

          key name;
          leaf name { type string; }

          list nonconfig-list3 {          // No callback
            key name;
            leaf name { type string; }
            leaf not-keyname { type string; }

            container int-con {           // No callback
              leaf con-leaf { type int32; }
            }
          }
        }
      }
    }
  }


  /* All in One callback within config true NP-container */
  container get3-config-cont2 {

    /* NP-container with a terminal node */
    container nonconfig-NPcont {        // All in One get2 CB
      ywx:sil-aio-get2 "val";
      config false;

      list nonconfig-list {             // No callback
        key name;
        leaf name { type string; }
      }
      leaf D { type int8; }
    }
  }
}


AIO VAL List Example


In the YANG module example above we define top level configuration parent "get3-config-cont/config-list" and next regular GET2 child "nonconfig-list" and then the AIO GET2 list child "nonconfig-list2".


In this case the server will invoke GET2 callbacks only for "nonconfig-list" and then for AIO "nonconfig-list2" list and will not invoke any descendent level callbacks. The server will expect that the AIO "nonconfig-list2" callback will supply the GET2 control block with the sufficient information about "nonconfig-list2" node children, complex children as well as terminal nodes.


The AIO GET2 callback may look as follow for the "/get3-config-cont/config-list/nonconfig-list/nonconfig-list2" list.

Refer to the attachment SIL code for complete code and more details:


/********************************************************************
* FUNCTION aio_test_get3_config_cont_config_list_nonconfig_list_nonconfig_list2_get
*
* Get database object callback for list nonconfig-list2
* Path: list /get3-config-cont/config-list/nonconfig-list/nonconfig-list2
* Fill in 'get2cb' response fields
*
* sil-aio-get2 extension enabled for this object;
* No callbacks for children will be called
*
* INPUTS:
*     see ncx/getcb.h for details (getcb_fn2_t)
*
* RETURNS:
*     error status
********************************************************************/
static status_t
    aio_test_get3_config_cont_config_list_nonconfig_list_nonconfig_list2_get (
        ses_cb_t *scb,
        xml_msg_hdr_t *msg,
        getcb_get2_t *get2cb)
{

    if (LOGDEBUG) {
        log_debug("\nEnter callback for /get3-config-cont/config-list/"
                  "nonconfig-list/nonconfig-list2");
    }

    (void)scb;
    (void)msg;

#if 0

    /* Use ancestor or local keys if needed */

    val_value_t *keyval = NULL;

    /* ancestor key aio-test:name */
    const xmlChar *k_get3_config_cont_config_list_name = 0;
    keyval = GETCB_GET2_FIRST_KEY(get2cb);
    if (keyval) {
        k_get3_config_cont_config_list_name = VAL_STRING(keyval);
    }

    /* ancestor key aio-test:name */
    const xmlChar *k_get3_config_cont_config_list_nonconfig_list_name = 0;
    keyval = GETCB_GET2_NEXT_KEY(get2cb, keyval);
    if (keyval) {
        k_get3_config_cont_config_list_nonconfig_list_name = VAL_STRING(keyval);
    }

    /* local key aio-test:name */
    const xmlChar *k_get3_config_cont_config_list_nonconfig_list_nonconfig_list2_name = 0;
    boolean name_fixed = FALSE;
    boolean name_present = FALSE;
    keyval =
        getcb_find_key_lvl(get2cb,
                           y_aio_test_M_aio_test,
                           y_aio_test_N_name,
                           (uint32)5);
    if (keyval) {
        k_get3_config_cont_config_list_nonconfig_list_nonconfig_list2_name = VAL_STRING(keyval);
        name_fixed = VAL_IS_FIXED_VALUE(keyval);
        name_present = TRUE;
    }

#endif

    obj_template_t *obj = GETCB_GET2_OBJ(get2cb);
    status_t res = NO_ERR;


    /* create 3 top level lists */
    uint32 key = 0;
    for (key = 1; key < 4; key++) {

        const xmlChar *key1 = NULL;
        if (key == (uint32)1) {
            key1 = (const xmlChar *)"name1";
        } else if (key == (uint32)2) {
            key1 = (const xmlChar *)"name2";
        } else if (key == (uint32)3) {
            key1 = (const xmlChar *)"name3";
        }

        /* make return value that will be added to the return_aioQ */
        val_value_t *retval = val_new_value();
        if (!retval) {
            return ERR_INTERNAL_MEM;
        }
        val_init_from_template(retval, obj);

        /* Use retval for the current callback obj and fill
         * it in with folowing terminal and complex nodes;
         * then add to get2cb with help of getcb_add_return_aioQ API
         */
        obj_template_t *childobj =
            getcb_first_requested_child(get2cb, obj);
        for (; childobj; childobj =
            getcb_next_requested_child(get2cb, childobj)) {

            const xmlChar *name = obj_get_name(childobj);

            /* Retrieve the value of this child node and
             * add it to retval of the current callback node
             */
            if (!xml_strcmp(name, (const xmlChar *)"name")) {
                /* leaf name (string) */
                val_value_t *child =
                    val_make_simval_obj(childobj,
                                        key1,
                                        &res);
                if (child) {
                    res = val_child_add(child, retval);
                    if (res != NO_ERR) {
                        val_free_value(child);
                        val_free_value(retval);
                        return ERR_NCX_INVALID_VALUE;
                    }
                } else {
                    val_free_value(retval);
                    return ERR_NCX_INVALID_VALUE;
                }
            } else if (!xml_strcmp(name, (const xmlChar *)"nonconfig-list3")) {

                /* list nonconfig-list3 (list) */
                uint32 nextlist_key = 0;
                for (nextlist_key = 1; nextlist_key < 3; nextlist_key++) {

                    const xmlChar *keyname = NULL;
                    if (nextlist_key == (uint32)1) {
                        keyname = (const xmlChar *)"name1";
                    } else if (nextlist_key == (uint32)2) {
                        keyname = (const xmlChar *)"name2";
                    }

                    /* create 5 list entries */
                    val_value_t *listval =
                        create_list_entry(childobj,
                                          (const xmlChar *)"name",
                                          keyname,
                                          &res);
                    if (!listval) {
                        val_free_value(retval);
                        return ERR_INTERNAL_MEM;
                    }

                    /* Use add_force to allow insertion lists with NO keys */
                    res = val_child_add(listval, retval);
                    if (res != NO_ERR) {
                        val_free_value(listval);
                        val_free_value(retval);
                        return ERR_NCX_INVALID_VALUE;
                    }
                }
            }
        }

        if (res == NO_ERR) {
            /* generate the internal index Q chain */
            res = val_gen_index_chain(obj, retval);
            if (res != NO_ERR) {
                val_free_value(retval);
                return res;
            }
        }

        /* Ensure that the generated value is correct and can be added
         * to the return Queue.
         */
        if (retval && res == NO_ERR) {
            res = val_validate_value(retval);
            if (res != NO_ERR) {
                val_free_value(retval);
                return res;
            }
        }

        /* Add created val_value_t to get2cb with help of
         * getcb_add_return_aioQ API; In case of list callbacks,
         * repeat above steps for another list entry
         */
        getcb_add_return_aioQ(get2cb, retval);
    }

    return res;

} /* aio_test_get3_config_cont_config_list_nonconfig_list_nonconfig_list2_get */


In the examples above we used a function "create_list_entry" that is a custom function that can be used as an example function that helps to build the subtree data. This is not a server API and used in this article just to demonstrate how the children nodes can be constructed. For more example you can refer to following articles:

How do I construct a data tree for a YANG list?

How do I construct a data tree for a YANG container?

How do I construct a data node for a YANG leaf? 


Also below is the example function that was used in he above AIO callback example:


/********************************************************************
* FUNCTION create_list_entry
*
* Make a list entry based on the key.
* Create the following subtree or as many nodes as found for the
* provided list object:
*
*
*     list nonconfig-list3 {
*       key name;
*       leaf name { type string; }
*       leaf not-keyname { type string; }
*
*        container int-con {
*          leaf int-con-leaf { type int32; }
*        }
*     }
*
* INPUTS:
*   res = return status
*
* RETURNS:
*    val_value_t of listval entry if no error
*    else NULL
*
*********************************************************************/
static val_value_t *
    create_list_entry (obj_template_t *list_obj,
                       const xmlChar *keyname,
                       const xmlChar *keystr,
                       status_t *res)
{
    /* find a key child obejct */
    obj_template_t *key_obj =
        obj_find_child(list_obj,
                       y_aio_test_M_aio_test,
                       keyname);
    if (!key_obj) {
        *res = ERR_NCX_INVALID_VALUE;
        return NULL;
    }

    val_value_t *list_value = val_new_value();
    if (!list_value) {
        *res = ERR_NCX_INVALID_VALUE;
        return NULL;
    }
    val_init_from_template(list_value, list_obj);

    /* make key leaf entry */
    val_value_t *child =
        val_make_simval_obj(key_obj,
                            keystr,
                            res);
    if (!child) {
        val_free_value(list_value);
        *res = ERR_NCX_INVALID_VALUE;
        return NULL;
    }

    *res = val_child_add(child, list_value);
    if (*res != NO_ERR) {
        val_free_value(child);
        val_free_value(list_value);
        return NULL;
    }

    obj_template_t *notkey_obj =
        obj_find_child(list_obj,
                       y_aio_test_M_aio_test,
                       (const xmlChar *)"not-keyname");
    if (notkey_obj) {
        /* make NON key leaf entry */
        child =
            val_make_simval_obj(notkey_obj,
                                (const xmlChar *)"some-value",
                                res);
        if (!child) {
            *res = ERR_NCX_INVALID_VALUE;
        }

        if (*res == NO_ERR) {
            *res = val_child_add(child, list_value);
            if (*res != NO_ERR) {
                val_free_value(child);
            }
        }
    }

    obj_template_t *cont_obj =
        obj_find_child(list_obj,
                       y_aio_test_M_aio_test,
                       (const xmlChar *)"int-con");
    if (cont_obj) {
        /* make return value that will be added to the return_aioQ */
        val_value_t *contval = val_new_value();
        if (!contval) {
            val_free_value(list_value);
            *res = ERR_NCX_INVALID_VALUE;
            return NULL;
        }
        val_init_from_template(contval, cont_obj);

        obj_template_t *leaf_obj =
            obj_find_child(cont_obj,
                           y_aio_test_M_aio_test,
                           (const xmlChar *)"con-leaf");
        if (leaf_obj) {
            val_value_t *leafval =
                val_make_simval_obj(leaf_obj,
                                    (const xmlChar *)"42",
                                    res);
            if (leafval) {
                *res = val_child_add(leafval, contval);
                if (*res != NO_ERR) {
                    val_free_value(leafval);
                    val_free_value(contval);
                }
            } else {
                val_free_value(contval);
                *res = ERR_NCX_INVALID_VALUE;
            }

            if (*res == NO_ERR) {
                *res = val_child_add(contval, list_value);
                if (*res != NO_ERR) {
                    val_free_value(contval);
                }
            }
        } else {
            val_free_value(contval);
        }
    }

    /* generate the internal index Q chain */
    *res = val_gen_index_chain(list_obj, list_value);
    if (*res != NO_ERR) {
        log_error("\nError: could not generate index chain (%s)",
                  get_error_string(*res));
        val_free_value(list_value);
        return NULL;
    }

    return list_value;

} /* create_list_entry */

The following section in the AIO callback function example is used to ensure that the constructed value is well-formed and can be safely used by the server. It runs simple sanity check to verify that if the value is a list it has all the keys setup. It checks descendant-or-self nodes for lists. Checks if they have index chains built already. If not, then try to add one for each of the key objects in order.

If the value is not a container or a list or if the list value index chain is malformed this function will return an error "invalid value".


    /* Ensure that the generated value is correct and can be added
     * to the return Queue.
     */
    if (retval && res == NO_ERR) {
        res = val_validate_value(retval);
        if (res != NO_ERR) {
            val_free_value(retval);
            return res;
        }
    }


The below section of the AIO callback is used to add a new val value into the Queue that will be used as a return values of the callbacks. That will be used later for server's processing, for filtering, and for other manipulations:


 /* Add created val_value_t to get2cb with help of
  * getcb_add_return_aioQ API; In case of list callbacks,
  * repeat above steps for another list entry
  */
    getcb_add_return_aioQ(get2cb, retval);



AIO VAL Container Example


A container example will be similar to the above list example, it will use the same API and custom functions. The difference will be that the callback does not have to repeat the same steps to add more lists, since this is a container and it can have only one sibling.


Assume the same YANG module example above we define top level configuration parent "get3-config-cont2/config-list" and next the AIO GET2 list child "nonconfig-NPcont".


In this case the server will invoke AIO callback for "nonconfig-NPcont" container and will not invoke any descendant level callbacks. The server will expect that the AIO "nonconfig-NPcont" callback will supply the GET2 control block with the sufficient information about "nonconfig-NPcont" node children, complex children as well as terminal nodes.


The AIO GET2 callback may look as follow for the "/get3-config-cont2/nonconfig-NPcont" container.

Refer to the attachment SIL code for complete code and more details:


/********************************************************************
* FUNCTION aio_test_get3_config_cont2_nonconfig_NPcont_get
*
* Get database object callback for container nonconfig-NPcont
* Path: container /get3-config-cont2/nonconfig-NPcont
* Fill in 'get2cb' response fields
*
* sil-aio-get2 extension enabled for this object;
* No callbacks for children will be called
*
* INPUTS:
*     see ncx/getcb.h for details (getcb_fn2_t)
*
* RETURNS:
*     error status
********************************************************************/
static status_t
    aio_test_get3_config_cont2_nonconfig_NPcont_get (ses_cb_t *scb,
                                                     xml_msg_hdr_t *msg,
                                                     getcb_get2_t *get2cb)
{
    if (LOGDEBUG) {
        log_debug("\nEnter aio_test_get3_config_cont2_nonconfig_NPcont_get");
    }

    (void)scb;
    (void)msg;

    /* an NP container always exists so no test for node_exists
     * by the SIL or SIL-SA callback is needed
     */
    obj_template_t *obj = GETCB_GET2_OBJ(get2cb);
    status_t res = NO_ERR;

    /* make return value that will be added to the return_aioQ */
    val_value_t *retval = val_new_value();
    if (!retval) {
        return ERR_INTERNAL_MEM;
    }
    val_init_from_template(retval, obj);

    /* Use retval for the current callback obj and fill
     * it in with folowing terminal and complex nodes;
     * then add to get2cb with help of getcb_add_return_aioQ API
     */
    obj_template_t *childobj =
        getcb_first_requested_child(get2cb, obj);
    for (; childobj; childobj =
        getcb_next_requested_child(get2cb, childobj)) {

        const xmlChar *name = obj_get_name(childobj);

        /* Retrieve the value of this child node and
         * add it to retval of the current callback node
         */
        if (!xml_strcmp(name, (const xmlChar *)"nonconfig-list")) {
            /* list nonconfig-list (list) */

            uint32 key = 0;
            for (key = 1; key < 3; key++) {

                /* create 2 list entries */
                const xmlChar *keyname = NULL;
                if (key == (uint32)1) {
                    keyname = (const xmlChar *)"name1";
                } else if (key == (uint32)2) {
                    keyname = (const xmlChar *)"name2";
                }

                val_value_t *listval =
                    create_list_entry(childobj,
                                      (const xmlChar *)"name",
                                      keyname,
                                      &res);
                if (!listval) {
                    val_free_value(retval);
                    return ERR_INTERNAL_MEM;
                }

                /* Use add_force to allow insertion lists with NO keys */
                res = val_child_add(listval, retval);
                if (res != NO_ERR) {
                    val_free_value(listval);
                    val_free_value(retval);
                    return ERR_NCX_INVALID_VALUE;
                }
            }
        } else if (!xml_strcmp(name, (const xmlChar *)"D")) {
            /* leaf D (int8) */
            val_value_t *child =
                val_make_simval_obj(childobj,
                                    (const xmlChar *)"42",
                                    &res);
            if (child) {
                res = val_child_add(child, retval);
                if (res != NO_ERR) {
                    val_free_value(child);
                    val_free_value(retval);
                    return ERR_NCX_INVALID_VALUE;
                }
            } else {
                val_free_value(retval);
                return ERR_NCX_INVALID_VALUE;
            }
        }
    }

    /* Ensure that the generated value is correct and can be added
     * to the return Queue.
     */
    if (retval && res == NO_ERR) {
        res = val_validate_value(retval);
        if (res != NO_ERR) {
            val_free_value(retval);
            return res;
        }
    }

    /* Add created val_value_t to get2cb with help of
     * getcb_add_return_aioQ API; In case of list callbacks,
     * repeat above steps for another list entry
     */
    getcb_add_return_aioQ(get2cb, retval);

    return res;

} /* aio_test_get3_config_cont2_nonconfig_NPcont_get */


As a result, whenever some north bound agent trying to retrieve the list or container that we have AIO callbacks registered, the callback is invoked and a client gets all the values that AIO callbacks generates.


To ensure that the data added by AIO callback was successfully generated an application can retrieve operational datastore with help of the following operation as an example. Assume, we already created parent configuration nodes.


  <get>
    <filter type="subtree">
      <get3-config-cont xmlns="http://yumaworks.com/ns/aio-test"/>
    </filter>
  </get>


The server should reply with:


 <rpc-reply message-id="4"
  xmlns:ncx="http://netconfcentral.org/ns/yuma-ncx"
  ncx:last-modified="2020-05-15T00:48:02Z" ncx:etag="105"
  xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <data>
   <get3-config-cont xmlns="http://yumaworks.com/ns/aio-test">
   <config-list>
    <name>list1</name>
    <nonconfig-list>
     <name>name1</name>
     <nonconfig-list2>
      <name>name1</name>
      <nonconfig-list3>
       <name>name1</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
      <nonconfig-list3>
       <name>name2</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
     </nonconfig-list2>
     <nonconfig-list2>
      <name>name2</name>
      <nonconfig-list3>
       <name>name1</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
      <nonconfig-list3>
       <name>name2</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
     </nonconfig-list2>
     <nonconfig-list2>
      <name>name3</name>
      <nonconfig-list3>
       <name>name1</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
      <nonconfig-list3>
       <name>name2</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
     </nonconfig-list2>
    </nonconfig-list>
    <nonconfig-list>
     <name>name2</name>
     <nonconfig-list2>
      <name>name1</name>
      <nonconfig-list3>
       <name>name1</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
      <nonconfig-list3>
       <name>name2</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
     </nonconfig-list2>
     <nonconfig-list2>
      <name>name2</name>
      <nonconfig-list3>
       <name>name1</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
      <nonconfig-list3>
       <name>name2</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
     </nonconfig-list2>
     <nonconfig-list2>
      <name>name3</name>
      <nonconfig-list3>
       <name>name1</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
      <nonconfig-list3>
       <name>name2</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
     </nonconfig-list2>
    </nonconfig-list>
    <nonconfig-list>
     <name>name3</name>
     <nonconfig-list2>
      <name>name1</name>
      <nonconfig-list3>
       <name>name1</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
      <nonconfig-list3>
       <name>name2</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
     </nonconfig-list2>
     <nonconfig-list2>
      <name>name2</name>
      <nonconfig-list3>
       <name>name1</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
      <nonconfig-list3>
       <name>name2</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
     </nonconfig-list2>
     <nonconfig-list2>
      <name>name3</name>
      <nonconfig-list3>
       <name>name1</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
      <nonconfig-list3>
       <name>name2</name>
       <not-keyname>some-value</not-keyname>
       <int-con>
        <con-leaf>42</con-leaf>
       </int-con>
      </nonconfig-list3>
     </nonconfig-list2>
    </nonconfig-list>
   </config-list>
  </get3-config-cont>
 </data>
</rpc-reply>