Add sub-modules to ietf-netconf-monitoring.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / datastore / populate_rec.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
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
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
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 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "populate.h"
21 #include "utils/log_utils.h"
22 #include "utils/rand_utils.h"
23 #include "utils/type_utils.h"
24 #include <stdio.h>
25 #include <inttypes.h>
26 #include <assert.h>
27
28 #include "core/session.h"
29 #include "core/framework.h"
30
31 #define SCHEMA_LEAFREF_TOTAL_ENTRIES      11
32
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);
36
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) {
38     assert_session();
39     assert(job);
40     assert(schema);
41     assert(instance);
42     
43     char *resolved_schema_path = lys_path(schema, LYS_PATH_FIRST_PREFIX);
44     bool schema_operational = ((schema->flags & LYS_CONFIG_W) == 0);
45
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
49         case LYS_CONTAINER: {
50             //add container
51
52             struct lyd_node *new_parent_o = parent_o;
53             struct lyd_node *new_parent_r = parent_r;
54
55             new_parent_o = lyd_new(parent_o, schema->module, schema->name);
56             if(!new_parent_o) {
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;
60             }
61
62             if(!schema_operational && !framework_arguments.operational_only) {
63                 new_parent_r = lyd_new(parent_r, schema->module, schema->name);
64                 if(!new_parent_r) {
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;
68                 }
69             }
70
71             if(!instance->init) {
72                 instance->init = true;
73                 instance->operational = new_parent_o;
74                 instance->running = new_parent_r;
75             }
76
77             char mandatory = ' ';
78             if((schema->flags & LYS_MAND_TRUE) != 0) {
79                 mandatory = 'M';
80             }
81             if((schema->parent) && (schema->parent->nodetype == LYS_CASE)) {
82                 if((schema->parent->flags & LYS_MAND_TRUE) != 0) {
83                     mandatory = 'M';
84                 }
85             }
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);
89             free(xpath);
90
91             int rc = schema_instance_add_module(instance, schema->module);
92             if(rc != NTS_ERR_OK) {
93                 log_error("schema_instance_add_module failed");
94                 return rc;
95             }
96
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");
102                     return rc;
103                 }
104             }
105         } break;
106
107         //choice does not appear into the data path. get all the avalable choices, and choose a random one
108         case LYS_CHOICE: {
109             int choice_no = 0;
110             struct lys_node_case *choice = (struct lys_node_case *)schema->child;
111             while(choice) {
112                 choice_no++;
113                 choice = (struct lys_node_case *)choice->next;
114             }
115
116             //select a random choice
117             choice_no = rand_uint16() % choice_no;
118
119             int i = 0;
120             choice = (struct lys_node_case *)schema->child;
121             while(i < choice_no) {
122                 i++;
123                 choice = (struct lys_node_case *)choice->next;
124             }
125
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;
129         } break;
130
131         //the actual "case" is this node's child, so we skip directly to that
132         case LYS_CASE:
133             //case contains mandatory
134             if(schema->child) {
135                 schema = schema->child;
136                 goto schema_populate_rerun_switch;
137             }
138             else {
139                 //blank case
140                 return NTS_ERR_OK;
141             }
142             break;
143
144         //populate a list
145         case LYS_LIST: {
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;
150             
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;
155                 }
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);
159                 }
160                 log_message(2, "populating %d times list '%s'\n", min_added, resolved_schema_path);
161
162                 //populate node with the intended number of values
163                 while(min_added) {
164                     //add list
165
166                     struct lyd_node *new_parent_o = parent_o;
167                     struct lyd_node *new_parent_r = parent_r;
168
169                     new_parent_o = lyd_new(parent_o, schema->module, schema->name);
170                     if(!new_parent_o) {
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;
174                     }
175
176                     if(!schema_operational && !framework_arguments.operational_only) {
177                         new_parent_r = lyd_new(parent_r, schema->module, schema->name);
178                         if(!new_parent_r) {
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;
182                         }
183                     }
184
185                     if(!instance->init) {
186                         instance->init = true;
187                         instance->operational = new_parent_o;
188                         instance->running = new_parent_r;
189                     }
190
191                     char mandatory = ' ';
192                     if((schema->flags & LYS_MAND_TRUE) != 0) {
193                         mandatory = 'M';
194                     }
195                     if((schema->parent) && (schema->parent->nodetype == LYS_CASE)) {
196                         if((schema->parent->flags & LYS_MAND_TRUE) != 0) {
197                             mandatory = 'M';
198                         }
199                     }
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);
203                     free(xpath);
204
205                     int rc = schema_instance_add_module(instance, schema->module);
206                     if(rc != NTS_ERR_OK) {
207                         log_error("schema_instance_add_module failed");
208                         return rc;
209                     }
210
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");
217                             return rc;
218                         }
219                     }
220
221                     min_added--;
222                 }
223             }
224             else {
225                 log_message(2, "not populating list '%s'\n", resolved_schema_path);
226             }
227         } break;
228
229         //populate the leaf
230         case LYS_LEAF: {
231             if(schema_populate_add_leaf(job, instance, schema, parent_o, parent_r) != NTS_ERR_OK) {
232                 return NTS_ERR_FAILED;
233             }            
234         } break;
235
236         //leaflist is treated the same as a LEAF, but with min/max characteristics of a LIST
237         case LYS_LEAFLIST: {
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;
242             
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;
247                 }
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);
251                 }
252                 log_message(2, "populating %d times leaflist '%s'\n", min_added, resolved_schema_path);
253
254                 //add the leafs
255                 while(min_added) {
256                     if(schema_populate_add_leaf(job, instance, schema, parent_o, parent_r) != NTS_ERR_OK) {
257                         return NTS_ERR_FAILED;
258                     }   
259                     min_added--;
260                 }
261             }
262             else {
263                 log_message(2, "not populating leaflist '%s'\n", resolved_schema_path);
264             }
265         } break;
266
267         case LYS_ACTION:
268         case LYS_INPUT:
269         case LYS_OUTPUT:
270         case LYS_NOTIF:
271             //don't do anything, since we don't want to add this or go further down the tree when we meet them
272             break;
273
274         //other node types (grouping, uses, augment, etc just traverse)
275         default:
276             log_message(1, "[%15s]      %s\n", typeutils_yang_nodetype_to_str(schema->nodetype), resolved_schema_path);
277
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) {
283                     return rc;
284                 }
285             }
286             break;
287     }
288
289     free(resolved_schema_path);
290
291     return NTS_ERR_OK;
292 }
293
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) {
295     assert_session();
296     assert(job);
297     assert(schema);
298     assert(parent_o);
299
300     int rc = schema_instance_add_module(instance, schema->module);
301     if(rc != NTS_ERR_OK) {
302         log_error("bad schema_instance_add module");
303         return rc;
304     }
305
306     struct lys_type *type = &((struct lys_node_leaf *)schema)->type;
307     
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));
310     if(!data_xpath) {
311         log_error("lyd_path failed");
312         return NTS_ERR_FAILED;
313     }
314     strcat(data_xpath, "/");
315     strcat(data_xpath, schema->name);
316
317     //check whether the value is MANDATORY or not (for logging purposes)
318     char mandatory = ' ';
319     if((schema->flags & LYS_MAND_TRUE) != 0) {
320         mandatory = 'M';
321     }
322
323     if((schema->parent) && (schema->parent->nodetype == LYS_CASE)) {
324         if((schema->parent->flags & LYS_MAND_TRUE) != 0) {
325             mandatory = 'M';
326         }
327     }
328
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);
331     free(data_xpath);
332
333
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);
337
338     schema_populate_add_leaf_rerun_switch:
339     switch(type->base) {
340         case LY_TYPE_UNION:
341             if((type->info.uni.count == 0) && (type->der != 0)) {
342                 type = &type->der->type;
343             }
344
345             type = &type->info.uni.types[0];
346             goto schema_populate_add_leaf_rerun_switch;
347             break;
348
349         case LY_TYPE_INST: {
350             struct lyd_node *parent = parent_o;
351             while(parent->parent) {
352                 parent = parent->parent;
353             }
354
355             if(value == 0) {
356                 value = lyd_path(parent);
357             }
358
359             goto schema_populate_add_leaf_actual_add;
360         } break;
361
362         case LY_TYPE_EMPTY:
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;
366             }
367             else {
368                 log_message(1, LOG_COLOR_CYAN"empty"LOG_COLOR_RESET"\n");
369                 return NTS_ERR_OK;
370             }
371             break;
372
373         case LY_TYPE_LEAFREF: {
374             if(value == 0) {
375                 int index = 0;
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));
379                     index++;
380                 }
381
382                 if(new_node == 0) {
383                     log_error("error on lyd_new_leaf schema %s. didn't work with any temp val", schema->name);
384                     return NTS_ERR_FAILED;
385                 }
386
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);
389                 lyd_free(new_node);
390
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 ?
394                     set_number++;
395                     if(set_number >= set->number) {
396                         set_number = 0;
397                     }
398                     asprintf(&value, "%s", ((struct lyd_node_leaf_list *)set->set.d[set_number])->value_str);
399                     if(!value) {
400                         log_error("bad asprintf");
401                         return NTS_ERR_FAILED;
402                     }
403
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");
407                         return rc;
408                     }
409
410                     ly_set_free(set);
411
412                     goto schema_populate_add_leaf_actual_add;
413                 }
414                 else {
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) {
418                         return rc;
419                     }
420
421                     if(!job->late_resolving) {
422                         log_message(1, LOG_COLOR_BOLD_YELLOW"added to late-resolve list...\n"LOG_COLOR_RESET);
423                     }
424                     else {
425                         log_message(1, LOG_COLOR_BOLD_YELLOW"REadded to late-resolve list...\n"LOG_COLOR_RESET);
426                     }
427
428                     return NTS_ERR_OK;
429                 }
430             }
431         } break;
432       
433         default:
434             if(value == 0) {
435                 value = rand_get_populate_value(type);
436             }
437             goto schema_populate_add_leaf_actual_add;
438             break;
439     }
440
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);
444         if(new_node == 0) {
445             log_error("error on lyd_new_leaf operational: %s", ly_errmsg(session_context));
446             return NTS_ERR_FAILED;
447         }
448         
449         //print out the value
450         if(value) {
451             log_message(1, LOG_COLOR_CYAN"'%s'"LOG_COLOR_RESET"\n",  value);
452         }
453         else {
454             log_message(1, "\n");
455         }
456
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);
460             if(new_node == 0) {
461                 log_error("error on lyd_new_leaf running: %s", ly_errmsg(session_context));
462                 return NTS_ERR_FAILED;
463             }
464         }
465         
466         free(value);
467     }
468
469     return NTS_ERR_OK;
470 }
471
472 static int schema_instance_add_module(populate_instance_t *instance, const struct lys_module *module) {
473     assert(module);
474     assert(instance);
475
476     for(int i = 0; i < instance->mod_count; i++) {
477         if(instance->modules[i] == module) {
478             return NTS_ERR_OK;
479         }
480     }
481
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;
486     }
487     instance->modules[instance->mod_count] = module;
488     instance->mod_count++;
489
490     return NTS_ERR_OK;
491 }
492
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) {
494     assert(job);
495     assert(instance);
496
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;
501     }
502     job->late_resolve_schema[job->late_resolve_count] = schema;
503
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;
508     }
509     job->late_resolve_parent_o[job->late_resolve_count] = parent_o;
510
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;
515     }
516     job->late_resolve_parent_r[job->late_resolve_count] = parent_r;
517
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;
522     }
523     job->late_resolve_instance[job->late_resolve_count] = instance;
524
525     job->late_resolve_count++;
526
527     return NTS_ERR_OK;
528 }
529
530 static const char* schema_leafref_temp_val(int index) {
531     switch(index) {
532         case 0:
533             return "1";
534             break;
535
536         case 1:
537             return "1.1.1.1";
538             break;
539
540         case 2:
541             return "Fd:4D:63:A5:21:C5";
542             break;
543
544         case 3:
545             return "";
546             break;
547
548         case 4:
549             return "::1";
550             break;
551
552         case 5:
553             return "false";
554             break;
555
556         case 6:
557             return "TDD";
558             break;
559
560         case 7:
561             return "NR";
562             break;
563
564         case 8:
565             return "best-effort";
566             break;
567
568         case 9:
569             return "yes-fault:o-ran-sc-alarm-type";
570             break;
571
572         case 10:
573             return "";
574             break;
575
576         
577
578
579         default:
580             log_error("index out of bounds");
581             return 0;
582             break;
583     }
584 }