diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 5e393c4a..67064502 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -568,6 +568,7 @@ main(int argc, */ clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(dbg, NULL); + yang_init(h); /* Find and read configfile */ if (clicon_options_main(h) < 0){ diff --git a/apps/cli/cli_auto.c b/apps/cli/cli_auto.c index 8ca1eafe..86395a46 100644 --- a/apps/cli/cli_auto.c +++ b/apps/cli/cli_auto.c @@ -759,8 +759,8 @@ cli_auto_show(clicon_handle h, cli_xml2cli(xc, prefix, gt, cligen_output); /* cli syntax */ break; case FORMAT_NETCONF: - fprintf(stdout, "", - NETCONF_BASE_NAMESPACE); + fprintf(stdout, "", + NETCONF_BASE_NAMESPACE, NETCONF_MESSAGE_ID_ATTR); if (pretty) fprintf(stdout, "\n"); if (isroot) diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 90f118e9..ad483d56 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -801,7 +801,7 @@ load_config_file(clicon_handle h, cxobj *xt = NULL; cxobj *x; cbuf *cbxml; - char *formatstr; + char *formatstr = NULL; enum format_enum format = FORMAT_XML; if (cvec_len(argv) < 2 || cvec_len(argv) > 4){ @@ -908,6 +908,7 @@ save_config_file(clicon_handle h, char *dbstr; char *varstr; cxobj *xt = NULL; + cxobj *x; cxobj *xerr; FILE *f = NULL; enum genmodel_type gt; @@ -970,21 +971,25 @@ save_config_file(clicon_handle h, goto done; break; case FORMAT_TEXT: - cli_xml2txt(xt, cligen_output, 0); /* tree-formed text */ + if (xml2txt(f, xt, 0) < 0) + goto done; break; case FORMAT_CLI: if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR) goto done; - if (xml2cli(f, xt, prefix, gt) < 0) - goto done; + x = NULL; + while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) { + if (xml2cli(f, x, prefix, gt) < 0) + goto done; + } break; case FORMAT_NETCONF: - fprintf(f, "", - NETCONF_BASE_NAMESPACE); + fprintf(f, "", + NETCONF_BASE_NAMESPACE, NETCONF_MESSAGE_ID_ATTR); fprintf(f, "\n"); if (clicon_xml2file(f, xt, 0, pretty) < 0) goto done; - fprintf(f, "]]>]]>\n"); + fprintf(f, "]]>]]>\n"); break; } /* switch */ retval = 0; diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index f085d539..c16f190b 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -483,8 +483,8 @@ main(int argc, * Logs, error and debug to stderr or syslog, set debug level */ clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst); - clicon_debug_init(dbg, NULL); + yang_init(h); /* Find, read and parse configfile */ if (clicon_options_main(h) < 0){ @@ -651,7 +651,7 @@ main(int argc, if ((yspec = yspec_new()) == NULL) goto done; clicon_dbspec_yang_set(h, yspec); - + /* Load Yang modules * 1. Load a yang module as a specific absolute filename */ if ((str = clicon_yang_main_file(h)) != NULL){ diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 86b0b713..32e22d4a 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -710,7 +710,8 @@ main(int argc, */ clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(dbg, NULL); - + yang_init(h); + /* Find, read and parse configfile */ if (clicon_options_main(h) < 0) goto done; diff --git a/apps/restconf/restconf_main_fcgi.c b/apps/restconf/restconf_main_fcgi.c index bb4ce85c..91e16b26 100644 --- a/apps/restconf/restconf_main_fcgi.c +++ b/apps/restconf/restconf_main_fcgi.c @@ -296,6 +296,7 @@ main(int argc, goto done; } + yang_init(h); /* Find and read configfile */ if (clicon_options_main(h) < 0) goto done; @@ -375,6 +376,7 @@ main(int argc, if ((yspec = yspec_new()) == NULL) goto done; clicon_dbspec_yang_set(h, yspec); + /* Initialize plugin module by creating a handle holding plugin and callback lists */ if (clixon_plugin_module_init(h) < 0) goto done; diff --git a/apps/restconf/restconf_main_native.c b/apps/restconf/restconf_main_native.c index ddad2d71..49e53278 100644 --- a/apps/restconf/restconf_main_native.c +++ b/apps/restconf/restconf_main_native.c @@ -1731,6 +1731,7 @@ restconf_clixon_init(clicon_handle h, if ((yspec = yspec_new()) == NULL) goto done; clicon_dbspec_yang_set(h, yspec); + /* Load restconf plugins before yangs are loaded (eg extension callbacks) */ if ((dir = clicon_restconf_dir(h)) != NULL) if (clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0) @@ -1987,6 +1988,7 @@ main(int argc, clicon_err(OE_DAEMON, errno, "Setting signal"); goto done; } + yang_init(h); /* Find and read configfile */ if (clicon_options_main(h) < 0) goto done; diff --git a/example/main/example_cli.c b/example/main/example_cli.c index f95435f8..f7a157cf 100644 --- a/example/main/example_cli.c +++ b/example/main/example_cli.c @@ -101,10 +101,11 @@ example_client_rpc(clicon_handle h, cva = cvec_find(cvv, "a"); /* get a cligen variable from vector */ /* Create XML for example netconf RPC */ if (clixon_xml_parse_va(YB_NONE, NULL, &xtop, NULL, - "" + "" "%s", NETCONF_BASE_NAMESPACE, clicon_username_get(h), + NETCONF_MESSAGE_ID_ATTR, cv_string_get(cva)) < 0) goto done; /* Skip top-level */ diff --git a/example/main/example_cli.cli b/example/main/example_cli.cli index 8afa850b..deecf153 100644 --- a/example/main/example_cli.cli +++ b/example/main/example_cli.cli @@ -99,6 +99,8 @@ save("Save candidate configuration to XML file") ("Filename (lo cli("Save configuration as CLI commands"), save_config_file("candidate","filename", "cli"); xml("Save configuration as XML"), save_config_file("candidate","filename", "xml"); json("Save configuration as JSON"), save_config_file("candidate","filename", "json"); + text("Save configuration as TEXT"), save_config_file("candidate","filename", "text"); + netconf("Save configuration as NETCONF"), save_config_file("candidate","filename", "netconf"); } load("Load configuration from XML file") ("Filename (local filename)"),load_config_file("filename", "replace");{ replace("Replace candidate with file contents"), load_config_file("filename", "replace");{ diff --git a/include/clixon_custom.h b/include/clixon_custom.h index fcf0582d..2537502e 100644 --- a/include/clixon_custom.h +++ b/include/clixon_custom.h @@ -139,3 +139,8 @@ * Consider enabling this option permanently after 5.4 */ #define YANG_ORDERING_WHEN_LAST + +/*! Use Ancestor config cache + * The cache uses two yang stmt flag bits. One to say it is active, the second its value + */ +#define USE_CONFIG_FLAG_CACHE diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 8df96b14..187694f3 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -61,6 +61,10 @@ #define YANG_FLAG_INDEX 0x08 /* This yang node under list is (extra) index. --> you can access * list elements using this index with binary search */ #endif +#ifdef USE_CONFIG_FLAG_CACHE +#define YANG_FLAG_CONFIG_CACHE 0x10 /* Ancestor config cache is active */ +#define YANG_FLAG_CONFIG_VALUE 0x20 /* Ancestor config cache value */ +#endif /* * Types @@ -272,5 +276,6 @@ int yang_type_cache_set(yang_stmt *ys, yang_stmt *resolved, int options, yang_stmt *yang_anydata_add(yang_stmt *yp, char *name); int yang_extension_value(yang_stmt *ys, char *name, char *ns, int *exist, char **value); int yang_sort_subelements(yang_stmt *ys); +int yang_init(clicon_handle h); #endif /* _CLIXON_YANG_H_ */ diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 5056517a..04479f7e 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -3190,11 +3190,29 @@ yang_config_ancestor(yang_stmt *ys) yp = ys; do { - if (yang_config(yp) == 0) +#ifdef USE_CONFIG_FLAG_CACHE + if (yang_flag_get(yp, YANG_FLAG_CONFIG_CACHE)) + return yang_flag_get(yp, YANG_FLAG_CONFIG_VALUE)?1:0; +#endif + if (yang_config(yp) == 0){ +#ifdef USE_CONFIG_FLAG_CACHE + yang_flag_set(yp, YANG_FLAG_CONFIG_CACHE); + yang_flag_reset(yp, YANG_FLAG_CONFIG_VALUE); +#endif return 0; - if (yang_keyword_get(yp) == Y_INPUT || yang_keyword_get(yp) == Y_OUTPUT || yang_keyword_get(yp) == Y_NOTIFICATION) + } + if (yang_keyword_get(yp) == Y_INPUT || yang_keyword_get(yp) == Y_OUTPUT || yang_keyword_get(yp) == Y_NOTIFICATION){ +#ifdef USE_CONFIG_FLAG_CACHE + yang_flag_set(yp, YANG_FLAG_CONFIG_CACHE); + yang_flag_reset(yp, YANG_FLAG_CONFIG_VALUE); +#endif return 0; + } } while((yp = yang_parent_get(yp)) != NULL); +#ifdef USE_CONFIG_FLAG_CACHE + yang_flag_set(ys, YANG_FLAG_CONFIG_CACHE); + yang_flag_set(ys, YANG_FLAG_CONFIG_VALUE); +#endif return 1; } @@ -3678,6 +3696,12 @@ yang_sort_subelements(yang_stmt *ys) return retval; } +int +yang_init(clicon_handle h) +{ + return yang_cardinality_init(h); +} + #ifdef XML_EXPLICIT_INDEX /*! Mark element as search_index in list * @retval 0 OK diff --git a/lib/src/clixon_yang_cardinality.c b/lib/src/clixon_yang_cardinality.c index b783dcd4..966543ae 100644 --- a/lib/src/clixon_yang_cardinality.c +++ b/lib/src/clixon_yang_cardinality.c @@ -111,11 +111,11 @@ struct ycard{ * 1 10 * 0..1 149 * 0..n 176 (no restrictions) - * @note assume array is ordered wrt parent + * @note The array MUST be ordered wrt parent and child for ycard_find_binary to use binary search * @note yang-version is optional in RFC6020 but mandatory in RFC7950, if not given, it defaults to 1. */ #define NMAX 1000000 /* Just a large number */ -static const struct ycard yclist[] = { +static const struct ycard _yclist[] = { {Y_ACTION, Y_DESCRIPTION, 0, 1, 0}, {Y_ACTION, Y_GROUPING, 0, NMAX, 0}, {Y_ACTION, Y_IF_FEATURE, 0, NMAX, 0}, @@ -176,6 +176,7 @@ static const struct ycard yclist[] = { {Y_CASE, Y_STATUS, 0, 1, 0}, {Y_CASE, Y_USES, 0, NMAX, 0}, {Y_CASE, Y_WHEN, 0, 1, 0}, + {Y_CHOICE, Y_ANYDATA, 0, NMAX, 0}, {Y_CHOICE, Y_ANYXML, 0, NMAX, 0}, {Y_CHOICE, Y_CASE, 0, NMAX, 0}, {Y_CHOICE, Y_CHOICE, 0, NMAX, 0}, @@ -191,7 +192,6 @@ static const struct ycard yclist[] = { {Y_CHOICE, Y_REFERENCE, 0, 1, 0}, {Y_CHOICE, Y_STATUS, 0, 1, 0}, {Y_CHOICE, Y_WHEN, 0, 1, 0}, - {Y_CHOICE, Y_ANYDATA, 0, NMAX, 0}, {Y_CONTAINER, Y_ACTION, 0, NMAX, 0}, {Y_CONTAINER, Y_ANYDATA, 0, NMAX, 0}, {Y_CONTAINER, Y_ANYXML, 0, NMAX, 0}, @@ -451,37 +451,22 @@ static const struct ycard yclist[] = { {Y_USES, Y_REFINE, 0, NMAX, 0}, {Y_USES, Y_STATUS, 0, 1, 0}, {Y_USES, Y_WHEN, 0, 1, 0}, + {Y_WHEN, Y_DESCRIPTION, 0, 1, 0}, + {Y_WHEN, Y_REFERENCE, 0, 1, 0}, {0,} }; -/*! Find yang parent and child combination in yang cardinality table - * @param[in] parent Parent Yang spec - * @param[in] child Child yang spec if 0 first - * @param[in] yc Yang cardinality map - * @param[in] p If set, quit as soon as parents dont match - * @retval NULL Not found - * @retval yp Found - * @note if cardinal list above is sorted, this search could do binary +/* Search matrix for lookups */ +static const struct ycard *_yc_search[Y_SPEC][Y_SPEC] = {0,}; + +/* Set to 1 if exists in search + * Some yang statements are not explicitly given cardinalities in RFC7950, although they are + * present in Section 14 BNF. + * But since the table above is from the explicit cardinalities in the RFC the others are skipped + * and = 0 in the following vector. + * Example: Y_REFINE */ -static const struct ycard * -ycard_find(enum rfc_6020 parent, - enum rfc_6020 child, - const struct ycard *yclist, - int p) -{ - const struct ycard *yc; - - for (yc = &yclist[0]; (int)yc->yc_parent; yc++){ - if (yc->yc_parent == parent){ - if (!child || yc->yc_child == child) - return yc; - } - else - if (p) - return NULL; /* premature quit */ - } - return NULL; -} +static int _yc_exist[Y_SPEC] = {0,}; /*! Check cardinality, ie if each yang node has the expected nr of children * @param[in] h Clicon handle @@ -503,16 +488,14 @@ yang_cardinality(clicon_handle h, int pk; int ck; int i; - int nr; - const struct ycard *ycplist; /* ycard parent table*/ const struct ycard *yc; int order; yang_stmt *yprev = NULL; + int nr; pk = yang_keyword_get(yt); - /* 0) Find parent sub-parts of cardinality vector */ - if ((ycplist = ycard_find(pk, 0, yclist, 0)) == NULL) - goto ok; /* skip */ + if (_yc_exist[pk] == 0) + goto ok; /* 1) For all children, if neither in 0..n, 0..1, 1 or 1..n ->ERROR * Also: check monotonically increasing order */ @@ -520,10 +503,10 @@ yang_cardinality(clicon_handle h, ys = NULL; while ((ys = yn_each(yt, ys)) != NULL) { ck = yang_keyword_get(ys); - if (ck == Y_UNKNOWN) /* special case */ + if (pk == Y_UNKNOWN || ck == Y_UNKNOWN) /* special case */ continue; /* Find entry in yang cardinality table from parent/child keyword pair */ - if ((yc = ycard_find(pk, ck, ycplist, 1)) == NULL){ + if ((yc = _yc_search[pk][ck]) == NULL){ clicon_err(OE_YANG, 0, "%s: \"%s\"(%s) is child of \"%s\"(%s), but should not be", modname, yang_key2str(ck), @@ -548,16 +531,16 @@ yang_cardinality(clicon_handle h, yprev = ys; } /* 2) For all in 1 and 1..n list, if 0 such children ->ERROR */ - for (yc = &ycplist[0]; (int)yc->yc_parent == pk; yc++){ + for (i=0; iyc_min && yang_find(yt, yc->yc_child, NULL) == NULL){ clicon_err(OE_YANG, 0, "%s: \"%s\" is missing but is mandatory child of \"%s\"", modname, yang_key2str(yc->yc_child), yang_key2str(pk)); goto done; } - } - /* 3) For all in 0..1 and 1 list, if >1 such children ->ERROR */ - for (yc = &ycplist[0]; (int)yc->yc_parent == pk; yc++){ if (yc->yc_maxyc_child, NULL)) > yc->yc_max){ clicon_err(OE_YANG, 0, "%s: \"%s\" has %d children of type \"%s\", but only %d allowed", @@ -569,7 +552,6 @@ yang_cardinality(clicon_handle h, goto done; } } - /* 4) Recurse */ i = 0; while (i< yang_len_get(yt)){ /* Note, children may be removed cant use yn_each */ @@ -601,7 +583,7 @@ yang_cardinality_interval(clicon_handle h, int retval = -1; const struct ycard *ycplist; /* ycard parent table*/ - if ((ycplist = ycard_find(parent_key, child_key, yclist, 0)) == NULL){ + if ((ycplist = _yc_search[parent_key][child_key]) == NULL){ clicon_err(OE_YANG, EINVAL, "keys %d %d do not have cardinality", parent_key, child_key); goto done; @@ -612,3 +594,17 @@ yang_cardinality_interval(clicon_handle h, done: return retval; } + +/*! Init */ +int +yang_cardinality_init(clicon_handle h) +{ + const struct ycard *yc; + + for (yc = &_yclist[0]; (int)yc->yc_parent; yc++){ + _yc_exist[yc->yc_parent] = 1; + _yc_search[yc->yc_parent][yc->yc_child] = yc; + } + return 0; +} + diff --git a/lib/src/clixon_yang_cardinality.h b/lib/src/clixon_yang_cardinality.h index ed3b350f..38ed70c6 100644 --- a/lib/src/clixon_yang_cardinality.h +++ b/lib/src/clixon_yang_cardinality.h @@ -39,7 +39,7 @@ * Prototypes */ int yang_cardinality(clicon_handle h, yang_stmt *yt, char *modname); - int yang_cardinality_interval(clicon_handle h, enum rfc_6020 parent_key, enum rfc_6020 child_key, int *min, int *max); +int yang_cardinality_init(clicon_handle h); #endif /* _CLIXON_YANG_CARDINALITY_H_ */ diff --git a/test/test_cli_auto.sh b/test/test_cli_auto.sh index 228fa5a8..2f799521 100755 --- a/test/test_cli_auto.sh +++ b/test/test_cli_auto.sh @@ -271,9 +271,7 @@ edit table show config netconf EOF new "show config netconf" -expectpart "$(cat $fin | $clixon_cli -f $cfg 2>&1)" 0 'a42]]>]]>' - -endtest +expectpart "$(cat $fin | $clixon_cli -f $cfg 2>&1)" 0 "a42]]>]]>" if [ $BE -ne 0 ]; then new "Kill backend" @@ -287,3 +285,6 @@ if [ $BE -ne 0 ]; then fi rm -rf $dir + +new "endtest" +endtest diff --git a/test/test_openconfig_interfaces.sh b/test/test_openconfig_interfaces.sh index d1302a76..572d9132 100755 --- a/test/test_openconfig_interfaces.sh +++ b/test/test_openconfig_interfaces.sh @@ -17,12 +17,14 @@ if [ ! -d "$OPENCONFIG" ]; then if [ "$s" = $0 ]; then exit 0; else return 0; fi fi +OCDIR=$OPENCONFIG/release/models + cat < $cfg $cfg ietf-netconf:startup /usr/local/share/clixon - $OPENCONFIG + $OCDIR $fyang /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/cli diff --git a/test/test_openconfig_network_instance.sh b/test/test_openconfig_network_instance.sh new file mode 100755 index 00000000..b773f832 --- /dev/null +++ b/test/test_openconfig_network_instance.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash +# Tests for openconfig network-instances +# See eg https://github.com/clicon/clixon/issues/287 + +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +APPNAME=example + +cfg=$dir/conf_yang.xml +fyang=$dir/clixon-example.yang + +new "openconfig" +if [ ! -d "$OPENCONFIG" ]; then +# err "Hmm Openconfig dir does not seem to exist, try git clone https://github.com/openconfig/public?" + echo "...skipped: OPENCONFIG not set" + if [ "$s" = $0 ]; then exit 0; else return 0; fi +fi + +OCDIR=$OPENCONFIG/release/models + +cat < $cfg + + $cfg + ietf-netconf:startup + /usr/local/share/clixon + $OCDIR + $fyang + /usr/local/lib/$APPNAME/clispec + /usr/local/lib/$APPNAME/cli + $APPNAME + $APPNAME + clixon-restconf ietf-interfaces + VARS + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/var/$APPNAME/$APPNAME.pidfile + $dir + true + +EOF + +# First using ietf-interfaces (not openconfig-interfaces) +# Example yang +cat < $fyang +module clixon-example{ + yang-version 1.1; + namespace "urn:example:example"; + prefix ex; + + import openconfig-network-instance { + prefix oc-netinst; + } +} +EOF + +# Example system +cat < $dir/startup_db + + + + + 0 /* XXX */ + + + + + + default + + + false + + + + oc-ni-types:DEFAULT_INSTANCE + true + 1.2.3.4 + + + + +EOF + +if [ $BE -ne 0 ]; then + new "kill old backend" + sudo clixon_backend -zf $cfg + if [ $? -ne 0 ]; then + err + fi + sudo pkill -f clixon_backend # to be sure + + new "start backend -s startup -f $cfg" + start_backend -s startup -f $cfg +fi + +new "wait backend" +wait_backend + +new "$clixon_cli -D $DBG -1f $cfg show version" +expectpart "$($clixon_cli -D $DBG -1f $cfg show version)" 0 "${CLIXON_VERSION}" + +new "$clixon_cli -D $DBG -1f $cfg save config as cli" +expectpart "$($clixon_cli -D $DBG -1f $cfg save $dir/config.cli cli)" 0 "^$" + +new "Check saved config" +expectpart "$(cat $dir/config.cli)" 0 "set network-instances network-instance default config type oc-ni-types:DEFAULT_INSTANCE" "set network-instances network-instance default config router-id 1.2.3.4" + +new "load saved cli config" +expectpart "$(cat $dir/config.cli | $clixon_cli -D $DBG -f $cfg 2>&1 > /dev/null)" 0 "^$" + +if [ $BE -ne 0 ]; then + new "Kill backend" + # Check if premature kill + pid=$(pgrep -u root -f clixon_backend) + if [ -z "$pid" ]; then + err "backend already dead" + fi + # kill backend + stop_backend -f $cfg +fi + +rm -rf $dir + +new "endtest" +endtest diff --git a/test/test_openconfig_system.sh b/test/test_openconfig_system.sh new file mode 100755 index 00000000..565b4686 --- /dev/null +++ b/test/test_openconfig_system.sh @@ -0,0 +1,179 @@ +#!/usr/bin/env bash +# Run a system around openconfig interface, ie: openconfig-if-ethernet +# Note first variant uses ietf-interfaces, maybe remove this? + +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +APPNAME=example + +cfg=$dir/conf_yang.xml +fyang=$dir/clixon-example.yang + +echo "...skipped: wrong" +if [ "$s" = $0 ]; then exit 0; else return 0; fi + +new "openconfig" +if [ ! -d "$OPENCONFIG" ]; then +# err "Hmm Openconfig dir does not seem to exist, try git clone https://github.com/openconfig/public?" + echo "...skipped: OPENCONFIG not set" + if [ "$s" = $0 ]; then exit 0; else return 0; fi +fi + +OCDIR=$OPENCONFIG/release/models + +cat < $cfg + + $cfg + ietf-netconf:startup + /usr/local/share/clixon + $OCDIR + $fyang + /usr/local/lib/$APPNAME/clispec + /usr/local/lib/$APPNAME/cli + $APPNAME + $APPNAME + clixon-restconf ietf-interfaces + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/var/$APPNAME/$APPNAME.pidfile + $dir + true + +EOF + +# First using ietf-interfaces (not openconfig-interfaces) +# Example yang +cat < $fyang +module clixon-example{ + yang-version 1.1; + namespace "urn:example:example"; + prefix ex; + + import openconfig-system { + prefix oc-sys; + } +} +EOF + +# Example system +cat < $dir/startup_db + + +EOF + +if [ $BE -ne 0 ]; then + new "kill old backend" + sudo clixon_backend -zf $cfg + if [ $? -ne 0 ]; then + err + fi + sudo pkill -f clixon_backend # to be sure + + new "start backend -s startup -f $cfg" + start_backend -s startup -f $cfg +fi + +new "wait backend" +wait_backend + +new "$clixon_cli -D $DBG -1f $cfg show version" +expectpart "$($clixon_cli -D $DBG -1f $cfg show version)" 0 "${CLIXON_VERSION}" + +new "$clixon_netconf -qf $cfg" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^eeex:ethfalsetrue00]]>]]>" + +new "cli show configuration" +expectpart "$($clixon_cli -1 -f $cfg show conf xml)" 0 "^" --not-- "" + +new "cli set interfaces interface complete: e" +expectpart "$(echo "set interfaces interface " | $clixon_cli -f $cfg)" 0 "interface e" + +# XXX See https://github.com/clicon/clixon/issues/218 +#new "cli set interfaces interface e complete: not ethernet" +#expectpart "$(echo "set interfaces interface e " | $clixon_cli -f $cfg)" 0 config hold-time subinterfaces --not-- ethernet + +if [ $BE -ne 0 ]; then + new "Kill backend" + # Check if premature kill + pid=$(pgrep -u root -f clixon_backend) + if [ -z "$pid" ]; then + err "backend already dead" + fi + # kill backend + stop_backend -f $cfg +fi + +# Second using openconfig-interfaces instead +# Example yang +cat < $fyang +module clixon-example{ + yang-version 1.1; + namespace "urn:example:example"; + prefix ex; + + import openconfig-vlan { + prefix oc-vlan; + } + import openconfig-if-ethernet { + prefix oc-eth; + } +} +EOF + +# Example system +cat < $dir/startup_db + + + + eth1 + + eth1 + ianaift:ethernetCsmacd + 9206 + true + oc-vlan-types:TPID_0X8100 + + + + 2c:53:4a:09:59:73 + + + + + +EOF + +if [ $BE -ne 0 ]; then + new "kill old backend" + sudo clixon_backend -zf $cfg + if [ $? -ne 0 ]; then + err + fi + sudo pkill -f clixon_backend # to be sure + + new "start backend -s startup -f $cfg" + start_backend -s startup -f $cfg +fi + +new "wait backend" +wait_backend + +new "$clixon_cli -D $DBG -1f $cfg show version" +expectpart "$($clixon_cli -D $DBG -1f $cfg show version)" 0 "${CLIXON_VERSION}" + +if [ $BE -ne 0 ]; then + new "Kill backend" + # Check if premature kill + pid=$(pgrep -u root -f clixon_backend) + if [ -z "$pid" ]; then + err "backend already dead" + fi + # kill backend + stop_backend -f $cfg +fi + + +rm -rf $dir + +new "endtest" +endtest diff --git a/util/clixon_util_path.c b/util/clixon_util_path.c index 7f7a034e..3e4debe1 100644 --- a/util/clixon_util_path.c +++ b/util/clixon_util_path.c @@ -162,6 +162,7 @@ main(int argc, break; } clicon_debug_init(dbg, NULL); + yang_init(h); /* Parse yang */ if (yang_file_dir){