* YANG schema mount RFC 8528, state data

This commit is contained in:
Olof Hagsand 2023-01-27 12:38:56 +01:00
parent 51ebbdf12f
commit a8e13047fc
21 changed files with 572 additions and 144 deletions

View file

@ -75,6 +75,7 @@
#include "clixon_netconf_lib.h"
#include "clixon_yang_type.h"
#include "clixon_yang_module.h"
#include "clixon_yang_schema_mount.h"
#include "clixon_xml_nsctx.h"
#include "clixon_xml_io.h"
#include "clixon_xml_default.h"
@ -854,21 +855,25 @@ text_modify(clicon_handle h,
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
x1cname = xml_name(x1c);
/* Get yang spec of the child by child matching */
yc = yang_find_datanode(y0, x1cname);
if (yc == NULL){
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1){
/* Add dummy Y_ANYDATA yang stmt, see ysp_add */
if ((yc = yang_anydata_add(y0, x1cname)) < 0)
goto done;
xml_spec_set(x1c, yc);
clicon_log(LOG_WARNING,
"%s: %d: No YANG spec for %s, anydata used",
__FUNCTION__, __LINE__, x1cname);
}
else{
if (netconf_unknown_element(cbret, "application", x1cname, "Unassigned yang spec") < 0)
goto done;
goto fail;
if ((yc = yang_find_datanode(y0, x1cname)) == NULL){
#ifdef YANG_SCHEMA_MOUNT
yc = xml_spec(x1c);
#endif
if (yc == NULL){
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1){
/* Add dummy Y_ANYDATA yang stmt, see ysp_add */
if ((yc = yang_anydata_add(y0, x1cname)) < 0)
goto done;
xml_spec_set(x1c, yc);
clicon_log(LOG_WARNING,
"%s: %d: No YANG spec for %s, anydata used",
__FUNCTION__, __LINE__, x1cname);
}
else{
if (netconf_unknown_element(cbret, "application", x1cname, "Unassigned yang spec") < 0)
goto done;
goto fail;
}
}
}
/* There is a cornercase (eg augment) of multi-namespace trees where
@ -898,8 +903,11 @@ text_modify(clicon_handle h,
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
x0c = x0vec[i++];
x1cname = xml_name(x1c);
yc = yang_find_datanode(y0, x1cname);
if ((yc = yang_find_datanode(y0, x1cname)) == NULL){
#ifdef YANG_SCHEMA_MOUNT
yc = xml_spec(x1c);
#endif
}
if ((ret = text_modify(h, x0c, x0, x0t, x1c, x1t,
yc, op,
username, xnacm, permit, cbret)) < 0)

View file

@ -547,9 +547,9 @@ plugin_context_get(void)
* @param[in,out] wh Either: NULL for init, will be assigned, OR previous handle (will be freed)
* @param[in] name Name of plugin for logging. Can be other name, context dependent
* @param[in] fn Typically name of callback, or caller function
* @retval -1 Error
* @retval 0 Fail, log on syslog using LOG_WARNING
* @retval 1 OK
* @retval 0 Fail, log on syslog using LOG_WARNING
* @retval -1 Error
* @note Only logs error, does not generate error
* @note name and fn are context dependent, since the env of callback calls are very different
* @see plugin_context_get
@ -786,9 +786,9 @@ clixon_plugin_exit_all(clicon_handle h)
* @param[out] authp NULL: Credentials failed, no user set (401 returned).
* String: Credentials OK, the associated user, must be mallloc:ed
* Parameter signtificant only if retval is 1/OK
* @retval -1 Fatal error
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval 1 OK, see authp parameter on result.
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval -1 Fatal error
* @note If authenticated either a callback was called and clicon_username_set()
* Or no callback was found.
*/
@ -833,9 +833,9 @@ clixon_plugin_auth_one(clixon_plugin_t *cp,
* @param[out] authp NULL: Credentials failed, no user set (401 returned).
* String: Credentials OK, the associated user, must be mallloc:ed
* Parameter signtificant only if retval is 1/OK
* @retval -1 Fatal error
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval 1 OK, see authp parameter for result.
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval -1 Fatal error
* @note If authp returns string, it should be malloced
*/
int
@ -981,8 +981,8 @@ clixon_plugin_datastore_upgrade_one(clixon_plugin_t *cp,
* @param[in] db Name of datastore, eg "running", "startup" or "tmp"
* @param[in] xt XML tree. Upgrade this "in place"
* @param[in] msd Module-state diff, info on datastore module-state
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
* Upgrade datastore on load before or as an alternative to module-specific upgrading mechanism
*/
int
@ -1003,6 +1003,72 @@ clixon_plugin_datastore_upgrade_all(clicon_handle h,
return retval;
}
/*! Call plugin YANG schema mount
*
* (No need to be yang bound?
* @param[in] cp Plugin handle
* @param[in] h Clixon handle
* @param[in] xt XML mount-point in XML tree
* @param[out] yanglib XML yang-lib module-set tree
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_plugin_yang_mount_one(clixon_plugin_t *cp,
clicon_handle h,
cxobj *xt,
cxobj **yanglib)
{
int retval = -1;
yang_mount_t *fn;
void *wh = NULL;
if ((fn = cp->cp_api.ca_yang_mount) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
goto done;
if (fn(h, xt, yanglib) < 0) {
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Yang mount callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name);
goto done;
}
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Call plugin YANG schema mount in all plugins, break at first return
*
* @param[in] h Clixon handle
* @param[in] xt XML mount-point in XML tree
* @param[out] yanglib XML yang-lib module-set tree (freed by caller)
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_plugin_yang_mount_all(clicon_handle h,
cxobj *xt,
cxobj **yanglib)
{
int retval = -1;
clixon_plugin_t *cp = NULL;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (clixon_plugin_yang_mount_one(cp, h, xt, yanglib) < 0)
goto done;
if (*yanglib)
break;
}
retval = 0;
done:
return retval;
}
/*--------------------------------------------------------------------
* RPC callbacks for both client/frontend and backend plugins.
*/
@ -1166,7 +1232,7 @@ rpc_callback_call(clicon_handle h,
*nrp = nr;
retval = 1; /* 0: none found, >0 nr of handlers called */
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
return retval;
fail:
retval = 0;
@ -1373,9 +1439,9 @@ upgrade_callback_delete_all(clicon_handle h)
* @param[in] from From revision on the form YYYYMMDD (if DEL or CHANGE)
* @param[in] to To revision on the form YYYYMMDD (if ADD or CHANGE)
* @param[out] cbret Return XML (as string in CLIgen buffer), on invalid
* @retval -1 Error
* @retval 0 Invalid - cbret contains reason as netconf
* @retval 1 OK
* @retval 0 Invalid - cbret contains reason as netconf
* @retval -1 Error
* @see upgrade_callback_reg_fn which registers the callbacks
*/
int

View file

@ -433,6 +433,7 @@ clicon_msg_rcv(int s,
clicon_debug(CLIXON_DBG_MSG, "Recv: %s", (*msg)->op_body);
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
if (0)
set_signal(SIGINT, oldhandler, NULL);
return retval;
@ -643,6 +644,7 @@ clicon_rpc(int sock,
struct clicon_msg *reply = NULL;
char *data = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (clicon_msg_send(sock, msg) < 0)
goto done;
if (clicon_msg_rcv(sock, &reply, eof) < 0)
@ -658,6 +660,7 @@ clicon_rpc(int sock,
ok:
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
if (reply)
free(reply);
return retval;

View file

@ -198,6 +198,7 @@ clicon_rpc_msg(clicon_handle h,
int s = -1;
int eof = 0;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
#ifdef RPC_USERNAME_ASSERT
assert(strstr(msg->op_body, "username")!=NULL); /* XXX */
#endif
@ -245,6 +246,7 @@ clicon_rpc_msg(clicon_handle h,
}
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
if (retdata)
free(retdata);
if (xret)
@ -961,6 +963,7 @@ clicon_rpc_get(clicon_handle h,
yang_stmt *yspec;
cvec *nscd = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -1044,6 +1047,7 @@ clicon_rpc_get(clicon_handle h,
}
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
if (nscd)
cvec_free(nscd);
if (cb)

View file

@ -69,6 +69,8 @@
#include "clixon_options.h"
#include "clixon_data.h"
#include "clixon_yang_module.h"
#include "clixon_yang_schema_mount.h"
#include "clixon_plugin.h"
#include "clixon_xml_nsctx.h"
#include "clixon_xpath_ctx.h"
#include "clixon_xpath.h"
@ -451,7 +453,34 @@ xml_bind_yang0_opt(clicon_handle h,
goto ok;
strip_body_objects(xt);
ybc = YB_PARENT;
#ifdef YANG_SCHEMA_MOUNT // Maybe in populate?
yspec1 = NULL;
if ((ret = xml_yang_mount_get(xt, &yspec1)) < 0)
goto done;
if (ret == 0)
yspec1 = yspec;
else{
if (yspec1)
ybc = YB_MODULE;
else if (h == NULL)
goto ok; /* treat as anydata */
else{
if ((ret = yang_schema_yanglib_parse_mount(h, xt)) < 0)
goto done;
if (ret == 0)
goto ok;
/* Try again */
if ((ret = xml_yang_mount_get(xt, &yspec1)) < 0)
goto done;
if (yspec1)
ybc = YB_MODULE;
else
goto ok;
}
}
#else
yspec1 = yspec;
#endif
xc = NULL; /* Apply on children */
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
/* It is xml2ns in populate_self_parent that needs improvement */

View file

@ -307,11 +307,10 @@ yang_cvec_set(yang_stmt *ys,
* @retval cv The new cligen variable
* @retval NULL Error
*/
static cg_var *
cg_var *
yang_cvec_add(yang_stmt *ys,
enum cv_type type,
char *name)
{
cg_var *cv;
cvec *cvv;
@ -657,18 +656,27 @@ ys_free1(yang_stmt *ys,
cg_var *cv;
rpc_callback_t *rc;
if (ys->ys_argument){
free(ys->ys_argument);
ys->ys_argument = NULL;
}
if ((cv = yang_cv_get(ys)) != NULL){
yang_cv_set(ys, NULL); /* only frees on replace */
cv_free(cv);
}
if (ys->ys_cvec){
#ifdef YANG_SCHEMA_MOUNT
/* Schema mount uses cvec in unknown to keep track of all yspecs
* Freed here once.
*/
if (yang_keyword_get(ys) == Y_UNKNOWN &&
strcmp(yang_argument_get(ys), "yangmnt:mount-point")==0){
xml_yang_mount_freeall(ys->ys_cvec);
}
#endif
cvec_free(ys->ys_cvec);
ys->ys_cvec = NULL;
}
if (ys->ys_argument){
free(ys->ys_argument);
ys->ys_argument = NULL;
}
if (ys->ys_typecache){
yang_type_cache_free(ys->ys_typecache);
ys->ys_typecache = NULL;
@ -1131,16 +1139,7 @@ yang_find_datanode(yang_stmt *yn,
yang_stmt *yspec;
yang_stmt *ysmatch = NULL;
char *name;
#ifdef YANG_SCHEMA_MOUNT
int ret;
/* Sanity-check mount-point extension */
if ((ret = yang_schema_mount_point(yn)) < 0)
goto done;
if (ret == 1){
; // NYI
}
#endif
ys = NULL;
while ((ys = yn_each(yn, ys)) != NULL){
if (yang_keyword_get(ys) == Y_CHOICE){ /* Look for its children */
@ -1904,7 +1903,7 @@ yang_spec_print(FILE *f,
fprintf(f, "%s", yang_key2str(ym->ys_keyword));
fprintf(f, " %s", ym->ys_argument);
if ((yrev = yang_find(ym, Y_REVISION, NULL)) != NULL){
fprintf(f, "@%u", cv_uint32_get(yang_cv_get(yrev)));
fprintf(f, "@%s", yang_argument_get(yrev));
}
fprintf(f, ".yang");
fprintf(f, "\n");
@ -2754,10 +2753,6 @@ ys_populate_unknown(clicon_handle h,
clicon_debug(1, "plugin_extension() failed");
return -1;
}
#endif
#ifdef YANG_SCHEMA_MOUNT
if (yang_schema_unknown(h, yext, ys) < 0)
goto done;
#endif
/* Make extension callbacks that may alter yang structure
* Note: this may be a "layering" violation: assuming plugins are loaded

View file

@ -96,6 +96,7 @@ struct yang_stmt{
types as <module>:<id> list
Y_UNIQUE: vector of descendant schema node ids
Y_EXTENSION: vector of instantiated UNKNOWNSo
Y_UNKNOWN: app-dep: yang-mount-points
*/
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
char *ys_when_xpath; /* Special conditional for a "when"-associated augment/uses xpath */

View file

@ -210,8 +210,10 @@ yang_modules_state_build(clicon_handle h,
yang_stmt *ysub;
char *name;
if ((ylib = yang_find(yspec, Y_MODULE, module)) == NULL &&
(ylib = yang_find(yspec, Y_SUBMODULE, module)) == NULL){
/* In case of several mountpoints, this is always the top-level */
if ((ylib = yang_find(yspec, Y_MODULE, module)) == NULL
/* && (ylib = yang_find(yspec0, Y_SUBMODULE, module)) == NULL */
){
clicon_err(OE_YANG, 0, "%s not found", module);
goto done;
}
@ -219,7 +221,6 @@ yang_modules_state_build(clicon_handle h,
clicon_err(OE_YANG, 0, "%s yang namespace not found", module);
goto done;
}
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895")){
cprintf(cb,"<modules-state xmlns=\"%s\">", yang_argument_get(yns));
cprintf(cb,"<module-set-id>%s</module-set-id>", msid);
@ -671,7 +672,7 @@ yang_find_module_by_namespace_revision(yang_stmt *yspec,
* @note a module may have many revisions, but only the first is significant
*/
yang_stmt *
yang_find_module_by_name_revision(yang_stmt *yspec,
yang_find_module_by_name_revision(yang_stmt *yspec,
const char *name,
const char *rev)
{
@ -824,3 +825,55 @@ yang_metadata_init(clicon_handle h)
done:
return retval;
}
/*! Given a yang-lib module-set XML tree, parse all modules into an yspec
*
* This function is used where a yang-lib module-set is available to populate an
* XML mount-point.
* @param[in] h Clicon handle
* @param[in] xylib yang-lib XML tree on the form <yang-lib>...
* @param[in] yspec Will be populated with YANGs, is consumed
* @retval 1 OK
* @retval 0 Parse error
* @retval -1 Error
* @see xml_schema_add_mount_points
*/
int
yang_lib2yspec(clicon_handle h,
cxobj *yanglib,
yang_stmt *yspec)
{
int retval = -1;
cxobj *xi;
char *name;
char *revision;
cvec *nsc = NULL;
cxobj **vec = NULL;
size_t veclen;
int i;
if (xpath_vec(yanglib, nsc, "module-set/module", &vec, &veclen) < 0)
goto done;
for (i=0; i<veclen; i++){
xi = vec[i];
if ((name = xml_find_body(xi, "name")) == NULL)
continue;
if ((revision = xml_find_body(xi, "revision")) == NULL)
continue;
if (yang_spec_parse_module(h, name, revision, yspec) < 0)
goto fail;
}
#ifdef YANG_SCHEMA_MOUNT_YANG_LIB_FORCE
/* XXX: Ensure yang-lib is always there otherwise get state dont work for mountpoint */
if (yang_spec_parse_module(h, "ietf-yang-library", "2019-01-04", yspec) < 0)
goto fail;
#endif
retval = 1;
done:
if (vec)
free(vec);
return retval;
fail:
retval = 0;
goto done;
}

View file

@ -1028,11 +1028,14 @@ value_stmt : K_VALUE integer_value_str stmtend
;
/* Grouping */
grouping_stmt : K_GROUPING identifier_str
grouping_stmt : K_GROUPING identifier_str ';'
{ if (ysp_add(_yy, Y_GROUPING, $2, NULL) == NULL) _YYERROR("grouping_stmt");
_PARSE_DEBUG("grouping-stmt -> GROUPING id-arg-str ;"); }
| K_GROUPING identifier_str
{ if (ysp_add_push(_yy, Y_GROUPING, $2, NULL) == NULL) _YYERROR("grouping_stmt"); }
'{' grouping_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("grouping_stmt");
_PARSE_DEBUG("grouping-stmt -> GROUPING id-arg-str { grouping-substmts }"); }
_PARSE_DEBUG("grouping-stmt -> GROUPING id-arg-str { grouping-substmts }"); }
;
grouping_substmts : grouping_substmts grouping_substmt

View file

@ -32,6 +32,19 @@
***** END LICENSE BLOCK *****
* RFC 8525 Yang schema mount support
*
* Structure of mount-points in XML:
* YANG mount extentsion -->* YANG unknown mount stmt -->* XML mount-points
* |
* cvec mapping xpath->yspec mountpoint
*
* The calls into this code are:
* 1. yang_schema_mount_point() Check that a yang nod eis mount-point
* 2. xml_yang_mount_get(): from xml_bind_yang and xmldb_put
* 3. xml_yang_mount_freeall(): from ys_free1 when deallocatin YANG trees
* 4. yang_schema_mount_statedata(): from get_common/get_statedata to retrieve system state
* 5. yang_schema_yanglib_parse_mount(): from xml_bind_yang to parse and mount
* 6. yang_schema_get_child(): from xmldb_put/text_modify when adding new XML nodes
*/
#ifdef HAVE_CONFIG_H
@ -43,6 +56,8 @@
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <assert.h>
#include <sys/param.h>
/* cligen */
#include <cligen/cligen.h>
@ -50,18 +65,25 @@
/* clixon */
#include "clixon_queue.h"
#include "clixon_hash.h"
#include "clixon_string.h"
#include "clixon_handle.h"
#include "clixon_err.h"
#include "clixon_log.h"
#include "clixon_yang.h"
#include "clixon_xml.h"
#include "clixon_xml_io.h"
#include "clixon_xml_map.h"
#include "clixon_data.h"
#include "clixon_xpath_ctx.h"
#include "clixon_xpath.h"
#include "clixon_yang_module.h"
#include "clixon_yang_parse_lib.h"
#include "clixon_plugin.h"
#include "clixon_xml_bind.h"
#include "clixon_netconf_lib.h"
#include "clixon_yang_schema_mount.h"
/*! Check if y is a RFC 8525 YANG schema mount
/*! Check if YANG node is a RFC 8525 YANG schema mount
*
* Check if:
* - y is CONTAINER or LIST, AND
@ -87,7 +109,14 @@ yang_schema_mount_point(yang_stmt *y)
goto done;
}
keyw = yang_keyword_get(y);
if (keyw != Y_CONTAINER && keyw != Y_LIST)
if (keyw != Y_CONTAINER
#ifndef YANG_SCHEMA_MOUNT_ONLY_PRESENCE_CONTAINERS
&& keyw != Y_LIST
#endif
#if 0 /* See this in some standard YANGs but RFC 8528 does not allow it */
&& keyw != Y_ANYDATA
#endif
)
goto fail;
if (yang_extension_value(y, "mount-point", YANG_SCHEMA_MOUNT_NAMESPACE, &exist, &value) < 0)
goto done;
@ -103,6 +132,113 @@ yang_schema_mount_point(yang_stmt *y)
goto done;
}
/*! Get yangspec mount-point
*
* @param[in] x XML moint-point node
* @param[out] yspec YANG stmt spec
* @retval 1 x is a mount-point: yspec may be set
* @retval 0 x is not a mount point
* @retval -1 Error
*/
int
xml_yang_mount_get(cxobj *x,
yang_stmt **yspec)
{
int retval = -1;
cvec *cvv = NULL;
cg_var *cv;
yang_stmt *y;
yang_stmt *yu;
char *xpath = NULL; // XXX free it
int ret;
if ((y = xml_spec(x)) == NULL)
goto fail;
if ((ret = yang_schema_mount_point(y)) < 0)
goto done;
if (ret == 0)
goto fail;
// XXX
if ((yu = yang_find(y, Y_UNKNOWN, "yangmnt:mount-point")) == NULL)
goto ok;
if (xml2xpath(x, NULL, &xpath) < 0)
goto done;
if ((cvv = yang_cvec_get(yu)) == NULL)
goto ok;
if ((cv = cvec_find(cvv, xpath)) == NULL)
goto ok;
if (yspec)
*yspec = cv_void_get(cv);
ok:
retval = 1;
done:
if (xpath)
free(xpath);
return retval;
fail:
retval = 0;
goto done;
}
/*! Set yangspec mount-point
*
* Stored in a separate structure (not in XML config tree)
* @param[in] x XML moint-point node
* @param[in] yspec Yangspec for this mount-point (consumed)
* @retval 0 OK
* @retval -1 Error
*/
int
xml_yang_mount_set(cxobj *x,
yang_stmt *yspec)
{
cg_var *cv;
yang_stmt *y;
yang_stmt *yu;
yang_stmt *yspec0;
char *xpath = NULL;
cvec *cvv;
if ((y = xml_spec(x)) == NULL ||
(yu = yang_find(y, Y_UNKNOWN, "yangmnt:mount-point")) == NULL){
goto done;
}
if (xml2xpath(x, NULL, &xpath) < 0)
goto done;
if ((cvv = yang_cvec_get(yu)) != NULL &&
(cv = cvec_find(cvv, xpath)) != NULL &&
(yspec0 = cv_void_get(cv)) != NULL){
assert(0);
ys_free(yspec0);
cv_void_set(cv, NULL);
}
else if ((cv = yang_cvec_add(yu, CGV_VOID, xpath)) == NULL)
return -1;
cv_void_set(cv, yspec);
done:
if (xpath)
free(xpath);
return 0;
}
/*! Free all yspec yang-mounts
* @aparm[in] cvv Cligen-variable vector containing xpath -> yspec mapping
*/
int
xml_yang_mount_freeall(cvec *cvv)
{
cg_var *cv = NULL;
yang_stmt *ys;
cv = NULL;
while ((cv = cvec_each(cvv, cv)) != NULL){
if ((ys = cv_void_get(cv)) != NULL)
ys_free(ys);
}
return 0;
}
/*! Find schema mounts - callback function for xml_apply
*
* @param[in] x XML node
@ -142,7 +278,6 @@ find_schema_mounts(cxobj *x,
* Brute force: traverse whole XML, match all x that have ymount as yspec
* Add yang-library state for all x
* @param[in] h Clicon handle
* @param[in] yspec Yang spec
* @param[in] xpath XML Xpath
* @param[in] nsc XML Namespace context for xpath
* @param[in,out] xret Existing XML tree, merge x into this
@ -159,20 +294,20 @@ find_schema_mounts(cxobj *x,
* Alt: see snmp_yang2xml to get instances instead of brute force traverse of whole tree
*/
static int
schema_mounts_yang_library(clicon_handle h,
yang_stmt *yspec,
char *xpath,
cvec *nsc,
cxobj **xret,
cxobj **xerr)
yang_schema_mount_statedata_yanglib(clicon_handle h,
char *xpath,
cvec *nsc,
cxobj **xret,
cxobj **xerr)
{
int retval = -1;
cvec *cvv = NULL;
cg_var *cv;
cxobj *xmp; /* xml mount-point */
cxobj *xylib = NULL; /* xml yang-lib */
cbuf *cb = NULL;
char *msid = "mount-point"; /* modules-set-id dummy */
int retval = -1;
cvec *cvv = NULL;
cg_var *cv;
cxobj *xmp; /* xml mount-point */
cxobj *yanglib = NULL; /* xml yang-lib */
cbuf *cb = NULL;
yang_stmt *yspec;
int ret;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, 0, "clicon buffer");
@ -187,25 +322,21 @@ schema_mounts_yang_library(clicon_handle h,
cv = NULL;
while ((cv = cvec_each(cvv, cv)) != NULL) {
xmp = cv_void_get(cv);
/* addsub here */
cbuf_reset(cb);
// XXX change yspec to mount-point
/* Build a cb string: <modules-state>... */
if (yang_modules_state_build(h, yspec, msid, 0, cb) < 0)
yanglib = NULL;
/* User callback */
if (clixon_plugin_yang_mount_all(h, xmp, &yanglib) < 0)
goto done;
/* Parse cb, x is on the form: <top><modules-state>...
* Note, list is not sorted since it is state (should not be)
*/
if (clixon_xml_parse_string(cbuf_get(cb), YB_MODULE, yspec, &xylib, NULL) < 0){
if (xret && netconf_operation_failed_xml(xret, "protocol", clicon_err_reason)< 0)
goto done;
if (yanglib == NULL)
continue;
yspec = clicon_dbspec_yang(h);
// if ((ret = xml_bind_yang(h, yanglib, YB_NONE, yspec, &xerr)) < 0)
if ((ret = xml_bind_yang0(h, yanglib, YB_MODULE, yspec, xerr)) < 0)
goto done;
if (ret == 0)
goto fail;
}
if (xml_rootchild(xylib, 0, &xylib) < 0)
if (xml_addsub(xmp, yanglib) < 0)
goto done;
if (xml_addsub(xmp, xylib) < 0)
goto done;
xylib = NULL;
yanglib = NULL;
}
retval = 1;
done:
@ -219,7 +350,7 @@ schema_mounts_yang_library(clicon_handle h,
goto done;
}
/*! Get modules state according to RFC 8528
/*! Get schema mount-point state according to RFC 8528
*
* @param[in] h Clicon handle
* @param[in] yspec Yang spec
@ -233,12 +364,12 @@ schema_mounts_yang_library(clicon_handle h,
* @note Only "inline" specification of mounted schema supported, not "shared schema"
*/
int
schema_mounts_state_get(clicon_handle h,
yang_stmt *yspec,
char *xpath,
cvec *nsc,
cxobj **xret,
cxobj **xerr)
yang_schema_mount_statedata(clicon_handle h,
yang_stmt *yspec,
char *xpath,
cvec *nsc,
cxobj **xret,
cxobj **xerr)
{
int retval = -1;
cbuf *cb = NULL;
@ -291,7 +422,7 @@ schema_mounts_state_get(clicon_handle h,
goto fail;
}
/* Find mount-points and return yang-library state */
if (0 && schema_mounts_yang_library(h, yspec, xpath, nsc, xret, xerr) < 0)
if (yang_schema_mount_statedata_yanglib(h, xpath, nsc, xret, xerr) < 0)
goto done;
ok:
retval = 1;
@ -306,41 +437,85 @@ schema_mounts_state_get(clicon_handle h,
goto done;
}
/*! Callback for yang schema mount-point extension
*
* @param[in] h Clixon handle
* @param[in] yext Yang node of extension
* @param[in] ys Yang node of (unknown) statement belonging to extension
* @retval 0 OK
* @retval -1 Error
// XXX his may not even be necessary
/*! Get yanglib, parse it and mount it
*/
int
yang_schema_unknown(clicon_handle h,
yang_stmt *yext,
yang_stmt *ys)
yang_schema_yanglib_parse_mount(clicon_handle h,
cxobj *xt)
{
int retval = -1;
cxobj *yanglib = NULL;
yang_stmt *yspec = NULL;
int ret;
if (clixon_plugin_yang_mount_all(h, xt, &yanglib) < 0)
goto done;
if (yanglib == NULL)
goto anydata;
/* Parse it and set mount-point */
if ((yspec = yspec_new()) == NULL)
goto done;
if ((ret = yang_lib2yspec(h, yanglib, yspec)) < 0)
goto done;
if (ret == 0)
goto anydata;
#ifdef YANG_SCHEMA_MOUNT_YANG_LIB_FORCE
/* XXX: Ensure yang-lib is always there otherwise get state dont work for mountpoint */
if (yang_spec_parse_module(h, "ietf-yang-library", "2019-01-04", yspec) < 0)
goto done;
#endif
if (xml_yang_mount_set(xt, yspec) < 0)
goto done;
retval = 1;
done:
if (yspec)
ys_free(yspec);
if (yanglib)
xml_free(yanglib);
return retval;
anydata: // Treat as anydata
retval = 0;
goto done;
}
/*! Check if XML nod is mount-point and return matching YANG child
* @param[in] h Clicon handle
* @param[in] x1 XML node
* @param[in] x1c A child of x1
* @param[out] yc YANG child
* @retval 1 OK, yc contains child
* @retval 0 No such child
* @retval -1 Error
* XXX maybe not needed
*/
int
yang_schema_get_child(clicon_handle h,
cxobj *x1,
cxobj *x1c,
yang_stmt **yc)
{
int retval = -1;
char *extname;
char *modname;
yang_stmt *ymod;
cg_var *cv;
char *label;
yang_stmt *yspec1;
yang_stmt *ymod1 = NULL;
char *x1cname;
int ret;
ymod = ys_module(yext);
modname = yang_argument_get(ymod);
extname = yang_argument_get(yext);
if (strcmp(modname, "ietf-yang-schema-mount") != 0 || strcmp(extname, "mount-point") != 0)
goto ok;
if ((cv = yang_cv_get(ys)) == NULL){
clicon_err(OE_YANG, 0, "mount-point extension must have label");
x1cname = xml_name(x1c);
if ((ret = xml_yang_mount_get(x1, &yspec1)) < 0)
goto done;
if (ret == 1 && yspec1 != NULL){
if (ys_module_by_xml(yspec1, x1c, &ymod1) <0)
goto done;
if (ymod1 != NULL)
*yc = yang_find_datanode(ymod1, x1cname);
else{ /* It is in fact a mountpoint, there is a yang mount, but it is not found */
goto fail;
}
}
label = cv_string_get(cv);
clicon_debug(1, "%s Enabled extension:%s:%s label:%s", __FUNCTION__, modname, extname, label);
// XXX his may not even be necessary
ok:
retval = 0;
retval = 1;
done:
return retval;
fail:
retval = 0;
goto done;
}