TR181-XPON  1.4.0
TR-181 PON manager.
populate_dm_startup.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2022 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or
8 ** without modification, are permitted provided that the following
9 ** conditions are met:
10 **
11 ** 1. Redistributions of source code must retain the above copyright
12 ** notice, this list of conditions and the following disclaimer.
13 **
14 ** 2. Redistributions in binary form must reproduce the above
15 ** copyright notice, this list of conditions and the following
16 ** disclaimer in the documentation and/or other materials provided
17 ** with the distribution.
18 **
19 ** Subject to the terms and conditions of this license, each
20 ** copyright holder and contributor hereby grants to those receiving
21 ** rights under this license a perpetual, worldwide, non-exclusive,
22 ** no-charge, royalty-free, irrevocable (except for failure to
23 ** satisfy the conditions of this license) patent license to make,
24 ** have made, use, offer to sell, sell, import, and otherwise
25 ** transfer this software, where such license applies only to those
26 ** patent claims, already acquired or hereafter acquired, licensable
27 ** by such copyright holder or contributor that are necessarily
28 ** infringed by:
29 **
30 ** (a) their Contribution(s) (the licensed copyrights of copyright
31 ** holders and non-copyrightable additions of contributors, in
32 ** source or binary form) alone; or
33 **
34 ** (b) combination of their Contribution(s) with the work of
35 ** authorship to which such Contribution(s) was added by such
36 ** copyright holder or contributor, if, at the time the Contribution
37 ** is added, such addition causes such combination to be necessarily
38 ** infringed. The patent license shall not apply to any other
39 ** combinations which include the Contribution.
40 **
41 ** Except as expressly stated above, no rights or licenses from any
42 ** copyright holder or contributor is granted under this license,
43 ** whether expressly, by implication, estoppel or otherwise.
44 **
45 ** DISCLAIMER
46 **
47 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
48 ** CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
49 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
50 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
51 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
52 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
53 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
54 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
55 ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
56 ** AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
58 ** ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
59 ** POSSIBILITY OF SUCH DAMAGE.
60 **
61 ****************************************************************************/
62 
63 /* Related header */
64 #include "populate_dm_startup.h"
65 
66 /* System headers */
67 #include <stdio.h> /* snprintf() */
68 #include <stdlib.h> /* free() */
69 #include <string.h> /* strlen() */
70 
71 /* Other libraries' headers */
72 #include <amxc/amxc_macros.h>
73 #include <amxc/amxc.h>
74 #include <amxp/amxp_timer.h>
75 
76 /* Own headers */
77 #include "data_model.h"
78 #include "dm_info.h"
79 #include "pon_ctrl.h"
80 #include "xpon_mgr_constants.h" /* SHORT_TIMEOUT_MS */
81 #include "xpon_trace.h"
82 
83 /* Timer to query for the existence of ONUs */
84 static amxp_timer_t* s_timer_query_onus = NULL;
89 static uint32_t s_cntr_query_onus = 0;
90 
91 /* List of tasks of type task_type_t. */
92 static amxc_llist_t s_tasks = { 0 };
93 /* Timer to handle tasks in 's_tasks' */
94 static amxp_timer_t* s_timer_handle_tasks = NULL;
95 /* List of ONU's to indicate they are initialised */
96 static bool s_onu_initialised[MAX_NR_OF_ONUS] = { 0 };
97 
98 
104 #define QUERY_ONUS_INTERVAL_MS 10000
105 #define QUERY_ONUS_NR_TIMES 30
106 
119 typedef enum _task_type {
125 
140 typedef struct _task {
141  amxc_string_t path;
142  uint32_t index;
144  amxc_llist_it_t it;
146 
147 static const char* task_type_to_string(task_type_t type) {
148  switch(type) {
149  case task_query_indexes: return "query_indexes";
150  case task_query_content: return "query_content";
151  default: break;
152  }
153  return "none";
154 }
155 
156 static void task_init(task_t* const task, const char* const path,
157  uint32_t index, task_type_t type) {
158  amxc_string_init(&task->path, 0);
159  amxc_string_set(&task->path, path);
160  task->index = index;
161  task->type = type;
162 }
163 
164 static void task_clean(task_t* const task) {
165  amxc_string_clean(&task->path);
166 }
167 
176 static task_t* task_create(const char* const path, uint32_t index, task_type_t type) {
177 
178  task_t* task = (task_t*) calloc(1, sizeof(task_t));
179  when_null_trace(task, exit, ERROR, "Failed to allocate memory for task_t");
180 
181  task_init(task, path, index, type);
182 
183  if(amxc_llist_append(&s_tasks, &task->it)) {
184  SAH_TRACEZ_ERROR(ME, "Failed to append task to 's_tasks'");
185  SAH_TRACEZ_ERROR(ME, " path='%s' index=%d type=%s", path, index,
186  task_type_to_string(type));
187  task_clean(task);
188  free(task);
189  task = NULL;
190  }
191 
192 exit:
193  return task;
194 }
195 
196 static void task_delete(amxc_llist_it_t* hit) {
197  task_t* task = amxc_container_of(hit, task_t, it);
198  const char* path = amxc_string_get(&task->path, 0);
199  SAH_TRACEZ_DEBUG(ME, "path='%s' index=%d type=%s", path, task->index,
200  task_type_to_string(task->type));
201  task_clean(task);
202  free(task);
203 }
204 
225 static bool check_return_values(int rc,
226  const amxc_var_t* const ret,
227  const char* func,
228  const char* const path,
229  uint32_t index) {
230  bool rv = false;
231 
232  amxc_string_t buf; /* for logging only */
233  amxc_string_init(&buf, 0);
234 
235  if(index) {
236  amxc_string_setf(&buf, "%s(%s.%d)", func, path, index);
237  } else {
238  amxc_string_setf(&buf, "%s(%s)", func, path);
239  }
240  const char* const fc = amxc_string_get(&buf, 0); /*function call */
241 
242  if(rc) {
243  SAH_TRACEZ_ERROR(ME, "%s failed: rc=%d", fc, rc);
244  goto exit;
245  }
246 
247  const uint32_t type = amxc_var_type_of(ret);
248  if(type != AMXC_VAR_ID_HTABLE) {
249  SAH_TRACEZ_ERROR(ME, "%s: type of 'ret'= %d != htable", fc, type);
250  goto exit;
251  }
252  rv = true;
253 exit:
254  amxc_string_clean(&buf);
255  return rv;
256 }
257 
288 static void query_children(const char* const path, uint32_t index,
289  object_id_t id, bool templates) {
290 
291  const object_info_t* const info = dm_get_object_info(id);
292  when_null(info, exit_no_cleanup);
293 
294  const char* const children_char = templates ? info->templates : info->singletons;
295  if(NULL == children_char) {
296  /* Nothing to do */
297  return;
298  }
299 
300  amxc_llist_t children;
301  amxc_llist_init(&children);
302 
303  amxc_string_t str;
304  amxc_string_init(&str, 0);
305  amxc_string_set(&str, children_char);
306 
307  if(AMXC_STRING_SPLIT_OK != amxc_string_split_to_llist(&str, &children, ',')) {
308  SAH_TRACEZ_ERROR(ME, "Failed to split '%s'", children_char);
309  goto exit;
310  }
311 
312  char child_path[256];
313 
314  amxc_llist_iterate(it, &children) {
315  const amxc_string_t* const child = amxc_string_from_llist_it(it);
316  const char* const child_cstr = amxc_string_get(child, 0);
317  if(index) {
318  snprintf(child_path, 256, "%s.%d.%s", path, index, child_cstr);
319  } else {
320  snprintf(child_path, 256, "%s.%s", path, child_cstr);
321  }
322  SAH_TRACEZ_DEBUG(ME, "Schedule query %s of %s",
323  templates ? "indexes" : "content", child_path);
324 
325  task_create(child_path, /*index=*/ 0,
326  templates ? task_query_indexes : task_query_content);
327  }
328 
329 exit:
330  amxc_llist_clean(&children, amxc_string_list_it_free);
331  amxc_string_clean(&str);
332 exit_no_cleanup:
333  return;
334 }
335 
356 static void query_content(const task_t* task) {
357 
358  const char* path = amxc_string_get(&task->path, 0);
359  if(!path) {
360  SAH_TRACEZ_ERROR(ME, "Failed to get path");
361  return;
362  }
363  SAH_TRACEZ_DEBUG(ME, "path='%s' index=%d", path, task->index);
364 
365  amxc_var_t ret;
366  amxc_var_init(&ret);
367 
368  const int rc = pon_ctrl_get_object_content(path, task->index, &ret);
369 
370  if(!check_return_values(rc, &ret, "get_object_content", path, task->index)) {
371  goto exit;
372  }
373  if(amxc_var_add_key(cstring_t, &ret, "path", path) == NULL) {
374  SAH_TRACEZ_ERROR(ME, "Failed to add 'path' to 'ret'");
375  goto exit;
376  }
377  if(task->index) {
378  if(amxc_var_add_key(uint32_t, &ret, "index", task->index) == NULL) {
379  SAH_TRACEZ_ERROR(ME, "Failed to add 'index' to 'ret'");
380  goto exit;
381  }
383  SAH_TRACEZ_ERROR(ME, "Failed to create %s.%d", path, task->index);
384  goto exit;
385  }
386  } else {
387  if(dm_change_object(&ret)) {
388  SAH_TRACEZ_ERROR(ME, "Failed to update %s", path);
389  /* Do not jump to 'exit'. Still attempt to update any sub-objects. */
390  }
391  }
392 
393  const object_id_t id = dm_get_object_id(path);
394  if(obj_id_unknown == id) {
395  SAH_TRACEZ_DEBUG(ME, "%s has no sub-objects", path);
396  goto exit;
397  }
398 
399  query_children(path, task->index, id, false);
400  query_children(path, task->index, id, true);
401 
402  if(obj_id_onu == id) {
403  if((task->index != 0) && (task->index <= MAX_NR_OF_ONUS)) {
404  SAH_TRACEZ_INFO(ME, "XPON.ONU.%d is initialised", task->index);
405  s_onu_initialised[task->index - 1] = 1;
406  } else {
407  SAH_TRACEZ_ERROR(ME, "XPON.ONU: invalid index: %d: not in [1, %d]",
408  task->index, MAX_NR_OF_ONUS);
409  }
410  }
411 
412 exit:
413  amxc_var_clean(&ret);
414 }
415 
436 static void query_indexes(const task_t* task) {
437 
438  const char* const path = amxc_string_get(&task->path, 0);
439  if(!path) {
440  SAH_TRACEZ_ERROR(ME, "Failed to get path");
441  return;
442  }
443  SAH_TRACEZ_DEBUG(ME, "path='%s' index=%d", path, task->index);
444 
445  amxc_var_t ret;
446  amxc_var_init(&ret);
447 
448  amxc_string_t indexes_str;
449  amxc_string_init(&indexes_str, 0);
450 
451  amxc_llist_t indexes_list;
452  amxc_llist_init(&indexes_list);
453 
454  const int rc = pon_ctrl_get_list_of_instances(path, &ret);
455 
456  if(!check_return_values(rc, &ret, "get_list_of_instances", path, task->index)) {
457  goto exit;
458  }
459 
460  const amxc_htable_t* const htable = amxc_var_constcast(amxc_htable_t, &ret);
461  if(!amxc_htable_contains(htable, "indexes")) {
462  SAH_TRACEZ_ERROR(ME, "htable 'ret' does not contain 'indexes'");
463  goto exit;
464  }
465 
466  const char* const indexes = GET_CHAR(&ret, "indexes");
467  if(0 == strlen(indexes)) {
468  SAH_TRACEZ_DEBUG(ME, "path='%s' index=%d: no instances", path, task->index);
469  goto exit;
470  }
471  SAH_TRACEZ_DEBUG(ME, "indexes='%s'", indexes);
472 
473  amxc_string_set(&indexes_str, indexes);
474 
475  if(AMXC_STRING_SPLIT_OK != amxc_string_split_to_llist(&indexes_str, &indexes_list, ',')) {
476  SAH_TRACEZ_ERROR(ME, "Failed to split '%s'", indexes);
477  goto exit;
478  }
479 
480  amxc_llist_iterate(it, &indexes_list) {
481  const amxc_string_t* const index_str = amxc_string_from_llist_it(it);
482  const char* const index_cstr = amxc_string_get(index_str, 0);
483  if(!amxc_string_is_numeric(index_str)) {
484  SAH_TRACEZ_ERROR(ME, "'%s' is not numeric", index_cstr);
485  continue;
486  }
487  const uint32_t index = atoi(index_cstr);
488 
494  SAH_TRACEZ_DEBUG(ME, "check instance already exists path=%s, index=%d", path, index);
495  if(strcmp(path, "XPON.ONU") == 0) {
496  if((0 == index) || (index > MAX_NR_OF_ONUS)) {
497  SAH_TRACEZ_ERROR(ME, "Invalid index: %d: not in [1, %d]", index, MAX_NR_OF_ONUS);
498  continue;
499  }
500 
501  if(dm_does_instance_exist(path, index) && s_onu_initialised[index - 1]) {
502  SAH_TRACEZ_DEBUG(ME, "%s.%d already exists", path, index);
503  continue;
504  }
505  } else {
506  if(dm_does_instance_exist(path, index)) {
507  SAH_TRACEZ_DEBUG(ME, "%s.%d already exists", path, index);
508  continue;
509  }
510 
511  }
512 
513  SAH_TRACEZ_DEBUG(ME, "Schedule query content of %s.%d", path, index);
514 
515  task_create(path, index, task_query_content);
516  }
517 
518 exit:
519  amxc_llist_clean(&indexes_list, amxc_string_list_it_free);
520  amxc_string_clean(&indexes_str);
521  amxc_var_clean(&ret);
522 }
523 
524 static void schedule_remaining_tasks(void) {
525 
526  if(!amxc_llist_is_empty(&s_tasks)) {
527  amxp_timer_start(s_timer_handle_tasks, SHORT_TIMEOUT_MS);
528  }
529 }
530 
536 static void handle_task(UNUSED amxp_timer_t* timer, UNUSED void* priv) {
537 
538  if(amxc_llist_is_empty(&s_tasks)) {
539  SAH_TRACEZ_WARNING(ME, "No tasks");
540  return;
541  }
542 
543  amxc_llist_it_t* const it = amxc_llist_get_first(&s_tasks);
544 
545  const task_t* const task = amxc_container_of(it, task_t, it);
546 
547  switch(task->type) {
548  case task_query_indexes:
549  query_indexes(task);
550  break;
551  case task_query_content:
552  query_content(task);
553  break;
554  default:
555  SAH_TRACEZ_WARNING(ME, "Unknown task type: %d", task->type);
556  break;
557  }
558  /* Remove the 1st task from the list and delete it */
559  amxc_llist_it_clean(it, task_delete);
560 
562 }
563 
574 static void query_onu_instances(amxp_timer_t* timer, UNUSED void* priv) {
575 
576  task_t task;
577  task_init(&task, "XPON.ONU", /*index=*/ 0, task_query_indexes);
578 
579  SAH_TRACEZ_DEBUG(ME, "s_cntr_query_onus=%d", s_cntr_query_onus);
580 
581  /* Check if all the ONU instances are initialised */
582  bool all_onus_initialised = true;
583  for(int i = 0; i < MAX_NR_OF_ONUS; i++) {
584  if(!s_onu_initialised[i]) {
585  all_onus_initialised = false;
586  break;
587  }
588  }
589  if(all_onus_initialised) {
590  SAH_TRACEZ_INFO(ME, "All %d ONUs found and initialised", MAX_NR_OF_ONUS);
591  amxp_timer_stop(timer);
592  goto exit;
593  }
594 
597  SAH_TRACEZ_DEBUG(ME, "Stop querying ONU instances");
598  amxp_timer_stop(timer);
599  goto exit;
600  }
601 
602  query_indexes(&task);
604 
605 exit:
606  task_clean(&task);
607 }
608 
619 bool pplt_dm_init(void) {
620  bool rv = false;
621 
622  amxc_llist_init(&s_tasks);
623 
624  if(amxp_timer_new(&s_timer_handle_tasks, handle_task, NULL)) {
625  SAH_TRACEZ_ERROR(ME, "Failed to create timer to handle tasks");
626  goto exit;
627  }
628 
629  if(amxp_timer_new(&s_timer_query_onus, query_onu_instances, NULL)) {
630  SAH_TRACEZ_ERROR(ME, "Failed to create timer to query ONUs");
631  goto exit;
632  }
633  amxp_timer_set_interval(s_timer_query_onus, QUERY_ONUS_INTERVAL_MS);
634 
635  /* Start querying the DM on the southbound IF */
636  amxp_timer_start(s_timer_query_onus, SHORT_TIMEOUT_MS);
637 
638  rv = true;
639 exit:
640  return rv;
641 }
642 
648 void pplt_dm_cleanup(void) {
649  amxc_llist_clean(&s_tasks, task_delete);
650  amxp_timer_delete(&s_timer_handle_tasks);
651  amxp_timer_delete(&s_timer_query_onus);
652 }
int dm_change_object(const amxc_var_t *const args)
Definition: data_model.c:821
int dm_add_or_change_instance_impl(const amxc_var_t *const args)
Definition: data_model.c:922
bool dm_does_instance_exist(const char *path, uint32_t index)
Definition: data_model.c:1141
object_id_t dm_get_object_id(const char *path)
Definition: dm_info.c:380
enum _xpon_object_id object_id_t
@ obj_id_onu
Definition: dm_info.h:80
@ obj_id_unknown
Definition: dm_info.h:91
const object_info_t * dm_get_object_info(object_id_t id)
Definition: dm_info.c:410
int pon_ctrl_get_object_content(const char *const path, uint32_t index, amxc_var_t *ret)
Definition: pon_ctrl.c:216
int pon_ctrl_get_list_of_instances(const char *const path, amxc_var_t *ret)
Definition: pon_ctrl.c:187
static void schedule_remaining_tasks(void)
enum _task_type task_type_t
static void handle_task(UNUSED amxp_timer_t *timer, UNUSED void *priv)
static void task_init(task_t *const task, const char *const path, uint32_t index, task_type_t type)
static void task_clean(task_t *const task)
static bool check_return_values(int rc, const amxc_var_t *const ret, const char *func, const char *const path, uint32_t index)
static const char * task_type_to_string(task_type_t type)
static amxp_timer_t * s_timer_handle_tasks
struct _task task_t
void pplt_dm_cleanup(void)
bool pplt_dm_init(void)
static void query_content(const task_t *task)
@ task_query_content
@ task_type_nr
@ task_query_indexes
@ task_none
static bool s_onu_initialised[MAX_NR_OF_ONUS]
static uint32_t s_cntr_query_onus
static task_t * task_create(const char *const path, uint32_t index, task_type_t type)
#define QUERY_ONUS_NR_TIMES
static void query_children(const char *const path, uint32_t index, object_id_t id, bool templates)
static amxc_llist_t s_tasks
static void query_onu_instances(amxp_timer_t *timer, UNUSED void *priv)
static void query_indexes(const task_t *task)
static amxp_timer_t * s_timer_query_onus
static void task_delete(amxc_llist_it_t *hit)
#define QUERY_ONUS_INTERVAL_MS
const char * singletons
Definition: dm_info.h:128
const char * templates
Definition: dm_info.h:129
task_type_t type
uint32_t index
amxc_string_t path
amxc_llist_it_t it
#define SHORT_TIMEOUT_MS
#define SAH_TRACEZ_DEBUG(zone, format,...)
Definition: xpon_trace.h:115
#define ME
Definition: xpon_trace.h:78