summaryrefslogtreecommitdiffstats
path: root/lib/yang.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/yang.c')
-rw-r--r--lib/yang.c196
1 files changed, 186 insertions, 10 deletions
diff --git a/lib/yang.c b/lib/yang.c
index 03044fc..44459df 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -11,13 +11,26 @@
#include "lib_errors.h"
#include "yang.h"
#include "yang_translator.h"
+#include <libyang/version.h>
#include "northbound.h"
+#include "frrstr.h"
#include "lib/config_paths.h"
DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module");
DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure");
+/* Safe to remove after libyang 2.2.8 */
+#if (LY_VERSION_MAJOR < 3)
+#define yang_lyd_find_xpath3(ctx_node, tree, xpath, format, prefix_data, vars, \
+ set) \
+ lyd_find_xpath3(ctx_node, tree, xpath, vars, set)
+#else
+#define yang_lyd_find_xpath3(ctx_node, tree, xpath, format, prefix_data, vars, \
+ set) \
+ lyd_find_xpath3(ctx_node, tree, xpath, LY_VALUE_JSON, NULL, vars, set)
+#endif
+
/* libyang container. */
struct ly_ctx *ly_native_ctx;
@@ -199,6 +212,16 @@ next:
if (ret == YANG_ITER_STOP)
return ret;
}
+ LY_LIST_FOR ((const struct lysc_node *)lysc_node_notifs(snode), child) {
+ ret = yang_snodes_iterate_subtree(child, module, cb, flags, arg);
+ if (ret == YANG_ITER_STOP)
+ return ret;
+ }
+ LY_LIST_FOR ((const struct lysc_node *)lysc_node_actions(snode), child) {
+ ret = yang_snodes_iterate_subtree(child, module, cb, flags, arg);
+ if (ret == YANG_ITER_STOP)
+ return ret;
+ }
return ret;
}
@@ -642,6 +665,16 @@ void yang_dnode_free(struct lyd_node *dnode)
lyd_free_all(dnode);
}
+void yang_dnode_rpc_output_add(struct lyd_node *output, const char *xpath,
+ const char *value)
+{
+ LY_ERR err;
+
+ err = lyd_new_path(output, ly_native_ctx, xpath, value,
+ LYD_NEW_PATH_OUTPUT | LYD_NEW_PATH_UPDATE, NULL);
+ assert(err == LY_SUCCESS);
+}
+
struct yang_data *yang_data_new(const char *xpath, const char *value)
{
struct yang_data *data;
@@ -691,7 +724,12 @@ struct yang_data *yang_data_list_find(const struct list *list,
}
/* Make libyang log its errors using FRR logging infrastructure. */
-static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
+static void ly_zlog_cb(LY_LOG_LEVEL level, const char *msg, const char *data_path
+#if !(LY_VERSION_MAJOR < 3)
+ ,
+ const char *schema_path, uint64_t line
+#endif
+)
{
int priority = LOG_ERR;
@@ -708,8 +746,14 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
break;
}
- if (path)
- zlog(priority, "libyang: %s (%s)", msg, path);
+ if (data_path)
+ zlog(priority, "libyang: %s (%s)", msg, data_path);
+#if !(LY_VERSION_MAJOR < 3)
+ else if (schema_path)
+ zlog(priority, "libyang %s (%s)\n", msg, schema_path);
+ else if (line)
+ zlog(priority, "libyang %s (line %" PRIu64 ")\n", msg, line);
+#endif
else
zlog(priority, "libyang: %s", msg);
}
@@ -736,7 +780,8 @@ LY_ERR yang_parse_notification(const char *xpath, LYD_FORMAT format,
return err;
}
- err = lyd_find_xpath3(NULL, tree, xpath, NULL, &set);
+ err = yang_lyd_find_xpath3(NULL, tree, xpath, LY_VALUE_JSON, NULL, NULL,
+ &set);
if (err) {
zlog_err("Failed to parse notification: %s", ly_last_errmsg());
lyd_free_all(tree);
@@ -753,6 +798,63 @@ LY_ERR yang_parse_notification(const char *xpath, LYD_FORMAT format,
return LY_SUCCESS;
}
+LY_ERR yang_parse_rpc(const char *xpath, LYD_FORMAT format, const char *data,
+ bool reply, struct lyd_node **rpc)
+{
+ const struct lysc_node *snode;
+ struct lyd_node *parent = NULL;
+ struct ly_in *in = NULL;
+ LY_ERR err;
+
+ snode = lys_find_path(ly_native_ctx, NULL, xpath, 0);
+ if (!snode) {
+ zlog_err("Failed to find RPC/action schema node: %s", xpath);
+ return LY_ENOTFOUND;
+ }
+
+ /* If it's an action, create its parent */
+ if (snode->nodetype == LYS_ACTION) {
+ char *parent_xpath = XSTRDUP(MTYPE_TMP, xpath);
+
+ if (yang_xpath_pop_node(parent_xpath) != NB_OK) {
+ XFREE(MTYPE_TMP, parent_xpath);
+ zlog_err("Invalid action xpath: %s", xpath);
+ return LY_EINVAL;
+ }
+
+ err = lyd_new_path2(NULL, ly_native_ctx, parent_xpath, NULL, 0,
+ 0, 0, NULL, &parent);
+ XFREE(MTYPE_TMP, parent_xpath);
+ if (err) {
+ zlog_err("Failed to create parent node for action: %s",
+ ly_last_errmsg());
+ return err;
+ }
+ } else if (snode->nodetype != LYS_RPC) {
+ zlog_err("Schema node is not an RPC/action: %s", xpath);
+ return LY_EINVAL;
+ }
+
+ err = ly_in_new_memory(data, &in);
+ if (err) {
+ lyd_free_all(parent);
+ zlog_err("Failed to initialize ly_in: %s", ly_last_errmsg());
+ return err;
+ }
+
+ err = lyd_parse_op(ly_native_ctx, parent, in, format,
+ reply ? LYD_TYPE_REPLY_YANG : LYD_TYPE_RPC_YANG,
+ NULL, rpc);
+ ly_in_free(in, 0);
+ if (err) {
+ lyd_free_all(parent);
+ zlog_err("Failed to parse RPC/action: %s", ly_last_errmsg());
+ return err;
+ }
+
+ return LY_SUCCESS;
+}
+
static ssize_t yang_print_darr(void *arg, const void *buf, size_t count)
{
uint8_t *dst = darr_append_n(*(uint8_t **)arg, count);
@@ -795,7 +897,7 @@ char *yang_convert_lyd_format(const char *data, size_t data_len,
assert(out_format != LYD_LYB);
- if (in_format != LYD_LYB && !MGMT_MSG_VALIDATE_NUL_TERM(data, data_len)) {
+ if (in_format != LYD_LYB && (!data_len || data[data_len - 1] != 0)) {
zlog_err("Corrupt input data, no NUL terminating byte");
return NULL;
}
@@ -829,23 +931,29 @@ char *yang_convert_lyd_format(const char *data, size_t data_len,
const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf, size_t buf_len)
{
- struct ly_err_item *ei;
+ const struct ly_err_item *ei;
ei = ly_err_first(ly_ctx);
if (!ei)
return "";
strlcpy(buf, "YANG error(s):\n", buf_len);
+#if (LY_VERSION_MAJOR < 3)
+#define data_path path
+#else
+#define data_path data_path
+#endif
for (; ei; ei = ei->next) {
- if (ei->path) {
+ if (ei->data_path) {
strlcat(buf, " Path: ", buf_len);
- strlcat(buf, ei->path, buf_len);
+ strlcat(buf, ei->data_path, buf_len);
strlcat(buf, "\n", buf_len);
}
strlcat(buf, " Error: ", buf_len);
strlcat(buf, ei->msg, buf_len);
strlcat(buf, "\n", buf_len);
}
+#undef data_path
ly_err_clean(ly_ctx, NULL);
@@ -897,7 +1005,12 @@ struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile)
void yang_init(bool embedded_modules, bool defer_compile)
{
/* Initialize libyang global parameters that affect all containers. */
- ly_set_log_clb(ly_log_cb, 1);
+ ly_set_log_clb(ly_zlog_cb
+#if (LY_VERSION_MAJOR < 3)
+ ,
+ 1
+#endif
+ );
ly_log_options(LY_LOLOG | LY_LOSTORE);
/* Initialize libyang container for native models. */
@@ -1112,6 +1225,32 @@ int yang_get_node_keys(struct lyd_node *node, struct yang_list_keys *keys)
return NB_OK;
}
+int yang_xpath_pop_node(char *xpath)
+{
+ int len = strlen(xpath);
+ bool abs = xpath[0] == '/';
+ char *slash;
+
+ /* "//" or "/" => NULL */
+ if (abs && (len == 1 || (len == 2 && xpath[1] == '/')))
+ return NB_ERR_NOT_FOUND;
+
+ slash = (char *)frrstr_back_to_char(xpath, '/');
+ /* "/foo/bar/" or "/foo/bar//" => "/foo " */
+ if (slash && slash == &xpath[len - 1]) {
+ xpath[--len] = 0;
+ slash = (char *)frrstr_back_to_char(xpath, '/');
+ if (slash && slash == &xpath[len - 1]) {
+ xpath[--len] = 0;
+ slash = (char *)frrstr_back_to_char(xpath, '/');
+ }
+ }
+ if (!slash)
+ return NB_ERR_NOT_FOUND;
+ *slash = 0;
+ return NB_OK;
+}
+
/*
* ------------------------
* Libyang Future Functions
@@ -1209,7 +1348,8 @@ LY_ERR yang_lyd_trim_xpath(struct lyd_node **root, const char *xpath)
*root = lyd_first_sibling(*root);
- err = lyd_find_xpath3(NULL, *root, xpath, NULL, &set);
+ err = yang_lyd_find_xpath3(NULL, *root, xpath, LY_VALUE_JSON, NULL,
+ NULL, &set);
if (err) {
flog_err_sys(EC_LIB_LIBYANG,
"cannot obtain specific result for xpath \"%s\": %s",
@@ -1265,6 +1405,42 @@ LY_ERR yang_lyd_trim_xpath(struct lyd_node **root, const char *xpath)
#endif
}
+/* Can be replaced by `lyd_parse_data` with libyang >= 2.1.156 */
+LY_ERR yang_lyd_parse_data(const struct ly_ctx *ctx, struct lyd_node *parent,
+ struct ly_in *in, LYD_FORMAT format,
+ uint32_t parse_options, uint32_t validate_options,
+ struct lyd_node **tree)
+{
+ struct lyd_node *child;
+ LY_ERR err;
+
+ err = lyd_parse_data(ctx, parent, in, format, parse_options,
+ validate_options, tree);
+ if (err)
+ return err;
+
+ if (!parent || !(parse_options & LYD_PARSE_ONLY))
+ return LY_SUCCESS;
+
+ /*
+ * Versions prior to 2.1.156 don't return `tree` if `parent` is not NULL
+ * and validation is disabled (`LYD_PARSE_ONLY`). To work around this,
+ * go through the children and find the one with `LYD_NEW` flag set.
+ */
+ *tree = NULL;
+
+ LY_LIST_FOR (lyd_child_no_keys(parent), child) {
+ if (child->flags & LYD_NEW) {
+ *tree = child;
+ break;
+ }
+ }
+
+ assert(tree);
+
+ return LY_SUCCESS;
+}
+
/*
* Safe to remove after libyang v2.1.128 is required
*/