lib: use libyang functions if they are present

Add configure.ac tests for libyang functions, if not present supply the
functionality ourselves in yang.[ch]

Signed-off-by: Christian Hopps <chopps@labn.net>
This commit is contained in:
Christian Hopps 2024-01-06 11:06:38 +00:00
parent cf67a7e265
commit 1e4229fc1f
6 changed files with 163 additions and 136 deletions

View file

@ -1968,6 +1968,13 @@ AC_CHECK_MEMBER([struct lyd_node.priv], [], [
Instructions for this are included in the build documentation for your platform at http://docs.frrouting.org/projects/dev-guide/en/latest/building.html]) Instructions for this are included in the build documentation for your platform at http://docs.frrouting.org/projects/dev-guide/en/latest/building.html])
]) ])
], [[#include <libyang/libyang.h>]]) ], [[#include <libyang/libyang.h>]])
AC_CHECK_LIB([yang],[lyd_find_xpath3],[],[AC_MSG_ERROR([m4_normalize([
libyang missing lyd_find_xpath3])])])
dnl -- don't add lyd_new_list3 to this list unless bug is fixed upstream
dnl -- https://github.com/CESNET/libyang/issues/2149
AC_CHECK_FUNCS([ly_strerrcode ly_strvecode lyd_trim_xpath])
CFLAGS="$ac_cflags_save" CFLAGS="$ac_cflags_save"
dnl --------------- dnl ---------------

View file

@ -1409,11 +1409,8 @@ static enum nb_error __walk(struct nb_op_yield_state *ys, bool is_resume)
*/ */
if (!node) { if (!node) {
/* NOTE: can also use lyd_new_list2 here when available */
err = yang_lyd_new_list(ni[-1].inner, sib, err = yang_lyd_new_list(ni[-1].inner, sib,
&ni->keys, &ni->keys, &node);
(struct lyd_node_inner *
*)&node);
if (err) { if (err) {
darr_pop(ys->node_infos); darr_pop(ys->node_infos);
ret = NB_ERR_RESOURCE; ret = NB_ERR_RESOURCE;

View file

@ -3688,88 +3688,9 @@ static void vty_out_yang_error(struct vty *vty, LYD_FORMAT format,
else if (ei->level == LY_LLWRN) else if (ei->level == LY_LLWRN)
severity = "warning"; severity = "warning";
switch (ei->no) { ecode = yang_ly_strerrcode(err);
case LY_SUCCESS: if (err == LY_EVALID && ei->vecode != LYVE_SUCCESS)
ecode = "ok"; evalid = yang_ly_strvecode(ei->vecode);
break;
case LY_EMEM:
ecode = "out of memory";
break;
case LY_ESYS:
ecode = "system error";
break;
case LY_EINVAL:
ecode = "invalid value given";
break;
case LY_EEXIST:
ecode = "item exists";
break;
case LY_ENOTFOUND:
ecode = "item not found";
break;
case LY_EINT:
ecode = "operation interrupted";
break;
case LY_EVALID:
ecode = "validation failed";
break;
case LY_EDENIED:
ecode = "access denied";
break;
case LY_EINCOMPLETE:
ecode = "incomplete";
break;
case LY_ERECOMPILE:
ecode = "compile error";
break;
case LY_ENOT:
ecode = "not";
break;
default:
case LY_EPLUGIN:
case LY_EOTHER:
ecode = "other";
break;
}
if (err == LY_EVALID) {
switch (ei->vecode) {
case LYVE_SUCCESS:
evalid = NULL;
break;
case LYVE_SYNTAX:
evalid = "syntax";
break;
case LYVE_SYNTAX_YANG:
evalid = "yang-syntax";
break;
case LYVE_SYNTAX_YIN:
evalid = "yin-syntax";
break;
case LYVE_REFERENCE:
evalid = "reference";
break;
case LYVE_XPATH:
evalid = "xpath";
break;
case LYVE_SEMANTICS:
evalid = "semantics";
break;
case LYVE_SYNTAX_XML:
evalid = "xml-syntax";
break;
case LYVE_SYNTAX_JSON:
evalid = "json-syntax";
break;
case LYVE_DATA:
evalid = "data";
break;
default:
case LYVE_OTHER:
evalid = "other";
break;
}
}
switch (format) { switch (format) {
case LYD_XML: case LYD_XML:

View file

@ -999,86 +999,109 @@ int yang_get_node_keys(struct lyd_node *node, struct yang_list_keys *keys)
return NB_OK; 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, LY_ERR yang_lyd_new_list(struct lyd_node_inner *parent,
const struct lysc_node *snode, const struct lysc_node *snode,
const struct yang_list_keys *list_keys, const struct yang_list_keys *list_keys,
struct lyd_node_inner **node) 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; struct lyd_node *pnode = &parent->node;
struct lyd_node **nodepp = (struct lyd_node **)node;
const char(*keys)[LIST_MAXKEYLEN] = list_keys->key; const char(*keys)[LIST_MAXKEYLEN] = list_keys->key;
/* assert(list_keys->num <= 8);
* When
* https://github.com/CESNET/libyang/commit/2c1e327c7c2dd3ba12d466a4ebcf62c1c44116c4
* is released in libyang we should add a configure.ac check for the
* lyd_new_list3 function and use it here.
*/
switch (list_keys->num) { switch (list_keys->num) {
case 0: case 0:
return lyd_new_list(pnode, snode->module, snode->name, false, return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp); node);
case 1: case 1:
return lyd_new_list(pnode, snode->module, snode->name, false, return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp, keys[0]); node, keys[0]);
case 2: case 2:
return lyd_new_list(pnode, snode->module, snode->name, false, return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp, keys[0], keys[1]); node, keys[0], keys[1]);
case 3: case 3:
return lyd_new_list(pnode, snode->module, snode->name, false, return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp, keys[0], keys[1], keys[2]); node, keys[0], keys[1], keys[2]);
case 4: case 4:
return lyd_new_list(pnode, snode->module, snode->name, false, return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp, keys[0], keys[1], keys[2], keys[3]); node, keys[0], keys[1], keys[2], keys[3]);
case 5: case 5:
return lyd_new_list(pnode, snode->module, snode->name, false, return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp, keys[0], keys[1], keys[2], keys[3], node, keys[0], keys[1], keys[2], keys[3],
keys[4]); keys[4]);
case 6: case 6:
return lyd_new_list(pnode, snode->module, snode->name, false, return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp, keys[0], keys[1], keys[2], keys[3], node, keys[0], keys[1], keys[2], keys[3],
keys[4], keys[5]); keys[4], keys[5]);
case 7: case 7:
return lyd_new_list(pnode, snode->module, snode->name, false, return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp, keys[0], keys[1], keys[2], keys[3], node, keys[0], keys[1], keys[2], keys[3],
keys[4], keys[5], keys[6]); keys[4], keys[5], keys[6]);
case 8: case 8:
return lyd_new_list(pnode, snode->module, snode->name, false, return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp, keys[0], keys[1], keys[2], keys[3], node, keys[0], keys[1], keys[2], keys[3],
keys[4], keys[5], keys[6], keys[7]); keys[4], keys[5], keys[6], keys[7]);
} }
_Static_assert(LIST_MAXKEYS == 8, "max key mismatch in switch unroll"); _Static_assert(LIST_MAXKEYS == 8, "max key mismatch in switch unroll");
/*NOTREACHED*/ /*NOTREACHED*/
return LY_EINVAL; return LY_EINVAL;
#endif
} }
int yang_trim_tree(struct lyd_node *root, const char *xpath) /*
* Safe to remove after libyang v2.1.144 is required
*/
LY_ERR yang_lyd_trim_xpath(struct lyd_node **root, const char *xpath)
{ {
enum nb_error ret = NB_OK;
LY_ERR err; LY_ERR err;
#if 0 #ifdef HAVE_LYD_TRIM_XPATH
err = lyd_trim_xpath(&root, xpath, NULL); err = lyd_trim_xpath(root, xpath, NULL);
if (err) { if (err) {
flog_err_sys(EC_LIB_LIBYANG, flog_err_sys(EC_LIB_LIBYANG,
"cannot obtain specific result for xpath \"%s\"", "cannot obtain specific result for xpath \"%s\": %s",
xpath); xpath, yang_ly_strerrcode(err));
return NB_ERR; return err;
} }
return NB_OK; return LY_SUCCESS;
#else #else
struct lyd_node *node; struct lyd_node *node;
struct lyd_node **remove = NULL; struct lyd_node **remove = NULL;
struct ly_set *set = NULL; struct ly_set *set = NULL;
uint32_t i; uint32_t i;
err = lyd_find_xpath3(NULL, root, xpath, NULL, &set); *root = lyd_first_sibling(*root);
err = lyd_find_xpath3(NULL, *root, xpath, NULL, &set);
if (err) { if (err) {
flog_err_sys(EC_LIB_LIBYANG, flog_err_sys(EC_LIB_LIBYANG,
"cannot obtain specific result for xpath \"%s\"", "cannot obtain specific result for xpath \"%s\": %s",
xpath); xpath, yang_ly_strerrcode(err));
ret = NB_ERR; return err;
goto done;
} }
/* /*
* Mark keepers and sweep deleting non-keepers. * Mark keepers and sweep deleting non-keepers.
@ -1100,7 +1123,7 @@ int yang_trim_tree(struct lyd_node *root, const char *xpath)
} }
darr_ensure_cap(remove, 128); darr_ensure_cap(remove, 128);
LYD_TREE_DFS_BEGIN (root, node) { LYD_TREE_DFS_BEGIN (*root, node) {
/* /*
* If this is a direct matching node then include it's subtree * If this is a direct matching node then include it's subtree
* which won't be marked and would otherwise be removed. * which won't be marked and would otherwise be removed.
@ -1108,19 +1131,100 @@ int yang_trim_tree(struct lyd_node *root, const char *xpath)
if (node->priv == (void *)2) if (node->priv == (void *)2)
LYD_TREE_DFS_continue = 1; LYD_TREE_DFS_continue = 1;
else if (!node->priv) { else if (!node->priv) {
LYD_TREE_DFS_continue = 1;
*darr_append(remove) = node; *darr_append(remove) = node;
LYD_TREE_DFS_continue = 1;
} }
LYD_TREE_DFS_END(root, node); LYD_TREE_DFS_END(*root, node);
} }
darr_foreach_i (remove, i) darr_foreach_i (remove, i) {
if (remove[i] == *root)
*root = (*root)->next;
lyd_free_tree(remove[i]); lyd_free_tree(remove[i]);
}
darr_free(remove); darr_free(remove);
done:
if (set) if (set)
ly_set_free(set, NULL); ly_set_free(set, NULL);
return ret; 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 #endif
} }

View file

@ -719,11 +719,6 @@ extern int yang_get_key_preds(char *s, const struct lysc_node *snode,
/* Get YANG keys from an existing dnode */ /* Get YANG keys from an existing dnode */
extern int yang_get_node_keys(struct lyd_node *node, struct yang_list_keys *keys); extern int yang_get_node_keys(struct lyd_node *node, struct yang_list_keys *keys);
/* Create a new list lyd_node using `yang_list_keys` */
extern LY_ERR yang_lyd_new_list(struct lyd_node_inner *parent,
const struct lysc_node *snode,
const struct yang_list_keys *keys,
struct lyd_node_inner **node);
/** /**
* yang_resolve_snodes() - Resolve an XPath to matching schema nodes. * yang_resolve_snodes() - Resolve an XPath to matching schema nodes.
* @ly_ctx: libyang context to operate on. * @ly_ctx: libyang context to operate on.
@ -744,14 +739,16 @@ extern LY_ERR yang_lyd_new_list(struct lyd_node_inner *parent,
extern LY_ERR yang_resolve_snode_xpath(struct ly_ctx *ly_ctx, const char *xpath, extern LY_ERR yang_resolve_snode_xpath(struct ly_ctx *ly_ctx, const char *xpath,
struct lysc_node ***snodes, bool *simple); struct lysc_node ***snodes, bool *simple);
/** /*
* yang_trim_tree() - trim the data tree to the given xpath * Libyang future functions
* @root: the data tree
* @xpath: the xpath to trim @root to.
*
* Return: enum nb_error..
*/ */
extern int yang_trim_tree(struct lyd_node *root, const char *xpath); extern const char *yang_ly_strerrcode(LY_ERR err);
extern const char *yang_ly_strvecode(LY_VECODE vecode);
extern LY_ERR yang_lyd_new_list(struct lyd_node_inner *parent,
const struct lysc_node *snode,
const struct yang_list_keys *keys,
struct lyd_node **nodes);
extern LY_ERR yang_lyd_trim_xpath(struct lyd_node **rootp, const char *xpath);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -1278,8 +1278,9 @@ static int txn_get_tree_data_done(struct mgmt_txn_ctx *txn,
/* /*
* We have a complex query so Filter results by the xpath query. * We have a complex query so Filter results by the xpath query.
*/ */
ret = yang_trim_tree(get_tree->client_results, if (yang_lyd_trim_xpath(&get_tree->client_results,
txn_req->req.get_tree->xpath); txn_req->req.get_tree->xpath))
ret = NB_ERR;
} }
if (ret == NB_OK) if (ret == NB_OK)