1 /*************************************************************************
3 * Copyright 2020 highstreet technologies GmbH and others
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
21 #include "utils/log_utils.h"
22 #include "utils/rand_utils.h"
23 #include "utils/type_utils.h"
28 #include "core/session.h"
29 #include "core/framework.h"
31 #define SCHEMA_LEAFREF_TOTAL_ENTRIES 11
33 static int schema_instance_add_module(populate_instance_t *instance, const struct lys_module *module);
34 static int schema_populate_late_resolve_add_leaf(populate_job_t *job, populate_instance_t *instance, struct lys_node *schema, struct lyd_node *parent_o, struct lyd_node *parent_r);
35 static const char* schema_leafref_temp_val(int index);
37 int schema_populate_recursive(populate_job_t *job, populate_instance_t *instance, struct lys_node *schema, struct lyd_node *parent_o, struct lyd_node *parent_r) {
43 char *resolved_schema_path = lys_path(schema, LYS_PATH_FIRST_PREFIX);
44 bool schema_operational = ((schema->flags & LYS_CONFIG_W) == 0);
46 schema_populate_rerun_switch:
47 switch(schema->nodetype) {
48 //for container, just add it to the xpath, and iterate it's childeren to further traverse the tree
52 struct lyd_node *new_parent_o = parent_o;
53 struct lyd_node *new_parent_r = parent_r;
55 new_parent_o = lyd_new(parent_o, schema->module, schema->name);
57 log_error("error creating container operational -> %s", schema->name);
58 log_error("ly_error: %s\n", ly_errmsg(session_context));
59 return NTS_ERR_FAILED;
62 if(!schema_operational && !framework_arguments.operational_only) {
63 new_parent_r = lyd_new(parent_r, schema->module, schema->name);
65 log_error("error creating container running -> %s", schema->name);
66 log_error("ly_error: %s\n", ly_errmsg(session_context));
67 return NTS_ERR_FAILED;
72 instance->init = true;
73 instance->operational = new_parent_o;
74 instance->running = new_parent_r;
78 if((schema->flags & LYS_MAND_TRUE) != 0) {
81 if((schema->parent) && (schema->parent->nodetype == LYS_CASE)) {
82 if((schema->parent->flags & LYS_MAND_TRUE) != 0) {
86 bool node_operational = ((schema->flags & LYS_CONFIG_W) == 0);
87 char *xpath = lyd_path(new_parent_o);
88 log_message(1, LOG_COLOR_BOLD_MAGENTA"[%15s] "LOG_COLOR_BOLD_YELLOW"[%c%c]"LOG_COLOR_RESET" %s\n", "CONTAINER", node_operational ? 'O' : 'R', mandatory, xpath);
91 int rc = schema_instance_add_module(instance, schema->module);
92 if(rc != NTS_ERR_OK) {
93 log_error("schema_instance_add_module failed");
97 struct lys_node *child = 0;
98 LY_TREE_FOR(schema->child, child) {
99 int rc = schema_populate_recursive(job, instance, child, new_parent_o, new_parent_r);
100 if(rc != NTS_ERR_OK) {
101 log_error("schema_populate_recursive failed");
107 //choice does not appear into the data path. get all the avalable choices, and choose a random one
110 struct lys_node_case *choice = (struct lys_node_case *)schema->child;
113 choice = (struct lys_node_case *)choice->next;
116 //select a random choice
117 choice_no = rand_uint16() % choice_no;
120 choice = (struct lys_node_case *)schema->child;
121 while(i < choice_no) {
123 choice = (struct lys_node_case *)choice->next;
126 //after the choice was made, rerun the adding without other tree-searching (will run into a CASE)
127 schema = (struct lys_node *)choice;
128 goto schema_populate_rerun_switch;
131 //the actual "case" is this node's child, so we skip directly to that
133 //case contains mandatory
135 schema = schema->child;
136 goto schema_populate_rerun_switch;
146 //get min-max for current list
147 struct lys_node_list *list = (struct lys_node_list *)schema;
148 int min_added = list->min ? list->min : 1;
149 int max_added = list->max ? list->max : 65536;
151 int populating_times = framework_populate_get_instance_count(resolved_schema_path);
152 if(populating_times != 0) {
153 if(min_added < populating_times) {
154 min_added = populating_times;
156 if(min_added > max_added) {
157 min_added = max_added;
158 log_error("min-elements exceeds max-elements for path %s. truncated to %d", resolved_schema_path, max_added);
160 log_message(2, "populating %d times list '%s'\n", min_added, resolved_schema_path);
162 //populate node with the intended number of values
166 struct lyd_node *new_parent_o = parent_o;
167 struct lyd_node *new_parent_r = parent_r;
169 new_parent_o = lyd_new(parent_o, schema->module, schema->name);
171 log_error("error creating list operational -> %s", schema->name);
172 log_error("ly_error: %s\n", ly_errmsg(session_context));
173 return NTS_ERR_FAILED;
176 if(!schema_operational && !framework_arguments.operational_only) {
177 new_parent_r = lyd_new(parent_r, schema->module, schema->name);
179 log_error("error creating container running -> %s", schema->name);
180 log_error("ly_error: %s\n", ly_errmsg(session_context));
181 return NTS_ERR_FAILED;
185 if(!instance->init) {
186 instance->init = true;
187 instance->operational = new_parent_o;
188 instance->running = new_parent_r;
191 char mandatory = ' ';
192 if((schema->flags & LYS_MAND_TRUE) != 0) {
195 if((schema->parent) && (schema->parent->nodetype == LYS_CASE)) {
196 if((schema->parent->flags & LYS_MAND_TRUE) != 0) {
200 bool node_operational = ((schema->flags & LYS_CONFIG_W) == 0);
201 char *xpath = lyd_path(new_parent_o);
202 log_message(1, LOG_COLOR_BOLD_MAGENTA"[%15s] "LOG_COLOR_BOLD_YELLOW"[%c%c]"LOG_COLOR_RESET" %s\n", "LIST", node_operational ? 'O' : 'R', mandatory, xpath);
205 int rc = schema_instance_add_module(instance, schema->module);
206 if(rc != NTS_ERR_OK) {
207 log_error("schema_instance_add_module failed");
211 //populate all list elements below in the tree
212 struct lys_node *child = 0;
213 LY_TREE_FOR(schema->child, child) {
214 int rc = schema_populate_recursive(job, instance, child, new_parent_o, new_parent_r);
215 if(rc != NTS_ERR_OK) {
216 log_error("schema_populate_recursive failed");
225 log_message(2, "not populating list '%s'\n", resolved_schema_path);
231 if(schema_populate_add_leaf(job, instance, schema, parent_o, parent_r) != NTS_ERR_OK) {
232 return NTS_ERR_FAILED;
236 //leaflist is treated the same as a LEAF, but with min/max characteristics of a LIST
238 //get min-max for the current leaflist
239 struct lys_node_leaflist *list = (struct lys_node_leaflist *)schema;
240 int min_added = list->min ? list->min : 1;
241 int max_added = list->max ? list->max : 65536;
243 int populating_times = framework_populate_get_instance_count(resolved_schema_path);
244 if(populating_times != 0) {
245 if(min_added < populating_times) {
246 min_added = populating_times;
248 if(min_added > max_added) {
249 min_added = max_added;
250 log_error("min-elements exceeds max-elements for path %s truncated to %d", resolved_schema_path, max_added);
252 log_message(2, "populating %d times leaflist '%s'\n", min_added, resolved_schema_path);
256 if(schema_populate_add_leaf(job, instance, schema, parent_o, parent_r) != NTS_ERR_OK) {
257 return NTS_ERR_FAILED;
263 log_message(2, "not populating leaflist '%s'\n", resolved_schema_path);
271 //don't do anything, since we don't want to add this or go further down the tree when we meet them
274 //other node types (grouping, uses, augment, etc just traverse)
276 log_message(1, "[%15s] %s\n", typeutils_yang_nodetype_to_str(schema->nodetype), resolved_schema_path);
278 //traverse the tree down for any other node types, without adding anything to the path
279 struct lys_node *child = 0;
280 LY_TREE_FOR(schema->child, child) {
281 int rc = schema_populate_recursive(job, instance, child, parent_o, parent_r);
282 if(rc != NTS_ERR_OK) {
289 free(resolved_schema_path);
294 int schema_populate_add_leaf(populate_job_t *job, populate_instance_t *instance, struct lys_node *schema, struct lyd_node *parent_o, struct lyd_node *parent_r) {
300 int rc = schema_instance_add_module(instance, schema->module);
301 if(rc != NTS_ERR_OK) {
302 log_error("bad schema_instance_add module");
306 struct lys_type *type = &((struct lys_node_leaf *)schema)->type;
308 char *data_xpath = lyd_path(parent_o);
309 data_xpath = (char *)realloc(data_xpath, sizeof(char) * (strlen(data_xpath) + 1 + strlen(schema->name) + 1));
311 log_error("lyd_path failed");
312 return NTS_ERR_FAILED;
314 strcat(data_xpath, "/");
315 strcat(data_xpath, schema->name);
317 //check whether the value is MANDATORY or not (for logging purposes)
318 char mandatory = ' ';
319 if((schema->flags & LYS_MAND_TRUE) != 0) {
323 if((schema->parent) && (schema->parent->nodetype == LYS_CASE)) {
324 if((schema->parent->flags & LYS_MAND_TRUE) != 0) {
329 bool node_operational = ((schema->flags & LYS_CONFIG_W) == 0);
330 log_message(1, LOG_COLOR_BOLD_MAGENTA"[%15s] "LOG_COLOR_BOLD_YELLOW"[%c%c]"LOG_COLOR_RESET" %s <-- ", typeutils_yang_type_to_str(type->base), node_operational ? 'O' : 'R', mandatory, data_xpath);
334 char *resolved_schema_path = lys_path(schema, LYS_PATH_FIRST_PREFIX);
335 char *value = framework_populate_get_restrict_schema(resolved_schema_path);
336 free(resolved_schema_path);
338 schema_populate_add_leaf_rerun_switch:
341 if((type->info.uni.count == 0) && (type->der != 0)) {
342 type = &type->der->type;
345 type = &type->info.uni.types[0];
346 goto schema_populate_add_leaf_rerun_switch;
350 struct lyd_node *parent = parent_o;
351 while(parent->parent) {
352 parent = parent->parent;
356 value = lyd_path(parent);
359 goto schema_populate_add_leaf_actual_add;
363 if(rand_bool()) { //if present, add it
364 log_message(1, LOG_COLOR_CYAN"present"LOG_COLOR_RESET"\n");
365 goto schema_populate_add_leaf_actual_add;
368 log_message(1, LOG_COLOR_CYAN"empty"LOG_COLOR_RESET"\n");
373 case LY_TYPE_LEAFREF: {
376 struct lyd_node *new_node = 0;
377 while((new_node == 0) && (index < SCHEMA_LEAFREF_TOTAL_ENTRIES)) {
378 new_node = lyd_new_leaf(parent_o, schema->module, schema->name, schema_leafref_temp_val(index));
383 log_error("error on lyd_new_leaf schema %s. didn't work with any temp val", schema->name);
384 return NTS_ERR_FAILED;
387 //based on the new_node's path, try to find elements of relative path for the leafref
388 struct ly_set *set = lyd_find_path(new_node, type->info.lref.path);
391 if(set && set->number) {
392 //choose a random schema and get its value
393 static int set_number = 0; //checkAL aici trebuia oare random ?
395 if(set_number >= set->number) {
398 asprintf(&value, "%s", ((struct lyd_node_leaf_list *)set->set.d[set_number])->value_str);
400 log_error("bad asprintf");
401 return NTS_ERR_FAILED;
404 int rc = schema_instance_add_module(instance, set->set.d[set_number]->schema->module);
405 if(rc != NTS_ERR_OK) {
406 log_error("bad schema_instance_add module");
412 goto schema_populate_add_leaf_actual_add;
415 //adding to late-resolve list, as we don't have any nodes in the leafref path
416 int rc = schema_populate_late_resolve_add_leaf(job, instance, schema, parent_o, parent_r);
417 if(rc != NTS_ERR_OK) {
421 if(!job->late_resolving) {
422 log_message(1, LOG_COLOR_BOLD_YELLOW"added to late-resolve list...\n"LOG_COLOR_RESET);
425 log_message(1, LOG_COLOR_BOLD_YELLOW"REadded to late-resolve list...\n"LOG_COLOR_RESET);
435 value = rand_get_populate_value(type);
437 goto schema_populate_add_leaf_actual_add;
441 schema_populate_add_leaf_actual_add: {
442 //add schema to operational
443 struct lyd_node *new_node = lyd_new_leaf(parent_o, schema->module, schema->name, value);
445 log_error("error on lyd_new_leaf operational: %s", ly_errmsg(session_context));
446 return NTS_ERR_FAILED;
449 //print out the value
451 log_message(1, LOG_COLOR_CYAN"'%s'"LOG_COLOR_RESET"\n", value);
454 log_message(1, "\n");
457 //if it fits the case, add it also to running
458 if(!node_operational && !framework_arguments.operational_only) {
459 struct lyd_node *new_node = lyd_new_leaf(parent_r, schema->module, schema->name, value);
461 log_error("error on lyd_new_leaf running: %s", ly_errmsg(session_context));
462 return NTS_ERR_FAILED;
472 static int schema_instance_add_module(populate_instance_t *instance, const struct lys_module *module) {
476 for(int i = 0; i < instance->mod_count; i++) {
477 if(instance->modules[i] == module) {
482 instance->modules = (const struct lys_module **)realloc(instance->modules, sizeof(const struct lys_module *) * (instance->mod_count + 1));
483 if(!instance->modules) {
484 log_error("bad realloc");
485 return NTS_ERR_FAILED;
487 instance->modules[instance->mod_count] = module;
488 instance->mod_count++;
493 static int schema_populate_late_resolve_add_leaf(populate_job_t *job, populate_instance_t *instance, struct lys_node *schema, struct lyd_node *parent_o, struct lyd_node *parent_r) {
497 job->late_resolve_schema = (struct lys_node **)realloc(job->late_resolve_schema, (job->late_resolve_count + 1) * sizeof(struct lys_node *));
498 if(!job->late_resolve_schema) {
499 log_error("bad realloc");
500 return NTS_ERR_FAILED;
502 job->late_resolve_schema[job->late_resolve_count] = schema;
504 job->late_resolve_parent_o = (struct lyd_node **)realloc(job->late_resolve_parent_o, (job->late_resolve_count + 1) * sizeof(struct lyd_node *));
505 if(!job->late_resolve_parent_o) {
506 log_error("bad realloc");
507 return NTS_ERR_FAILED;
509 job->late_resolve_parent_o[job->late_resolve_count] = parent_o;
511 job->late_resolve_parent_r = (struct lyd_node **)realloc(job->late_resolve_parent_r, (job->late_resolve_count + 1) * sizeof(struct lyd_node *));
512 if(!job->late_resolve_parent_r) {
513 log_error("bad realloc");
514 return NTS_ERR_FAILED;
516 job->late_resolve_parent_r[job->late_resolve_count] = parent_r;
518 job->late_resolve_instance = (populate_instance_t **)realloc(job->late_resolve_instance, (job->late_resolve_count + 1) * sizeof(populate_instance_t *));
519 if(!job->late_resolve_instance) {
520 log_error("bad realloc");
521 return NTS_ERR_FAILED;
523 job->late_resolve_instance[job->late_resolve_count] = instance;
525 job->late_resolve_count++;
530 static const char* schema_leafref_temp_val(int index) {
541 return "Fd:4D:63:A5:21:C5";
565 return "best-effort";
569 return "yes-fault:o-ran-sc-alarm-type";
580 log_error("index out of bounds");