summaryrefslogtreecommitdiffstats
path: root/lib/yang.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/yang.c')
-rw-r--r--lib/yang.c512
1 files changed, 464 insertions, 48 deletions
diff --git a/lib/yang.c b/lib/yang.c
index 4dd8654..03044fc 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -6,12 +6,15 @@
#include <zebra.h>
+#include "darr.h"
#include "log.h"
#include "lib_errors.h"
#include "yang.h"
#include "yang_translator.h"
#include "northbound.h"
+#include "lib/config_paths.h"
+
DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module");
DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure");
@@ -37,7 +40,8 @@ static LY_ERR yang_module_imp_clb(const char *mod_name, const char *mod_rev,
struct yang_module_embed *e;
if (!strcmp(mod_name, "ietf-inet-types") ||
- !strcmp(mod_name, "ietf-yang-types"))
+ !strcmp(mod_name, "ietf-yang-types") ||
+ !strcmp(mod_name, "ietf-yang-metadata"))
/* libyang has these built in, don't try finding them here */
return LY_ENOTFOUND;
@@ -97,13 +101,14 @@ RB_GENERATE(yang_modules, yang_module, entry, yang_module_compare)
struct yang_modules yang_modules = RB_INITIALIZER(&yang_modules);
-struct yang_module *yang_module_load(const char *module_name)
+struct yang_module *yang_module_load(const char *module_name,
+ const char **features)
{
struct yang_module *module;
const struct lys_module *module_info;
- module_info =
- ly_ctx_load_module(ly_native_ctx, module_name, NULL, NULL);
+ module_info = ly_ctx_load_module(ly_native_ctx, module_name, NULL,
+ features);
if (!module_info) {
flog_err(EC_LIB_YANG_MODULE_LOAD,
"%s: failed to load data model: %s", __func__,
@@ -127,8 +132,10 @@ struct yang_module *yang_module_load(const char *module_name)
void yang_module_load_all(void)
{
+ static const char * const all_features[] = { "*", NULL };
+
for (size_t i = 0; i < array_size(frr_native_modules); i++)
- yang_module_load(frr_native_modules[i]);
+ yang_module_load(frr_native_modules[i], (const char **)all_features);
}
struct yang_module *yang_module_find(const char *module_name)
@@ -250,19 +257,44 @@ 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)
+LY_ERR yang_resolve_snode_xpath(struct ly_ctx *ly_ctx, const char *xpath,
+ struct lysc_node ***snodes, bool *simple)
{
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;
+ /* lys_find_path will not resolve complex xpaths */
+ snode = (struct lysc_node *)lys_find_path(ly_ctx, NULL, xpath, 0);
+ if (snode) {
+ *darr_append(*snodes) = snode;
+ *simple = true;
+ return LY_SUCCESS;
+ }
+
+ /* Try again to catch complex query cases */
+ err = lys_find_xpath(ly_native_ctx, NULL, xpath, 0, &set);
+ if (err)
+ return err;
+ if (!set->count) {
+ ly_set_free(set, NULL);
+ return LY_ENOTFOUND;
+ }
- snode = set->snodes[0];
+ *simple = false;
+ darr_ensure_i(*snodes, set->count - 1);
+ memcpy(*snodes, set->snodes, set->count * sizeof(set->snodes[0]));
ly_set_free(set, NULL);
+ return LY_SUCCESS;
+}
+
+
+struct lysc_node *yang_find_snode(struct ly_ctx *ly_ctx, const char *xpath,
+ uint32_t options)
+{
+ struct lysc_node *snode;
+
+ snode = (struct lysc_node *)lys_find_path(ly_ctx, NULL, xpath, 0);
return snode;
}
@@ -370,33 +402,10 @@ unsigned int yang_snode_num_keys(const struct lysc_node *snode)
return count;
}
-void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath,
- size_t xpath_len)
-{
- lyd_path(dnode, LYD_PATH_STD, xpath, xpath_len);
-}
-
-const char *yang_dnode_get_schema_name(const struct lyd_node *dnode,
- const char *xpath_fmt, ...)
+char *yang_dnode_get_path(const struct lyd_node *dnode, char *xpath,
+ size_t xpath_len)
{
- if (xpath_fmt) {
- va_list ap;
- char xpath[XPATH_MAXLEN];
-
- va_start(ap, xpath_fmt);
- vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
- va_end(ap);
-
- dnode = yang_dnode_get(dnode, xpath);
- if (!dnode) {
- flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
- "%s: couldn't find %s", __func__, xpath);
- zlog_backtrace(LOG_ERR);
- abort();
- }
- }
-
- return dnode->schema->name;
+ return lyd_path(dnode, LYD_PATH_STD, xpath, xpath_len);
}
struct lyd_node *yang_dnode_get(const struct lyd_node *dnode, const char *xpath)
@@ -505,6 +514,30 @@ void yang_dnode_iterate(yang_dnode_iter_cb cb, void *arg,
ly_set_free(set, NULL);
}
+uint32_t yang_dnode_count(const struct lyd_node *dnode, const char *xpath_fmt,
+ ...)
+{
+ va_list ap;
+ char xpath[XPATH_MAXLEN];
+ struct ly_set *set;
+ uint32_t count;
+
+ va_start(ap, xpath_fmt);
+ vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+ va_end(ap);
+
+ if (lyd_find_xpath(dnode, xpath, &set)) {
+ assert(0);
+ return 0;
+ }
+
+ count = set->count;
+
+ ly_set_free(set, NULL);
+
+ return count;
+}
+
bool yang_dnode_is_default(const struct lyd_node *dnode, const char *xpath)
{
const struct lysc_node *snode;
@@ -596,7 +629,8 @@ struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode)
{
struct lyd_node *dup = NULL;
LY_ERR err;
- err = lyd_dup_siblings(dnode, NULL, LYD_DUP_RECURSIVE, &dup);
+ err = lyd_dup_siblings(dnode, NULL,
+ LYD_DUP_RECURSIVE | LYD_DUP_WITH_FLAGS, &dup);
assert(!err);
return dup;
}
@@ -680,10 +714,122 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
zlog(priority, "libyang: %s", msg);
}
+LY_ERR yang_parse_notification(const char *xpath, LYD_FORMAT format,
+ const char *data, struct lyd_node **notif)
+{
+ struct lyd_node *tree;
+ struct ly_set *set = NULL;
+ struct ly_in *in = NULL;
+ LY_ERR err;
+
+ err = ly_in_new_memory(data, &in);
+ if (err) {
+ zlog_err("Failed to initialize ly_in: %s", ly_last_errmsg());
+ return err;
+ }
+
+ err = lyd_parse_op(ly_native_ctx, NULL, in, format, LYD_TYPE_NOTIF_YANG,
+ &tree, NULL);
+ ly_in_free(in, 0);
+ if (err) {
+ zlog_err("Failed to parse notification: %s", ly_last_errmsg());
+ return err;
+ }
+
+ err = lyd_find_xpath3(NULL, tree, xpath, NULL, &set);
+ if (err) {
+ zlog_err("Failed to parse notification: %s", ly_last_errmsg());
+ lyd_free_all(tree);
+ return err;
+ }
+ if (set->count == 0) {
+ zlog_err("Notification not found in the parsed tree: %s", xpath);
+ ly_set_free(set, NULL);
+ lyd_free_all(tree);
+ return LY_ENOTFOUND;
+ }
+ *notif = set->dnodes[0];
+ ly_set_free(set, NULL);
+ 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);
+
+ memcpy(dst, buf, count);
+ return count;
+}
+
+LY_ERR yang_print_tree_append(uint8_t **darr, const struct lyd_node *root,
+ LYD_FORMAT format, uint32_t options)
+{
+ LY_ERR err;
+
+ err = lyd_print_clb(yang_print_darr, darr, root, format, options);
+ if (err)
+ zlog_err("Failed to save yang tree: %s", ly_last_errmsg());
+ else if (format != LYD_LYB)
+ *darr_append(*darr) = 0;
+ return err;
+}
+
+uint8_t *yang_print_tree(const struct lyd_node *root, LYD_FORMAT format,
+ uint32_t options)
+{
+ uint8_t *darr = NULL;
+
+ if (yang_print_tree_append(&darr, root, format, options))
+ return NULL;
+ return darr;
+}
+
+char *yang_convert_lyd_format(const char *data, size_t data_len,
+ LYD_FORMAT in_format, LYD_FORMAT out_format,
+ bool shrink)
+{
+ struct lyd_node *tree = NULL;
+ uint32_t options = LYD_PRINT_WD_EXPLICIT | LYD_PRINT_WITHSIBLINGS;
+ uint8_t *result = NULL;
+ LY_ERR err;
+
+ assert(out_format != LYD_LYB);
+
+ if (in_format != LYD_LYB && !MGMT_MSG_VALIDATE_NUL_TERM(data, data_len)) {
+ zlog_err("Corrupt input data, no NUL terminating byte");
+ return NULL;
+ }
+
+ if (in_format == out_format)
+ return darr_strdup((const char *)data);
+
+ err = lyd_parse_data_mem(ly_native_ctx, (const char *)data, in_format,
+ LYD_PARSE_ONLY, 0, &tree);
+
+ if (err) {
+ flog_err_sys(EC_LIB_LIBYANG,
+ "cannot parse input data to convert: %s",
+ ly_last_errmsg());
+ return NULL;
+ }
+
+ if (shrink)
+ options |= LYD_PRINT_SHRINK;
+
+ /* Take a guess at the initial capacity based on input data size */
+ darr_ensure_cap(result, data_len);
+ err = yang_print_tree_append(&result, tree, out_format, options);
+ lyd_free_all(tree);
+ if (err) {
+ darr_free(result);
+ return NULL;
+ }
+ return (char *)result;
+}
+
const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf, size_t buf_len)
{
struct ly_err_item *ei;
- const char *path;
ei = ly_err_first(ly_ctx);
if (!ei)
@@ -691,18 +837,16 @@ const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf, size_t buf_len)
strlcpy(buf, "YANG error(s):\n", buf_len);
for (; ei; ei = ei->next) {
- strlcat(buf, " ", buf_len);
+ if (ei->path) {
+ strlcat(buf, " Path: ", buf_len);
+ strlcat(buf, ei->path, buf_len);
+ strlcat(buf, "\n", buf_len);
+ }
+ strlcat(buf, " Error: ", buf_len);
strlcat(buf, ei->msg, buf_len);
strlcat(buf, "\n", buf_len);
}
- path = ly_errpath(ly_ctx);
- if (path) {
- strlcat(buf, " YANG path: ", buf_len);
- strlcat(buf, path, buf_len);
- strlcat(buf, "\n", buf_len);
- }
-
ly_err_clean(ly_ctx, NULL);
return buf;
@@ -723,6 +867,7 @@ struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile)
{
struct ly_ctx *ctx = NULL;
const char *yang_models_path = YANG_MODELS_PATH;
+ uint options;
LY_ERR err;
if (access(yang_models_path, R_OK | X_OK)) {
@@ -736,7 +881,7 @@ struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile)
YANG_MODELS_PATH);
}
- uint options = LY_CTX_NO_YANGLIBRARY | LY_CTX_DISABLE_SEARCHDIR_CWD;
+ options = LY_CTX_NO_YANGLIBRARY | LY_CTX_DISABLE_SEARCHDIR_CWD;
if (explicit_compile)
options |= LY_CTX_EXPLICIT_COMPILE;
err = ly_ctx_new(yang_models_path, options, &ctx);
@@ -927,3 +1072,274 @@ uint32_t yang_get_list_elements_count(const struct lyd_node *node)
} while (node);
return count;
}
+
+int yang_get_key_preds(char *s, const struct lysc_node *snode,
+ struct yang_list_keys *keys, ssize_t space)
+{
+ const struct lysc_node_leaf *skey;
+ ssize_t len2, len = 0;
+ ssize_t i = 0;
+
+ LY_FOR_KEYS (snode, skey) {
+ assert(i < keys->num);
+ len2 = snprintf(s + len, space - len, "[%s='%s']", skey->name,
+ keys->key[i]);
+ if (len2 > space - len)
+ len = space;
+ else
+ len += len2;
+ i++;
+ }
+
+ assert(i == keys->num);
+ return i;
+}
+
+int yang_get_node_keys(struct lyd_node *node, struct yang_list_keys *keys)
+{
+ struct lyd_node *child = lyd_child(node);
+
+ keys->num = 0;
+ for (; child && lysc_is_key(child->schema); child = child->next) {
+ const char *value = lyd_get_value(child);
+
+ if (!value)
+ return NB_ERR;
+ strlcpy(keys->key[keys->num], value,
+ sizeof(keys->key[keys->num]));
+ keys->num++;
+ }
+ return NB_OK;
+}
+
+/*
+ * ------------------------
+ * Libyang Future Functions
+ * ------------------------
+ *
+ * All these functions are implemented in libyang versions (perhaps unreleased)
+ * beyond what we require currently so we must supply the functionality.
+ */
+
+/*
+ * Safe to remove after libyang v2.1.xxx is required (.144 has a bug so
+ * something > .144) https://github.com/CESNET/libyang/issues/2149
+ */
+LY_ERR yang_lyd_new_list(struct lyd_node_inner *parent,
+ const struct lysc_node *snode,
+ const struct yang_list_keys *list_keys,
+ struct lyd_node **node)
+{
+#if defined(HAVE_LYD_NEW_LIST3) && 0
+ LY_ERR err;
+ const char *keys[LIST_MAXKEYS];
+
+ assert(list_keys->num <= LIST_MAXKEYS);
+ for (int i = 0; i < list_keys->num; i++)
+ keys[i] = list_keys->key[i];
+
+ err = lyd_new_list3(&parent->node, snode->module, snode->name, keys,
+ NULL, 0, node);
+ return err;
+#else
+ struct lyd_node *pnode = &parent->node;
+ const char(*keys)[LIST_MAXKEYLEN] = list_keys->key;
+
+ assert(list_keys->num <= 8);
+ switch (list_keys->num) {
+ case 0:
+ return lyd_new_list(pnode, snode->module, snode->name, false,
+ node);
+ case 1:
+ return lyd_new_list(pnode, snode->module, snode->name, false,
+ node, keys[0]);
+ case 2:
+ return lyd_new_list(pnode, snode->module, snode->name, false,
+ node, keys[0], keys[1]);
+ case 3:
+ return lyd_new_list(pnode, snode->module, snode->name, false,
+ node, keys[0], keys[1], keys[2]);
+ case 4:
+ return lyd_new_list(pnode, snode->module, snode->name, false,
+ node, keys[0], keys[1], keys[2], keys[3]);
+ case 5:
+ return lyd_new_list(pnode, snode->module, snode->name, false,
+ node, keys[0], keys[1], keys[2], keys[3],
+ keys[4]);
+ case 6:
+ return lyd_new_list(pnode, snode->module, snode->name, false,
+ node, keys[0], keys[1], keys[2], keys[3],
+ keys[4], keys[5]);
+ case 7:
+ return lyd_new_list(pnode, snode->module, snode->name, false,
+ node, keys[0], keys[1], keys[2], keys[3],
+ keys[4], keys[5], keys[6]);
+ case 8:
+ return lyd_new_list(pnode, snode->module, snode->name, false,
+ node, keys[0], keys[1], keys[2], keys[3],
+ keys[4], keys[5], keys[6], keys[7]);
+ }
+ _Static_assert(LIST_MAXKEYS == 8, "max key mismatch in switch unroll");
+ /*NOTREACHED*/
+ return LY_EINVAL;
+#endif
+}
+
+
+/*
+ * Safe to remove after libyang v2.1.144 is required
+ */
+LY_ERR yang_lyd_trim_xpath(struct lyd_node **root, const char *xpath)
+{
+ LY_ERR err;
+#ifdef HAVE_LYD_TRIM_XPATH
+ err = lyd_trim_xpath(root, xpath, NULL);
+ if (err) {
+ flog_err_sys(EC_LIB_LIBYANG,
+ "cannot obtain specific result for xpath \"%s\": %s",
+ xpath, yang_ly_strerrcode(err));
+ return err;
+ }
+ return LY_SUCCESS;
+#else
+ struct lyd_node *node, *sib;
+ struct lyd_node **remove = NULL;
+ struct ly_set *set = NULL;
+ uint32_t i;
+
+ *root = lyd_first_sibling(*root);
+
+ err = lyd_find_xpath3(NULL, *root, xpath, NULL, &set);
+ if (err) {
+ flog_err_sys(EC_LIB_LIBYANG,
+ "cannot obtain specific result for xpath \"%s\": %s",
+ xpath, yang_ly_strerrcode(err));
+ return err;
+ }
+ /*
+ * Mark keepers and sweep deleting non-keepers.
+ *
+ * NOTE: We assume the data-nodes have NULL priv pointers and use that
+ * for our mark.
+ */
+
+ /* Mark */
+ for (i = 0; i < set->count; i++) {
+ for (node = set->dnodes[i]; node; node = &node->parent->node) {
+ if (node->priv)
+ break;
+ if (node == set->dnodes[i])
+ node->priv = (void *)2;
+ else
+ node->priv = (void *)1;
+ }
+ }
+
+ darr_ensure_cap(remove, 128);
+ LY_LIST_FOR(*root, sib) {
+ LYD_TREE_DFS_BEGIN (sib, node) {
+ /*
+ * If this is a direct matching node then include its
+ * subtree which won't be marked and would otherwise
+ * be removed.
+ */
+ if (node->priv == (void *)2)
+ LYD_TREE_DFS_continue = 1;
+ else if (!node->priv) {
+ *darr_append(remove) = node;
+ LYD_TREE_DFS_continue = 1;
+ }
+ LYD_TREE_DFS_END(sib, node);
+ }
+ }
+ darr_foreach_i (remove, i) {
+ if (remove[i] == *root)
+ *root = (*root)->next;
+ lyd_free_tree(remove[i]);
+ }
+ darr_free(remove);
+
+ ly_set_free(set, NULL);
+
+ return LY_SUCCESS;
+#endif
+}
+
+/*
+ * Safe to remove after libyang v2.1.128 is required
+ */
+const char *yang_ly_strerrcode(LY_ERR err)
+{
+#ifdef HAVE_LY_STRERRCODE
+ return ly_strerrcode(err);
+#else
+ switch (err) {
+ case LY_SUCCESS:
+ return "ok";
+ case LY_EMEM:
+ return "out of memory";
+ case LY_ESYS:
+ return "system error";
+ case LY_EINVAL:
+ return "invalid value given";
+ case LY_EEXIST:
+ return "item exists";
+ case LY_ENOTFOUND:
+ return "item not found";
+ case LY_EINT:
+ return "operation interrupted";
+ case LY_EVALID:
+ return "validation failed";
+ case LY_EDENIED:
+ return "access denied";
+ case LY_EINCOMPLETE:
+ return "incomplete";
+ case LY_ERECOMPILE:
+ return "compile error";
+ case LY_ENOT:
+ return "not";
+ case LY_EPLUGIN:
+ case LY_EOTHER:
+ return "other";
+ default:
+ return "unknown";
+ }
+#endif
+}
+
+/*
+ * Safe to remove after libyang v2.1.128 is required
+ */
+const char *yang_ly_strvecode(LY_VECODE vecode)
+{
+#ifdef HAVE_LY_STRVECODE
+ return ly_strvecode(vecode);
+#else
+ switch (vecode) {
+ case LYVE_SUCCESS:
+ return "";
+ case LYVE_SYNTAX:
+ return "syntax";
+ case LYVE_SYNTAX_YANG:
+ return "yang-syntax";
+ case LYVE_SYNTAX_YIN:
+ return "yin-syntax";
+ case LYVE_REFERENCE:
+ return "reference";
+ case LYVE_XPATH:
+ return "xpath";
+ case LYVE_SEMANTICS:
+ return "semantics";
+ case LYVE_SYNTAX_XML:
+ return "xml-syntax";
+ case LYVE_SYNTAX_JSON:
+ return "json-syntax";
+ case LYVE_DATA:
+ return "data";
+ case LYVE_OTHER:
+ return "other";
+ default:
+ return "unknown";
+ }
+#endif
+}