* YANG schema mount RFC 8528, state data
This commit is contained in:
parent
51ebbdf12f
commit
a8e13047fc
21 changed files with 572 additions and 144 deletions
|
|
@ -43,11 +43,14 @@ Expected: beginning of 2023
|
|||
|
||||
### New features
|
||||
|
||||
* YANG schema mount RFC 8528 (work in progress)
|
||||
* YANG schema mount RFC 8528
|
||||
* Experimental
|
||||
* Restrictions:
|
||||
* only schema-ref=inline, not shared-schema
|
||||
* Only schema-ref=inline, not shared-schema
|
||||
* Only presence containers can be mount-points
|
||||
* New plugin callback: `ca_yang_mount`
|
||||
* Standards: RFC 8528
|
||||
* Enable `YANG_SCHEMA_MOUNT`
|
||||
* To enable: define `YANG_SCHEMA_MOUNT`
|
||||
* Netconf monitoring RFC 6022 , part 2
|
||||
* Datastores and sessions
|
||||
* Added clixon-specific transport identities: cli, snmp, netconf, restconf
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ General Public License Version 2; you choose, see [LICENSE.md](LICENSE.md).
|
|||
Clixon has a master branch continuously tested with CI, but releases are made ca every second month. Latest 6.0.0 release is from November 2022. Next is planned for January 2023. See [CHANGELOG.md](CHANGELOG.md) release history.
|
||||
|
||||
Clixon interaction is best done posting issues, pull requests, or joining the
|
||||
Matrix channels: https://matrix.to/#/#clixondev:matrix.org for general info and discussion, and
|
||||
https://matrix.to/#/#clixontech:matrix.org for technical details and issues.
|
||||
Matrix clixon forum https://matrix.to/#/#clixonforum:matrix.org.
|
||||
|
||||
Clixon is sponsored by [Rubicon Communications LLC(Netgate)](https://www.netgate.com/) and [Akamai Technologies, Inc.](https://www.akamai.com).
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ get_statedata(clicon_handle h,
|
|||
goto fail;
|
||||
}
|
||||
#ifdef YANG_SCHEMA_MOUNT
|
||||
if ((ret = schema_mounts_state_get(h, yspec, xpath, nsc, xret, &xerr)) < 0)
|
||||
if ((ret = yang_schema_mount_statedata(h, yspec, xpath, nsc, xret, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (clixon_netconf_internal_error(xerr, " . Internal error, schema_mounts_state_get returned invalid XML", NULL) < 0)
|
||||
|
|
|
|||
|
|
@ -880,6 +880,50 @@ example_upgrade(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Example YANG schema mount
|
||||
*
|
||||
* Given an XML mount-point xt, return XML yang-lib modules-set
|
||||
* @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
|
||||
* XXX hardcoded to clixon-example@2022-11-01.yang regardless of xt
|
||||
* @see RFC 8528
|
||||
*/
|
||||
int
|
||||
main_yang_mount(clicon_handle h,
|
||||
cxobj *xt,
|
||||
cxobj **yanglib)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">");
|
||||
cprintf(cb, "<module-set>");
|
||||
cprintf(cb, "<name>mount</name>");
|
||||
cprintf(cb, "<module>");
|
||||
cprintf(cb, "<name>clixon-example</name>");
|
||||
cprintf(cb, "<revision>2022-11-01</revision>");
|
||||
cprintf(cb, "<namespace>urn:example:urn</namespace>");
|
||||
cprintf(cb, "</module>");
|
||||
cprintf(cb, "</module-set>");
|
||||
cprintf(cb, "</yang-library>");
|
||||
if (clixon_xml_parse_string(cbuf_get(cb), YB_NONE, NULL, yanglib, NULL) < 0)
|
||||
goto done;
|
||||
if (xml_rootchild(*yanglib, 0, yanglib) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Testcase module-specific upgrade function moving interfaces-state to interfaces
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xn XML tree to be updated
|
||||
|
|
@ -1302,6 +1346,7 @@ static clixon_plugin_api api = {
|
|||
.ca_trans_end=main_end, /* trans end */
|
||||
.ca_trans_abort=main_abort, /* trans abort */
|
||||
.ca_datastore_upgrade=example_upgrade, /* general-purpose upgrade. */
|
||||
.ca_yang_mount=main_yang_mount /* RFC 8528 schema mount */
|
||||
};
|
||||
|
||||
/*! Backend plugin initialization
|
||||
|
|
|
|||
|
|
@ -192,8 +192,8 @@
|
|||
*/
|
||||
#undef NETCONF_DEFAULT_RETRIEVAL_REPORT_ALL
|
||||
|
||||
/*! Development option for RFC 8528 YANG schema mount
|
||||
* Work-in-progress
|
||||
/*! RFC 8528 YANG schema mount
|
||||
* Experimental
|
||||
* See also test/test_yang_schema_mount.sh
|
||||
*/
|
||||
#undef YANG_SCHEMA_MOUNT
|
||||
|
|
|
|||
|
|
@ -269,6 +269,26 @@ typedef char *(cli_prompthook_t)(clicon_handle, char *mode);
|
|||
*/
|
||||
typedef int (datastore_upgrade_t)(clicon_handle h, const char *db, cxobj *xt, modstate_diff_t *msd);
|
||||
|
||||
/*! YANG schema mount
|
||||
*
|
||||
* Given an XML mount-point xt, return XML yang-lib modules-set
|
||||
* Return yanglib as XML tree on the RFC8525 form:
|
||||
* <yang-library>
|
||||
* <module-set>
|
||||
* <module>...</module>
|
||||
* ...
|
||||
* </module-set>
|
||||
* </yang-library>
|
||||
* No need to YANG bind.
|
||||
* @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
|
||||
* @see RFC 8528 (schema-mount) and RFC 8525 (yang-lib)
|
||||
*/
|
||||
typedef int (yang_mount_t)(clicon_handle h, cxobj *xt, cxobj **yanglib);
|
||||
|
||||
/*! Startup status for use in startup-callback
|
||||
* Note that for STARTUP_ERR and STARTUP_INVALID, running runs in failsafe mode
|
||||
* and startup contains the erroneous or invalid database.
|
||||
|
|
@ -322,6 +342,7 @@ struct clixon_plugin_api{
|
|||
trans_cb_t *cb_trans_end; /* Transaction completed */
|
||||
trans_cb_t *cb_trans_abort; /* Transaction aborted */
|
||||
datastore_upgrade_t *cb_datastore_upgrade; /* General-purpose datastore upgrade */
|
||||
yang_mount_t *cb_yang_mount; /* RFC 8528 schema mount */
|
||||
} cau_backend;
|
||||
} u;
|
||||
};
|
||||
|
|
@ -344,6 +365,7 @@ struct clixon_plugin_api{
|
|||
#define ca_trans_end u.cau_backend.cb_trans_end
|
||||
#define ca_trans_abort u.cau_backend.cb_trans_abort
|
||||
#define ca_datastore_upgrade u.cau_backend.cb_datastore_upgrade
|
||||
#define ca_yang_mount u.cau_backend.cb_yang_mount
|
||||
|
||||
/*
|
||||
* Macros
|
||||
|
|
@ -419,6 +441,9 @@ int clixon_plugin_extension_all(clicon_handle h, yang_stmt *yext, yang_stmt *ys)
|
|||
int clixon_plugin_datastore_upgrade_one(clixon_plugin_t *cp, clicon_handle h, const char *db, cxobj *xt, modstate_diff_t *msd);
|
||||
int clixon_plugin_datastore_upgrade_all(clicon_handle h, const char *db, cxobj *xt, modstate_diff_t *msd);
|
||||
|
||||
int clixon_plugin_yang_mount_one(clixon_plugin_t *cp, clicon_handle h, cxobj *xt, cxobj **yanglib);
|
||||
int clixon_plugin_yang_mount_all(clicon_handle h, cxobj *xt, cxobj **yanglib);
|
||||
|
||||
/* rpc callback API */
|
||||
int rpc_callback_register(clicon_handle h, clicon_rpc_cb cb, void *arg, const char *ns, const char *name);
|
||||
int rpc_callback_call(clicon_handle h, cxobj *xe, void *arg, int *nrp, cbuf *cbret);
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ cg_var *yang_cv_get(yang_stmt *ys);
|
|||
int yang_cv_set(yang_stmt *ys, cg_var *cv);
|
||||
cvec *yang_cvec_get(yang_stmt *ys);
|
||||
int yang_cvec_set(yang_stmt *ys, cvec *cvv);
|
||||
cg_var *yang_cvec_add(yang_stmt *ys, enum cv_type type, char *name);
|
||||
uint16_t yang_flag_get(yang_stmt *ys, uint16_t flag);
|
||||
int yang_flag_set(yang_stmt *ys, uint16_t flag);
|
||||
int yang_flag_reset(yang_stmt *ys, uint16_t flag);
|
||||
|
|
|
|||
|
|
@ -78,5 +78,6 @@ yang_stmt *yang_find_module_by_name_revision(yang_stmt *yspec, const char *name,
|
|||
yang_stmt *yang_find_module_by_name(yang_stmt *yspec, char *name);
|
||||
int yang_metadata_annotation_check(cxobj *x, yang_stmt *ymod, int *ismeta);
|
||||
int yang_metadata_init(clicon_handle h);
|
||||
int yang_lib2yspec(clicon_handle h, cxobj *yanglib,yang_stmt *yspec);
|
||||
|
||||
#endif /* _CLIXON_YANG_MODULE_H_ */
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
* Prototypes
|
||||
*/
|
||||
yang_stmt *yang_parse_file(FILE *fp, const char *name, yang_stmt *ysp);
|
||||
int yang_file_find_match(clicon_handle h, const char *module, const char *revision, cbuf *fbuf);
|
||||
yang_stmt *yang_parse_filename(const char *filename, yang_stmt *ysp);
|
||||
int yang_parse_post(clicon_handle h, yang_stmt *yspec, int modmin);
|
||||
int yang_spec_parse_module(clicon_handle h, const char *module,
|
||||
|
|
|
|||
|
|
@ -44,12 +44,26 @@
|
|||
*/
|
||||
#define YANG_SCHEMA_MOUNT_NAMESPACE "urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount"
|
||||
|
||||
/* Limitations/deviations from RFC 8528 */
|
||||
/*! Only support YANG presende containers as mount-points
|
||||
* This is a limitation of othe current implementation
|
||||
*/
|
||||
#define YANG_SCHEMA_MOUNT_ONLY_PRESENCE_CONTAINERS
|
||||
|
||||
/*! Force add ietf-yang-library@2019-01-04 on all mount-points
|
||||
* This is a limitation of othe current implementation
|
||||
*/
|
||||
#define YANG_SCHEMA_MOUNT_YANG_LIB_FORCE
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int yang_schema_mount_point(yang_stmt *y);
|
||||
|
||||
int schema_mounts_state_get(clicon_handle h, yang_stmt *yspec, char *xpath, cvec *nsc, cxobj **xret, cxobj **xerr);
|
||||
int yang_schema_unknown(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
|
||||
int xml_yang_mount_get(cxobj *x, yang_stmt **yspec);
|
||||
int xml_yang_mount_set(cxobj *x, yang_stmt *yspec);
|
||||
int xml_yang_mount_freeall(cvec *cvv);
|
||||
int yang_schema_mount_statedata(clicon_handle h, yang_stmt *yspec, char *xpath, cvec *nsc, cxobj **xret, cxobj **xerr);
|
||||
int yang_schema_yanglib_parse_mount(clicon_handle h, cxobj *xt);
|
||||
int yang_schema_get_child(clicon_handle h, cxobj *x1, cxobj *x1c, yang_stmt **yc);
|
||||
|
||||
#endif /* _CLIXON_YANG_SCHEMA_MOUNT_H_ */
|
||||
|
|
|
|||
|
|
@ -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,7 +855,10 @@ 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 = 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 */
|
||||
|
|
@ -871,6 +875,7 @@ text_modify(clicon_handle h,
|
|||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* There is a cornercase (eg augment) of multi-namespace trees where
|
||||
* the yang child has a different namespace.
|
||||
* As an alternative, return in populate where this is detected first time.
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1028,7 +1028,10 @@ 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");
|
||||
|
|
|
|||
|
|
@ -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,8 +294,7 @@ 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,
|
||||
yang_schema_mount_statedata_yanglib(clicon_handle h,
|
||||
char *xpath,
|
||||
cvec *nsc,
|
||||
cxobj **xret,
|
||||
|
|
@ -170,9 +304,10 @@ schema_mounts_yang_library(clicon_handle h,
|
|||
cvec *cvv = NULL;
|
||||
cg_var *cv;
|
||||
cxobj *xmp; /* xml mount-point */
|
||||
cxobj *xylib = NULL; /* xml yang-lib */
|
||||
cxobj *yanglib = NULL; /* xml yang-lib */
|
||||
cbuf *cb = NULL;
|
||||
char *msid = "mount-point"; /* modules-set-id dummy */
|
||||
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)
|
||||
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,7 +364,7 @@ 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_schema_mount_statedata(clicon_handle h,
|
||||
yang_stmt *yspec,
|
||||
char *xpath,
|
||||
cvec *nsc,
|
||||
|
|
@ -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;
|
||||
char *extname;
|
||||
char *modname;
|
||||
yang_stmt *ymod;
|
||||
cg_var *cv;
|
||||
char *label;
|
||||
cxobj *yanglib = NULL;
|
||||
yang_stmt *yspec = NULL;
|
||||
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");
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
/*! 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;
|
||||
yang_stmt *yspec1;
|
||||
yang_stmt *ymod1 = NULL;
|
||||
char *x1cname;
|
||||
int ret;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ if true; then # enable YANG_SCHEMA_MOUNT
|
|||
if [ -z "${CLIXON_YANG_PATCH}" -a "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
fi
|
||||
|
||||
|
||||
APPNAME=example
|
||||
|
||||
cfg=$dir/conf_mount.xml
|
||||
|
|
@ -33,6 +32,7 @@ cat <<EOF > $cfg
|
|||
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
|
||||
<CLICON_NETCONF_MONITORING>true</CLICON_NETCONF_MONITORING>
|
||||
<CLICON_VALIDATE_STATE_XML>true</CLICON_VALIDATE_STATE_XML>
|
||||
<CLICON_STREAM_DISCOVERY_RFC5277>true</CLICON_STREAM_DISCOVERY_RFC5277>
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
|
|
@ -45,17 +45,20 @@ module clixon-example{
|
|||
prefix yangmnt;
|
||||
}
|
||||
container top{
|
||||
list root{
|
||||
list mylist{
|
||||
key name;
|
||||
leaf name{
|
||||
type string;
|
||||
}
|
||||
container root{
|
||||
presence "Otherwise root is not visible";
|
||||
yangmnt:mount-point "myroot"{
|
||||
description "Root for other yang models";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
new "test params: -f $cfg"
|
||||
|
|
@ -73,19 +76,19 @@ fi
|
|||
new "wait backend"
|
||||
wait_backend
|
||||
|
||||
new "Add two mountpoints: x and y"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><top xmlns=\"urn:example:clixon\"><root><name>x</name></root><root><name>y</name></root></top></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "Add two mountpoints: x and y"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><top xmlns=\"urn:example:clixon\"><mylist><name>x</name><root/></mylist><mylist><name>y</name><root/></mylist></top></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
new "netconf commit"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><commit/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "Retrieve schema-mounts with <get> Operation"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"subtree\"><schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\"></schema-mounts></filter></get></rpc>" "<rpc-reply $DEFAULTNS><data><schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\"><mount-point><module>clixon-example</module><label>myroot</label><config>true</config><inline/></mount-point></schema-mounts></data></rpc-reply>"
|
||||
|
||||
if true; then
|
||||
new "get yang-lib at mountpoint"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"subtree\"><top xmlns=\"urn:example:clixon\"><root></root></top>></filter></get></rpc>" "<rpc-reply $DEFAULTNS><data><top xmlns=\"urn:example:clixon\"><root><name>x</name></root><root><name>y</name></root></top></data></rpc-reply>"
|
||||
fi
|
||||
# XXX maybe too many yangs here, difficult to maintain
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"subtree\"><top xmlns=\"urn:example:clixon\"><mylist/></top>></filter></get></rpc>" "<rpc-reply $DEFAULTNS><data><top xmlns=\"urn:example:clixon\"><mylist><name>x</name><root>
|
||||
<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"><module-set><name>default</name><module><name>clixon-autocli</name><revision>2022-02-11</revision><namespace>http://clicon.org/autocli</namespace></module><module><name>clixon-example</name><revision>2022-11-01</revision><namespace>urn:example:clixon</namespace></module><module><name>ietf-datastores</name><revision>2018-02-14</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace></module><module><name>ietf-inet-types</name><revision>2021-02-22</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace></module><module><name>ietf-yang-library</name><revision>2019-01-04</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace></module><module><name>ietf-yang-types</name><revision>2013-07-15</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace></module></module-set><content-id>mount-point</content-id></yang-library></root></mylist><mylist><name>y</name><root><yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"><module-set><name>default</name><module><name>clixon-autocli</name><revision>2022-02-11</revision><namespace>http://clicon.org/autocli</namespace></module><module><name>clixon-example</name><revision>2022-11-01</revision><namespace>urn:example:clixon</namespace></module><module><name>ietf-datastores</name><revision>2018-02-14</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace></module><module><name>ietf-inet-types</name><revision>2021-02-22</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace></module><module><name>ietf-yang-library</name><revision>2019-01-04</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace></module><module><name>ietf-yang-types</name><revision>2013-07-15</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace></module></module-set><content-id>mount-point</content-id></yang-library></root></mylist></top></data></rpc-reply>"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
new "Kill backend"
|
||||
|
|
@ -98,7 +101,6 @@ if [ $BE -ne 0 ]; then
|
|||
stop_backend -f $cfg
|
||||
fi
|
||||
|
||||
|
||||
rm -rf $dir
|
||||
|
||||
new "endtest"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue