From 034ab632f1c1bb77afb8e9573cc1ef86120bb5a4 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Sun, 29 Jan 2023 20:02:56 +0100 Subject: [PATCH] * C-API: Added `vlev` validate level parameter to `candidate_commit` * `vlev` : validate level --- CHANGELOG.md | 5 +- apps/backend/backend_client.c | 2 +- apps/backend/backend_commit.c | 87 +++++++++++++++------------ apps/backend/backend_confirm.c | 2 +- apps/backend/clixon_backend_commit.h | 3 +- lib/clixon/clixon_validate.h | 10 +++ lib/clixon/clixon_yang_parse_lib.h | 1 + lib/clixon/clixon_yang_schema_mount.h | 5 -- lib/src/clixon_validate.c | 17 ++++++ lib/src/clixon_yang_module.c | 17 ++++-- lib/src/clixon_yang_parse_lib.c | 2 +- lib/src/clixon_yang_schema_mount.c | 5 -- util/clixon_util_validate.c | 2 +- 13 files changed, 98 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7526106f..bd1d2024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -173,7 +173,10 @@ Developers may need to change their code * Added three-value return. * Code need to be changed from: checking for `<0` to `<1` to keep same semantics * Added `skiptop` parameter to `xml2json_vec()` - * Added `xe` argument to `candidate_commit` for confirmed commit extra parameters + * Added two arguments to `candidate_commit` + * `myid` : Client-id of incoming message + * `vlev` : validate level + * Both parameters are default `0` for backward-compatibility ### Minor features diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 60d49dc9..871c0427 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -567,7 +567,7 @@ from_client_edit_config(clicon_handle h, break; } } - if ((ret = candidate_commit(h, NULL, "candidate", myid, cbret)) < 0){ /* Assume validation fail, nofatal */ + if ((ret = candidate_commit(h, NULL, "candidate", myid, VL_FULL, cbret)) < 0){ /* Assume validation fail, nofatal */ if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0) goto done; xmldb_copy(h, "running", "candidate"); diff --git a/apps/backend/backend_commit.c b/apps/backend/backend_commit.c index 36e14c73..402bdfec 100644 --- a/apps/backend/backend_commit.c +++ b/apps/backend/backend_commit.c @@ -518,7 +518,7 @@ validate_common(clicon_handle h, &td->td_tcvec, /* changed: wanted values */ &td->td_clen) < 0) goto done; - transaction_dbg(h, CLIXON_DBG_DEFAULT, td, __FUNCTION__); + transaction_dbg(h, CLIXON_DBG_DETAIL, td, __FUNCTION__); /* Mark as changed in tree */ for (i=0; itd_dlen; i++){ /* Also down */ xn = td->td_dvec[i]; @@ -648,6 +648,7 @@ candidate_validate(clicon_handle h, * @param[in] xe Request: (or NULL) * @param[in] db A candidate database, not necessarily "candidate" * @param[in] myid Client id of triggering incoming message (or 0) + * @param[in] vlev Validation level (0: full validation) * @param[out] cbret Return xml tree, eg ..., td_target) < 0) - goto done; - if (xmldb_get0_clear(h, td->td_src) < 0) - goto done; + /* Clear cached trees from default values and marking */ + if (xmldb_get0_clear(h, td->td_target) < 0) + goto done; + if (xmldb_get0_clear(h, td->td_src) < 0) + goto done; - /* 8. Success: Copy candidate to running - */ - if (xmldb_copy(h, db, "running") < 0) - goto done; - xmldb_modified_set(h, db, 0); /* reset dirty bit */ - /* Here pointers to old (source) tree are obsolete */ - if (td->td_dvec){ - td->td_dlen = 0; + /* 8. Success: Copy candidate to running + */ + if (xmldb_copy(h, db, "running") < 0) + goto done; + xmldb_modified_set(h, db, 0); /* reset dirty bit */ + /* Here pointers to old (source) tree are obsolete */ + if (td->td_dvec){ + td->td_dlen = 0; free(td->td_dvec); td->td_dvec = NULL; - } - if (td->td_scvec){ + } + if (td->td_scvec){ free(td->td_scvec); td->td_scvec = NULL; - } + } /* 9. Call plugin transaction end callbacks */ plugin_transaction_end_all(h, td); retval = 1; done: - /* In case of failure (or error), call plugin transaction termination callbacks */ - if (td){ - if (retval < 1) - plugin_transaction_abort_all(h, td); - xmldb_get0_free(h, &td->td_target); - xmldb_get0_free(h, &td->td_src); - transaction_free(td); - } - if (xret) - xml_free(xret); - return retval; + /* In case of failure (or error), call plugin transaction termination callbacks */ + if (td){ + if (retval < 1) + plugin_transaction_abort_all(h, td); + xmldb_get0_free(h, &td->td_target); + xmldb_get0_free(h, &td->td_src); + transaction_free(td); + } + if (xret) + xml_free(xret); + return retval; fail: retval = 0; goto done; @@ -818,7 +827,7 @@ from_client_commit(clicon_handle h, goto done; goto ok; } - if ((ret = candidate_commit(h, xe, "candidate", myid, cbret)) < 0){ /* Assume validation fail, nofatal */ + if ((ret = candidate_commit(h, xe, "candidate", myid, VL_FULL, cbret)) < 0){ /* Assume validation fail, nofatal */ clicon_debug(1, "Commit candidate failed"); if (ret < 0) if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0) @@ -1085,7 +1094,7 @@ load_failsafe(clicon_handle h, goto done; if (xmldb_db_reset(h, "running") < 0) goto done; - ret = candidate_commit(h, NULL, db, 0, cbret); + ret = candidate_commit(h, NULL, db, 0, VL_FULL, cbret); if (ret != 1) if (xmldb_copy(h, "tmp", "running") < 0) goto done; diff --git a/apps/backend/backend_confirm.c b/apps/backend/backend_confirm.c index 46260189..fa8fb371 100644 --- a/apps/backend/backend_confirm.c +++ b/apps/backend/backend_confirm.c @@ -653,7 +653,7 @@ do_rollback(clicon_handle h, confirmed_commit_persist_id_set(h, NULL); } confirmed_commit_state_set(h, ROLLBACK); - if (candidate_commit(h, NULL, "rollback", 0, cbret) < 0) { /* Assume validation fail, nofatal */ + if (candidate_commit(h, NULL, "rollback", 0, VL_FULL, cbret) < 0) { /* Assume validation fail, nofatal */ /* theoretically, this should never error, since the rollback database was previously active and therefore * had itself been previously and successfully committed. */ diff --git a/apps/backend/clixon_backend_commit.h b/apps/backend/clixon_backend_commit.h index 808298d5..c274c974 100644 --- a/apps/backend/clixon_backend_commit.h +++ b/apps/backend/clixon_backend_commit.h @@ -71,7 +71,8 @@ int from_client_confirmed_commit(clicon_handle h, cxobj *xe, uint32_t myid, cbuf int startup_validate(clicon_handle h, char *db, cxobj **xtr, cbuf *cbret); int startup_commit(clicon_handle h, char *db, cbuf *cbret); int candidate_validate(clicon_handle h, char *db, cbuf *cbret); -int candidate_commit(clicon_handle h, cxobj *xe, char *db, uint32_t myid, cbuf *cbret); +int candidate_commit(clicon_handle h, cxobj *xe, char *db, uint32_t myid, + validate_level vlev, cbuf *cbret); int from_client_commit(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg); int from_client_discard_changes(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg); diff --git a/lib/clixon/clixon_validate.h b/lib/clixon/clixon_validate.h index 0f6483cc..ec8ad0df 100644 --- a/lib/clixon/clixon_validate.h +++ b/lib/clixon/clixon_validate.h @@ -40,6 +40,16 @@ #ifndef _CLIXON_VALIDATE_H_ #define _CLIXON_VALIDATE_H_ +/* + * Types + */ +/* Validation level at commit */ +enum validate_level_t { + VL_FULL = 0, /* Do full RFC 7950 validation , 0 : backward-compatible */ + VL_NONE, /* Do not do any validation */ +}; +typedef enum validate_level_t validate_level; + /* * Prototypes */ diff --git a/lib/clixon/clixon_yang_parse_lib.h b/lib/clixon/clixon_yang_parse_lib.h index fe3efb05..9ffcabdc 100644 --- a/lib/clixon/clixon_yang_parse_lib.h +++ b/lib/clixon/clixon_yang_parse_lib.h @@ -54,6 +54,7 @@ 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); +yang_stmt *yang_parse_module(clicon_handle h, const char *module, const char *revision, yang_stmt *yspec, char *origname); int yang_parse_post(clicon_handle h, yang_stmt *yspec, int modmin); int yang_spec_parse_module(clicon_handle h, const char *module, const char *revision, yang_stmt *yspec); diff --git a/lib/clixon/clixon_yang_schema_mount.h b/lib/clixon/clixon_yang_schema_mount.h index 01be5f47..f7ef7afa 100644 --- a/lib/clixon/clixon_yang_schema_mount.h +++ b/lib/clixon/clixon_yang_schema_mount.h @@ -50,11 +50,6 @@ */ #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 */ diff --git a/lib/src/clixon_validate.c b/lib/src/clixon_validate.c index 34fa276f..6dfa24b9 100644 --- a/lib/src/clixon_validate.c +++ b/lib/src/clixon_validate.c @@ -75,6 +75,7 @@ #include "clixon_xpath.h" #include "clixon_yang_module.h" #include "clixon_yang_type.h" +#include "clixon_yang_schema_mount.h" #include "clixon_xml_default.h" #include "clixon_xml_map.h" #include "clixon_xml_bind.h" @@ -1007,6 +1008,15 @@ xml_yang_validate_add(clicon_handle h, cg_var *cv0; enum cv_type cvtype; +#ifdef YANG_SCHEMA_MOUNT + /* Do not validate beyond mountpoints */ + if ((ret = xml_yang_mount_get(xt, NULL)) < 0) + goto done; + if (ret == 1){ + retval = 1; + goto done; + } +#endif /* if not given by argument (overide) use default link and !Node has a config sub-statement and it is false */ if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0){ @@ -1215,6 +1225,13 @@ xml_yang_validate_all(clicon_handle h, cvec *nsc = NULL; int hit = 0; +#ifdef YANG_SCHEMA_MOUNT + /* Do not validate beyond mountpoints */ + if ((ret = xml_yang_mount_get(xt, NULL)) < 0) + goto done; + if (ret == 1) + goto ok; +#endif /* if not given by argument (overide) use default link and !Node has a config sub-statement and it is false */ if ((yt = xml_spec(xt)) == NULL){ diff --git a/lib/src/clixon_yang_module.c b/lib/src/clixon_yang_module.c index 51c9b074..d12aac77 100644 --- a/lib/src/clixon_yang_module.c +++ b/lib/src/clixon_yang_module.c @@ -82,6 +82,11 @@ #include "clixon_xml_map.h" #include "clixon_yang_parse_lib.h" +/*! 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 + /*! Create modstate structure * * @retval md modstate struct @@ -826,10 +831,10 @@ yang_metadata_init(clicon_handle h) return retval; } -/*! Given a yang-lib module-set XML tree, parse all modules into an yspec +/*! Given 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. + * 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 ... * @param[in] yspec Will be populated with YANGs, is consumed @@ -860,14 +865,16 @@ yang_lib2yspec(clicon_handle h, continue; if ((revision = xml_find_body(xi, "revision")) == NULL) continue; - if (yang_spec_parse_module(h, name, revision, yspec) < 0) + if (yang_parse_module(h, name, revision, yspec, NULL) == NULL) 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) + if (yang_parse_module(h, "ietf-yang-library", "2019-01-04", yspec, NULL) < 0) goto fail; #endif + if (yang_parse_post(h, yspec, 0) < 0) + goto done; retval = 1; done: if (vec) diff --git a/lib/src/clixon_yang_parse_lib.c b/lib/src/clixon_yang_parse_lib.c index 0bb59e81..249d522b 100644 --- a/lib/src/clixon_yang_parse_lib.c +++ b/lib/src/clixon_yang_parse_lib.c @@ -1059,7 +1059,7 @@ yang_parse_filename(const char *filename, * * See top of file for diagram of calling order */ -static yang_stmt * +yang_stmt * yang_parse_module(clicon_handle h, const char *module, const char *revision, diff --git a/lib/src/clixon_yang_schema_mount.c b/lib/src/clixon_yang_schema_mount.c index 5e95fdf1..d1dc6316 100644 --- a/lib/src/clixon_yang_schema_mount.c +++ b/lib/src/clixon_yang_schema_mount.c @@ -459,11 +459,6 @@ yang_schema_yanglib_parse_mount(clicon_handle h, 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; diff --git a/util/clixon_util_validate.c b/util/clixon_util_validate.c index a9a3550a..3ed5e427 100644 --- a/util/clixon_util_validate.c +++ b/util/clixon_util_validate.c @@ -227,7 +227,7 @@ main(int argc, goto done; } if (commit){ - if ((ret = candidate_commit(h, NULL, database, 0, cb)) < 0) + if ((ret = candidate_commit(h, NULL, database, 0, VL_FULL, cb)) < 0) goto done; } else{