back to topotato report
topotato coverage report
Current view: top level - lib - yang.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 136 438 31.1 %
Date: 2023-11-16 17:19:14 Functions: 20 100 20.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 2018  NetDEF, Inc.
       4             :  *                     Renato Westphal
       5             :  */
       6             : 
       7             : #include <zebra.h>
       8             : 
       9             : #include "log.h"
      10             : #include "lib_errors.h"
      11             : #include "yang.h"
      12             : #include "yang_translator.h"
      13             : #include "northbound.h"
      14             : 
      15          12 : DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module");
      16          12 : DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure");
      17             : 
      18             : /* libyang container. */
      19             : struct ly_ctx *ly_native_ctx;
      20             : 
      21             : static struct yang_module_embed *embeds, **embedupd = &embeds;
      22             : 
      23          80 : void yang_module_embed(struct yang_module_embed *embed)
      24             : {
      25          80 :         embed->next = NULL;
      26          80 :         *embedupd = embed;
      27          80 :         embedupd = &embed->next;
      28          80 : }
      29             : 
      30          46 : static LY_ERR yang_module_imp_clb(const char *mod_name, const char *mod_rev,
      31             :                                   const char *submod_name,
      32             :                                   const char *submod_rev, void *user_data,
      33             :                                   LYS_INFORMAT *format,
      34             :                                   const char **module_data,
      35             :                                   void (**free_module_data)(void *, void *))
      36             : {
      37          46 :         struct yang_module_embed *e;
      38             : 
      39          46 :         if (!strcmp(mod_name, "ietf-inet-types") ||
      40          46 :             !strcmp(mod_name, "ietf-yang-types"))
      41             :                 /* libyang has these built in, don't try finding them here */
      42             :                 return LY_ENOTFOUND;
      43             : 
      44         424 :         for (e = embeds; e; e = e->next) {
      45         424 :                 if (e->sub_mod_name && submod_name) {
      46           0 :                         if (strcmp(e->sub_mod_name, submod_name))
      47           0 :                                 continue;
      48             : 
      49           0 :                         if (submod_rev && strcmp(e->sub_mod_rev, submod_rev))
      50           0 :                                 continue;
      51             :                 } else {
      52         424 :                         if (strcmp(e->mod_name, mod_name))
      53         378 :                                 continue;
      54             : 
      55          46 :                         if (mod_rev && strcmp(e->mod_rev, mod_rev))
      56           0 :                                 continue;
      57             :                 }
      58             : 
      59          46 :                 *format = e->format;
      60          46 :                 *module_data = e->data;
      61          46 :                 return LY_SUCCESS;
      62             :         }
      63             : 
      64             :         /* We get here for indirect modules like ietf-inet-types */
      65           0 :         zlog_debug(
      66             :                 "YANG model \"%s@%s\" \"%s@%s\"not embedded, trying external file",
      67             :                 mod_name, mod_rev ? mod_rev : "*",
      68             :                 submod_name ? submod_name : "*", submod_rev ? submod_rev : "*");
      69             : 
      70           0 :         return LY_ENOTFOUND;
      71             : }
      72             : 
      73             : /* clang-format off */
      74             : static const char *const frr_native_modules[] = {
      75             :         "frr-interface",
      76             :         "frr-vrf",
      77             :         "frr-routing",
      78             :         "frr-affinity-map",
      79             :         "frr-route-map",
      80             :         "frr-nexthop",
      81             :         "frr-ripd",
      82             :         "frr-ripngd",
      83             :         "frr-isisd",
      84             :         "frr-vrrpd",
      85             :         "frr-zebra",
      86             :         "frr-pathd",
      87             : };
      88             : /* clang-format on */
      89             : 
      90             : /* Generate the yang_modules tree. */
      91          46 : static inline int yang_module_compare(const struct yang_module *a,
      92             :                                       const struct yang_module *b)
      93             : {
      94          46 :         return strcmp(a->name, b->name);
      95             : }
      96          46 : RB_GENERATE(yang_modules, yang_module, entry, yang_module_compare)
      97             : 
      98             : struct yang_modules yang_modules = RB_INITIALIZER(&yang_modules);
      99             : 
     100          26 : struct yang_module *yang_module_load(const char *module_name)
     101             : {
     102          26 :         struct yang_module *module;
     103          26 :         const struct lys_module *module_info;
     104             : 
     105          26 :         module_info =
     106          26 :                 ly_ctx_load_module(ly_native_ctx, module_name, NULL, NULL);
     107          26 :         if (!module_info) {
     108           0 :                 flog_err(EC_LIB_YANG_MODULE_LOAD,
     109             :                          "%s: failed to load data model: %s", __func__,
     110             :                          module_name);
     111           0 :                 exit(1);
     112             :         }
     113             : 
     114          26 :         module = XCALLOC(MTYPE_YANG_MODULE, sizeof(*module));
     115          26 :         module->name = module_name;
     116          26 :         module->info = module_info;
     117             : 
     118          26 :         if (RB_INSERT(yang_modules, &yang_modules, module) != NULL) {
     119           0 :                 flog_err(EC_LIB_YANG_MODULE_LOADED_ALREADY,
     120             :                          "%s: YANG module is loaded already: %s", __func__,
     121             :                          module_name);
     122           0 :                 exit(1);
     123             :         }
     124             : 
     125          26 :         return module;
     126             : }
     127             : 
     128           0 : void yang_module_load_all(void)
     129             : {
     130           0 :         for (size_t i = 0; i < array_size(frr_native_modules); i++)
     131           0 :                 yang_module_load(frr_native_modules[i]);
     132           0 : }
     133             : 
     134           0 : struct yang_module *yang_module_find(const char *module_name)
     135             : {
     136           0 :         struct yang_module s;
     137             : 
     138           0 :         s.name = module_name;
     139           0 :         return RB_FIND(yang_modules, &yang_modules, &s);
     140             : }
     141             : 
     142       24078 : int yang_snodes_iterate_subtree(const struct lysc_node *snode,
     143             :                                 const struct lys_module *module,
     144             :                                 yang_iterate_cb cb, uint16_t flags, void *arg)
     145             : {
     146       24078 :         const struct lysc_node *child;
     147       24078 :         int ret = YANG_ITER_CONTINUE;
     148             : 
     149       24078 :         if (module && snode->module != module)
     150       11790 :                 goto next;
     151             : 
     152       12288 :         switch (snode->nodetype) {
     153         790 :         case LYS_CONTAINER:
     154         790 :                 if (CHECK_FLAG(flags, YANG_ITER_FILTER_NPCONTAINERS)) {
     155           0 :                         if (!CHECK_FLAG(snode->flags, LYS_PRESENCE))
     156           0 :                                 goto next;
     157             :                 }
     158             :                 break;
     159        6966 :         case LYS_LEAF:
     160        6966 :                 if (CHECK_FLAG(flags, YANG_ITER_FILTER_LIST_KEYS)) {
     161             :                         /* Ignore list keys. */
     162           0 :                         if (lysc_is_key(snode))
     163           0 :                                 goto next;
     164             :                 }
     165             :                 break;
     166         224 :         case LYS_INPUT:
     167             :         case LYS_OUTPUT:
     168         224 :                 if (CHECK_FLAG(flags, YANG_ITER_FILTER_INPUT_OUTPUT))
     169           0 :                         goto next;
     170             :                 break;
     171        4308 :         default:
     172        4308 :                 assert(snode->nodetype != LYS_AUGMENT
     173             :                        && snode->nodetype != LYS_GROUPING
     174             :                        && snode->nodetype != LYS_USES);
     175             :                 break;
     176             :         }
     177             : 
     178       12288 :         ret = (*cb)(snode, arg);
     179       12288 :         if (ret == YANG_ITER_STOP)
     180             :                 return ret;
     181             : 
     182       12234 : next:
     183             :         /*
     184             :          * YANG leafs and leaf-lists can't have child nodes.
     185             :          */
     186       24024 :         if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
     187             :                 return YANG_ITER_CONTINUE;
     188             : 
     189       33358 :         LY_LIST_FOR (lysc_node_child(snode), child) {
     190       23320 :                 ret = yang_snodes_iterate_subtree(child, module, cb, flags,
     191             :                                                   arg);
     192       23320 :                 if (ret == YANG_ITER_STOP)
     193             :                         return ret;
     194             :         }
     195             :         return ret;
     196             : }
     197             : 
     198          38 : int yang_snodes_iterate(const struct lys_module *module, yang_iterate_cb cb,
     199             :                         uint16_t flags, void *arg)
     200             : {
     201          38 :         const struct lys_module *module_iter;
     202          38 :         uint32_t idx = 0;
     203          38 :         int ret = YANG_ITER_CONTINUE;
     204             : 
     205          38 :         idx = ly_ctx_internal_modules_count(ly_native_ctx);
     206         446 :         while ((module_iter = ly_ctx_get_module_iter(ly_native_ctx, &idx))) {
     207         408 :                 struct lysc_node *snode;
     208             : 
     209         408 :                 if (!module_iter->implemented)
     210         152 :                         continue;
     211             : 
     212         474 :                 LY_LIST_FOR (module_iter->compiled->data, snode) {
     213         218 :                         ret = yang_snodes_iterate_subtree(snode, module, cb,
     214             :                                                           flags, arg);
     215         218 :                         if (ret == YANG_ITER_STOP)
     216             :                                 return ret;
     217             :                 }
     218         564 :                 LY_LIST_FOR (&module_iter->compiled->rpcs->node, snode) {
     219         308 :                         ret = yang_snodes_iterate_subtree(snode, module, cb,
     220             :                                                           flags, arg);
     221         308 :                         if (ret == YANG_ITER_STOP)
     222             :                                 return ret;
     223             :                 }
     224         256 :                 LY_LIST_FOR (&module_iter->compiled->notifs->node, snode) {
     225           0 :                         ret = yang_snodes_iterate_subtree(snode, module, cb,
     226             :                                                           flags, arg);
     227           0 :                         if (ret == YANG_ITER_STOP)
     228             :                                 return ret;
     229             :                 }
     230             :         }
     231             : 
     232             :         return ret;
     233             : }
     234             : 
     235        1908 : void yang_snode_get_path(const struct lysc_node *snode,
     236             :                          enum yang_path_type type, char *xpath,
     237             :                          size_t xpath_len)
     238             : {
     239        1908 :         switch (type) {
     240           0 :         case YANG_PATH_SCHEMA:
     241           0 :                 (void)lysc_path(snode, LYSC_PATH_LOG, xpath, xpath_len);
     242           0 :                 break;
     243        1908 :         case YANG_PATH_DATA:
     244        1908 :                 (void)lysc_path(snode, LYSC_PATH_DATA, xpath, xpath_len);
     245        1908 :                 break;
     246           0 :         default:
     247           0 :                 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown yang path type: %u",
     248             :                          __func__, type);
     249           0 :                 exit(1);
     250             :         }
     251        1908 : }
     252             : 
     253         634 : struct lysc_node *yang_find_snode(struct ly_ctx *ly_ctx, const char *xpath,
     254             :                                   uint32_t options)
     255             : {
     256         634 :         struct lysc_node *snode;
     257             : 
     258         634 :         snode = (struct lysc_node *)lys_find_path(ly_ctx, NULL, xpath, 0);
     259             : 
     260         634 :         return snode;
     261             : }
     262             : 
     263        1908 : struct lysc_node *yang_snode_real_parent(const struct lysc_node *snode)
     264             : {
     265        1908 :         struct lysc_node *parent = snode->parent;
     266             : 
     267        5354 :         while (parent) {
     268        4870 :                 switch (parent->nodetype) {
     269         820 :                 case LYS_CONTAINER:
     270         820 :                         if (CHECK_FLAG(parent->flags, LYS_PRESENCE))
     271           0 :                                 return parent;
     272             :                         break;
     273             :                 case LYS_LIST:
     274             :                         return parent;
     275             :                 default:
     276             :                         break;
     277             :                 }
     278        3446 :                 parent = parent->parent;
     279             :         }
     280             : 
     281             :         return NULL;
     282             : }
     283             : 
     284        1908 : struct lysc_node *yang_snode_parent_list(const struct lysc_node *snode)
     285             : {
     286        1908 :         struct lysc_node *parent = snode->parent;
     287             : 
     288        5354 :         while (parent) {
     289        4870 :                 switch (parent->nodetype) {
     290             :                 case LYS_LIST:
     291             :                         return parent;
     292             :                 default:
     293        3446 :                         break;
     294             :                 }
     295        3446 :                 parent = parent->parent;
     296             :         }
     297             : 
     298             :         return NULL;
     299             : }
     300             : 
     301           0 : bool yang_snode_is_typeless_data(const struct lysc_node *snode)
     302             : {
     303           0 :         const struct lysc_node_leaf *sleaf;
     304             : 
     305           0 :         switch (snode->nodetype) {
     306           0 :         case LYS_LEAF:
     307           0 :                 sleaf = (struct lysc_node_leaf *)snode;
     308           0 :                 if (sleaf->type->basetype == LY_TYPE_EMPTY)
     309             :                         return true;
     310             :                 return false;
     311             :         case LYS_LEAFLIST:
     312             :                 return false;
     313             :         default:
     314             :                 return true;
     315             :         }
     316             : }
     317             : 
     318           0 : const char *yang_snode_get_default(const struct lysc_node *snode)
     319             : {
     320           0 :         const struct lysc_node_leaf *sleaf;
     321             : 
     322           0 :         switch (snode->nodetype) {
     323           0 :         case LYS_LEAF:
     324           0 :                 sleaf = (const struct lysc_node_leaf *)snode;
     325           0 :                 return sleaf->dflt ? lyd_value_get_canonical(sleaf->module->ctx,
     326             :                                                              sleaf->dflt)
     327           0 :                                    : NULL;
     328             :         case LYS_LEAFLIST:
     329             :                 /* TODO: check leaf-list default values */
     330             :                 return NULL;
     331             :         default:
     332             :                 return NULL;
     333             :         }
     334             : }
     335             : 
     336           0 : const struct lysc_type *yang_snode_get_type(const struct lysc_node *snode)
     337             : {
     338           0 :         struct lysc_node_leaf *sleaf = (struct lysc_node_leaf *)snode;
     339           0 :         struct lysc_type *type;
     340             : 
     341           0 :         if (!CHECK_FLAG(sleaf->nodetype, LYS_LEAF | LYS_LEAFLIST))
     342             :                 return NULL;
     343             : 
     344           0 :         type = sleaf->type;
     345           0 :         while (type->basetype == LY_TYPE_LEAFREF)
     346           0 :                 type = ((struct lysc_type_leafref *)type)->realtype;
     347             : 
     348             :         return type;
     349             : }
     350             : 
     351         112 : unsigned int yang_snode_num_keys(const struct lysc_node *snode)
     352             : {
     353         112 :         const struct lysc_node_leaf *skey;
     354         112 :         uint count = 0;
     355             : 
     356         112 :         if (!CHECK_FLAG(snode->nodetype, LYS_LIST))
     357             :                 return 0;
     358             : 
     359             :         /* Walk list of children */
     360         228 :         LY_FOR_KEYS (snode, skey) {
     361         116 :                 count++;
     362             :         }
     363             :         return count;
     364             : }
     365             : 
     366           0 : void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath,
     367             :                          size_t xpath_len)
     368             : {
     369           0 :         lyd_path(dnode, LYD_PATH_STD, xpath, xpath_len);
     370           0 : }
     371             : 
     372           0 : const char *yang_dnode_get_schema_name(const struct lyd_node *dnode,
     373             :                                        const char *xpath_fmt, ...)
     374             : {
     375           0 :         if (xpath_fmt) {
     376           0 :                 va_list ap;
     377           0 :                 char xpath[XPATH_MAXLEN];
     378             : 
     379           0 :                 va_start(ap, xpath_fmt);
     380           0 :                 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     381           0 :                 va_end(ap);
     382             : 
     383           0 :                 dnode = yang_dnode_get(dnode, xpath);
     384           0 :                 if (!dnode) {
     385           0 :                         flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
     386             :                                  "%s: couldn't find %s", __func__, xpath);
     387           0 :                         zlog_backtrace(LOG_ERR);
     388           0 :                         abort();
     389             :                 }
     390             :         }
     391             : 
     392           0 :         return dnode->schema->name;
     393             : }
     394             : 
     395           0 : struct lyd_node *yang_dnode_get(const struct lyd_node *dnode, const char *xpath)
     396             : {
     397           0 :         struct ly_set *set = NULL;
     398           0 :         struct lyd_node *dnode_ret = NULL;
     399             : 
     400             :         /*
     401             :          * XXX a lot of the code uses this for style I guess. It shouldn't, as
     402             :          * it adds to the xpath parsing complexity in libyang.
     403             :          */
     404           0 :         if (xpath[0] == '.' && xpath[1] == '/')
     405           0 :                 xpath += 2;
     406             : 
     407           0 :         if (lyd_find_xpath(dnode, xpath, &set)) {
     408             :                 /*
     409             :                  * Commenting out the below assert failure as it crashes mgmtd
     410             :                  * when bad xpath is passed.
     411             :                  *
     412             :                  * assert(0);  XXX replicates old libyang1 base code
     413             :                  */
     414           0 :                 goto exit;
     415             :         }
     416           0 :         if (set->count == 0)
     417           0 :                 goto exit;
     418             : 
     419           0 :         if (set->count > 1) {
     420           0 :                 flog_warn(EC_LIB_YANG_DNODE_NOT_FOUND,
     421             :                           "%s: found %u elements (expected 0 or 1) [xpath %s]",
     422             :                           __func__, set->count, xpath);
     423           0 :                 goto exit;
     424             :         }
     425             : 
     426           0 :         dnode_ret = set->dnodes[0];
     427             : 
     428           0 : exit:
     429           0 :         ly_set_free(set, NULL);
     430             : 
     431           0 :         return dnode_ret;
     432             : }
     433             : 
     434           0 : struct lyd_node *yang_dnode_getf(const struct lyd_node *dnode,
     435             :                                  const char *xpath_fmt, ...)
     436             : {
     437           0 :         va_list ap;
     438           0 :         char xpath[XPATH_MAXLEN];
     439             : 
     440           0 :         va_start(ap, xpath_fmt);
     441           0 :         vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     442           0 :         va_end(ap);
     443             : 
     444           0 :         return yang_dnode_get(dnode, xpath);
     445             : }
     446             : 
     447           0 : bool yang_dnode_exists(const struct lyd_node *dnode, const char *xpath)
     448             : {
     449           0 :         struct ly_set *set = NULL;
     450           0 :         bool exists = false;
     451             : 
     452           0 :         if (xpath[0] == '.' && xpath[1] == '/')
     453           0 :                 xpath += 2;
     454           0 :         if (lyd_find_xpath(dnode, xpath, &set))
     455             :                 return false;
     456           0 :         exists = set->count > 0;
     457           0 :         ly_set_free(set, NULL);
     458           0 :         return exists;
     459             : }
     460             : 
     461           0 : bool yang_dnode_existsf(const struct lyd_node *dnode, const char *xpath_fmt,
     462             :                         ...)
     463             : {
     464           0 :         va_list ap;
     465           0 :         char xpath[XPATH_MAXLEN];
     466             : 
     467           0 :         va_start(ap, xpath_fmt);
     468           0 :         vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     469           0 :         va_end(ap);
     470             : 
     471           0 :         return yang_dnode_exists(dnode, xpath);
     472             : }
     473             : 
     474           0 : void yang_dnode_iterate(yang_dnode_iter_cb cb, void *arg,
     475             :                         const struct lyd_node *dnode, const char *xpath_fmt,
     476             :                         ...)
     477             : {
     478           0 :         va_list ap;
     479           0 :         char xpath[XPATH_MAXLEN];
     480           0 :         struct ly_set *set;
     481             : 
     482           0 :         va_start(ap, xpath_fmt);
     483           0 :         vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     484           0 :         va_end(ap);
     485             : 
     486           0 :         if (lyd_find_xpath(dnode, xpath, &set)) {
     487           0 :                 assert(0); /* XXX libyang2: ly1 code asserted success */
     488             :                 return;
     489             :         }
     490           0 :         for (unsigned int i = 0; i < set->count; i++) {
     491           0 :                 int ret;
     492             : 
     493           0 :                 ret = (*cb)(set->dnodes[i], arg);
     494           0 :                 if (ret == YANG_ITER_STOP)
     495             :                         break;
     496             :         }
     497             : 
     498           0 :         ly_set_free(set, NULL);
     499             : }
     500             : 
     501           0 : bool yang_dnode_is_default(const struct lyd_node *dnode, const char *xpath)
     502             : {
     503           0 :         const struct lysc_node *snode;
     504           0 :         struct lysc_node_leaf *sleaf;
     505             : 
     506           0 :         if (xpath)
     507           0 :                 dnode = yang_dnode_get(dnode, xpath);
     508             : 
     509           0 :         assert(dnode);
     510           0 :         snode = dnode->schema;
     511           0 :         switch (snode->nodetype) {
     512           0 :         case LYS_LEAF:
     513           0 :                 sleaf = (struct lysc_node_leaf *)snode;
     514           0 :                 if (sleaf->type->basetype == LY_TYPE_EMPTY)
     515             :                         return false;
     516           0 :                 return lyd_is_default(dnode);
     517             :         case LYS_LEAFLIST:
     518             :                 /* TODO: check leaf-list default values */
     519             :                 return false;
     520           0 :         case LYS_CONTAINER:
     521           0 :                 if (CHECK_FLAG(snode->flags, LYS_PRESENCE))
     522           0 :                         return false;
     523             :                 return true;
     524             :         default:
     525             :                 return false;
     526             :         }
     527             : }
     528             : 
     529           0 : bool yang_dnode_is_defaultf(const struct lyd_node *dnode, const char *xpath_fmt,
     530             :                             ...)
     531             : {
     532           0 :         if (!xpath_fmt)
     533           0 :                 return yang_dnode_is_default(dnode, NULL);
     534             :         else {
     535           0 :                 va_list ap;
     536           0 :                 char xpath[XPATH_MAXLEN];
     537             : 
     538           0 :                 va_start(ap, xpath_fmt);
     539           0 :                 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     540           0 :                 va_end(ap);
     541             : 
     542           0 :                 return yang_dnode_is_default(dnode, xpath);
     543             :         }
     544             : }
     545             : 
     546           0 : bool yang_dnode_is_default_recursive(const struct lyd_node *dnode)
     547             : {
     548           0 :         struct lyd_node *root, *dnode_iter;
     549             : 
     550           0 :         if (!yang_dnode_is_default(dnode, NULL))
     551             :                 return false;
     552             : 
     553           0 :         if (CHECK_FLAG(dnode->schema->nodetype, LYS_LEAF | LYS_LEAFLIST))
     554             :                 return true;
     555             : 
     556           0 :         LY_LIST_FOR (lyd_child(dnode), root) {
     557           0 :                 LYD_TREE_DFS_BEGIN (root, dnode_iter) {
     558           0 :                         if (!yang_dnode_is_default(dnode_iter, NULL))
     559             :                                 return false;
     560             : 
     561           0 :                         LYD_TREE_DFS_END(root, dnode_iter);
     562             :                 }
     563             :         }
     564             : 
     565             :         return true;
     566             : }
     567             : 
     568           0 : void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value)
     569             : {
     570           0 :         assert(dnode->schema->nodetype == LYS_LEAF);
     571           0 :         lyd_change_term(dnode, value);
     572           0 : }
     573             : 
     574           8 : struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only)
     575             : {
     576           8 :         struct lyd_node *dnode = NULL;
     577           8 :         int options = config_only ? LYD_VALIDATE_NO_STATE : 0;
     578             : 
     579           8 :         if (lyd_validate_all(&dnode, ly_ctx, options, NULL) != 0) {
     580             :                 /* Should never happen. */
     581           0 :                 flog_err(EC_LIB_LIBYANG, "%s: lyd_validate() failed", __func__);
     582           0 :                 exit(1);
     583             :         }
     584             : 
     585           8 :         return dnode;
     586             : }
     587             : 
     588           0 : struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode)
     589             : {
     590           0 :         struct lyd_node *dup = NULL;
     591           0 :         LY_ERR err;
     592           0 :         err = lyd_dup_siblings(dnode, NULL, LYD_DUP_RECURSIVE, &dup);
     593           0 :         assert(!err);
     594           0 :         return dup;
     595             : }
     596             : 
     597          16 : void yang_dnode_free(struct lyd_node *dnode)
     598             : {
     599          16 :         while (dnode->parent)
     600           0 :                 dnode = lyd_parent(dnode);
     601          16 :         lyd_free_all(dnode);
     602          16 : }
     603             : 
     604           0 : struct yang_data *yang_data_new(const char *xpath, const char *value)
     605             : {
     606           0 :         struct yang_data *data;
     607             : 
     608           0 :         data = XCALLOC(MTYPE_YANG_DATA, sizeof(*data));
     609           0 :         strlcpy(data->xpath, xpath, sizeof(data->xpath));
     610           0 :         if (value)
     611           0 :                 data->value = strdup(value);
     612             : 
     613           0 :         return data;
     614             : }
     615             : 
     616           0 : void yang_data_free(struct yang_data *data)
     617             : {
     618           0 :         if (data->value)
     619           0 :                 free(data->value);
     620           0 :         XFREE(MTYPE_YANG_DATA, data);
     621           0 : }
     622             : 
     623           0 : struct list *yang_data_list_new(void)
     624             : {
     625           0 :         struct list *list;
     626             : 
     627           0 :         list = list_new();
     628           0 :         list->del = (void (*)(void *))yang_data_free;
     629             : 
     630           0 :         return list;
     631             : }
     632             : 
     633           0 : struct yang_data *yang_data_list_find(const struct list *list,
     634             :                                       const char *xpath_fmt, ...)
     635             : {
     636           0 :         char xpath[XPATH_MAXLEN];
     637           0 :         struct yang_data *data;
     638           0 :         struct listnode *node;
     639           0 :         va_list ap;
     640             : 
     641           0 :         va_start(ap, xpath_fmt);
     642           0 :         vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     643           0 :         va_end(ap);
     644             : 
     645           0 :         for (ALL_LIST_ELEMENTS_RO(list, node, data))
     646           0 :                 if (strmatch(data->xpath, xpath))
     647           0 :                         return data;
     648             : 
     649             :         return NULL;
     650             : }
     651             : 
     652             : /* Make libyang log its errors using FRR logging infrastructure. */
     653           0 : static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
     654             : {
     655           0 :         int priority = LOG_ERR;
     656             : 
     657           0 :         switch (level) {
     658             :         case LY_LLERR:
     659             :                 priority = LOG_ERR;
     660             :                 break;
     661           0 :         case LY_LLWRN:
     662           0 :                 priority = LOG_WARNING;
     663           0 :                 break;
     664           0 :         case LY_LLVRB:
     665             :         case LY_LLDBG:
     666           0 :                 priority = LOG_DEBUG;
     667           0 :                 break;
     668             :         }
     669             : 
     670           0 :         if (path)
     671           0 :                 zlog(priority, "libyang: %s (%s)", msg, path);
     672             :         else
     673           0 :                 zlog(priority, "libyang: %s", msg);
     674           0 : }
     675             : 
     676           0 : const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf, size_t buf_len)
     677             : {
     678           0 :         struct ly_err_item *ei;
     679             : 
     680           0 :         ei = ly_err_first(ly_ctx);
     681           0 :         if (!ei)
     682             :                 return "";
     683             : 
     684           0 :         strlcpy(buf, "YANG error(s):\n", buf_len);
     685           0 :         for (; ei; ei = ei->next) {
     686           0 :                 if (ei->path) {
     687           0 :                         strlcat(buf, " Path: ", buf_len);
     688           0 :                         strlcat(buf, ei->path, buf_len);
     689           0 :                         strlcat(buf, "\n", buf_len);
     690             :                 }
     691           0 :                 strlcat(buf, " Error: ", buf_len);
     692           0 :                 strlcat(buf, ei->msg, buf_len);
     693           0 :                 strlcat(buf, "\n", buf_len);
     694             :         }
     695             : 
     696           0 :         ly_err_clean(ly_ctx, NULL);
     697             : 
     698           0 :         return buf;
     699             : }
     700             : 
     701           0 : void yang_debugging_set(bool enable)
     702             : {
     703           0 :         if (enable) {
     704           0 :                 ly_log_level(LY_LLDBG);
     705           0 :                 ly_log_dbg_groups(0xFF);
     706             :         } else {
     707           0 :                 ly_log_level(LY_LLERR);
     708           0 :                 ly_log_dbg_groups(0);
     709             :         }
     710           0 : }
     711             : 
     712           8 : struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile)
     713             : {
     714           8 :         struct ly_ctx *ctx = NULL;
     715           8 :         const char *yang_models_path = YANG_MODELS_PATH;
     716           8 :         LY_ERR err;
     717             : 
     718           8 :         if (access(yang_models_path, R_OK | X_OK)) {
     719           0 :                 yang_models_path = NULL;
     720           0 :                 if (errno == ENOENT)
     721           0 :                         zlog_info("yang model directory \"%s\" does not exist",
     722             :                                   YANG_MODELS_PATH);
     723             :                 else
     724           0 :                         flog_err_sys(EC_LIB_LIBYANG,
     725             :                                      "cannot access yang model directory \"%s\"",
     726             :                                      YANG_MODELS_PATH);
     727             :         }
     728             : 
     729           8 :         uint options = LY_CTX_NO_YANGLIBRARY | LY_CTX_DISABLE_SEARCHDIR_CWD;
     730           8 :         if (explicit_compile)
     731           0 :                 options |= LY_CTX_EXPLICIT_COMPILE;
     732           8 :         err = ly_ctx_new(yang_models_path, options, &ctx);
     733           8 :         if (err)
     734             :                 return NULL;
     735             : 
     736           8 :         if (embedded_modules)
     737           8 :                 ly_ctx_set_module_imp_clb(ctx, yang_module_imp_clb, NULL);
     738             : 
     739           8 :         return ctx;
     740             : }
     741             : 
     742           4 : void yang_init(bool embedded_modules, bool defer_compile)
     743             : {
     744             :         /* Initialize libyang global parameters that affect all containers. */
     745           4 :         ly_set_log_clb(ly_log_cb, 1);
     746           4 :         ly_log_options(LY_LOLOG | LY_LOSTORE);
     747             : 
     748             :         /* Initialize libyang container for native models. */
     749           4 :         ly_native_ctx = yang_ctx_new_setup(embedded_modules, defer_compile);
     750           4 :         if (!ly_native_ctx) {
     751           0 :                 flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
     752           0 :                 exit(1);
     753             :         }
     754             : 
     755           4 :         yang_translator_init();
     756           4 : }
     757             : 
     758           0 : void yang_init_loading_complete(void)
     759             : {
     760             :         /* Compile everything */
     761           0 :         if (ly_ctx_compile(ly_native_ctx) != LY_SUCCESS) {
     762           0 :                 flog_err(EC_LIB_YANG_MODULE_LOAD,
     763             :                          "%s: failed to compile loaded modules: %s", __func__,
     764             :                          ly_errmsg(ly_native_ctx));
     765           0 :                 exit(1);
     766             :         }
     767           0 : }
     768             : 
     769           8 : void yang_terminate(void)
     770             : {
     771           8 :         struct yang_module *module;
     772             : 
     773           8 :         yang_translator_terminate();
     774             : 
     775           8 :         while (!RB_EMPTY(yang_modules, &yang_modules)) {
     776          52 :                 module = RB_ROOT(yang_modules, &yang_modules);
     777             : 
     778             :                 /*
     779             :                  * We shouldn't call ly_ctx_remove_module() here because this
     780             :                  * function also removes other modules that depend on it.
     781             :                  *
     782             :                  * ly_ctx_destroy() will release all memory for us.
     783             :                  */
     784          52 :                 RB_REMOVE(yang_modules, &yang_modules, module);
     785          60 :                 XFREE(MTYPE_YANG_MODULE, module);
     786             :         }
     787             : 
     788           8 :         ly_ctx_destroy(ly_native_ctx);
     789           8 : }
     790             : 
     791           0 : const struct lyd_node *yang_dnode_get_parent(const struct lyd_node *dnode,
     792             :                                              const char *name)
     793             : {
     794           0 :         const struct lyd_node *orig_dnode = dnode;
     795             : 
     796           0 :         while (orig_dnode) {
     797           0 :                 switch (orig_dnode->schema->nodetype) {
     798           0 :                 case LYS_LIST:
     799             :                 case LYS_CONTAINER:
     800           0 :                         if (!strcmp(orig_dnode->schema->name, name))
     801           0 :                                 return orig_dnode;
     802             :                         break;
     803             :                 default:
     804             :                         break;
     805             :                 }
     806             : 
     807             :                 orig_dnode = lyd_parent(orig_dnode);
     808             :         }
     809             : 
     810             :         return NULL;
     811             : }
     812             : 
     813           0 : bool yang_is_last_list_dnode(const struct lyd_node *dnode)
     814             : {
     815           0 :         return (((dnode->next == NULL)
     816           0 :              || (dnode->next
     817           0 :                  && (strcmp(dnode->next->schema->name, dnode->schema->name)
     818             :                      != 0)))
     819           0 :             && dnode->prev
     820           0 :             && ((dnode->prev == dnode)
     821           0 :                 || (strcmp(dnode->prev->schema->name, dnode->schema->name)
     822             :                     != 0)));
     823             : }
     824             : 
     825           0 : bool yang_is_last_level_dnode(const struct lyd_node *dnode)
     826             : {
     827           0 :         const struct lyd_node *parent;
     828           0 :         const struct lyd_node *key_leaf;
     829           0 :         uint8_t keys_size;
     830             : 
     831           0 :         switch (dnode->schema->nodetype) {
     832           0 :         case LYS_LIST:
     833           0 :                 assert(dnode->parent);
     834           0 :                 parent = lyd_parent(dnode);
     835           0 :                 uint snode_num_keys = yang_snode_num_keys(parent->schema);
     836             :                 /* XXX libyang2: q: really don't understand this code. */
     837           0 :                 key_leaf = dnode->prev;
     838           0 :                 for (keys_size = 1; keys_size < snode_num_keys; keys_size++)
     839           0 :                         key_leaf = key_leaf->prev;
     840           0 :                 if (key_leaf->prev == dnode)
     841             :                         return true;
     842             :                 break;
     843             :         case LYS_CONTAINER:
     844             :                 return true;
     845             :         default:
     846             :                 break;
     847             :         }
     848             : 
     849             :         return false;
     850             : }
     851             : 
     852             : const struct lyd_node *
     853           0 : yang_get_subtree_with_no_sibling(const struct lyd_node *dnode)
     854             : {
     855           0 :         bool parent = true;
     856           0 :         const struct lyd_node *node;
     857             : 
     858           0 :         node = dnode;
     859           0 :         if (node->schema->nodetype != LYS_LIST)
     860             :                 return node;
     861             : 
     862           0 :         while (parent) {
     863           0 :                 switch (node->schema->nodetype) {
     864           0 :                 case LYS_CONTAINER:
     865           0 :                         if (!CHECK_FLAG(node->schema->flags, LYS_PRESENCE)) {
     866           0 :                                 if (node->parent
     867           0 :                                     && (node->parent->schema->module
     868           0 :                                         == dnode->schema->module))
     869           0 :                                         node = lyd_parent(node);
     870             :                                 else
     871             :                                         parent = false;
     872             :                         } else
     873             :                                 parent = false;
     874             :                         break;
     875           0 :                 case LYS_LIST:
     876           0 :                         if (yang_is_last_list_dnode(node)
     877           0 :                             && yang_is_last_level_dnode(node)) {
     878           0 :                                 if (node->parent
     879           0 :                                     && (node->parent->schema->module
     880           0 :                                         == dnode->schema->module))
     881           0 :                                         node = lyd_parent(node);
     882             :                                 else
     883             :                                         parent = false;
     884             :                         } else
     885             :                                 parent = false;
     886             :                         break;
     887             :                 default:
     888             :                         parent = false;
     889             :                         break;
     890             :                 }
     891             :         }
     892             :         return node;
     893             : }
     894             : 
     895           0 : uint32_t yang_get_list_pos(const struct lyd_node *node)
     896             : {
     897           0 :         return lyd_list_pos(node);
     898             : }
     899             : 
     900           0 : uint32_t yang_get_list_elements_count(const struct lyd_node *node)
     901             : {
     902           0 :         unsigned int count;
     903           0 :         const struct lysc_node *schema;
     904             : 
     905           0 :         if (!node
     906           0 :             || ((node->schema->nodetype != LYS_LIST)
     907           0 :                 && (node->schema->nodetype != LYS_LEAFLIST))) {
     908             :                 return 0;
     909             :         }
     910             : 
     911             :         schema = node->schema;
     912             :         count = 0;
     913           0 :         do {
     914           0 :                 if (node->schema == schema)
     915           0 :                         ++count;
     916           0 :                 node = node->next;
     917           0 :         } while (node);
     918             :         return count;
     919             : }

Generated by: LCOV version v1.16-topotato