From b03cf426a436b6db0d344d084a25d870baa5bce2 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Thu, 19 Aug 2021 13:37:45 +0200 Subject: [PATCH] * Protyped netconf native pagination --- apps/backend/backend_client.c | 346 +++++++++++++----- include/clixon_custom.h | 4 + lib/clixon/clixon_xpath.h | 1 + lib/src/clixon_netconf_lib.c | 5 + lib/src/clixon_xpath.c | 39 ++ test/test_pagination.sh | 14 +- yang/clixon/Makefile.in | 1 + ...on-netconf-list-pagination@2021-08-27.yang | 168 +++++++++ 8 files changed, 493 insertions(+), 85 deletions(-) create mode 100644 yang/clixon/clixon-netconf-list-pagination@2021-08-27.yang diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 445cf5f0..f6d16f9d 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -412,37 +412,89 @@ client_get_config_only(clicon_handle h, yang_stmt *yspec, char *db, char *xpath, +#ifdef CLIXON_PAGINATION + uint32_t limit, + uint32_t offset, + char *xpathpred, +#endif /* CLIXON_PAGINATION */ char *username, int32_t depth, cbuf *cbret) { - int retval = -1; - cxobj *xret = NULL; - cxobj *xnacm = NULL; - cxobj **xvec = NULL; - cxobj *xerr = NULL; - size_t xlen; - int ret; + int retval = -1; + cxobj *xret = NULL; + cxobj *xnacm = NULL; + cxobj **xvec = NULL; + cxobj *xerr = NULL; + size_t xlen; + int ret; +#ifdef CLIXON_PAGINATION + cxobj *xcache = NULL; + uint32_t total = 0; + cbuf *cb = NULL; + uint32_t remaining = 0; + +#endif /* Note xret can be pruned by nacm below (and change name), * so zero-copy cant be used * Also, must use external namespace context here due to = (offset + limit)) + remaining = total - (offset + limit); + } + /* XXX need only first for remaining, but all for NACM */ + if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) + goto done; + /* Add remain attribute to first returning element */ + if (xlen){ + cxobj *x; + cxobj *xa; + x = xvec[0]; + if ((xa = xml_new("remaining", x, CX_ATTR)) == NULL) + goto done; + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + cprintf(cb, "%u", remaining); + if (xml_value_set(xa, cbuf_get(cb)) < 0) + goto done; + if (xml_prefix_set(xa, "cp") < 0) + goto done; + if (xmlns_set(x, "cp", "http://clicon.org/clixon-netconf-list-pagination") < 0) + goto done; + } +#endif /* Pre-NACM access step */ xnacm = clicon_nacm_cache(h); if (xnacm != NULL){ /* Do NACM validation */ +#ifndef CLIXON_PAGINATION if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; +#endif /* NACM datanode/module read validation */ if (nacm_datanode_read(h, xret, xvec, xlen, username, xnacm) < 0) goto done; @@ -460,6 +512,8 @@ client_get_config_only(clicon_handle h, ok: retval = 0; done: + if (cb) + cbuf_free(cb); if (xerr) xml_free(xerr); if (xvec) @@ -469,6 +523,59 @@ client_get_config_only(clicon_handle h, return retval; } +#if defined(LIST_PAGINATION) || defined(CLIXON_PAGINATION) +/*! Help function for parsing restconf query parameter and setting netconf attribute + * + * If not "unbounded", parse and set a numeric value + * @param[in] h Clixon handle + * @param[in] name Name of attribute + * @param[in] defaultstr Default string which is accepted and sets value to 0 + * @param[in,out] cbret Output buffer for internal RPC message + * @param[out] value Value + * @retval -1 Error + * @retval 0 Invalid, cbret set + * @retval 1 OK + */ +static int +element2value(clicon_handle h, + cxobj *xe, + char *name, + char *defaultstr, + cbuf *cbret, + uint32_t *value) +{ + int retval = -1; + char *valstr; + int ret; + char *reason = NULL; + cxobj *x; + + *value = 0; + if ((x = xml_find_type(xe, NULL, name, CX_ELMNT)) != NULL && + (valstr = xml_body(x)) != NULL && + strcmp(valstr, defaultstr) != 0){ + if ((ret = parse_uint32(valstr, value, &reason)) < 0){ + clicon_err(OE_XML, errno, "parse_uint32"); + goto done; + } + if (ret == 0){ + if (netconf_bad_element(cbret, "application", + name, "Unrecognized value") < 0) + goto done; + goto fail; + } + } + retval = 1; + done: + if (reason) + free(reason); + return retval; + fail: + retval = 0; + goto done; +} +#endif + /*! Retrieve all or part of a specified configuration. * * @param[in] h Clicon handle @@ -500,6 +607,15 @@ from_client_get_config(clicon_handle h, char *attr; char *xpath0; cvec *nsc1 = NULL; +#ifdef CLIXON_PAGINATION + uint32_t limit = 0; + uint32_t offset = 0; + char *direction = NULL; + char *sort = NULL; + char *where = NULL; + cbuf *cbpath = NULL; + cxobj *x; +#endif /* CLIXON_PAGINATION */ username = clicon_username_get(h); if ((yspec = clicon_dbspec_yang(h)) == NULL){ @@ -551,7 +667,57 @@ from_client_get_config(clicon_handle h, goto ok; } } - if ((ret = client_get_config_only(h, nsc, yspec, db, xpath, username, -1, cbret)) < 0) +#ifdef CLIXON_PAGINATION + /* limit */ + if ((ret = element2value(h, xe, "limit", "unbounded", cbret, &limit)) < 0) + goto done; + /* offset */ + if (ret && (ret = element2value(h, xe, "offset", "none", cbret, &offset)) < 0) + goto done; + /* direction */ + if (ret && (x = xml_find_type(xe, NULL, "direction", CX_ELMNT)) != NULL){ + direction = xml_body(x); + if (strcmp(direction, "forward") != 0 && strcmp(direction, "reverse") != 0){ + if (netconf_bad_attribute(cbret, "application", + "direction", "Unrecognized value of direction attribute") < 0) + goto done; + goto ok; + } + } + /* sort */ + if (ret && (x = xml_find_type(xe, NULL, "sort", CX_ELMNT)) != NULL) + sort = xml_body(x); + if (sort) ; /* XXX */ + /* where */ + if (ret && (x = xml_find_type(xe, NULL, "where", CX_ELMNT)) != NULL) + where = xml_body(x); + /* Build a "predicate" cbuf + * This solution uses xpath predicates to translate "limit" and "offset" to + * relational operators <>. + */ + if ((cbpath = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + /* This uses xpath. Maybe limit should use parameters */ + cprintf(cbpath, "%s", xpath); + if (where) + cprintf(cbpath, "[%s]", where); + if (offset){ + cprintf(cbpath, "[%u <= position()", offset); + if (limit) + cprintf(cbpath, " and position() < %u", limit+offset); + cprintf(cbpath, "]"); + } + else if (limit) + cprintf(cbpath, "[position() < %u]", limit); +#endif /* CLIXON_PAGINATION */ + if ((ret = client_get_config_only(h, nsc, yspec, db, xpath, +#ifdef CLIXON_PAGINATION + limit, offset, + cbuf_get(cbpath), +#endif + username, -1, cbret)) < 0) goto done; ok: retval = 0; @@ -1078,6 +1244,15 @@ from_client_get(clicon_handle h, cxobj *xerr = NULL; int ret; char *reason = NULL; +#ifdef CLIXON_PAGINATION + uint32_t limit = 0; + uint32_t offset = 0; + char *direction = NULL; + char *sort = NULL; + char *where = NULL; + cbuf *cbpath = NULL; + cxobj *x; +#endif /* CLIXON_PAGINATION */ clicon_debug(1, "%s", __FUNCTION__); username = clicon_username_get(h); @@ -1119,8 +1294,58 @@ from_client_get(clicon_handle h, goto ok; } } +#ifdef CLIXON_PAGINATION + /* limit */ + if ((ret = element2value(h, xe, "limit", "unbounded", cbret, &limit)) < 0) + goto done; + /* offset */ + if (ret && (ret = element2value(h, xe, "offset", "none", cbret, &offset)) < 0) + goto done; + /* direction */ + if (ret && (x = xml_find_type(xe, NULL, "direction", CX_ELMNT)) != NULL){ + direction = xml_body(x); + if (strcmp(direction, "forward") != 0 && strcmp(direction, "reverse") != 0){ + if (netconf_bad_attribute(cbret, "application", + "direction", "Unrecognized value of direction attribute") < 0) + goto done; + goto ok; + } + } + /* sort */ + if (ret && (x = xml_find_type(xe, NULL, "sort", CX_ELMNT)) != NULL) + sort = xml_body(x); + if (sort) ; /* XXX */ + /* where */ + if (ret && (x = xml_find_type(xe, NULL, "where", CX_ELMNT)) != NULL) + where = xml_body(x); + /* Build a "predicate" cbuf + * This solution uses xpath predicates to translate "limit" and "offset" to + * relational operators <>. + */ + if ((cbpath = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + /* This uses xpath. Maybe limit should use parameters */ + cprintf(cbpath, "%s", xpath); + if (where) + cprintf(cbpath, "[%s]", where); + if (offset){ + cprintf(cbpath, "[%u <= position()", offset); + if (limit) + cprintf(cbpath, " and position() < %u", limit+offset); + cprintf(cbpath, "]"); + } + else if (limit) + cprintf(cbpath, "[position() < %u]", limit); +#endif /* CLIXON_PAGINATION */ if (content == CONTENT_CONFIG){ /* config only, no state */ - if (client_get_config_only(h, nsc, yspec, "running", xpath, username, depth, cbret) < 0) + if (client_get_config_only(h, nsc, yspec, "running", xpath, +#ifdef CLIXON_PAGINATION + limit, offset, + cbuf_get(cbpath), +#endif + username, depth, cbret) < 0) goto done; goto ok; } @@ -1239,6 +1464,9 @@ from_client_get(clicon_handle h, retval = 0; done: clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); + + if (cbpath) + cbuf_free(cbpath); if (reason) free(reason); if (xerr) @@ -1337,56 +1565,6 @@ from_client_kill_session(clicon_handle h, } #ifdef LIST_PAGINATION -/*! Help function for parsing restconf query parameter and setting netconf attribute - * - * If not "unbounded", parse and set a numeric value - * @param[in] h Clixon handle - * @param[in] name Name of attribute - * @param[in] defaultstr Default string which is accepted and sets value to 0 - * @param[in,out] cbret Output buffer for internal RPC message - * @param[out] value Value - * @retval -1 Error - * @retval 0 Invalid, cbret set - * @retval 1 OK - */ -static int -element2value(clicon_handle h, - cxobj *xe, - char *name, - char *defaultstr, - cbuf *cbret, - uint32_t *value) -{ - int retval = -1; - char *valstr; - int ret; - char *reason = NULL; - cxobj *x; - - *value = 0; - if ((x = xml_find_type(xe, NULL, name, CX_ELMNT)) != NULL && - (valstr = xml_body(x)) != NULL && - strcmp(valstr, defaultstr) != 0){ - if ((ret = parse_uint32(valstr, value, &reason)) < 0){ - clicon_err(OE_XML, errno, "parse_uint32"); - goto done; - } - if (ret == 0){ - if (netconf_bad_element(cbret, "application", - name, "Unrecognized value") < 0) - goto done; - goto fail; - } - } - retval = 1; - done: - if (reason) - free(reason); - return retval; - fail: - retval = 0; - goto done; -} /*! Retrieve collection configuration and device state information * @@ -1423,16 +1601,17 @@ from_client_get_pageable_list(clicon_handle h, int i; cxobj *xerr = NULL; int ret; + cbuf *cb = NULL; uint32_t limit = 0; uint32_t offset = 0; - size_t total = 0; + uint32_t total = 0; uint32_t remaining = 0; char *direction = NULL; char *sort = NULL; char *where = NULL; char *datastore = NULL; char *reason = NULL; - cbuf *cb = NULL; + cbuf *cbpath = NULL; cxobj *xtop = NULL; yang_stmt *y; char *ns; @@ -1535,22 +1714,22 @@ from_client_get_pageable_list(clicon_handle h, * This solution uses xpath predicates to translate "limit" and "offset" to * relational operators <>. */ - if ((cb = cbuf_new()) == NULL){ + if ((cbpath = cbuf_new()) == NULL){ clicon_err(OE_UNIX, errno, "cbuf_new"); goto done; } /* This uses xpath. Maybe limit should use parameters */ - cprintf(cb, "%s", xpath); + cprintf(cbpath, "%s", xpath); if (where) - cprintf(cb, "[%s]", where); + cprintf(cbpath, "[%s]", where); if (offset){ - cprintf(cb, "[%u <= position()", offset); + cprintf(cbpath, "[%u <= position()", offset); if (limit) - cprintf(cb, " and position() < %u", limit+offset); - cprintf(cb, "]"); + cprintf(cbpath, " and position() < %u", limit+offset); + cprintf(cbpath, "]"); } else if (limit) - cprintf(cb, "[position() < %u]", limit); + cprintf(cbpath, "[position() < %u]", limit); /* Split into CT or CF */ if (yang_config_ancestor(y) == 1){ /* CT */ @@ -1565,13 +1744,9 @@ from_client_get_pageable_list(clicon_handle h, goto done; goto ok; } - /* First get number of hits */ - if (xpath_vec(xret, nsc, "%s", &xvec, &total, xpath) < 0) + /* First get number of hits (ALL entries: note not optimized) */ + if (xpath_count(xret, nsc, xpath, &total) < 0) goto done; - if (xvec){ - free(xvec); - xvec = NULL; - } if (total < (offset + limit)) remaining = 0; else @@ -1579,14 +1754,14 @@ from_client_get_pageable_list(clicon_handle h, } /* There may be CF data in a CT collection */ if (content == CONTENT_ALL){ - if ((ret = client_statedata(h, cbuf_get(cb), nsc, content, &xret)) < 0) + if ((ret = client_statedata(h, cbuf_get(cbpath), nsc, content, &xret)) < 0) goto done; } } else { /* CF */ /* There can be no CT data in a CF collection */ if (content == CONTENT_NONCONFIG || content == CONTENT_ALL){ - if ((ret = client_statedata(h, cbuf_get(cb), nsc, content, &xret)) < 0) + if ((ret = client_statedata(h, cbuf_get(cbpath), nsc, content, &xret)) < 0) goto done; if (ret == 0){ /* Error from callback (error in xret) */ if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0) @@ -1634,7 +1809,7 @@ from_client_get_pageable_list(clicon_handle h, * Actually this is a safety catch, should really be done in plugins * and modules_state functions. */ - if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, cbuf_get(cb)) < 0) + if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, cbuf_get(cbpath)) < 0) goto done; /* Pre-NACM access step */ @@ -1646,7 +1821,11 @@ from_client_get_pageable_list(clicon_handle h, } cprintf(cbret, "", NETCONF_BASE_NAMESPACE, NETCONF_COLLECTION_NAMESPACE); /* OK */ - if ((ns = yang_find_mynamespace(y)) != NULL) + if ((ns = yang_find_mynamespace(y)) != NULL) { + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } for (i=0; i0?depth+1:depth) < 0) goto done; } + } cprintf(cbret, ""); ok: retval = 0; @@ -1682,6 +1862,8 @@ from_client_get_pageable_list(clicon_handle h, clixon_path_free(path_tree); if (xtop) xml_free(xtop); + if (cbpath) + cbuf_free(cbpath); if (cb) cbuf_free(cb); if (reason) diff --git a/include/clixon_custom.h b/include/clixon_custom.h index 3f7f6aa9..669268b9 100644 --- a/include/clixon_custom.h +++ b/include/clixon_custom.h @@ -124,3 +124,7 @@ * draft-wwlh-netconf-list-pagination-rc-01 */ #define LIST_PAGINATION + +/*! Clixon netconf pagination + */ +#define CLIXON_PAGINATION diff --git a/lib/clixon/clixon_xpath.h b/lib/clixon/clixon_xpath.h index 295be064..efc00254 100644 --- a/lib/clixon/clixon_xpath.h +++ b/lib/clixon/clixon_xpath.h @@ -161,5 +161,6 @@ int xpath_vec(cxobj *xcur, cvec *nsc, const char *xpformat, cxobj ***vec, si #endif int xpath2canonical(const char *xpath0, cvec *nsc0, yang_stmt *yspec, char **xpath1, cvec **nsc1); +int xpath_count(cxobj *xcur, cvec *nsc, const char *xpath, uint32_t *count); #endif /* _CLIXON_XPATH_H */ diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index dc3a8861..17db459a 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -1543,6 +1543,11 @@ netconf_module_load(clicon_handle h) if (yang_spec_parse_module(h, "ietf-list-pagination", NULL, yspec)< 0) goto done; #endif +#ifdef CLIXON_PAGINATION + /* Load clixon netconf list pagination */ + if (yang_spec_parse_module(h, "clixon-netconf-list-pagination", NULL, yspec)< 0) + goto done; +#endif #endif retval = 0; done: diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index cdf11c2e..0ef44f48 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -75,6 +75,7 @@ #include #include #include +#include /* NaN */ /* cligen */ #include @@ -1064,3 +1065,41 @@ xpath2canonical(const char *xpath0, xpath_tree_free(xpt); return retval; } + +/*! Return a count(xpath) + * + * @param[in] xcur xml-tree where to search + * @param[in] nsc External XML namespace context, or NULL + * @param[in] xpath XPATH syntax + * @param[oit] count Nr of elements of xpath + * @note This function is made for making optimizations in certain circumstances, such as a list + */ +int +xpath_count(cxobj *xcur, + cvec *nsc, + const char *xpath, + uint32_t *count) +{ + int retval = -1; + xp_ctx *xc = NULL; + cbuf *cb = NULL; + + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + cprintf(cb, "count(%s)", xpath); + if (xpath_vec_ctx(xcur, nsc, cbuf_get(cb), 0, &xc) < 0) + goto done; + if (xc && xc->xc_type == XT_NUMBER && xc->xc_number != NAN) + *count = (uint32_t)xc->xc_number; + else + *count = 0; + retval = 0; + done: + if (cb) + cbuf_free(cb); + if (xc) + ctx_free(xc); + return retval; +} diff --git a/test/test_pagination.sh b/test/test_pagination.sh index 46765a0a..81bcf064 100755 --- a/test/test_pagination.sh +++ b/test/test_pagination.sh @@ -38,7 +38,7 @@ cat < $cfg $APPNAME /usr/local/lib/$APPNAME/cli /usr/local/lib/$APPNAME/clispec - true + false $RESTCONFIG EOF @@ -257,7 +257,7 @@ cat< $fstate EOF -# Run limitonly test with netconf, restconf+xml and restconf+json +# Run limit-only test with netconf, restconf+xml and restconf+json # Args: # 1. limit # 2. remaining @@ -267,7 +267,15 @@ function testlimit() limit=$1 remaining=$2 - new "limit=$limit NETCONF" + # "clixon get" + new "clixon limit=$limit NETCONF get-config" + expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO$limit]]>]]>" "alicepublic17]]>]]>$" + + new "clixon limit=$limit NETCONF get" +# expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO$limit]]>]]>" "alicepublic17]]>]]>$" + + # "old: ietf" + new "ietf limit=$limit NETCONF" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOds:running/es:members/es:member[es:member-id='alice']/es:favorites/es:uint8-numbers$limit]]>]]>" "17]]>]]>$" new "limit=$limit Parameter RESTCONF xml" diff --git a/yang/clixon/Makefile.in b/yang/clixon/Makefile.in index ddd83935..b417d639 100644 --- a/yang/clixon/Makefile.in +++ b/yang/clixon/Makefile.in @@ -46,6 +46,7 @@ YANGSPECS += clixon-lib@2021-03-08.yang # 5.1 YANGSPECS += clixon-rfc5277@2008-07-01.yang YANGSPECS += clixon-xml-changelog@2019-03-21.yang YANGSPECS += clixon-restconf@2021-05-20.yang # 5.2 +YANGSPECS += clixon-netconf-list-pagination@2021-08-27.yang APPNAME = clixon # subdir ehere these files are installed diff --git a/yang/clixon/clixon-netconf-list-pagination@2021-08-27.yang b/yang/clixon/clixon-netconf-list-pagination@2021-08-27.yang new file mode 100644 index 00000000..d64e5251 --- /dev/null +++ b/yang/clixon/clixon-netconf-list-pagination@2021-08-27.yang @@ -0,0 +1,168 @@ +module clixon-netconf-list-pagination { + yang-version 1.1; + namespace "http://clicon.org/clixon-netconf-list-pagination"; + prefix cp; + + import ietf-yang-types { + prefix yang; + reference + "RFC 6991: Common YANG Data Types"; + } + import ietf-yang-metadata { + prefix "md"; + reference + "RFC 7952: Defining and Using Metadata with YANG"; + } + import ietf-netconf { + prefix nc; + reference + "RFC 6241: Network Configuration Protocol (NETCONF)"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + contact + "WG Web: + WG List: + + Editor: + + Editor: + + Editor: "; + description + "This module define a new operation -- + to support YANG based pagination. + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL + NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED', + 'MAY', and 'OPTIONAL' in this document are to be interpreted as + described in BCP 14 (RFC 2119) (RFC 8174) when, and only when, + they appear in all capitals, as shown here. + + Copyright (c) 2019 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject to + the license terms contained in, the Simplified BSD License set + forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 8526; see + the RFC itself for full legal notices. + + Clixon: + - changed get-pagable -> get-pageable + - renamed count -> limit + - renamed skip -> offset + - added import ietf-yang-metadata + - added md:annotation remaining + "; + revision 2021-08-27 { + description + "Dervied from ietf-netconf-list-pagination@2020-10-30."; + reference + "RFC XXXX: YANG Based Pagination."; + } + + // Annotations + md:annotation remaining { + type uint32; + description + "This annotation contains the number of elements removed + from a result set after a 'limit' or 'sublist-limit' + operation. If no elements were removed, this annotation + MUST NOT appear. The minimum value (0), which never + occurs in normal operation, is reserved to represent + 'unknown'. The maximum value (2^32-1) is reserved to + represent any value greater than or equal to 2^32-1 + elements."; + } + grouping pageing-parameters { + leaf limit { + type union { + type uint32; + type string { + pattern 'unbounded'; + } + } + default "unbounded"; + description + "The maximum number of list entries to return. The + value of the 'count' parameter is either an integer + greater than or equal to 1, or the string 'unbounded'. + The string 'unbounded' is the default value."; + } + leaf offset { + type union { + type uint32; + type string { + pattern 'none'; + } + } + default "none"; + description + "The first list item to return. + the 'skip' parameter is either an integer greater than + or equal to 1, or the string 'unbounded'. The string + 'unbounded' is the default value."; + } + leaf direction { + type enumeration { + enum forward; + enum reverse; + } + default "forward"; + description + "Direction relative to the 'sort' order through list + or leaf-list. It can be forward direction or reverse + direction."; + } + leaf sort { + type union { + type string { + length "1..max" { + description + "The name of a descendent node to sort on. For + 'Config false' lists and leaf-lists, the node SHOULD + have the 'TBD' extension indicating that it has been + indexed, enabling efficient sorts."; + } + } + type enumeration { + enum default { + description + "Indicates that the 'default' order is assumed. For + 'ordered-by user' lists and leaf-lists, the default order + is the user-configured order. For 'ordered-by system' + lists and leaf-lists, the default order is specified by the + system."; + } + } + } + default "default"; + description + "Indicates how the entries in a list are to be sorted."; + } + leaf where { + type yang:xpath1.0; + description + "The boolean filter to select data instances to return from + the list or leaf-list target. The Xpath expression MAY be + constrained either server-wide, by datastore, by 'config' + status, or per list or leaf-list. Details regarding how + constraints are communicated are TBD. This parameter + is optional; no filtering is applied when it is not + specified."; + } + } + augment /nc:get-config/nc:input { + uses pageing-parameters; + } + // extending the get operation + augment /nc:get/nc:input { + uses pageing-parameters; + } +}