diff --git a/lib/src/clixon_validate.c b/lib/src/clixon_validate.c index 4e0c195b9..e72a0d7ee 100644 --- a/lib/src/clixon_validate.c +++ b/lib/src/clixon_validate.c @@ -283,6 +283,25 @@ leafref_opt_cache_new(yang_stmt *ys, return 0; } +/*! Count children of xp with yang spec ys + * + * @param[in] xp XML parent + * @param[in] ys Yang spec of children to count + * @retval n Number of children + */ +static size_t +leafref_opt_count(cxobj *xp, + yang_stmt *ys) +{ + cxobj *x = NULL; + size_t n = 0; + + while ((x = xml_child_each(xp, x, CX_ELMNT)) != NULL) + if (xml_spec(x) == ys) + n++; + return n; +} + /*! Detect if binary search can be used * * If xlen is very large, this takes time @@ -294,6 +313,7 @@ leafref_opt_cache_new(yang_stmt *ys, * IF yang of all elements is same YANG * AND that yang is LEAF-LIST AND is ordered-by system * OR that yang's parent is LIST AND is ordered-by system + * AND xvec contains all such siblings, ie not filtered by xpath predicates * THEN use binary search * @param[in] xvec Vector of matching XML values * @param[in] xlen Length of xvec @@ -369,6 +389,15 @@ leafref_opt_search_detect(cxobj **xvec, } } if (i == xlen && x0 != NULL && xml_parent(x0) && xml_spec(x0)){ + /* Binary search covers all siblings, but xvec may be a subset filtered by + * xpath predicates, eg ../iface[enabled='true']/name + */ + if (is_list){ + if (xpp == NULL || leafref_opt_count(xpp, y0p) != xlen) + return 0; + } + else if (leafref_opt_count(x0p, y0) != xlen) + return 0; *search = 1; *x0pp = x0; } diff --git a/test/test_leafref.sh b/test/test_leafref.sh index 7c902e246..69ec1f97d 100755 --- a/test/test_leafref.sh +++ b/test/test_leafref.sh @@ -99,7 +99,18 @@ module example{ leaf template{ type leafref{ path "/sender/name"; - require-instance true; + require-instance true; + } + } + leaf enabled{ + type boolean; + } + /* leafref filtered by predicate: binary search must not match + * entries excluded by the predicate */ + leaf active-template{ + type leafref{ + path "/sender[enabled='true']/name"; + require-instance true; } } } @@ -279,6 +290,24 @@ expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" " new "issue 669: discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" +# Leafref path with predicate on the list: xvec is a subset of the list entries. +# LEAFREF_OPTIMIZE binary search must not be used, it searches all entries and +# would accept a reference to an entry excluded by the predicate. +new "leafref predicate: add senders s1,s3 enabled, s2 disabled, s4 refers to disabled s2" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "s1trues2falses3trues4s2" "" "" + +new "leafref predicate: validate expect failure (s2 is disabled)" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" + +new "leafref predicate: set s4 to refer to enabled s3" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "s4s3" "" "" + +new "leafref predicate: validate expect OK (s3 is enabled)" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" + +new "leafref predicate: discard-changes" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" + # Leafref to non-key leaf in a list: LEAFREF_OPTIMIZE binary search must not # be used when the target leaf is not the list key. With two routers present # (key "vrf-id"), the target leaf "area-tag" is a non-key unique leaf.