diff --git a/CHANGELOG.md b/CHANGELOG.md
index 207c5843..11165081 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -50,6 +50,8 @@ Expected: May 2020
### Minor changes
+* Added option `CLICON_YANG_UNKNOWN_ANYDATA` to treat unknown XML (wrt YANG) as anydata.
+ * This is to be (very) forgiving but you need to accept eg unsynchronized YANG and XML
* Compile-time option: `USE_CLIGEN44` for running clixon-45 with cligen-44.
* Temporary fix since cligen-45 have some non-backward compatible behaviour.
* Optimizations
diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c
index bf90e137..91c4f9c5 100644
--- a/apps/backend/backend_main.c
+++ b/apps/backend/backend_main.c
@@ -523,7 +523,6 @@ main(int argc,
usage(h, argv[0]);
return -1;
}
-
/* External NACM file? */
nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE");
if (nacm_mode && strcmp(nacm_mode, "external") == 0)
@@ -692,6 +691,9 @@ main(int argc,
clicon_configfile(h));
goto done;
}
+ /* Treat unknown XML as anydata */
+ if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
+ xml_bind_yang_unknown_anydata(1);
/* Publish stream on pubsub channels.
* CLICON_STREAM_PUB should be set to URL to where streams are published
diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c
index 9ad836ce..0a3a9fa4 100644
--- a/apps/cli/cli_main.c
+++ b/apps/cli/cli_main.c
@@ -515,6 +515,10 @@ main(int argc, char **argv)
if (netconf_module_features(h) < 0)
goto done;
+ /* Treat unknwon XML as anydata */
+ if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
+ xml_bind_yang_unknown_anydata(1);
+
/* Create top-level and store as option */
if ((yspec = yspec_new()) == NULL)
goto done;
diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c
index 67a0dc6f..8a9bb9da 100644
--- a/apps/restconf/restconf_main.c
+++ b/apps/restconf/restconf_main.c
@@ -715,6 +715,9 @@ main(int argc,
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
+ /* Treat unknown XML as anydata */
+ if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
+ xml_bind_yang_unknown_anydata(1);
/* Load restconf plugins before yangs are loaded (eg extension callbacks) */
if ((dir = clicon_restconf_dir(h)) != NULL)
diff --git a/lib/clixon/clixon_xml_bind.h b/lib/clixon/clixon_xml_bind.h
index eff92121..55818d81 100644
--- a/lib/clixon/clixon_xml_bind.h
+++ b/lib/clixon/clixon_xml_bind.h
@@ -43,6 +43,7 @@
/*
* Prototypes
*/
+int xml_bind_yang_unknown_anydata(int bool);
int xml_bind_yang_rpc(cxobj *xrpc, yang_stmt *yspec, cxobj **xerr);
int xml_bind_yang_rpc_reply(cxobj *xrpc, char *name, yang_stmt *yspec, cxobj **xerr);
int xml_bind_yang0(cxobj *xt, yang_bind yb, yang_stmt *yspec, cxobj **xerr);
diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c
index bc78f092..1798f6f9 100644
--- a/lib/src/clixon_options.c
+++ b/lib/src/clixon_options.c
@@ -555,7 +555,7 @@ clicon_option_int_set(clicon_handle h,
*/
int
clicon_option_bool(clicon_handle h,
- const char *name)
+ const char *name)
{
char *s;
@@ -563,7 +563,9 @@ clicon_option_bool(clicon_handle h,
return 0;
if (strcmp(s,"true")==0)
return 1;
- return 0; /* Hopefully false, but anything else than "true" */
+ if (strcmp(s,"1")==0)
+ return 1;
+ return 0; /* Hopefully false, but anything else than "true" or "one" */
}
/*! Set option given as bool
@@ -578,8 +580,14 @@ clicon_option_bool_set(clicon_handle h,
{
char s[64];
- if (snprintf(s, sizeof(s)-1, "%u", val) < 0)
+ if (val != 0 && val != 1){
+ clicon_err(OE_CFG, EINVAL, "val is %d, 0 or 1 expected", val);
return -1;
+ }
+ if (snprintf(s, sizeof(s)-1, "%s", val?"true":"false") < 0){
+ clicon_err(OE_CFG, errno, "snprintf");
+ return -1;
+ }
return clicon_option_str_set(h, name, s);
}
diff --git a/lib/src/clixon_validate.c b/lib/src/clixon_validate.c
index b7705dbc..16466235 100644
--- a/lib/src/clixon_validate.c
+++ b/lib/src/clixon_validate.c
@@ -1091,15 +1091,17 @@ xml_yang_validate_all(clicon_handle h,
and !Node has a config sub-statement and it is false */
ys=xml_spec(xt);
if (ys==NULL){
+ if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
+ goto ok;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
- if (xml2ns(xt, xml_prefix(xt), &namespace) < 0)
- goto done;
cprintf(cb, "Failed to find YANG spec of XML node: %s", xml_name(xt));
if ((xp = xml_parent(xt)) != NULL)
cprintf(cb, " with parent: %s", xml_name(xp));
+ if (xml2ns(xt, xml_prefix(xt), &namespace) < 0)
+ goto done;
if (namespace)
cprintf(cb, " in namespace: %s", namespace);
if (netconf_unknown_element_xml(xret, "application", xml_name(xt), cbuf_get(cb)) < 0)
diff --git a/lib/src/clixon_xml_bind.c b/lib/src/clixon_xml_bind.c
index 9bac9ed7..98cd10c7 100644
--- a/lib/src/clixon_xml_bind.c
+++ b/lib/src/clixon_xml_bind.c
@@ -79,6 +79,21 @@
#include "clixon_yang_type.h"
#include "clixon_xml_bind.h"
+/*
+ * Local variables
+ */
+static int _yang_unknown_anydata = 0;
+
+/*! Kludge to equate unknown XML with anydata
+ * The problem with this is that its global and shuld be bound to a handle
+ */
+int
+xml_bind_yang_unknown_anydata(int bool)
+{
+ _yang_unknown_anydata = bool;
+ return 0;
+}
+
/*! After yang binding, bodies of containers and lists are stripped from XML bodies
* May apply to other nodes?
*/
@@ -156,6 +171,10 @@ populate_self_parent(cxobj *xt,
if (xml2ns(xt, xml_prefix(xt), &ns) < 0)
goto done;
if ((y = yang_find_datanode(yparent, name)) == NULL){
+ if (_yang_unknown_anydata){
+ retval = 2; /* treat as anydata */
+ goto done;
+ }
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
@@ -244,6 +263,10 @@ populate_self_top(cxobj *xt,
if (xml2ns(xt, xml_prefix(xt), &ns) < 0)
goto done;
if ((y = yang_find_schemanode(ymod, name)) == NULL){ /* also rpc */
+ if (_yang_unknown_anydata){
+ retval = 2; /* treat as anydata */
+ goto done;
+ }
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
diff --git a/test/lib.sh b/test/lib.sh
index 4a2c82aa..d4d2277b 100755
--- a/test/lib.sh
+++ b/test/lib.sh
@@ -106,6 +106,9 @@ fi
# Backend user
BUSER=clicon
+# If set, unknown XML is treated as ANYDATA
+: ${YANG_UNKNOWN_ANYDATA:=false}
+
# Follow the binary programs that can be parametrized (eg with valgrind)
: ${clixon_cli:=clixon_cli}
diff --git a/test/test_copy_config.sh b/test/test_copy_config.sh
index 07d1c8b7..1aad72ab 100755
--- a/test/test_copy_config.sh
+++ b/test/test_copy_config.sh
@@ -150,7 +150,9 @@ new "copy startup->candidate"
expecteof "$clixon_netconf -qf $cfg" 0 "