Coverage Report

Created: 2025-10-08 06:07

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