summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/northbound.c6
-rw-r--r--lib/northbound_cli.c14
-rw-r--r--lib/northbound_sysrepo.c2
-rw-r--r--lib/yang.c17
-rw-r--r--lib/yang.h21
-rw-r--r--lib/yang_translator.c9
-rw-r--r--lib/yang_wrappers.c6
-rw-r--r--tests/topotests/lib/topogen.py7
-rw-r--r--tests/topotests/lib/topotest.py2
-rw-r--r--tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py12
10 files changed, 76 insertions, 20 deletions
diff --git a/lib/northbound.c b/lib/northbound.c
index 307cf0fb49..775f6ff92f 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -167,7 +167,7 @@ struct nb_node *nb_node_find(const char *path)
* Use libyang to find the schema node associated to the path and get
* the northbound node from there (snode private pointer).
*/
- snode = lys_find_path(ly_native_ctx, NULL, path, 0);
+ snode = yang_find_snode(ly_native_ctx, path, 0);
if (!snode)
return NULL;
@@ -2129,8 +2129,8 @@ int nb_oper_data_iterate(const char *xpath, struct yang_translator *translator,
* all YANG lists (if any).
*/
- LY_ERR err = lyd_new_path(NULL, ly_native_ctx, xpath, NULL,
- LYD_NEW_PATH_UPDATE, &dnode);
+ LY_ERR err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0,
+ LYD_NEW_PATH_UPDATE, NULL, &dnode);
if (err || !dnode) {
const char *errmsg =
err ? ly_errmsg(ly_native_ctx) : "node not found";
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 5cf5f93b43..c5582fc21c 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -1434,6 +1434,7 @@ DEFPY (show_yang_operational_data,
struct lyd_node *dnode;
char *strp;
uint32_t print_options = LYD_PRINT_WITHSIBLINGS;
+ int ret;
if (xml)
format = LYD_XML;
@@ -1454,10 +1455,15 @@ DEFPY (show_yang_operational_data,
/* Obtain data. */
dnode = yang_dnode_new(ly_ctx, false);
- if (nb_oper_data_iterate(xpath, translator, 0, nb_cli_oper_data_cb,
- dnode)
- != NB_OK) {
- vty_out(vty, "%% Failed to fetch operational data.\n");
+ ret = nb_oper_data_iterate(xpath, translator, 0, nb_cli_oper_data_cb,
+ dnode);
+ if (ret != NB_OK) {
+ if (format == LYD_JSON)
+ vty_out(vty, "{}\n");
+ else {
+ /* embed ly_last_errmsg() when we get newer libyang */
+ vty_out(vty, "<!-- Not found -->\n");
+ }
yang_dnode_free(dnode);
return CMD_WARNING;
}
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 86105d2e77..7fd4af8356 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -357,7 +357,7 @@ static int frr_sr_state_data_iter_cb(const struct lysc_node *snode,
ly_errno = 0;
ly_errno = lyd_new_path(NULL, ly_native_ctx, data->xpath, data->value,
0, &dnode);
- if (!dnode && ly_errno) {
+ if (ly_errno) {
flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed",
__func__);
yang_data_free(data);
diff --git a/lib/yang.c b/lib/yang.c
index 70a3251ab3..4dd8654217 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -250,6 +250,23 @@ void yang_snode_get_path(const struct lysc_node *snode,
}
}
+struct lysc_node *yang_find_snode(struct ly_ctx *ly_ctx, const char *xpath,
+ uint32_t options)
+{
+ struct lysc_node *snode;
+ struct ly_set *set;
+ LY_ERR err;
+
+ err = lys_find_xpath(ly_native_ctx, NULL, xpath, options, &set);
+ if (err || !set->count)
+ return NULL;
+
+ snode = set->snodes[0];
+ ly_set_free(set, NULL);
+
+ return snode;
+}
+
struct lysc_node *yang_snode_real_parent(const struct lysc_node *snode)
{
struct lysc_node *parent = snode->parent;
diff --git a/lib/yang.h b/lib/yang.h
index 654c246f0d..37369c09bf 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -210,6 +210,27 @@ extern void yang_snode_get_path(const struct lysc_node *snode,
enum yang_path_type type, char *xpath,
size_t xpath_len);
+
+/*
+ * Find libyang schema node for the given xpath. Uses `lys_find_xpath`,
+ * returning only the first of a set of nodes -- normally there should only
+ * be one.
+ *
+ * ly_ctx
+ * libyang context to operate on.
+ *
+ * xpath
+ * XPath expression (absolute or relative) to find the schema node for.
+ *
+ * options
+ * Libyang findxpathoptions value (see lys_find_xpath).
+ *
+ * Returns:
+ * The libyang schema node if found, or NULL if not found.
+ */
+extern struct lysc_node *yang_find_snode(struct ly_ctx *ly_ctx,
+ const char *xpath, uint32_t options);
+
/*
* Find first parent schema node which is a presence-container or a list
* (non-presence containers are ignored).
diff --git a/lib/yang_translator.c b/lib/yang_translator.c
index de668230ab..eae7577a0d 100644
--- a/lib/yang_translator.c
+++ b/lib/yang_translator.c
@@ -235,8 +235,8 @@ struct yang_translator *yang_translator_load(const char *path)
xpath_custom =
yang_dnode_get_string(set->dnodes[i], "./custom");
- snode_custom = lys_find_path(translator->ly_ctx, NULL,
- xpath_custom, 0);
+ snode_custom =
+ yang_find_snode(translator->ly_ctx, xpath_custom, 0);
if (!snode_custom) {
flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD,
"%s: unknown data path: %s", __func__,
@@ -247,8 +247,7 @@ struct yang_translator *yang_translator_load(const char *path)
xpath_native =
yang_dnode_get_string(set->dnodes[i], "./native");
- snode_native =
- lys_find_path(ly_native_ctx, NULL, xpath_native, 0);
+ snode_native = yang_find_snode(ly_native_ctx, xpath_native, 0);
if (!snode_native) {
flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD,
"%s: unknown data path: %s", __func__,
@@ -315,7 +314,7 @@ yang_translate_xpath(const struct yang_translator *translator, int dir,
else
ly_ctx = ly_native_ctx;
- snode = lys_find_path(ly_ctx, NULL, xpath, 0);
+ snode = yang_find_snode(ly_ctx, xpath, 0);
if (!snode) {
flog_warn(EC_LIB_YANG_TRANSLATION_ERROR,
"%s: unknown data path: %s", __func__, xpath);
diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c
index 509c4dd856..dc049a374a 100644
--- a/lib/yang_wrappers.c
+++ b/lib/yang_wrappers.c
@@ -89,7 +89,7 @@ static const char *yang_get_default_value(const char *xpath)
const struct lysc_node *snode;
const char *value;
- snode = lys_find_path(ly_native_ctx, NULL, xpath, 0);
+ snode = yang_find_snode(ly_native_ctx, xpath, 0);
if (snode == NULL) {
flog_err(EC_LIB_YANG_UNKNOWN_DATA_PATH,
"%s: unknown data path: %s", __func__, xpath);
@@ -206,7 +206,7 @@ int yang_str2enum(const char *xpath, const char *value)
const struct lysc_type_enum *type;
const struct lysc_type_bitenum_item *enums;
- snode = lys_find_path(ly_native_ctx, NULL, xpath, 0);
+ snode = yang_find_snode(ly_native_ctx, xpath, 0);
if (snode == NULL) {
flog_err(EC_LIB_YANG_UNKNOWN_DATA_PATH,
"%s: unknown data path: %s", __func__, xpath);
@@ -241,7 +241,7 @@ struct yang_data *yang_data_new_enum(const char *xpath, int value)
const struct lysc_type_enum *type;
const struct lysc_type_bitenum_item *enums;
- snode = lys_find_path(ly_native_ctx, NULL, xpath, 0);
+ snode = yang_find_snode(ly_native_ctx, xpath, 0);
if (snode == NULL) {
flog_err(EC_LIB_YANG_UNKNOWN_DATA_PATH,
"%s: unknown data path: %s", __func__, xpath);
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index f5b3ad06d9..d505317e4e 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -33,6 +33,7 @@ import os
import platform
import pwd
import re
+import shlex
import subprocess
import sys
from collections import OrderedDict
@@ -946,9 +947,11 @@ class TopoRouter(TopoGear):
if daemon is not None:
dparam += "-d {}".format(daemon)
- vtysh_command = 'vtysh {} -c "{}" 2>/dev/null'.format(dparam, command)
+ vtysh_command = "vtysh {} -c {} 2>/dev/null".format(
+ dparam, shlex.quote(command)
+ )
- self.logger.debug('vtysh command => "{}"'.format(command))
+ self.logger.debug("vtysh command => {}".format(shlex.quote(command)))
output = self.run(vtysh_command)
dbgout = output.strip()
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 86a7f2000f..ef04d59e29 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -1840,6 +1840,8 @@ class Router(Node):
logger.info(
"%s: %s %s launched in gdb window", self, self.routertype, daemon
)
+ # Need better check for daemons running.
+ time.sleep(5)
else:
if daemon != "snmpd":
cmdopt += " -d "
diff --git a/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py b/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py
index b0ba146984..acc0aea9e8 100644
--- a/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py
+++ b/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py
@@ -52,10 +52,18 @@ def test_rip_allow_ecmp():
r1 = tgen.gears["r1"]
def _show_rip_routes():
- output = json.loads(
- r1.vtysh_cmd("show yang operational-data /frr-ripd:ripd ripd")
+ xpath = (
+ "/frr-ripd:ripd/instance[vrf='default']"
+ "/state/routes/route[prefix='10.10.10.1/32']"
)
try:
+ output = json.loads(
+ r1.vtysh_cmd(f"show yang operational-data {xpath} ripd")
+ )
+ except Exception:
+ return False
+
+ try:
output = output["frr-ripd:ripd"]["instance"][0]["state"]["routes"]
except KeyError:
return False