blob: 36d540c52a3e776addbc934a1b811ec579376315 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file tree_data_helpers.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Parsing and validation helper functions for data trees
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Radek Krejcie7b95092019-05-15 11:03:07 +020014
15#include <assert.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020016#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020017#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020018#include <string.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020019
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
21#include "context.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020022#include "hash_table.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include "log.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020024#include "lyb.h"
25#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020026#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "tree_data.h"
Michal Vasko60ea6352020-06-29 13:39:39 +020028#include "tree_data_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020029#include "tree_schema.h"
30
31struct lyd_node **
32lyd_node_children_p(struct lyd_node *node)
33{
34 assert(node);
Michal Vasko52927e22020-03-16 17:26:14 +010035
36 if (!node->schema) {
37 return &((struct lyd_node_opaq *)node)->child;
38 } else {
39 switch (node->schema->nodetype) {
40 case LYS_CONTAINER:
41 case LYS_LIST:
Michal Vasko1bf09392020-03-27 12:38:10 +010042 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +010043 case LYS_ACTION:
44 case LYS_NOTIF:
45 return &((struct lyd_node_inner *)node)->child;
46 default:
47 return NULL;
48 }
Radek Krejcie7b95092019-05-15 11:03:07 +020049 }
50}
51
Radek Krejcidae0ee82020-05-06 16:53:24 +020052API struct lyd_node *
Michal Vasko5bfd4be2020-06-23 13:26:19 +020053lyd_node_children(const struct lyd_node *node, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +020054{
Michal Vasko5bfd4be2020-06-23 13:26:19 +020055 struct lyd_node **children, *child;
Radek Krejcie7b95092019-05-15 11:03:07 +020056
57 if (!node) {
58 return NULL;
59 }
60
Michal Vasko5bfd4be2020-06-23 13:26:19 +020061 children = lyd_node_children_p((struct lyd_node *)node);
Radek Krejcie7b95092019-05-15 11:03:07 +020062 if (children) {
Michal Vasko5bfd4be2020-06-23 13:26:19 +020063 child = *children;
64 if (options & LYD_CHILDREN_SKIP_KEYS) {
Michal Vasko04091642020-06-29 11:50:14 +020065 while (child && child->schema && (child->schema->flags & LYS_KEY)) {
Michal Vasko5bfd4be2020-06-23 13:26:19 +020066 child = child->next;
67 }
68 }
69 return child;
Radek Krejcie7b95092019-05-15 11:03:07 +020070 } else {
71 return NULL;
72 }
73}
Michal Vasko9b368d32020-02-14 13:53:31 +010074
Michal Vaskoc193ce92020-03-06 11:04:48 +010075API const struct lys_module *
76lyd_owner_module(const struct lyd_node *node)
Michal Vasko9b368d32020-02-14 13:53:31 +010077{
78 const struct lysc_node *schema;
79
Michal Vasko52927e22020-03-16 17:26:14 +010080 if (!node || !node->schema) {
Michal Vaskoc193ce92020-03-06 11:04:48 +010081 return NULL;
82 }
Michal Vasko9b368d32020-02-14 13:53:31 +010083
84 for (schema = node->schema; schema->parent; schema = schema->parent);
85 return schema->module;
86}
Michal Vaskob1b5c262020-03-05 14:29:47 +010087
88const struct lys_module *
89lyd_mod_next_module(struct lyd_node *tree, const struct lys_module **modules, int mod_count, const struct ly_ctx *ctx,
90 uint32_t *i, struct lyd_node **first)
91{
92 struct lyd_node *iter;
93 const struct lys_module *mod;
94
95 /* get the next module */
96 if (modules && mod_count) {
97 if (*i < (unsigned)mod_count) {
98 mod = modules[(*i)++];
99 } else {
100 mod = NULL;
101 }
102 } else {
103 do {
104 mod = ly_ctx_get_module_iter(ctx, i);
105 } while (mod && !mod->implemented);
106 }
107
108 /* find its data */
109 *first = NULL;
110 if (mod) {
111 LY_LIST_FOR(tree, iter) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100112 if (lyd_owner_module(iter) == mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100113 *first = iter;
114 break;
115 }
116 }
117 }
118
119 return mod;
120}
121
122const struct lys_module *
123lyd_data_next_module(struct lyd_node **next, struct lyd_node **first)
124{
125 const struct lys_module *mod;
126
127 if (!*next) {
128 /* all data traversed */
129 *first = NULL;
130 return NULL;
131 }
132
133 *first = *next;
134
135 /* prepare next */
Michal Vaskoc193ce92020-03-06 11:04:48 +0100136 mod = lyd_owner_module(*next);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100137 LY_LIST_FOR(*next, *next) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100138 if (lyd_owner_module(*next) != mod) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100139 break;
140 }
141 }
142
143 return mod;
144}
Michal Vasko9f96a052020-03-10 09:41:45 +0100145
146LY_ERR
147lyd_parse_check_keys(struct lyd_node *node)
148{
149 const struct lysc_node *skey = NULL;
150 const struct lyd_node *key;
151
152 assert(node->schema->nodetype == LYS_LIST);
153
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200154 key = lyd_node_children(node, 0);
Michal Vasko9f96a052020-03-10 09:41:45 +0100155 while ((skey = lys_getnext(skey, node->schema, NULL, 0)) && (skey->flags & LYS_KEY)) {
156 if (!key || (key->schema != skey)) {
157 LOGVAL(node->schema->module->ctx, LY_VLOG_LYD, node, LY_VCODE_NOKEY, skey->name);
158 return LY_EVALID;
159 }
160
161 key = key->next;
162 }
163
164 return LY_SUCCESS;
165}
Michal Vasko60ea6352020-06-29 13:39:39 +0200166
167void
168lyd_parse_set_data_flags(struct lyd_node *node, struct ly_set *when_check, struct lyd_meta **meta, int options)
169{
170 struct lyd_meta *meta2, *prev_meta = NULL;
171
172 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && node->schema->when) {
173 if (options & LYD_OPT_TRUSTED) {
174 /* just set it to true */
175 node->flags |= LYD_WHEN_TRUE;
176 } else {
177 /* remember we need to evaluate this node's when */
178 ly_set_add(when_check, node, LY_SET_OPT_USEASLIST);
179 }
180 }
181
182 if (options & LYD_OPT_TRUSTED) {
183 /* node is valid */
184 node->flags &= ~LYD_NEW;
185 }
186
187 LY_LIST_FOR(*meta, meta2) {
188 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults")
189 && meta2->value.boolean) {
190 /* node is default according to the metadata */
191 node->flags |= LYD_DEFAULT;
192
193 /* delete the metadata */
194 if (prev_meta) {
195 prev_meta->next = meta2->next;
196 } else {
197 *meta = (*meta)->next;
198 }
199 lyd_free_meta(LYD_NODE_CTX(node), meta2, 0);
200 break;
201 }
202
203 prev_meta = meta2;
204 }
205}
206
207LYB_HASH
208lyb_hash(struct lysc_node *sibling, uint8_t collision_id)
209{
210 const struct lys_module *mod;
211 int ext_len;
212 uint32_t full_hash;
213 LYB_HASH hash;
214
215 if ((collision_id < LYS_NODE_HASH_COUNT) && sibling->hash[collision_id]) {
216 return sibling->hash[collision_id];
217 }
218
219 mod = sibling->module;
220
221 full_hash = dict_hash_multi(0, mod->name, strlen(mod->name));
222 full_hash = dict_hash_multi(full_hash, sibling->name, strlen(sibling->name));
223 if (collision_id) {
224 if (collision_id > strlen(mod->name)) {
225 /* fine, we will not hash more bytes, just use more bits from the hash than previously */
226 ext_len = strlen(mod->name);
227 } else {
228 /* use one more byte from the module name than before */
229 ext_len = collision_id;
230 }
231 full_hash = dict_hash_multi(full_hash, mod->name, ext_len);
232 }
233 full_hash = dict_hash_multi(full_hash, NULL, 0);
234
235 /* use the shortened hash */
236 hash = full_hash & (LYB_HASH_MASK >> collision_id);
237 /* add colision identificator */
238 hash |= LYB_HASH_COLLISION_ID >> collision_id;
239
240 /* save this hash */
241 if (collision_id < LYS_NODE_HASH_COUNT) {
242 sibling->hash[collision_id] = hash;
243 }
244
245 return hash;
246}
247
248int
249lyb_has_schema_model(const struct lysc_node *sibling, const struct lys_module **models)
250{
251 LY_ARRAY_SIZE_TYPE u;
252
253 LY_ARRAY_FOR(models, u) {
254 if (sibling->module == models[u]) {
255 return 1;
256 }
257 }
258
259 return 0;
260}