Add VES stndDefined PM and subscription for O-DU.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / datastore / populate_recursive.c
1 /*************************************************************************
2 *
3 * Copyright 2021 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 #define _GNU_SOURCE
18
19 #include "populate.h"
20 #include "populate_internal.h"
21 #include "utils/log_utils.h"
22 #include "utils/rand_utils.h"
23 #include "utils/type_utils.h"
24
25 #include "core/datastore/schema.h"
26 #include "core/framework.h"
27 #include "core/session.h"
28
29 #include <sysrepo.h>
30 #include <libyang/libyang.h>
31
32 #include <stdlib.h>
33 #include <assert.h>
34
35
36 int populate_recursive(populate_job_t *job, populate_instance_t *instance, struct lys_node *schema, struct lyd_node *parent_d, struct lyd_node *parent_o, struct lyd_node *parent_r, int operational_only) {
37     assert(schema);
38     
39     char *resolved_schema_path = lys_path(schema, LYS_PATH_FIRST_PREFIX);
40     bool element_operational = ((schema->flags & LYS_CONFIG_W) == 0);
41
42     populate_recursive_rerun_switch:
43     switch(schema->nodetype) {
44         //for container, just add it to the xpath, and iterate it's childeren to further traverse the tree
45         case LYS_CONTAINER: {
46             //don't add if populating only operational
47             if(operational_only && !element_operational) {
48                 return NTS_ERR_OK;
49             }
50
51             //add container
52
53             struct lyd_node *new_parent_d = parent_d;
54             struct lyd_node *new_parent_o = parent_o;
55             struct lyd_node *new_parent_r = parent_r;
56
57             new_parent_d = lyd_new(parent_d, schema->module, schema->name);
58             if(!new_parent_d) {
59                 log_error("error creating container dev -> %s\n", schema->name);
60                 log_error("ly_error: %s\n", ly_errmsg(session_context));
61                 return NTS_ERR_FAILED;
62             }
63
64             new_parent_o = lyd_new(parent_o, schema->module, schema->name);
65             if(!new_parent_o) {
66                 log_error("error creating container operational -> %s\n", schema->name);
67                 log_error("ly_error: %s\n", ly_errmsg(session_context));
68                 return NTS_ERR_FAILED;
69             }
70
71             if(!element_operational) {
72                 new_parent_r = lyd_new(parent_r, schema->module, schema->name);
73                 if(!new_parent_r) {
74                     log_error("error creating container running -> %s\n", schema->name);
75                     log_error("ly_error: %s\n", ly_errmsg(session_context));
76                     return NTS_ERR_FAILED;
77                 }
78             }
79
80             if(!instance->init) {
81                 instance->init = true;
82                 instance->dev = new_parent_d;
83                 instance->operational = new_parent_o;
84                 instance->running = new_parent_r;
85             }
86
87             char *xpath = lyd_path(new_parent_d);
88             log_add_verbose(1, LOG_COLOR_BOLD_MAGENTA"[%15s] "LOG_COLOR_BOLD_YELLOW"[%c%c]"LOG_COLOR_RESET" %s\n", "CONTAINER", element_operational ? 'O' : 'R', populate_info_get_mandatory(schema), xpath);
89             free(xpath);
90
91             int rc = populate_instance_add_module(instance, schema->module);
92             if(rc != NTS_ERR_OK) {
93                 log_error("instance_add_module failed\n");
94                 return rc;
95             }
96
97             struct lys_node *child = 0;
98             LY_TREE_FOR(schema->child, child) {
99                 int rc = populate_recursive(job, instance, child, new_parent_d, new_parent_o, new_parent_r, operational_only);
100                 if(rc != NTS_ERR_OK) {
101                     log_error("populate_recursive failed\n");
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 populate_recursive_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 populate_recursive_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             //don't add if populating only operational
147             if(operational_only && !element_operational) {
148                 return NTS_ERR_OK;
149             }
150
151             //get min-max for current list
152             struct lys_node_list *list = (struct lys_node_list *)schema;
153             int min_added = list->min ? list->min : 1;
154             int max_added = list->max ? list->max : 65536;
155             
156             int populating_times = populate_instance_get_count(resolved_schema_path);
157             if(populating_times != 0) {
158                 if(min_added < populating_times) {
159                     min_added = populating_times;
160                 }
161                 if(min_added > max_added) {
162                     min_added = max_added;
163                     log_error("min-elements exceeds max-elements for path %s. truncated to %d\n", resolved_schema_path, max_added);
164                 }
165                 log_add_verbose(2, "populating %d times list '%s'\n", min_added, resolved_schema_path);
166
167                 //populate node with the intended number of values
168                 while(min_added) {
169                     //add list
170
171                     struct lyd_node *new_parent_d = parent_d;
172                     struct lyd_node *new_parent_o = parent_o;
173                     struct lyd_node *new_parent_r = parent_r;
174
175                     new_parent_d = lyd_new(parent_d, schema->module, schema->name);
176                     if(!new_parent_d) {
177                         log_error("error creating list dev -> %s\n", schema->name);
178                         log_error("ly_error: %s\n", ly_errmsg(session_context));
179                         return NTS_ERR_FAILED;
180                     }
181
182
183                     new_parent_o = lyd_new(parent_o, schema->module, schema->name);
184                     if(!new_parent_o) {
185                         log_error("error creating list operational -> %s\n", schema->name);
186                         log_error("ly_error: %s\n", ly_errmsg(session_context));
187                         return NTS_ERR_FAILED;
188                     }
189
190                     if(!element_operational) {
191                         new_parent_r = lyd_new(parent_r, schema->module, schema->name);
192                         if(!new_parent_r) {
193                             log_error("error creating container running -> %s\n", schema->name);
194                             log_error("ly_error: %s\n", ly_errmsg(session_context));
195                             return NTS_ERR_FAILED;
196                         }
197                     }
198
199                     if(!instance->init) {
200                         instance->init = true;
201                         instance->dev = new_parent_d;
202                         instance->operational = new_parent_o;
203                         instance->running = new_parent_r;
204                     }
205
206                     char *xpath = lyd_path(new_parent_d);
207                     log_add_verbose(1, LOG_COLOR_BOLD_MAGENTA"[%15s] "LOG_COLOR_BOLD_YELLOW"[%c%c]"LOG_COLOR_RESET" %s\n", "LIST", element_operational ? 'O' : 'R', populate_info_get_mandatory(schema), xpath);
208                     free(xpath);
209
210                     int rc = populate_instance_add_module(instance, schema->module);
211                     if(rc != NTS_ERR_OK) {
212                         log_error("instance_add_module failed\n");
213                         return rc;
214                     }
215
216                     //populate all list elements below in the tree
217                     struct lys_node *child = 0;
218                     LY_TREE_FOR(schema->child, child) {
219                         int rc = populate_recursive(job, instance, child, new_parent_d, new_parent_o, new_parent_r, operational_only);
220                         if(rc != NTS_ERR_OK) {
221                             log_error("populate_recursive failed\n");
222                             return rc;
223                         }
224                     }
225
226                     min_added--;
227                 }
228             }
229             else {
230                 log_add_verbose(2, "not populating list '%s'\n", resolved_schema_path);
231             }
232         } break;
233
234         //populate the leaf
235         case LYS_LEAF: {
236             //don't add if populating only operational
237             if(operational_only && !element_operational) {
238                 return NTS_ERR_OK;
239             }
240
241             if(populate_add_leaf(job, instance, schema, parent_d, parent_o, parent_r) != NTS_ERR_OK) {
242                 return NTS_ERR_FAILED;
243             }            
244         } break;
245
246         //leaflist is treated the same as a LEAF, but with min/max characteristics of a LIST
247         case LYS_LEAFLIST: {
248             //don't add if populating only operational
249             if(operational_only && !element_operational) {
250                 return NTS_ERR_OK;
251             }
252
253             //get min-max for the current leaflist
254             struct lys_node_leaflist *list = (struct lys_node_leaflist *)schema;
255             int min_added = list->min ? list->min : 1;
256             int max_added = list->max ? list->max : 65536;
257             
258             int populating_times = populate_instance_get_count(resolved_schema_path);
259             if(populating_times != 0) {
260                 if(min_added < populating_times) {
261                     min_added = populating_times;
262                 }
263                 if(min_added > max_added) {
264                     min_added = max_added;
265                     log_error("min-elements exceeds max-elements for path %s truncated to %d\n", resolved_schema_path, max_added);
266                 }
267                 log_add_verbose(2, "populating %d times leaflist '%s'\n", min_added, resolved_schema_path);
268
269                 //add the leafs
270                 while(min_added) {
271                     if(populate_add_leaf(job, instance, schema, parent_d, parent_o, parent_r) != NTS_ERR_OK) {
272                         return NTS_ERR_FAILED;
273                     }   
274                     min_added--;
275                 }
276             }
277             else {
278                 log_add_verbose(2, "not populating leaflist '%s'\n", resolved_schema_path);
279             }
280         } break;
281
282         case LYS_ACTION:
283         case LYS_INPUT:
284         case LYS_OUTPUT:
285         case LYS_NOTIF:
286             //don't do anything, since we don't want to add this or go further down the tree when we meet them
287             break;
288
289         //other node types (grouping, uses, augment, etc just traverse)
290         default:
291             log_add_verbose(1, "[%15s]      %s\n", typeutils_yang_nodetype_to_str(schema->nodetype), resolved_schema_path);
292
293             //traverse the tree down for any other node types, without adding anything to the path
294             struct lys_node *child = 0;
295             LY_TREE_FOR(schema->child, child) {
296                 int rc = populate_recursive(job, instance, child, parent_d, parent_o, parent_r, operational_only);
297                 if(rc != NTS_ERR_OK) {
298                     return rc;
299                 }
300             }
301             break;
302     }
303
304     free(resolved_schema_path);
305
306     return NTS_ERR_OK;
307 }
308
309 int populate_add_leaf(populate_job_t *job, populate_instance_t *instance, struct lys_node *schema, struct lyd_node *parent_d, struct lyd_node *parent_o, struct lyd_node *parent_r) {
310     assert_session();
311     assert(job);
312     assert(schema);
313     assert(parent_d);
314
315     int rc = populate_instance_add_module(instance, schema->module);
316     if(rc != NTS_ERR_OK) {
317         log_error("bad schema_instance_add module\n");
318         return rc;
319     }
320
321     struct lys_type *type = &((struct lys_node_leaf *)schema)->type;
322     
323     char *data_xpath = lyd_path(parent_d);
324     data_xpath = (char *)realloc(data_xpath, sizeof(char) * (strlen(data_xpath) + 1 + strlen(schema->name) + 1));
325     if(!data_xpath) {
326         log_error("lyd_path failed\n");
327         return NTS_ERR_FAILED;
328     }
329     strcat(data_xpath, "/");
330     strcat(data_xpath, schema->name);
331
332     bool leaf_operational = ((schema->flags & LYS_CONFIG_W) == 0);
333     log_add_verbose(1, LOG_COLOR_BOLD_MAGENTA"[%15s] "LOG_COLOR_BOLD_YELLOW"[%c%c]"LOG_COLOR_RESET" %s <-- ", typeutils_yang_type_to_str(type->base), leaf_operational ? 'O' : 'R', populate_info_get_mandatory(schema), data_xpath);
334     free(data_xpath);
335
336
337     char *resolved_schema_path = lys_path(schema, LYS_PATH_FIRST_PREFIX);
338     char *value = populate_get_restrict_schema(resolved_schema_path);
339     free(resolved_schema_path);
340
341     populate_add_leaf_rerun_switch:
342     switch(type->base) {
343         case LY_TYPE_UNION:
344             if((type->info.uni.count == 0) && (type->der != 0)) {
345                 type = &type->der->type;
346             }
347
348             type = &type->info.uni.types[0];
349             goto populate_add_leaf_rerun_switch;
350             break;
351
352         case LY_TYPE_INST: {
353             struct lyd_node *parent = parent_o;
354             while(parent->parent) {
355                 parent = parent->parent;
356             }
357
358             if(value == 0) {
359                 value = lyd_path(parent);
360             }
361
362             goto populate_add_leaf_actual_add;
363         } break;
364
365         case LY_TYPE_EMPTY:
366             if(rand_bool()) {   //if present, add it
367                 log_add(1, LOG_COLOR_CYAN"present"LOG_COLOR_RESET"\n");
368                 goto populate_add_leaf_actual_add;
369             }
370             else {
371                 log_add(1, LOG_COLOR_CYAN"empty"LOG_COLOR_RESET"\n");
372                 return NTS_ERR_OK;
373             }
374             break;
375
376         case LY_TYPE_LEAFREF: {
377             if(value == 0) {
378                 int index = 0;
379                 struct lyd_node *new_node = 0;
380                 while((new_node == 0) && (index < POPULATE_LEAFREF_TEST_ENTRIES_TOTAL)) {
381                     new_node = lyd_new_leaf(parent_d, schema->module, schema->name, populate_leafref_test_val(index));
382                     index++;
383                 }
384
385                 if(new_node == 0) {
386                     log_error("error on lyd_new_leaf schema %s. didn't work with any temp val\n", schema->name);
387                     return NTS_ERR_FAILED;
388                 }
389
390                 //based on the new_node's path, try to find elements of relative path for the leafref
391                 struct ly_set *set = lyd_find_path(new_node, type->info.lref.path);
392                 lyd_free(new_node);
393
394                 if(set && set->number) {
395                     //choose a random schema and get its value
396                     static int set_number = 0;
397                     set_number++;
398                     if(set_number >= set->number) {
399                         set_number = 0;
400                     }
401                     asprintf(&value, "%s", ((struct lyd_node_leaf_list *)set->set.d[set_number])->value_str);
402                     if(!value) {
403                         log_error("bad asprintf\n");
404                         return NTS_ERR_FAILED;
405                     }
406
407                     int rc = populate_instance_add_module(instance, set->set.d[set_number]->schema->module);
408                     if(rc != NTS_ERR_OK) {
409                         log_error("bad schema_instance_add module\n");
410                         return rc;
411                     }
412
413                     ly_set_free(set);
414
415                     goto populate_add_leaf_actual_add;
416                 }
417                 else {
418                     //adding to late-resolve list, as we don't have any nodes in the leafref path
419                     int rc = populate_late_resolve_add_leaf(job, instance, schema, parent_d, parent_o, parent_r);
420                     if(rc != NTS_ERR_OK) {
421                         return rc;
422                     }
423
424                     if(!job->late_resolving) {
425                         log_add(1, LOG_COLOR_BOLD_YELLOW"added to late-resolve list...\n"LOG_COLOR_RESET);
426                     }
427                     else {
428                         log_add(1, LOG_COLOR_BOLD_YELLOW"REadded to late-resolve list...\n"LOG_COLOR_RESET);
429                     }
430
431                     return NTS_ERR_OK;
432                 }
433             }
434         } break;
435       
436         default:
437             if(value == 0) {
438                 value = rand_get_populate_value(type);
439             }
440             goto populate_add_leaf_actual_add;
441             break;
442     }
443
444     populate_add_leaf_actual_add: {
445         //add schema to dev
446         struct lyd_node *new_node = lyd_new_leaf(parent_d, schema->module, schema->name, value);
447         if(new_node == 0) {
448             log_error("error on lyd_new_leaf dev: %s\n", ly_errmsg(session_context));
449             return NTS_ERR_FAILED;
450         }
451
452         //print out the value
453         if(value) {
454             log_add(1, LOG_COLOR_CYAN"'%s'"LOG_COLOR_RESET"\n",  value);
455         }
456         else {
457             log_add(1, "\n");
458         }
459
460         //if it fits the case, add it also to running
461         if(leaf_operational || (lys_is_key((const struct lys_node_leaf *)schema, 0) != 0)) {
462             //add schema to operational
463             struct lyd_node *new_node = lyd_new_leaf(parent_o, schema->module, schema->name, value);
464             if(new_node == 0) {
465                 log_error("error on lyd_new_leaf operational: %s\n", ly_errmsg(session_context));
466                 return NTS_ERR_FAILED;
467             }
468         }
469         
470         if(!leaf_operational) {
471             struct lyd_node *new_node = lyd_new_leaf(parent_r, schema->module, schema->name, value);
472             if(new_node == 0) {
473                 log_error("error on lyd_new_leaf running: %s\n", ly_errmsg(session_context));
474                 return NTS_ERR_FAILED;
475             }
476         }
477         
478         free(value);
479     }
480
481     return NTS_ERR_OK;
482 }