* C-API: Added vlev validate level parameter to candidate_commit

* `vlev` : validate level
This commit is contained in:
Olof Hagsand 2023-01-29 20:02:56 +01:00
parent a8e13047fc
commit 034ab632f1
13 changed files with 98 additions and 60 deletions

View file

@ -173,7 +173,10 @@ Developers may need to change their code
* Added three-value return. * Added three-value return.
* Code need to be changed from: checking for `<0` to `<1` to keep same semantics * Code need to be changed from: checking for `<0` to `<1` to keep same semantics
* Added `skiptop` parameter to `xml2json_vec()` * 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 ### Minor features

View file

@ -567,7 +567,7 @@ from_client_edit_config(clicon_handle h,
break; 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) if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
goto done; goto done;
xmldb_copy(h, "running", "candidate"); xmldb_copy(h, "running", "candidate");

View file

@ -518,7 +518,7 @@ validate_common(clicon_handle h,
&td->td_tcvec, /* changed: wanted values */ &td->td_tcvec, /* changed: wanted values */
&td->td_clen) < 0) &td->td_clen) < 0)
goto done; goto done;
transaction_dbg(h, CLIXON_DBG_DEFAULT, td, __FUNCTION__); transaction_dbg(h, CLIXON_DBG_DETAIL, td, __FUNCTION__);
/* Mark as changed in tree */ /* Mark as changed in tree */
for (i=0; i<td->td_dlen; i++){ /* Also down */ for (i=0; i<td->td_dlen; i++){ /* Also down */
xn = td->td_dvec[i]; xn = td->td_dvec[i];
@ -648,6 +648,7 @@ candidate_validate(clicon_handle h,
* @param[in] xe Request: <rpc><xn></rpc> (or NULL) * @param[in] xe Request: <rpc><xn></rpc> (or NULL)
* @param[in] db A candidate database, not necessarily "candidate" * @param[in] db A candidate database, not necessarily "candidate"
* @param[in] myid Client id of triggering incoming message (or 0) * @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 <rpc-reply>..., <rpc-error.. (if retval = 0) * @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error.. (if retval = 0)
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed (with cbret set) * @retval 0 Validation failed (with cbret set)
@ -658,6 +659,7 @@ candidate_commit(clicon_handle h,
cxobj *xe, cxobj *xe,
char *db, char *db,
uint32_t myid, uint32_t myid,
validate_level vlev,
cbuf *cbret) cbuf *cbret)
{ {
int retval = -1; int retval = -1;
@ -673,8 +675,15 @@ candidate_commit(clicon_handle h,
/* Common steps (with validate). Load candidate and running and compute diffs /* Common steps (with validate). Load candidate and running and compute diffs
* Note this is only call that uses 3-values * Note this is only call that uses 3-values
*/ */
switch (vlev){
case VL_FULL:
if ((ret = validate_common(h, db, td, &xret)) < 0) if ((ret = validate_common(h, db, td, &xret)) < 0)
goto done; goto done;
break;
default:
ret = 1;
break;
}
/* If the confirmed-commit feature is enabled, execute phase 2: /* If the confirmed-commit feature is enabled, execute phase 2:
* - If a valid confirming-commit, cancel the rollback event * - If a valid confirming-commit, cancel the rollback event
@ -818,7 +827,7 @@ from_client_commit(clicon_handle h,
goto done; goto done;
goto ok; 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"); clicon_debug(1, "Commit candidate failed");
if (ret < 0) if (ret < 0)
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0) if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
@ -1085,7 +1094,7 @@ load_failsafe(clicon_handle h,
goto done; goto done;
if (xmldb_db_reset(h, "running") < 0) if (xmldb_db_reset(h, "running") < 0)
goto done; goto done;
ret = candidate_commit(h, NULL, db, 0, cbret); ret = candidate_commit(h, NULL, db, 0, VL_FULL, cbret);
if (ret != 1) if (ret != 1)
if (xmldb_copy(h, "tmp", "running") < 0) if (xmldb_copy(h, "tmp", "running") < 0)
goto done; goto done;

View file

@ -653,7 +653,7 @@ do_rollback(clicon_handle h,
confirmed_commit_persist_id_set(h, NULL); confirmed_commit_persist_id_set(h, NULL);
} }
confirmed_commit_state_set(h, ROLLBACK); 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 /* theoretically, this should never error, since the rollback database was previously active and therefore
* had itself been previously and successfully committed. * had itself been previously and successfully committed.
*/ */

View file

@ -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_validate(clicon_handle h, char *db, cxobj **xtr, cbuf *cbret);
int startup_commit(clicon_handle h, char *db, cbuf *cbret); int startup_commit(clicon_handle h, char *db, cbuf *cbret);
int candidate_validate(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_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); int from_client_discard_changes(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);

View file

@ -40,6 +40,16 @@
#ifndef _CLIXON_VALIDATE_H_ #ifndef _CLIXON_VALIDATE_H_
#define _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 * Prototypes
*/ */

View file

@ -54,6 +54,7 @@
yang_stmt *yang_parse_file(FILE *fp, const char *name, yang_stmt *ysp); 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); 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_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_parse_post(clicon_handle h, yang_stmt *yspec, int modmin);
int yang_spec_parse_module(clicon_handle h, const char *module, int yang_spec_parse_module(clicon_handle h, const char *module,
const char *revision, yang_stmt *yspec); const char *revision, yang_stmt *yspec);

View file

@ -50,11 +50,6 @@
*/ */
#define YANG_SCHEMA_MOUNT_ONLY_PRESENCE_CONTAINERS #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 * Prototypes
*/ */

View file

@ -75,6 +75,7 @@
#include "clixon_xpath.h" #include "clixon_xpath.h"
#include "clixon_yang_module.h" #include "clixon_yang_module.h"
#include "clixon_yang_type.h" #include "clixon_yang_type.h"
#include "clixon_yang_schema_mount.h"
#include "clixon_xml_default.h" #include "clixon_xml_default.h"
#include "clixon_xml_map.h" #include "clixon_xml_map.h"
#include "clixon_xml_bind.h" #include "clixon_xml_bind.h"
@ -1007,6 +1008,15 @@ xml_yang_validate_add(clicon_handle h,
cg_var *cv0; cg_var *cv0;
enum cv_type cvtype; 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 /* if not given by argument (overide) use default link
and !Node has a config sub-statement and it is false */ and !Node has a config sub-statement and it is false */
if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0){ if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0){
@ -1215,6 +1225,13 @@ xml_yang_validate_all(clicon_handle h,
cvec *nsc = NULL; cvec *nsc = NULL;
int hit = 0; 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 /* if not given by argument (overide) use default link
and !Node has a config sub-statement and it is false */ and !Node has a config sub-statement and it is false */
if ((yt = xml_spec(xt)) == NULL){ if ((yt = xml_spec(xt)) == NULL){

View file

@ -82,6 +82,11 @@
#include "clixon_xml_map.h" #include "clixon_xml_map.h"
#include "clixon_yang_parse_lib.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 /*! Create modstate structure
* *
* @retval md modstate struct * @retval md modstate struct
@ -826,10 +831,10 @@ yang_metadata_init(clicon_handle h)
return retval; 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 * This function is used where a yang-lib module-set is available to populate
* XML mount-point. * an XML mount-point.
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] xylib yang-lib XML tree on the form <yang-lib>... * @param[in] xylib yang-lib XML tree on the form <yang-lib>...
* @param[in] yspec Will be populated with YANGs, is consumed * @param[in] yspec Will be populated with YANGs, is consumed
@ -860,14 +865,16 @@ yang_lib2yspec(clicon_handle h,
continue; continue;
if ((revision = xml_find_body(xi, "revision")) == NULL) if ((revision = xml_find_body(xi, "revision")) == NULL)
continue; continue;
if (yang_spec_parse_module(h, name, revision, yspec) < 0) if (yang_parse_module(h, name, revision, yspec, NULL) == NULL)
goto fail; goto fail;
} }
#ifdef YANG_SCHEMA_MOUNT_YANG_LIB_FORCE #ifdef YANG_SCHEMA_MOUNT_YANG_LIB_FORCE
/* XXX: Ensure yang-lib is always there otherwise get state dont work for mountpoint */ /* 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; goto fail;
#endif #endif
if (yang_parse_post(h, yspec, 0) < 0)
goto done;
retval = 1; retval = 1;
done: done:
if (vec) if (vec)

View file

@ -1059,7 +1059,7 @@ yang_parse_filename(const char *filename,
* *
* See top of file for diagram of calling order * See top of file for diagram of calling order
*/ */
static yang_stmt * yang_stmt *
yang_parse_module(clicon_handle h, yang_parse_module(clicon_handle h,
const char *module, const char *module,
const char *revision, const char *revision,

View file

@ -459,11 +459,6 @@ yang_schema_yanglib_parse_mount(clicon_handle h,
goto done; goto done;
if (ret == 0) if (ret == 0)
goto anydata; 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) if (xml_yang_mount_set(xt, yspec) < 0)
goto done; goto done;
retval = 1; retval = 1;

View file

@ -227,7 +227,7 @@ main(int argc,
goto done; goto done;
} }
if (commit){ 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; goto done;
} }
else{ else{