Skip to content

Commit a531358

Browse files
committed
schema: add lysc_node_lref_xpath_targets() helper
There is currently no way to retrieve leafref target xpaths from a schema node. The lysc_node_lref_targets() helper returns a node in the schema, but if the xpath itself had added restrictions such as only matching certain list keys, then there was no way to retrieve that information. The `struct lyxp_expr` that contains the xpath is not public, so external users have no way to access this data. This adds the appropriate helper, sharing as much code as possible with lysc_node_lref_targets() and also adds a test case to check for this. Signed-off-by: Brad House <[email protected]>
1 parent 529a594 commit a531358

File tree

3 files changed

+149
-8
lines changed

3 files changed

+149
-8
lines changed

src/tree_schema.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,6 +1927,18 @@ LIBYANG_API_DECL const struct lysc_node *lysc_node_lref_target(const struct lysc
19271927
*/
19281928
LIBYANG_API_DECL LY_ERR lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set);
19291929

1930+
/**
1931+
* @brief Get the target xpath(s) of a leafref node or union node with leafrefs.
1932+
*
1933+
* @param[in] node Term node to use.
1934+
* @param[out] set Set with all the leafref target xpaths, may be empty if the node is a different type or the targets
1935+
* are not found. The set is filled with NULL-terminated "const char *" strings which can be retrieved via the
1936+
* objs member.
1937+
* @return LY_SUCCESS on success.
1938+
* @return LY_ERR value on error.
1939+
*/
1940+
LIBYANG_API_DECL LY_ERR lysc_node_lref_xpath_targets(const struct lysc_node *node, struct ly_set **set);
1941+
19301942
/**
19311943
* @brief Get all the leafref (or union with leafrefs) nodes that target a specific node.
19321944
*

src/tree_schema_common.c

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "tree_edit.h"
4141
#include "tree_schema.h"
4242
#include "tree_schema_internal.h"
43+
#include "xpath.h"
4344

4445
LY_ERR
4546
lysp_check_prefix(struct lysp_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value)
@@ -1847,8 +1848,8 @@ lysc_node_lref_target(const struct lysc_node *node)
18471848
return lysc_type_lref_target(node, ((struct lysc_node_leaf *)node)->type);
18481849
}
18491850

1850-
LIBYANG_API_DEF LY_ERR
1851-
lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set)
1851+
static LY_ERR
1852+
lysc_node_lref_targets_fetch(const struct lysc_node *node, struct ly_set **set, ly_bool return_xpaths)
18521853
{
18531854
LY_ERR rc = LY_SUCCESS;
18541855
struct lysc_type *type;
@@ -1871,16 +1872,32 @@ lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set)
18711872
continue;
18721873
}
18731874

1874-
target = lysc_type_lref_target(node, type_un->types[u]);
1875-
if (target) {
1876-
LY_CHECK_GOTO(rc = ly_set_add(*set, target, 1, NULL), cleanup);
1875+
if (return_xpaths) {
1876+
struct lysc_type_leafref *lref_type = (struct lysc_type_leafref *)type_un->types[u];
1877+
1878+
if (lref_type->path && lref_type->path->expr) {
1879+
LY_CHECK_GOTO(rc = ly_set_add(*set, lref_type->path->expr, 1, NULL), cleanup);
1880+
}
1881+
} else {
1882+
target = lysc_type_lref_target(node, type_un->types[u]);
1883+
if (target) {
1884+
LY_CHECK_GOTO(rc = ly_set_add(*set, target, 1, NULL), cleanup);
1885+
}
18771886
}
18781887
}
18791888
} else if (type->basetype == LY_TYPE_LEAFREF) {
18801889
/* leafref */
1881-
target = lysc_type_lref_target(node, type);
1882-
if (target) {
1883-
LY_CHECK_GOTO(rc = ly_set_add(*set, target, 1, NULL), cleanup);
1890+
if (return_xpaths) {
1891+
struct lysc_type_leafref *lref_type = (struct lysc_type_leafref *)type;
1892+
1893+
if (lref_type->path && lref_type->path->expr) {
1894+
LY_CHECK_GOTO(rc = ly_set_add(*set, lref_type->path->expr, 1, NULL), cleanup);
1895+
}
1896+
} else {
1897+
target = lysc_type_lref_target(node, type);
1898+
if (target) {
1899+
LY_CHECK_GOTO(rc = ly_set_add(*set, target, 1, NULL), cleanup);
1900+
}
18841901
}
18851902
}
18861903

@@ -1892,6 +1909,18 @@ lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set)
18921909
return rc;
18931910
}
18941911

1912+
LIBYANG_API_DEF LY_ERR
1913+
lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set)
1914+
{
1915+
return lysc_node_lref_targets_fetch(node, set, 0);
1916+
}
1917+
1918+
LIBYANG_API_DEF LY_ERR
1919+
lysc_node_lref_xpath_targets(const struct lysc_node *node, struct ly_set **set)
1920+
{
1921+
return lysc_node_lref_targets_fetch(node, set, 1);
1922+
}
1923+
18951924
struct lysc_node_lref_backlings_arg {
18961925
const struct lysc_node *node;
18971926
ly_bool match_ancestors;

tests/utests/schema/test_schema.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,6 +2106,105 @@ test_lysc_backlinks(void **state)
21062106
}
21072107
}
21082108

2109+
static void
2110+
test_lysc_lref_xpath_targets(void **state)
2111+
{
2112+
const char *expect1[] = {
2113+
"/sbg:sonic-bgp-global/sbg:BGP_GLOBALS/sbg:BGP_GLOBALS_LIST[sbg:vrf_name=current()/../vrf_name]/sbg:local_asn",
2114+
"/sbg:sonic-bgp-global/sbg:BGP_GLOBALS/sbg:any_asn",
2115+
NULL
2116+
};
2117+
2118+
struct {
2119+
const char *xpath;
2120+
const char **expected_paths;
2121+
} tests[] = {
2122+
{"/sonic-device-metadata:sonic-device-metadata/DEVICE_METADATA/DEVICE_METADATA_LIST/bgp_asn", expect1},
2123+
};
2124+
const char *str;
2125+
uint32_t i;
2126+
2127+
str = "module sonic-bgp-global {"
2128+
" namespace \"http://github.com/Azure/sonic-bgp-global\";\n"
2129+
" prefix sbgpg;\n"
2130+
" container sonic-bgp-global {\n"
2131+
" container BGP_GLOBALS {\n"
2132+
" list BGP_GLOBALS_LIST {\n"
2133+
" key \"vrf_name\";\n"
2134+
" leaf vrf_name {\n"
2135+
" type string;\n"
2136+
" }\n"
2137+
" leaf local_asn {\n"
2138+
" type uint32;\n"
2139+
" }\n"
2140+
" }\n"
2141+
" leaf any_asn {\n"
2142+
" type uint32;\n"
2143+
" }\n"
2144+
" }\n"
2145+
" }\n"
2146+
"}\n";
2147+
2148+
2149+
assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_SUCCESS);
2150+
CHECK_LOG_CTX(NULL, NULL, 0);
2151+
2152+
str = "module sonic-device-metadata {\n"
2153+
" namespace \"http://github.com/Azure/sonic-device-metadata\";\n"
2154+
" prefix sdm;\n"
2155+
" import sonic-bgp-global {\n"
2156+
" prefix sbg;\n"
2157+
" }\n"
2158+
" container sonic-device-metadata {\n"
2159+
" container DEVICE_METADATA {\n"
2160+
" list DEVICE_METADATA_LIST {\n"
2161+
" key \"name\";\n"
2162+
" max-elements 1;\n"
2163+
" leaf name {\n"
2164+
" type string;\n"
2165+
" }\n"
2166+
" leaf vrf_name {\n"
2167+
" type string;\n"
2168+
" default default;\n"
2169+
" }\n"
2170+
" leaf bgp_asn {\n"
2171+
" type union {\n"
2172+
" type leafref {\n"
2173+
" path \"/sbg:sonic-bgp-global/sbg:BGP_GLOBALS/sbg:BGP_GLOBALS_LIST[sbg:vrf_name=current()/../vrf_name]/sbg:local_asn\";\n"
2174+
" }\n"
2175+
" type leafref {\n"
2176+
" path \"/sbg:sonic-bgp-global/sbg:BGP_GLOBALS/sbg:any_asn\";\n"
2177+
" }\n"
2178+
" type string {\n"
2179+
" pattern \"none\";\n"
2180+
" }\n"
2181+
" }\n"
2182+
" }\n"
2183+
" }\n"
2184+
" }\n"
2185+
" }\n"
2186+
"}\n";
2187+
2188+
assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_SUCCESS);
2189+
CHECK_LOG_CTX(NULL, NULL, 0);
2190+
2191+
for (i = 0; i < sizeof tests / sizeof *tests; i++) {
2192+
const struct lysc_node *node = NULL;
2193+
struct ly_set *expected = NULL, *received = NULL;
2194+
2195+
node = lys_find_path(UTEST_LYCTX, NULL, tests[i].xpath, 0);
2196+
assert_non_null(node);
2197+
2198+
assert_int_equal(LY_SUCCESS, lysc_node_lref_xpath_targets(node, &received));
2199+
2200+
expected = strlist_to_pathset(tests[i].expected_paths);
2201+
assert_int_equal(1, compare_str_nodeset(expected, received));
2202+
2203+
ly_set_free(expected, NULL);
2204+
ly_set_free(received, NULL);
2205+
}
2206+
}
2207+
21092208
int
21102209
main(void)
21112210
{
@@ -2129,6 +2228,7 @@ main(void)
21292228
UTEST(test_ext_recursive),
21302229
UTEST(test_lysc_path),
21312230
UTEST(test_lysc_backlinks),
2231+
UTEST(test_lysc_lref_xpath_targets)
21322232
};
21332233

21342234
return cmocka_run_group_tests(tests, NULL, NULL);

0 commit comments

Comments
 (0)