diff --git a/lib/src/clixon_xml_bind.c b/lib/src/clixon_xml_bind.c index ab84f1737..eb4a3a304 100644 --- a/lib/src/clixon_xml_bind.c +++ b/lib/src/clixon_xml_bind.c @@ -168,13 +168,22 @@ populate_self_parent(clixon_handle h, yang_stmt *yspec1; yang_stmt *ymod; int ret; + int ns_resolved = 0; name = xml_name(xt); /* optimization for massive lists - use the first element as role model */ if (xsibling && xml_child_nr_type(xt, CX_ATTR) == 0){ - y = xml_spec(xsibling); - goto set; + if ((y = xml_spec(xsibling)) != NULL){ + if (xml2ns(xt, xml_prefix(xt), &ns) < 0) + goto done; + ns_resolved++; + nsy = yang_find_mynamespace(y); + if (nsy != NULL && ns != NULL && strcmp(ns, nsy) == 0) + goto set; + y = NULL; + nsy = NULL; + } } if ((xp = xml_parent(xt)) == NULL){ if (xerr && @@ -194,7 +203,8 @@ populate_self_parent(clixon_handle h, retval = 2; goto done; } - if (xml2ns(xt, xml_prefix(xt), &ns) < 0) + if (!ns_resolved && + xml2ns(xt, xml_prefix(xt), &ns) < 0) goto done; /* Special case since action is not a datanode */ if ((y = yang_find(yparent, Y_ACTION, name)) == NULL){ diff --git a/test/test_xml_bind_namespace_collision.sh b/test/test_xml_bind_namespace_collision.sh new file mode 100755 index 000000000..a331b2628 --- /dev/null +++ b/test/test_xml_bind_namespace_collision.sh @@ -0,0 +1,206 @@ +#!/usr/bin/env bash +# Reproduce sibling namespace collision during XML/YANG bind/translate. +# Two modules use the same local root/container/list names, but different +# namespaces. The UM branch is valid in its own module, but show/translate +# currently binds its subtree against the locald module. + +# 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 + +clispec=$dir/$APPNAME/clispec +mkdir -p "$clispec" + +dbdir=$(mktemp -d "$dir/${APPNAME}.xmldb.XXXXXX") +rundir=$(mktemp -d "$dir/${APPNAME}.run.XXXXXX") + +chmod 777 "$dbdir" "$rundir" + +cfg=$dir/conf_yang.xml + +cat < $cfg + + $cfg + *:* + ${YANG_INSTALLDIR} + $dir + $dir + $clispec + $APPNAME + $rundir/$APPNAME.sock + $rundir/$APPNAME.pidfile + $dbdir + +EOF + +cat < $clispec/example_cli.cli +CLICON_MODE="$APPNAME"; +CLICON_PROMPT="%U@%H %W> "; + +show("Show a particular state of the system"){ + configuration("Show configuration"), cli_show_config("running", "xml", "/"); +} +quit("Quit"), cli_quit(); +EOF + +cat <<'EOF' > $dir/Cisco-IOS-XR-aaa-lib-cfg@2020-10-22.yang +module Cisco-IOS-XR-aaa-lib-cfg { + yang-version 1.1; + namespace "http://cisco.com/ns/yang/Cisco-IOS-XR-aaa-lib-cfg"; + prefix aaa-lib; + + revision 2020-10-22; + + container aaa; +} +EOF + +cat <<'EOF' > $dir/Cisco-IOS-XR-aaa-locald-cfg@2022-11-28.yang +module Cisco-IOS-XR-aaa-locald-cfg { + yang-version 1.1; + namespace "http://cisco.com/ns/yang/Cisco-IOS-XR-aaa-locald-cfg"; + prefix aaa-locald; + + import Cisco-IOS-XR-aaa-lib-cfg { + prefix aaa-lib; + } + + revision 2022-11-28; + + augment "/aaa-lib:aaa" { + container usernames { + list username { + key "ordering-index name"; + leaf ordering-index { + type uint32; + } + leaf name { + type string; + } + container secret { + leaf type { + type enumeration { + enum type10; + } + } + leaf secret10 { + when "../type = 'type10'"; + type string; + } + } + } + } + } +} +EOF + +cat <<'EOF' > $dir/Cisco-IOS-XR-um-aaa-cfg@2023-09-07.yang +module Cisco-IOS-XR-um-aaa-cfg { + yang-version 1.1; + namespace "http://cisco.com/ns/yang/Cisco-IOS-XR-um-aaa-cfg"; + prefix um-aaa; + + revision 2023-09-07; + + container aaa; +} +EOF + +cat <<'EOF' > $dir/Cisco-IOS-XR-um-aaa-task-user-cfg@2023-02-15.yang +module Cisco-IOS-XR-um-aaa-task-user-cfg { + yang-version 1.1; + namespace "http://cisco.com/ns/yang/Cisco-IOS-XR-um-aaa-task-user-cfg"; + prefix um-aaa-task-user; + + import Cisco-IOS-XR-um-aaa-cfg { + prefix um-aaa; + } + + revision 2023-02-15; + + augment "/um-aaa:aaa" { + container usernames { + list username { + key "ordering-index name"; + leaf ordering-index { + type uint32; + } + leaf name { + type string; + } + container secret { + leaf ten { + type string; + } + } + } + } + } +} +EOF + +cat <<'EOF' > $dbdir/startup_db + + + + + 0 + root + + type10 + xx + + + + + + + + 0 + root + + xx + + + + + +EOF + +new "test params: -f $cfg" +if [ $BE -ne 0 ]; then + new "kill old backend" + $clixon_backend -z -f $cfg >/dev/null 2>&1 || true + new "start backend -s startup -f $cfg" + $clixon_backend -D $DBG -s startup -f $cfg + if [ $? -ne 0 ]; then + err + fi +fi + +new "wait backend" +wait_backend + +new "show configuration preserves namespace-specific secret leaves" +expectpart "$($clixon_cli -1 -f $cfg show configuration 2>&1)" 0 \ + "" \ + "" \ + "type10" \ + "xx" \ + "" \ + "" \ + "xx" + +if [ $BE -ne 0 ]; then + new "Kill backend" + $clixon_backend -z -f $cfg + if [ $? -ne 0 ]; then + err "kill backend" + fi +fi + +rm -rf "$dir" + +new "endtest" +endtest