Skip to content

Commit

Permalink
lib: use libyang functions if they are present
Browse files Browse the repository at this point in the history
Add configure.ac tests for libyang functions, if not present supply the
functionality ourselves in yang.[ch]

Signed-off-by: Christian Hopps <[email protected]>
  • Loading branch information
choppsv1 committed Jan 7, 2024
1 parent cf67a7e commit 1e4229f
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 136 deletions.
7 changes: 7 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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])
])
], [[#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"

dnl ---------------
Expand Down
5 changes: 1 addition & 4 deletions lib/northbound_oper.c
Original file line number Diff line number Diff line change
Expand Up @@ -1409,11 +1409,8 @@ static enum nb_error __walk(struct nb_op_yield_state *ys, bool is_resume)
*/

if (!node) {
/* NOTE: can also use lyd_new_list2 here when available */
err = yang_lyd_new_list(ni[-1].inner, sib,
&ni->keys,
(struct lyd_node_inner *
*)&node);
&ni->keys, &node);
if (err) {
darr_pop(ys->node_infos);
ret = NB_ERR_RESOURCE;
Expand Down
85 changes: 3 additions & 82 deletions lib/vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -3688,88 +3688,9 @@ static void vty_out_yang_error(struct vty *vty, LYD_FORMAT format,
else if (ei->level == LY_LLWRN)
severity = "warning";

switch (ei->no) {
case LY_SUCCESS:
ecode = "ok";
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;
}
}
ecode = yang_ly_strerrcode(err);
if (err == LY_EVALID && ei->vecode != LYVE_SUCCESS)
evalid = yang_ly_strvecode(ei->vecode);

switch (format) {
case LYD_XML:
Expand Down
176 changes: 140 additions & 36 deletions lib/yang.c
Original file line number Diff line number Diff line change
Expand Up @@ -999,86 +999,109 @@ int yang_get_node_keys(struct lyd_node *node, struct yang_list_keys *keys)
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_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 **nodepp = (struct lyd_node **)node;
const char(*keys)[LIST_MAXKEYLEN] = list_keys->key;

/*
* 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.
*/
assert(list_keys->num <= 8);
switch (list_keys->num) {
case 0:
return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp);
node);
case 1:
return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp, keys[0]);
node, keys[0]);
case 2:
return lyd_new_list(pnode, snode->module, snode->name, false,
nodepp, keys[0], keys[1]);
node, keys[0], keys[1]);
case 3:
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:
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:
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]);
case 6:
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]);
case 7:
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]);
case 8:
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]);
}
_Static_assert(LIST_MAXKEYS == 8, "max key mismatch in switch unroll");
/*NOTREACHED*/
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;
#if 0
err = lyd_trim_xpath(&root, xpath, NULL);
#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\"",
xpath);
return NB_ERR;
"cannot obtain specific result for xpath \"%s\": %s",
xpath, yang_ly_strerrcode(err));
return err;
}
return NB_OK;
return LY_SUCCESS;
#else
struct lyd_node *node;
struct lyd_node **remove = NULL;
struct ly_set *set = NULL;
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) {
flog_err_sys(EC_LIB_LIBYANG,
"cannot obtain specific result for xpath \"%s\"",
xpath);
ret = NB_ERR;
goto done;
"cannot obtain specific result for xpath \"%s\": %s",
xpath, yang_ly_strerrcode(err));
return err;
}
/*
* Mark keepers and sweep deleting non-keepers.
Expand All @@ -1100,27 +1123,108 @@ int yang_trim_tree(struct lyd_node *root, const char *xpath)
}

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
* which won't be marked and would otherwise be removed.
*/
if (node->priv == (void *)2)
LYD_TREE_DFS_continue = 1;
else if (!node->priv) {
LYD_TREE_DFS_continue = 1;
*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]);
}
darr_free(remove);

done:
if (set)
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
}
Loading

0 comments on commit 1e4229f

Please sign in to comment.