back to topotato report
topotato coverage report
Current view: top level - lib - yang.c (source / functions) Hit Total Coverage
Test: test_bgp_aggregate_address_origin.py::BGPAggregateAddressOrigin Lines: 166 436 38.1 %
Date: 2023-02-24 18:36:37 Functions: 25 50 50.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2018  NetDEF, Inc.
       3             :  *                     Renato Westphal
       4             :  *
       5             :  * This program is free software; you can redistribute it and/or modify it
       6             :  * under the terms of the GNU General Public License as published by the Free
       7             :  * Software Foundation; either version 2 of the License, or (at your option)
       8             :  * any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      11             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      13             :  * more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License along
      16             :  * with this program; see the file COPYING; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      18             :  */
      19             : 
      20             : #include <zebra.h>
      21             : 
      22             : #include "log.h"
      23             : #include "lib_errors.h"
      24             : #include "yang.h"
      25             : #include "yang_translator.h"
      26             : #include "northbound.h"
      27             : 
      28          12 : DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module");
      29          12 : DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure");
      30             : 
      31             : /* libyang container. */
      32             : struct ly_ctx *ly_native_ctx;
      33             : 
      34             : static struct yang_module_embed *embeds, **embedupd = &embeds;
      35             : 
      36          72 : void yang_module_embed(struct yang_module_embed *embed)
      37             : {
      38          72 :         embed->next = NULL;
      39          72 :         *embedupd = embed;
      40          72 :         embedupd = &embed->next;
      41          72 : }
      42             : 
      43          42 : static LY_ERR yang_module_imp_clb(const char *mod_name, const char *mod_rev,
      44             :                                   const char *submod_name,
      45             :                                   const char *submod_rev, void *user_data,
      46             :                                   LYS_INFORMAT *format,
      47             :                                   const char **module_data,
      48             :                                   void (**free_module_data)(void *, void *))
      49             : {
      50          42 :         struct yang_module_embed *e;
      51             : 
      52          42 :         if (!strcmp(mod_name, "ietf-inet-types") ||
      53          42 :             !strcmp(mod_name, "ietf-yang-types"))
      54             :                 /* libyang has these built in, don't try finding them here */
      55             :                 return LY_ENOTFOUND;
      56             : 
      57         330 :         for (e = embeds; e; e = e->next) {
      58         330 :                 if (e->sub_mod_name && submod_name) {
      59           0 :                         if (strcmp(e->sub_mod_name, submod_name))
      60           0 :                                 continue;
      61             : 
      62           0 :                         if (submod_rev && strcmp(e->sub_mod_rev, submod_rev))
      63           0 :                                 continue;
      64             :                 } else {
      65         330 :                         if (strcmp(e->mod_name, mod_name))
      66         288 :                                 continue;
      67             : 
      68          42 :                         if (mod_rev && strcmp(e->mod_rev, mod_rev))
      69           0 :                                 continue;
      70             :                 }
      71             : 
      72          42 :                 *format = e->format;
      73          42 :                 *module_data = e->data;
      74          42 :                 return LY_SUCCESS;
      75             :         }
      76             : 
      77             :         /* We get here for indirect modules like ietf-inet-types */
      78           0 :         zlog_debug(
      79             :                 "YANG model \"%s@%s\" \"%s@%s\"not embedded, trying external file",
      80             :                 mod_name, mod_rev ? mod_rev : "*",
      81             :                 submod_name ? submod_name : "*", submod_rev ? submod_rev : "*");
      82             : 
      83           0 :         return LY_ENOTFOUND;
      84             : }
      85             : 
      86             : /* clang-format off */
      87             : static const char *const frr_native_modules[] = {
      88             :         "frr-interface",
      89             :         "frr-vrf",
      90             :         "frr-routing",
      91             :         "frr-route-map",
      92             :         "frr-nexthop",
      93             :         "frr-ripd",
      94             :         "frr-ripngd",
      95             :         "frr-isisd",
      96             :         "frr-vrrpd",
      97             :         "frr-zebra",
      98             :         "frr-pathd",
      99             : };
     100             : /* clang-format on */
     101             : 
     102             : /* Generate the yang_modules tree. */
     103          42 : static inline int yang_module_compare(const struct yang_module *a,
     104             :                                       const struct yang_module *b)
     105             : {
     106          42 :         return strcmp(a->name, b->name);
     107             : }
     108          42 : RB_GENERATE(yang_modules, yang_module, entry, yang_module_compare)
     109             : 
     110             : struct yang_modules yang_modules = RB_INITIALIZER(&yang_modules);
     111             : 
     112          24 : struct yang_module *yang_module_load(const char *module_name)
     113             : {
     114          24 :         struct yang_module *module;
     115          24 :         const struct lys_module *module_info;
     116             : 
     117          24 :         module_info =
     118          24 :                 ly_ctx_load_module(ly_native_ctx, module_name, NULL, NULL);
     119          24 :         if (!module_info) {
     120           0 :                 flog_err(EC_LIB_YANG_MODULE_LOAD,
     121             :                          "%s: failed to load data model: %s", __func__,
     122             :                          module_name);
     123           0 :                 exit(1);
     124             :         }
     125             : 
     126          24 :         module = XCALLOC(MTYPE_YANG_MODULE, sizeof(*module));
     127          24 :         module->name = module_name;
     128          24 :         module->info = module_info;
     129             : 
     130          24 :         if (RB_INSERT(yang_modules, &yang_modules, module) != NULL) {
     131           0 :                 flog_err(EC_LIB_YANG_MODULE_LOADED_ALREADY,
     132             :                          "%s: YANG module is loaded already: %s", __func__,
     133             :                          module_name);
     134           0 :                 exit(1);
     135             :         }
     136             : 
     137          24 :         return module;
     138             : }
     139             : 
     140           0 : void yang_module_load_all(void)
     141             : {
     142           0 :         for (size_t i = 0; i < array_size(frr_native_modules); i++)
     143           0 :                 yang_module_load(frr_native_modules[i]);
     144           0 : }
     145             : 
     146           0 : struct yang_module *yang_module_find(const char *module_name)
     147             : {
     148           0 :         struct yang_module s;
     149             : 
     150           0 :         s.name = module_name;
     151           0 :         return RB_FIND(yang_modules, &yang_modules, &s);
     152             : }
     153             : 
     154       21256 : int yang_snodes_iterate_subtree(const struct lysc_node *snode,
     155             :                                 const struct lys_module *module,
     156             :                                 yang_iterate_cb cb, uint16_t flags, void *arg)
     157             : {
     158       21256 :         const struct lysc_node *child;
     159       21256 :         int ret = YANG_ITER_CONTINUE;
     160             : 
     161       21256 :         if (module && snode->module != module)
     162        9828 :                 goto next;
     163             : 
     164       11428 :         switch (snode->nodetype) {
     165         678 :         case LYS_CONTAINER:
     166         678 :                 if (CHECK_FLAG(flags, YANG_ITER_FILTER_NPCONTAINERS)) {
     167           0 :                         if (!CHECK_FLAG(snode->flags, LYS_PRESENCE))
     168           0 :                                 goto next;
     169             :                 }
     170             :                 break;
     171        6622 :         case LYS_LEAF:
     172        6622 :                 if (CHECK_FLAG(flags, YANG_ITER_FILTER_LIST_KEYS)) {
     173             :                         /* Ignore list keys. */
     174           0 :                         if (lysc_is_key(snode))
     175           0 :                                 goto next;
     176             :                 }
     177             :                 break;
     178         224 :         case LYS_INPUT:
     179             :         case LYS_OUTPUT:
     180         224 :                 if (CHECK_FLAG(flags, YANG_ITER_FILTER_INPUT_OUTPUT))
     181           0 :                         goto next;
     182             :                 break;
     183        3904 :         default:
     184        3904 :                 assert(snode->nodetype != LYS_AUGMENT
     185             :                        && snode->nodetype != LYS_GROUPING
     186             :                        && snode->nodetype != LYS_USES);
     187             :                 break;
     188             :         }
     189             : 
     190       11428 :         ret = (*cb)(snode, arg);
     191       11428 :         if (ret == YANG_ITER_STOP)
     192             :                 return ret;
     193             : 
     194       11378 : next:
     195             :         /*
     196             :          * YANG leafs and leaf-lists can't have child nodes.
     197             :          */
     198       21206 :         if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
     199             :                 return YANG_ITER_CONTINUE;
     200             : 
     201       29252 :         LY_LIST_FOR (lysc_node_child(snode), child) {
     202       20586 :                 ret = yang_snodes_iterate_subtree(child, module, cb, flags,
     203             :                                                   arg);
     204       20586 :                 if (ret == YANG_ITER_STOP)
     205             :                         return ret;
     206             :         }
     207             :         return ret;
     208             : }
     209             : 
     210          36 : int yang_snodes_iterate(const struct lys_module *module, yang_iterate_cb cb,
     211             :                         uint16_t flags, void *arg)
     212             : {
     213          36 :         const struct lys_module *module_iter;
     214          36 :         uint32_t idx = 0;
     215          36 :         int ret = YANG_ITER_CONTINUE;
     216             : 
     217          36 :         idx = ly_ctx_internal_modules_count(ly_native_ctx);
     218         384 :         while ((module_iter = ly_ctx_get_module_iter(ly_native_ctx, &idx))) {
     219         348 :                 struct lysc_node *snode;
     220             : 
     221         348 :                 if (!module_iter->implemented)
     222         128 :                         continue;
     223             : 
     224         404 :                 LY_LIST_FOR (module_iter->compiled->data, snode) {
     225         184 :                         ret = yang_snodes_iterate_subtree(snode, module, cb,
     226             :                                                           flags, arg);
     227         184 :                         if (ret == YANG_ITER_STOP)
     228             :                                 return ret;
     229             :                 }
     230         500 :                 LY_LIST_FOR (&module_iter->compiled->rpcs->node, snode) {
     231         280 :                         ret = yang_snodes_iterate_subtree(snode, module, cb,
     232             :                                                           flags, arg);
     233         280 :                         if (ret == YANG_ITER_STOP)
     234             :                                 return ret;
     235             :                 }
     236         220 :                 LY_LIST_FOR (&module_iter->compiled->notifs->node, snode) {
     237           0 :                         ret = yang_snodes_iterate_subtree(snode, module, cb,
     238             :                                                           flags, arg);
     239           0 :                         if (ret == YANG_ITER_STOP)
     240             :                                 return ret;
     241             :                 }
     242             :         }
     243             : 
     244             :         return ret;
     245             : }
     246             : 
     247        1802 : void yang_snode_get_path(const struct lysc_node *snode,
     248             :                          enum yang_path_type type, char *xpath,
     249             :                          size_t xpath_len)
     250             : {
     251        1802 :         switch (type) {
     252           0 :         case YANG_PATH_SCHEMA:
     253           0 :                 (void)lysc_path(snode, LYSC_PATH_LOG, xpath, xpath_len);
     254           0 :                 break;
     255        1802 :         case YANG_PATH_DATA:
     256        1802 :                 (void)lysc_path(snode, LYSC_PATH_DATA, xpath, xpath_len);
     257        1802 :                 break;
     258           0 :         default:
     259           0 :                 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown yang path type: %u",
     260             :                          __func__, type);
     261           0 :                 exit(1);
     262             :         }
     263        1802 : }
     264             : 
     265        1802 : struct lysc_node *yang_snode_real_parent(const struct lysc_node *snode)
     266             : {
     267        1802 :         struct lysc_node *parent = snode->parent;
     268             : 
     269        5034 :         while (parent) {
     270        4556 :                 switch (parent->nodetype) {
     271         724 :                 case LYS_CONTAINER:
     272         724 :                         if (CHECK_FLAG(parent->flags, LYS_PRESENCE))
     273           0 :                                 return parent;
     274             :                         break;
     275             :                 case LYS_LIST:
     276             :                         return parent;
     277             :                 default:
     278             :                         break;
     279             :                 }
     280        3232 :                 parent = parent->parent;
     281             :         }
     282             : 
     283             :         return NULL;
     284             : }
     285             : 
     286        1802 : struct lysc_node *yang_snode_parent_list(const struct lysc_node *snode)
     287             : {
     288        1802 :         struct lysc_node *parent = snode->parent;
     289             : 
     290        5034 :         while (parent) {
     291        4556 :                 switch (parent->nodetype) {
     292             :                 case LYS_LIST:
     293             :                         return parent;
     294             :                 default:
     295        3232 :                         break;
     296             :                 }
     297        3232 :                 parent = parent->parent;
     298             :         }
     299             : 
     300             :         return NULL;
     301             : }
     302             : 
     303           0 : bool yang_snode_is_typeless_data(const struct lysc_node *snode)
     304             : {
     305           0 :         const struct lysc_node_leaf *sleaf;
     306             : 
     307           0 :         switch (snode->nodetype) {
     308           0 :         case LYS_LEAF:
     309           0 :                 sleaf = (struct lysc_node_leaf *)snode;
     310           0 :                 if (sleaf->type->basetype == LY_TYPE_EMPTY)
     311             :                         return true;
     312             :                 return false;
     313             :         case LYS_LEAFLIST:
     314             :                 return false;
     315             :         default:
     316             :                 return true;
     317             :         }
     318             : }
     319             : 
     320           3 : const char *yang_snode_get_default(const struct lysc_node *snode)
     321             : {
     322           3 :         const struct lysc_node_leaf *sleaf;
     323             : 
     324           3 :         switch (snode->nodetype) {
     325           0 :         case LYS_LEAF:
     326           0 :                 sleaf = (const struct lysc_node_leaf *)snode;
     327           0 :                 return sleaf->dflt ? lyd_value_get_canonical(sleaf->module->ctx,
     328             :                                                              sleaf->dflt)
     329           0 :                                    : NULL;
     330             :         case LYS_LEAFLIST:
     331             :                 /* TODO: check leaf-list default values */
     332             :                 return NULL;
     333             :         default:
     334             :                 return NULL;
     335             :         }
     336             : }
     337             : 
     338           0 : const struct lysc_type *yang_snode_get_type(const struct lysc_node *snode)
     339             : {
     340           0 :         struct lysc_node_leaf *sleaf = (struct lysc_node_leaf *)snode;
     341           0 :         struct lysc_type *type;
     342             : 
     343           0 :         if (!CHECK_FLAG(sleaf->nodetype, LYS_LEAF | LYS_LEAFLIST))
     344             :                 return NULL;
     345             : 
     346           0 :         type = sleaf->type;
     347           0 :         while (type->basetype == LY_TYPE_LEAFREF)
     348           0 :                 type = ((struct lysc_type_leafref *)type)->realtype;
     349             : 
     350             :         return type;
     351             : }
     352             : 
     353         102 : unsigned int yang_snode_num_keys(const struct lysc_node *snode)
     354             : {
     355         102 :         const struct lysc_node_leaf *skey;
     356         102 :         uint count = 0;
     357             : 
     358         102 :         if (!CHECK_FLAG(snode->nodetype, LYS_LIST))
     359             :                 return 0;
     360             : 
     361             :         /* Walk list of children */
     362         208 :         LY_FOR_KEYS (snode, skey) {
     363         106 :                 count++;
     364             :         }
     365             :         return count;
     366             : }
     367             : 
     368           3 : void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath,
     369             :                          size_t xpath_len)
     370             : {
     371           3 :         lyd_path(dnode, LYD_PATH_STD, xpath, xpath_len);
     372           3 : }
     373             : 
     374           0 : const char *yang_dnode_get_schema_name(const struct lyd_node *dnode,
     375             :                                        const char *xpath_fmt, ...)
     376             : {
     377           0 :         if (xpath_fmt) {
     378           0 :                 va_list ap;
     379           0 :                 char xpath[XPATH_MAXLEN];
     380             : 
     381           0 :                 va_start(ap, xpath_fmt);
     382           0 :                 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     383           0 :                 va_end(ap);
     384             : 
     385           0 :                 dnode = yang_dnode_get(dnode, xpath);
     386           0 :                 if (!dnode) {
     387           0 :                         flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
     388             :                                  "%s: couldn't find %s", __func__, xpath);
     389           0 :                         zlog_backtrace(LOG_ERR);
     390           0 :                         abort();
     391             :                 }
     392             :         }
     393             : 
     394           0 :         return dnode->schema->name;
     395             : }
     396             : 
     397          12 : struct lyd_node *yang_dnode_get(const struct lyd_node *dnode, const char *xpath)
     398             : {
     399          12 :         struct ly_set *set = NULL;
     400          12 :         struct lyd_node *dnode_ret = NULL;
     401             : 
     402             :         /*
     403             :          * XXX a lot of the code uses this for style I guess. It shouldn't, as
     404             :          * it adds to the xpath parsing complexity in libyang.
     405             :          */
     406          12 :         if (xpath[0] == '.' && xpath[1] == '/')
     407           9 :                 xpath += 2;
     408             : 
     409          12 :         if (lyd_find_xpath(dnode, xpath, &set)) {
     410           0 :                 assert(0); /* XXX replicates old libyang1 base code */
     411             :                 goto exit;
     412             :         }
     413          12 :         if (set->count == 0)
     414           0 :                 goto exit;
     415             : 
     416          12 :         if (set->count > 1) {
     417           0 :                 flog_warn(EC_LIB_YANG_DNODE_NOT_FOUND,
     418             :                           "%s: found %u elements (expected 0 or 1) [xpath %s]",
     419             :                           __func__, set->count, xpath);
     420           0 :                 goto exit;
     421             :         }
     422             : 
     423          12 :         dnode_ret = set->dnodes[0];
     424             : 
     425          12 : exit:
     426          12 :         ly_set_free(set, NULL);
     427             : 
     428          12 :         return dnode_ret;
     429             : }
     430             : 
     431           0 : struct lyd_node *yang_dnode_getf(const struct lyd_node *dnode,
     432             :                                  const char *xpath_fmt, ...)
     433             : {
     434           0 :         va_list ap;
     435           0 :         char xpath[XPATH_MAXLEN];
     436             : 
     437           0 :         va_start(ap, xpath_fmt);
     438           0 :         vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     439           0 :         va_end(ap);
     440             : 
     441           0 :         return yang_dnode_get(dnode, xpath);
     442             : }
     443             : 
     444           0 : bool yang_dnode_exists(const struct lyd_node *dnode, const char *xpath)
     445             : {
     446           0 :         struct ly_set *set = NULL;
     447           0 :         bool exists = false;
     448             : 
     449           0 :         if (xpath[0] == '.' && xpath[1] == '/')
     450           0 :                 xpath += 2;
     451           0 :         if (lyd_find_xpath(dnode, xpath, &set))
     452             :                 return false;
     453           0 :         exists = set->count > 0;
     454           0 :         ly_set_free(set, NULL);
     455           0 :         return exists;
     456             : }
     457             : 
     458           0 : bool yang_dnode_existsf(const struct lyd_node *dnode, const char *xpath_fmt,
     459             :                         ...)
     460             : {
     461           0 :         va_list ap;
     462           0 :         char xpath[XPATH_MAXLEN];
     463             : 
     464           0 :         va_start(ap, xpath_fmt);
     465           0 :         vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     466           0 :         va_end(ap);
     467             : 
     468           0 :         return yang_dnode_exists(dnode, xpath);
     469             : }
     470             : 
     471           0 : void yang_dnode_iterate(yang_dnode_iter_cb cb, void *arg,
     472             :                         const struct lyd_node *dnode, const char *xpath_fmt,
     473             :                         ...)
     474             : {
     475           0 :         va_list ap;
     476           0 :         char xpath[XPATH_MAXLEN];
     477           0 :         struct ly_set *set;
     478             : 
     479           0 :         va_start(ap, xpath_fmt);
     480           0 :         vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     481           0 :         va_end(ap);
     482             : 
     483           0 :         if (lyd_find_xpath(dnode, xpath, &set)) {
     484           0 :                 assert(0); /* XXX libyang2: ly1 code asserted success */
     485             :                 return;
     486             :         }
     487           0 :         for (unsigned int i = 0; i < set->count; i++) {
     488           0 :                 int ret;
     489             : 
     490           0 :                 ret = (*cb)(set->dnodes[i], arg);
     491           0 :                 if (ret == YANG_ITER_STOP)
     492             :                         break;
     493             :         }
     494             : 
     495           0 :         ly_set_free(set, NULL);
     496             : }
     497             : 
     498           0 : bool yang_dnode_is_default(const struct lyd_node *dnode, const char *xpath)
     499             : {
     500           0 :         const struct lysc_node *snode;
     501           0 :         struct lysc_node_leaf *sleaf;
     502             : 
     503           0 :         if (xpath)
     504           0 :                 dnode = yang_dnode_get(dnode, xpath);
     505             : 
     506           0 :         assert(dnode);
     507           0 :         snode = dnode->schema;
     508           0 :         switch (snode->nodetype) {
     509           0 :         case LYS_LEAF:
     510           0 :                 sleaf = (struct lysc_node_leaf *)snode;
     511           0 :                 if (sleaf->type->basetype == LY_TYPE_EMPTY)
     512             :                         return false;
     513           0 :                 return lyd_is_default(dnode);
     514             :         case LYS_LEAFLIST:
     515             :                 /* TODO: check leaf-list default values */
     516             :                 return false;
     517           0 :         case LYS_CONTAINER:
     518           0 :                 if (CHECK_FLAG(snode->flags, LYS_PRESENCE))
     519           0 :                         return false;
     520             :                 return true;
     521             :         default:
     522             :                 return false;
     523             :         }
     524             : }
     525             : 
     526           0 : bool yang_dnode_is_defaultf(const struct lyd_node *dnode, const char *xpath_fmt,
     527             :                             ...)
     528             : {
     529           0 :         if (!xpath_fmt)
     530           0 :                 return yang_dnode_is_default(dnode, NULL);
     531             :         else {
     532           0 :                 va_list ap;
     533           0 :                 char xpath[XPATH_MAXLEN];
     534             : 
     535           0 :                 va_start(ap, xpath_fmt);
     536           0 :                 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     537           0 :                 va_end(ap);
     538             : 
     539           0 :                 return yang_dnode_is_default(dnode, xpath);
     540             :         }
     541             : }
     542             : 
     543           0 : bool yang_dnode_is_default_recursive(const struct lyd_node *dnode)
     544             : {
     545           0 :         struct lyd_node *root, *dnode_iter;
     546             : 
     547           0 :         if (!yang_dnode_is_default(dnode, NULL))
     548             :                 return false;
     549             : 
     550           0 :         if (CHECK_FLAG(dnode->schema->nodetype, LYS_LEAF | LYS_LEAFLIST))
     551             :                 return true;
     552             : 
     553           0 :         LY_LIST_FOR (lyd_child(dnode), root) {
     554           0 :                 LYD_TREE_DFS_BEGIN (root, dnode_iter) {
     555           0 :                         if (!yang_dnode_is_default(dnode_iter, NULL))
     556             :                                 return false;
     557             : 
     558           0 :                         LYD_TREE_DFS_END(root, dnode_iter);
     559             :                 }
     560             :         }
     561             : 
     562             :         return true;
     563             : }
     564             : 
     565           0 : void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value)
     566             : {
     567           0 :         assert(dnode->schema->nodetype == LYS_LEAF);
     568           0 :         lyd_change_term(dnode, value);
     569           0 : }
     570             : 
     571           8 : struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only)
     572             : {
     573           8 :         struct lyd_node *dnode = NULL;
     574           8 :         int options = config_only ? LYD_VALIDATE_NO_STATE : 0;
     575             : 
     576           8 :         if (lyd_validate_all(&dnode, ly_ctx, options, NULL) != 0) {
     577             :                 /* Should never happen. */
     578           0 :                 flog_err(EC_LIB_LIBYANG, "%s: lyd_validate() failed", __func__);
     579           0 :                 exit(1);
     580             :         }
     581             : 
     582           8 :         return dnode;
     583             : }
     584             : 
     585           3 : struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode)
     586             : {
     587           3 :         struct lyd_node *dup = NULL;
     588           3 :         LY_ERR err;
     589           3 :         err = lyd_dup_siblings(dnode, NULL, LYD_DUP_RECURSIVE, &dup);
     590           3 :         assert(!err);
     591           3 :         return dup;
     592             : }
     593             : 
     594          19 : void yang_dnode_free(struct lyd_node *dnode)
     595             : {
     596          19 :         while (dnode->parent)
     597           0 :                 dnode = lyd_parent(dnode);
     598          19 :         lyd_free_all(dnode);
     599          19 : }
     600             : 
     601           3 : struct yang_data *yang_data_new(const char *xpath, const char *value)
     602             : {
     603           3 :         struct yang_data *data;
     604             : 
     605           3 :         data = XCALLOC(MTYPE_YANG_DATA, sizeof(*data));
     606           3 :         strlcpy(data->xpath, xpath, sizeof(data->xpath));
     607           3 :         if (value)
     608           0 :                 data->value = strdup(value);
     609             : 
     610           3 :         return data;
     611             : }
     612             : 
     613           3 : void yang_data_free(struct yang_data *data)
     614             : {
     615           3 :         if (data->value)
     616           0 :                 free(data->value);
     617           3 :         XFREE(MTYPE_YANG_DATA, data);
     618           3 : }
     619             : 
     620           0 : struct list *yang_data_list_new(void)
     621             : {
     622           0 :         struct list *list;
     623             : 
     624           0 :         list = list_new();
     625           0 :         list->del = (void (*)(void *))yang_data_free;
     626             : 
     627           0 :         return list;
     628             : }
     629             : 
     630           0 : struct yang_data *yang_data_list_find(const struct list *list,
     631             :                                       const char *xpath_fmt, ...)
     632             : {
     633           0 :         char xpath[XPATH_MAXLEN];
     634           0 :         struct yang_data *data;
     635           0 :         struct listnode *node;
     636           0 :         va_list ap;
     637             : 
     638           0 :         va_start(ap, xpath_fmt);
     639           0 :         vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
     640           0 :         va_end(ap);
     641             : 
     642           0 :         for (ALL_LIST_ELEMENTS_RO(list, node, data))
     643           0 :                 if (strmatch(data->xpath, xpath))
     644           0 :                         return data;
     645             : 
     646             :         return NULL;
     647             : }
     648             : 
     649             : /* Make libyang log its errors using FRR logging infrastructure. */
     650           0 : static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
     651             : {
     652           0 :         int priority = LOG_ERR;
     653             : 
     654           0 :         switch (level) {
     655             :         case LY_LLERR:
     656             :                 priority = LOG_ERR;
     657             :                 break;
     658           0 :         case LY_LLWRN:
     659           0 :                 priority = LOG_WARNING;
     660           0 :                 break;
     661           0 :         case LY_LLVRB:
     662             :         case LY_LLDBG:
     663           0 :                 priority = LOG_DEBUG;
     664           0 :                 break;
     665             :         }
     666             : 
     667           0 :         if (path)
     668           0 :                 zlog(priority, "libyang: %s (%s)", msg, path);
     669             :         else
     670           0 :                 zlog(priority, "libyang: %s", msg);
     671           0 : }
     672             : 
     673           0 : const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf, size_t buf_len)
     674             : {
     675           0 :         struct ly_err_item *ei;
     676           0 :         const char *path;
     677             : 
     678           0 :         ei = ly_err_first(ly_ctx);
     679           0 :         if (!ei)
     680             :                 return "";
     681             : 
     682           0 :         strlcpy(buf, "YANG error(s):\n", buf_len);
     683           0 :         for (; ei; ei = ei->next) {
     684           0 :                 strlcat(buf, " ", buf_len);
     685           0 :                 strlcat(buf, ei->msg, buf_len);
     686           0 :                 strlcat(buf, "\n", buf_len);
     687             :         }
     688             : 
     689           0 :         path = ly_errpath(ly_ctx);
     690           0 :         if (path) {
     691           0 :                 strlcat(buf, " YANG path: ", buf_len);
     692           0 :                 strlcat(buf, path, 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          48 :                 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          48 :                 RB_REMOVE(yang_modules, &yang_modules, module);
     785          56 :                 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