Skip to content

Commit d97ee52

Browse files
committed
schema: add lysc_node_lref_xpath_targets() helper
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. 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 d97ee52

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)