blob: cbbe9734f1b2eb23d40d52818f04d6bc43c58cc5 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2<:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7Unless you and Broadcom execute a separate written software license
8agreement governing use of this software, this software is licensed
9to you under the terms of the GNU General Public License version 2
10(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11with the following added to such license:
12
13 As a special exception, the copyright holders of this software give
14 you permission to link this software with independent modules, and
15 to copy and distribute the resulting executable under terms of your
16 choice, provided that you also meet, for each linked independent
17 module, the terms and conditions of the license of that module.
18 An independent module is a module which is not derived from this
19 software. The special exception does not apply to any modifications
20 of the software.
21
22Not withstanding the above, under no circumstances may you combine
23this software in any way with any other Broadcom software provided
24under a license other than the GPL, without Broadcom's express prior
25written consent.
26
27:>
28 */
29
30#include <bcmos_system.h>
31#include <bcmcli.h>
32#include <bal_api.h>
33#include "bal_api_cli.h"
34#include "bal_api_cli_helpers.h"
35#include "bal_api_cli_handlers.h"
36
37#define BCMBAL_APICLI_CAST_DISCARD_CONST(p, type) (type)((long)(p))
38
39/* bool enum table */
40static bcmcli_enum_val bool_enum[] =
41{
42 { .name = "yes", .val = 1 },
43 { .name = "no", .val = 0 },
44 BCMCLI_ENUM_LAST
45};
46
47static bcmbal_apicli_type_descr bool_type_descr = {
48 .name = "bool",
49 .descr = "Boolean",
50 .base_type = BCMBAL_APICLI_BASE_TYPE_ID_ENUM,
51 .size = sizeof(bcmos_bool),
52 .x = {.e = bool_enum}
53};
54
55/* parameter data */
56typedef struct
57{
58 const bcmbal_apicli_prop_descr *prop; /* property */
59 const bcmbal_apicli_field_descr *field; /* field or NULL */
60 const bcmbal_apicli_field_descr *array_fd; /* array field descriptor or NULL */
61 uint16_t offset; /* offset from the beginning of the property */
62 uint16_t array_fd_offset; /* offset of array_fd from the beginning of the property */
63 bcmbal_mgt_group group; /* management group */
64} bcmbal_apicli_parm_data;
65
66typedef enum
67{
68 BCMBAL_APICLI_FLAGS_NONE = 0,
69 BCMBAL_APICLI_FLAGS_IGNORE_FIELDS = 1 << 0
70} bcmbal_apicli_flags;
71
72/* Current session */
73static bcmcli_session *current_session;
74
75/*
76 * helpers
77 */
78
79/* calculate number of fields in type */
80static uint32_t bcmbal_apicli_get_num_fields_in_type(const bcmbal_apicli_type_descr *td)
81{
82 uint16_t f;
83 uint32_t nf = 0;
84
85
86 switch (td->base_type)
87 {
88 case BCMBAL_APICLI_BASE_TYPE_ID_STRUCT:
89 {
90 if (!td->x.s.num_fields)
91 return 0;
92 BUG_ON(!td->x.s.fields);
93 for (f = 0; f < td->x.s.num_fields; f++)
94 {
95 nf += bcmbal_apicli_get_num_fields_in_type(td->x.s.fields[f].type);
96 }
97 break;
98 }
99
100 case BCMBAL_APICLI_BASE_TYPE_ID_UNION:
101 {
102 /* Union. Count only common fields */
103 nf = td->x.u.num_common_fields;
104 break;
105 }
106
107 case BCMBAL_APICLI_BASE_TYPE_ID_ARR_FIXED:
108 {
109 nf = bcmbal_apicli_get_num_fields_in_type(td->x.arr_fixed.elem_type);
110 break;
111 }
112
113 case BCMBAL_APICLI_BASE_TYPE_ID_ARR_DYN:
114 {
115 nf = bcmbal_apicli_get_num_fields_in_type(td->x.arr_dyn.elem_type);
116 break;
117 }
118
119 default:
120 {
121 nf = 1;
122 break;
123 }
124 }
125
126 return nf;
127}
128
129/* calculate number of property fields for given object+group+subgroup+access. simple property=single field */
130static bcmos_errno bcmbal_apicli_get_num_fields_in_group(bcmbal_obj_id o, bcmbal_mgt_group group, uint16_t subgroup,
131 bcmbal_apicli_prop_access_id access_level, uint32_t *nfields)
132{
133 uint32_t nf = 0;
134 int i;
135 bcmos_errno rc = BCM_ERR_OK;
136
137 for (i = 0; rc != BCM_ERR_RANGE; i++)
138 {
139 const bcmbal_apicli_prop_descr *pd;
140 rc = bcmbal_apicli_object_property(o, group, subgroup, i, &pd);
141 if (rc == BCM_ERR_OK && (pd->access & access_level))
142 {
143 /* Calculate number of fields if write access. Count only properties for read access */
144 if ((access_level & BCMBAL_APICLI_PROP_ACCESS_ID_W) != 0)
145 {
146 BUG_ON(!pd->type);
147 nf += bcmbal_apicli_get_num_fields_in_type(pd->type);
148 }
149 else
150 {
151 ++nf;
152 }
153 }
154 }
155 *nfields = nf;
156
157 return BCM_ERR_OK;
158}
159
160/*
161 * Command handlers
162 */
163
164static bcmos_errno bcmbal_apicli_objects_handler(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
165{
166 int rc;
167 bcmbal_obj_id o;
168 const char *name, *descr;
169
170 bcmcli_print(session, "System Object Types:\n");
171 bcmcli_print(session, "=======================================\n");
172 bcmcli_print(session, "Id Name Description\n");
173 bcmcli_print(session, "=======================================\n");
174 for (o = 0; o < BCMBAL_OBJ_ID__NUM_OF; o++)
175 {
176 rc = bcmbal_apicli_object_name(o, &name, &descr);
177 if (!rc)
178 bcmcli_print(session, "%.4d %-22s %s\n", o, name, descr);
179 }
180
181 return 0;
182}
183
184static bcmos_errno bcmbal_apicli_set_handler(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
185{
186 return bcmbal_apicli_call(BCMBAL_MGT_GROUP_CFG, BCMBAL_OBJ_MSG_TYPE_SET, session);
187}
188
189static bcmos_errno bcmbal_apicli_get_handler(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
190{
191 return bcmbal_apicli_call(BCMBAL_MGT_GROUP_CFG, BCMBAL_OBJ_MSG_TYPE_GET, session);
192}
193
194static bcmos_errno bcmbal_apicli_clear_handler(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
195{
196 return bcmbal_apicli_call(BCMBAL_MGT_GROUP_CFG, BCMBAL_OBJ_MSG_TYPE_CLEAR, session);
197}
198
199static bcmos_errno bcmbal_apicli_stat_handler(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
200{
201 return bcmbal_apicli_call(BCMBAL_MGT_GROUP_STAT, BCMBAL_OBJ_MSG_TYPE_GET, session);
202}
203
204/*
205 * Init-time helpers
206 */
207
208/* map to CLI type */
209static bcmos_errno bcmbal_apicli_map_type(
210 const bcmbal_apicli_type_descr *td,
211 const bcmbal_apicli_type_descr *array_td,
212 bcmcli_cmd_parm *cmd_parm)
213{
214 bcmbal_apicli_parm_data *parm_data = cmd_parm->user_data;
215 bcmos_errno rc = BCM_ERR_OK;
216
217 /* Map type */
218 switch(td->base_type)
219 {
220 case BCMBAL_APICLI_BASE_TYPE_ID_SNUM:
221 cmd_parm->type = BCMCLI_PARM_NUMBER;
222 break;
223 case BCMBAL_APICLI_BASE_TYPE_ID_UNUM:
224 cmd_parm->type = BCMCLI_PARM_UNUMBER;
225 break;
226 case BCMBAL_APICLI_BASE_TYPE_ID_UNUM_HEX:
227 cmd_parm->type = BCMCLI_PARM_HEX;
228 break;
229 case BCMBAL_APICLI_BASE_TYPE_ID_BOOL:
230 cmd_parm->type = BCMCLI_PARM_ENUM;
231 cmd_parm->enum_table = bool_enum;
232 break;
233 case BCMBAL_APICLI_BASE_TYPE_ID_FLOAT:
234 cmd_parm->type = td->size == sizeof(double) ? BCMCLI_PARM_DOUBLE : BCMCLI_PARM_FLOAT;
235 break;
236 case BCMBAL_APICLI_BASE_TYPE_ID_STRING:
237 cmd_parm->type = BCMCLI_PARM_STRING;
238 break;
239 case BCMBAL_APICLI_BASE_TYPE_ID_IPV4:
240 cmd_parm->type = BCMCLI_PARM_IP;
241 break;
242 case BCMBAL_APICLI_BASE_TYPE_ID_MAC:
243 cmd_parm->type = BCMCLI_PARM_MAC;
244 break;
245 case BCMBAL_APICLI_BASE_TYPE_ID_ENUM:
246 cmd_parm->type = BCMCLI_PARM_ENUM;
247 cmd_parm->enum_table = td->x.e;
248 break;
249 case BCMBAL_APICLI_BASE_TYPE_ID_ENUM_MASK:
250 cmd_parm->type = BCMCLI_PARM_ENUM_MASK;
251 cmd_parm->enum_table = td->x.e;
252 break;
253 default:
254 bcmcli_print(current_session, "*** can't map type %s (%d)\n", td->name, (int)td->base_type);
255 rc = BCM_ERR_NOT_SUPPORTED;
256 break;
257 }
258
259 /* Map uint8_t array to buffer if it is independent (not structure field) */
260 if (array_td &&
261 td->size == 1 &&
262 (td->base_type == BCMBAL_APICLI_BASE_TYPE_ID_UNUM || td->base_type == BCMBAL_APICLI_BASE_TYPE_ID_UNUM_HEX) &&
263 (parm_data->array_fd == parm_data->field || !parm_data->field))
264 {
265 cmd_parm->type = BCMCLI_PARM_BUFFER;
266 }
267
268 return rc;
269}
270
271/* allocate memory for name and description and copy to to parm */
272static bcmos_errno bcmbal_apicli_copy_parm_name(bcmcli_cmd_parm *parm, const char *name, const char *descr)
273{
274 parm->name = bcmos_alloc(strlen(name) + 1);
275 parm->description = bcmos_alloc(strlen(descr) + 1);
276 if ((parm->name == NULL) || (parm->description == NULL))
277 {
278 /* Successful allocation if any will be released by common cleanup
279 * along with the rest of dynamic parameter fields */
280 return BCM_ERR_NOMEM;
281 }
282 strcpy(BCMBAL_APICLI_CAST_DISCARD_CONST(parm->name, void *), name);
283 strcpy(BCMBAL_APICLI_CAST_DISCARD_CONST(parm->description, void *), descr);
284 return BCM_ERR_OK;
285}
286
287/* populate single parameter */
288static int bcmbal_apicli_populate_parm1(
289 const bcmbal_apicli_prop_descr *pd,
290 const bcmbal_apicli_field_descr *fd,
291 const bcmbal_apicli_type_descr *td,
292 const bcmbal_apicli_field_descr *array_fd,
293 uint32_t offset,
294 uint32_t array_fd_offset,
295 bcmcli_cmd_parm *cmd_parm,
296 uint32_t cmd_flags,
297 char *name,
298 char *help)
299{
300 bcmbal_apicli_parm_data *parm_data = cmd_parm->user_data;
301 int rc;
302
303 parm_data->prop = pd;
304 parm_data->field = fd;
305 parm_data->offset = offset;
306 parm_data->array_fd = array_fd;
307 parm_data->array_fd_offset = array_fd_offset;
308
309 rc = bcmbal_apicli_copy_parm_name(cmd_parm, name, help);
310 if (rc)
311 {
312 return rc;
313 }
314 cmd_parm->flags = cmd_flags;
315 if (td->min_val != td->max_val || td->min_val)
316 {
317 cmd_parm->flags |= BCMCLI_PARM_FLAG_RANGE;
318 cmd_parm->low_val = td->min_val;
319 cmd_parm->hi_val = td->max_val;
320 }
321 rc = bcmbal_apicli_map_type(td, array_fd ? array_fd->type : NULL, cmd_parm);
322 if (rc < 0)
323 {
324 return rc;
325 }
326
327 /* Arrays require more work.
328 * - Calculate size. Known for fixed arrays, hard-coded max for dynamic
329 * - Allocate either buffer or array of values based on CLI parameter type
330 * - Calculate offset from the beginning of array entry
331 */
332 if (array_fd)
333 {
334 uint32_t array_size;
335
336 if (array_fd->type->base_type == BCMBAL_APICLI_BASE_TYPE_ID_ARR_FIXED)
337 {
338 array_size = array_fd->type->x.arr_fixed.size;
339 }
340 else
341 {
342 array_size = array_fd->type->x.arr_dyn.max_size;
343 }
344 if (!array_size)
345 {
346 bcmcli_print(current_session, "*** Error in %s array descriptor. Size is not set.\n", array_fd->name);
347 return BCM_ERR_INTERNAL;
348 }
349 if (cmd_parm->type == BCMCLI_PARM_BUFFER)
350 {
351 rc = bcmbal_buf_alloc(&cmd_parm->value.buffer, array_size);
352 if (rc)
353 {
354 return rc;
355 }
356 }
357 else
358 {
359 cmd_parm->values = bcmos_calloc(sizeof(bcmcli_parm_value) * array_size);
360 if (!cmd_parm->values)
361 {
362 return BCM_ERR_NOMEM;
363 }
364 cmd_parm->max_array_size = array_size;
365 }
366 }
367
368 return 1;
369}
370
371
372/* populate name buf and help buf */
373static void bcmbal_apicli_populate_name_help(const bcmbal_apicli_field_descr *fld, char *name_buf0, char *help_buf0,
374 char *name_buf, char *help_buf)
375{
376 name_buf[0] = 0;
377 help_buf[0] = 0;
378 bcmcli_strncpy(name_buf, name_buf0, BCMBAL_APICLI_MAX_PARM_NAME_LENGTH);
379 if (strlen(name_buf))
380 bcmcli_strncat(name_buf, ".", BCMBAL_APICLI_MAX_PARM_NAME_LENGTH);
381 bcmcli_strncat(name_buf, fld->cli_name ? fld->cli_name : fld->name, BCMBAL_APICLI_MAX_PARM_NAME_LENGTH);
382 bcmcli_strncpy(help_buf, help_buf0, BCMBAL_APICLI_MAX_PARM_HELP_LENGTH);
383 bcmcli_strncat(help_buf, " - ", BCMBAL_APICLI_MAX_PARM_HELP_LENGTH);
384 bcmcli_strncat(help_buf, fld->descr ? fld->descr : fld->name, BCMBAL_APICLI_MAX_PARM_HELP_LENGTH);
385}
386
387/* Allocate CLI parameter array. Set up parm->data */
388static bcmcli_cmd_parm *bcmbal_apicli_parm_alloc(int nparms)
389{
390 uint32_t size;
391 bcmcli_cmd_parm *parms;
392 bcmbal_apicli_parm_data *parm_data;
393 int i;
394
395 /* Allocate parameter table and populate it */
396 size = (sizeof(bcmcli_cmd_parm) + sizeof(bcmbal_apicli_parm_data)) * (nparms + 1);
397 parms = bcmos_calloc(size);
398 if (!parms)
399 return NULL;
400
401 /* Associate parameter_data structs with parameters */
402 parm_data = (bcmbal_apicli_parm_data *)(parms + nparms + 1);
403 for (i = 0; i < nparms; i++)
404 {
405 parms[i].user_data = &parm_data[i];
406 }
407 return parms;
408}
409
410/* clone enum table */
411static bcmcli_enum_val *bcmbal_apicli_clone_enum_table(bcmcli_cmd_parm *parm)
412{
413 bcmcli_enum_val *org_table = parm->enum_table;
414 bcmcli_enum_val *val = org_table;
415 bcmcli_enum_val *clone_table = org_table;
416 int i, n;
417
418 BUG_ON(parm->type != BCMCLI_PARM_ENUM);
419 while (val && val->name)
420 {
421 ++val;
422 }
423 n = val - org_table;
424
425 clone_table = bcmos_calloc(sizeof(bcmcli_enum_val) * (n + 1));
426 if (!clone_table)
427 {
428 return NULL;
429 }
430 for (i = 0; i < n; i++)
431 {
432 clone_table[i].name = org_table[i].name;
433 clone_table[i].val = org_table[i].val;
434 }
435 return clone_table;
436}
437
438
439/* populate CLI parameter(s) from a single property. Can be multiple parameters
440 * if property contains multiple fields.
441 * Returns number of parameters populated >= 0 or error < 0
442 */
443static int bcmbal_apicli_populate_parms_from_property(const bcmbal_apicli_prop_descr *pd,
444 const bcmbal_apicli_field_descr *fd, const bcmbal_apicli_field_descr *array_fd, uint32_t offset,
445 uint32_t array_fd_offset, bcmcli_cmd_parm *parms, bcmbal_apicli_prop_access_id access_level, uint32_t cmd_flags,
446 char *name_buf0, char *help_buf0)
447{
448 const bcmbal_apicli_type_descr *td = fd ? fd->type : pd->type;
449 uint32_t nf = 0;
450 char name_buf[BCMBAL_APICLI_MAX_PARM_NAME_LENGTH];
451 char help_buf[BCMBAL_APICLI_MAX_PARM_HELP_LENGTH];
452 int rc = 0;
453
454 /* presence masks are not set directly, they are calculated based on other fields */
455 if (fd != NULL && (fd->flags & BCMBAL_APICLI_FIELD_DESCR_FLAGS_PRESENCE_MASK) != 0)
456 {
457 return BCM_ERR_READ_ONLY;
458 }
459
460 /* At top level take name from property */
461 if (td == pd->type)
462 {
463 /* In case there's a global prefix */
464 char *top_name_buf = name_buf0;
465 uint32_t top_name_buf_len = BCMBAL_APICLI_MAX_PARM_NAME_LENGTH;
466 uint32_t prefix_len = strlen(name_buf0);
467 if (prefix_len > 0)
468 {
469 top_name_buf += prefix_len;
470 top_name_buf_len -= prefix_len;
471 }
472
473 bcmcli_strncpy(top_name_buf, pd->cli_name ? pd->cli_name : pd->name, top_name_buf_len);
474 bcmcli_strncpy(help_buf0, pd->descr ? pd->descr : pd->name, BCMBAL_APICLI_MAX_PARM_HELP_LENGTH);
475 }
476
477 /* For read access we only mark whether read property or not. It is not field-by-field operation */
478 if (access_level == BCMBAL_APICLI_PROP_ACCESS_ID_R)
479 {
480 td = &bool_type_descr;
481 }
482
483 /* In case of arrays we should
484 * - check that there is no array in array. It is not supported
485 * - store array type descriptor FFU and replace the "current" type descriptor with element type
486 * - reset offset because for array fields it should be calculated from array base rather than property
487 */
488 if (td->base_type == BCMBAL_APICLI_BASE_TYPE_ID_ARR_DYN || td->base_type == BCMBAL_APICLI_BASE_TYPE_ID_ARR_FIXED)
489 {
490 if (array_fd)
491 {
492 bcmcli_print(
493 current_session,
494 "*** %s in %s: arrays-in-arrays are not supported\n",
495 pd->name,
496 array_fd->name);
497 return BCM_ERR_NOT_SUPPORTED;
498 }
499 /* store array type and fetch element type */
500 array_fd = fd ? fd : (const bcmbal_apicli_field_descr *)pd;
501 if (td->base_type == BCMBAL_APICLI_BASE_TYPE_ID_ARR_DYN)
502 {
503 td = td->x.arr_dyn.elem_type;
504 }
505 else
506 {
507 td = td->x.arr_fixed.elem_type;
508 }
509 array_fd_offset = offset;
510 offset = 0;
511 }
512
513 if (td->base_type == BCMBAL_APICLI_BASE_TYPE_ID_STRUCT)
514 {
515 uint16_t f;
516 if (!td->x.s.num_fields)
517 return 0;
518 BUG_ON(!td->x.s.fields);
519 for (f = 0; f < td->x.s.num_fields; f++)
520 {
521 const bcmbal_apicli_field_descr *fld = &td->x.s.fields[f];
522 bcmbal_apicli_populate_name_help(fld, name_buf0, help_buf0, name_buf, help_buf);
523 rc = bcmbal_apicli_populate_parms_from_property(pd, fld, array_fd, offset+fld->offset,
524 array_fd_offset, &parms[nf], access_level, cmd_flags, name_buf, help_buf);
525 if (rc > 0)
526 nf += rc;
527 }
528 }
529 else if (td->base_type == BCMBAL_APICLI_BASE_TYPE_ID_UNION)
530 {
531 /* Union */
532 uint16_t f;
533 const bcmbal_apicli_field_descr *fld;
534 bcmcli_cmd_parm *sel_parm;
535 bcmbal_apicli_parm_data *sel_data;
536 bcmcli_enum_val *e;
537
538 if (!td->x.u.num_common_fields)
539 return 0;
540 BUG_ON(!td->x.u.common_fields);
541
542 /* Populate parameters preceding the union selector */
543 for (f = 0; f < td->x.u.classifier_idx; f++)
544 {
545 fld = &td->x.u.common_fields[f];
546 bcmbal_apicli_populate_name_help(fld, name_buf0, help_buf0, name_buf, help_buf);
547 rc = bcmbal_apicli_populate_parms_from_property(pd, fld, array_fd,
548 offset+fld->offset, array_fd_offset, &parms[nf], access_level, cmd_flags, name_buf, help_buf);
549 if (rc > 0)
550 nf += rc;
551 }
552
553 /* Now populate parameter for selector */
554 sel_parm = &parms[nf];
555 fld = &td->x.u.common_fields[f];
556 bcmbal_apicli_populate_name_help(fld, name_buf0, help_buf0, name_buf, help_buf);
557 rc = bcmbal_apicli_populate_parms_from_property(pd, fld, array_fd,
558 offset+fld->offset, array_fd_offset, sel_parm, access_level, cmd_flags, name_buf, help_buf);
559 if (rc > 0)
560 nf += rc;
561 /* Clone enum table in order to allow modifying it */
562 if (rc >= 1)
563 {
564 sel_parm->enum_table = bcmbal_apicli_clone_enum_table(sel_parm);
565 if (!sel_parm->enum_table)
566 {
567 rc = BCM_ERR_NOMEM;
568 }
569 }
570
571 /* Now set-up selector */
572 sel_parm->flags |= BCMCLI_PARM_FLAG_SELECTOR;
573 sel_data = sel_parm->user_data;
574 e = sel_parm->enum_table;
575 while (e && e->name && rc >= 0)
576 {
577 fld = &td->x.u.union_fields[e - sel_parm->enum_table];
578 if (fld->type)
579 {
580 int np = bcmbal_apicli_get_num_fields_in_type(fld->type);
581 int i;
582
583 e->parms = bcmbal_apicli_parm_alloc(np);
584 if (!e->parms)
585 {
586 rc = BCM_ERR_NOMEM;
587 break;
588 }
589 for (i = 0; i < np; i++)
590 {
591 bcmbal_apicli_parm_data *data = e->parms[i].user_data;
592 data->group = sel_data->group;
593 }
594 /* Collapse substructure name */
595 if (fld->type->base_type == BCMBAL_APICLI_BASE_TYPE_ID_STRUCT ||
596 fld->type->base_type == BCMBAL_APICLI_BASE_TYPE_ID_UNION)
597 {
598 bcmcli_strncpy(name_buf, name_buf0, sizeof(name_buf));
599 bcmcli_strncpy(help_buf, help_buf0, sizeof(help_buf));
600 }
601 else
602 {
603 bcmbal_apicli_populate_name_help(fld, name_buf0, help_buf0, name_buf, help_buf);
604 }
605 rc = bcmbal_apicli_populate_parms_from_property(pd, fld, array_fd,
606 offset+fld->offset, array_fd_offset, e->parms, access_level, cmd_flags, name_buf, help_buf);
607 }
608 ++e;
609 }
610
611 /* Finally populate parameters following the selector parameter */
612 for (f = td->x.u.classifier_idx + 1; f < td->x.u.num_common_fields && rc >= 0; f++)
613 {
614 fld = &td->x.u.common_fields[f];
615 bcmbal_apicli_populate_name_help(fld, name_buf0, help_buf0, name_buf, help_buf);
616 rc = bcmbal_apicli_populate_parms_from_property(pd, fld, array_fd,
617 offset+fld->offset, array_fd_offset, &parms[nf], access_level, cmd_flags, name_buf, help_buf);
618 if (rc > 0)
619 nf += rc;
620 }
621 }
622 else
623 {
624 /* Finally! Simple type that maps to a single CLI parameter */
625 nf = bcmbal_apicli_populate_parm1(pd, fd, td, array_fd, offset, array_fd_offset,
626 &parms[0], cmd_flags, name_buf0, help_buf0);
627 }
628 return (rc >= 0) ? nf : rc;
629}
630
631/* populate CLI parameter table */
632static int bcmbal_apicli_populate_parms(
633 bcmbal_obj_id o,
634 bcmbal_mgt_group group,
635 uint16_t subgroup,
636 bcmbal_apicli_prop_access_id access_level,
637 bcmcli_cmd_parm *parms,
638 uint32_t cmd_flags,
639 const char *prefix)
640{
641 int nf = 0;
642 int i;
643 bcmos_errno rc = BCM_ERR_OK;
644
645 for (i = 0; rc != BCM_ERR_RANGE; i++)
646 {
647 const bcmbal_apicli_prop_descr *pd;
648 char name_buf[BCMBAL_APICLI_MAX_PARM_NAME_LENGTH] = "";
649 char help_buf[BCMBAL_APICLI_MAX_PARM_HELP_LENGTH] = "";
650
651 strncpy(name_buf, prefix, BCMBAL_APICLI_MAX_PARM_NAME_LENGTH-1);
652 name_buf[BCMBAL_APICLI_MAX_PARM_NAME_LENGTH-1] = 0;
653
654 rc = bcmbal_apicli_object_property(o, group, subgroup, i, &pd);
655 if (rc == BCM_ERR_OK && (pd->access & access_level))
656 {
657 rc = bcmbal_apicli_populate_parms_from_property(pd, NULL, NULL, 0, 0, &parms[nf],
658 access_level, cmd_flags, name_buf, help_buf);
659 if (rc > 0)
660 nf += rc;
661 }
662 }
663 return nf;
664}
665
666
667/* compact selector table. squeeze out values that don't have parameter table attached */
668static void bcmbal_apicli_compact_selector(bcmcli_enum_val *selector, int size)
669{
670 int i, j;
671
672 for (i = 0; i < size; i++)
673 {
674 if (!selector[i].parms)
675 {
676 for ( j = i + 1; j < size && !selector[j].parms; j ++)
677 ;
678 if (j < size)
679 {
680 memcpy(&selector[i], &selector[j], sizeof(bcmcli_enum_val));
681 memset(&selector[j], 0, sizeof(bcmcli_enum_val));
682 }
683 else
684 {
685 memset(&selector[i], 0, sizeof(bcmcli_enum_val));
686 }
687 }
688 }
689}
690
691/* Free CLI parameters. both name and description are allocated dynamically */
692static void bcmbal_apicli_free_parms(bcmcli_cmd_parm *parms)
693{
694 bcmcli_cmd_parm *p = parms;
695
696 while (p->name)
697 {
698 if ((p->flags & BCMCLI_PARM_FLAG_SELECTOR))
699 {
700 /* Remove selector table */
701 bcmcli_enum_val *sel = p->enum_table;
702 if (sel)
703 {
704 bcmcli_enum_val *e = sel;
705 while(e->name)
706 {
707 if (e->parms)
708 {
709 bcmbal_apicli_free_parms(e->parms);
710 }
711 ++e;
712 }
713 bcmos_free(sel);
714 }
715 }
716 if (p->description)
717 bcmos_free(BCMBAL_APICLI_CAST_DISCARD_CONST(p->description, void *));
718 if (p->name)
719 bcmos_free(BCMBAL_APICLI_CAST_DISCARD_CONST(p->name, void *));
720 if (p->max_array_size && p->values)
721 bcmos_free(p->values);
722 if (p->value.buffer.start)
723 bcmbal_buf_free(&p->value.buffer);
724
725 ++p;
726 }
727 bcmos_free(parms);
728}
729
730static uint8_t bcmbal_apicli_get_num_cmd_parms(bcmbal_mgt_group group, bcmbal_apicli_flags flags)
731{
732 if (group == BCMBAL_MGT_GROUP_STAT)
733 return 2; /* object + stat ID */
734 else
735 return 1; /* object */
736}
737
738/* Read generated info and add CLI command */
739static bcmos_errno bcmbal_apicli_add(bcmcli_entry *dir, const char *cmd_name, const char *cmd_descr,
740 bcmbal_mgt_group group, bcmbal_apicli_prop_access_id access_level, bcmcli_cmd_cb cmd_handler,
741 bcmbal_apicli_flags flags)
742{
743 bcmcli_cmd_extra_parm cmd_extras = { .free_parms = bcmbal_apicli_free_parms };
744 bcmcli_cmd_parm *cmd_parms;
745 bcmcli_enum_val *obj_selector;
746 bcmbal_obj_id o;
747 bcmos_errno rc = BCM_ERR_OK;
748 uint32_t cmd_flags = 0;
749 uint8_t num_cmd_parms = bcmbal_apicli_get_num_cmd_parms(group, flags);
750 int n_obj;
751 int i;
752
753 /* Command flags: parameters in the following groups are optional */
754 if (group == BCMBAL_MGT_GROUP_CFG || group == BCMBAL_MGT_GROUP_STAT || group == BCMBAL_MGT_GROUP_AUTO_CFG)
755 cmd_flags = BCMCLI_PARM_FLAG_OPTIONAL;
756
757 /* command parameters are:
758 * - object_name (selector)
759 * - object_key_fields
760 * - object_per_group_fields filtered by access
761 * Therefore, there is 1 top-level enum parameter (object type) with per-value parameter tables
762 * In the case of operations or proxy messages, there is also a top-level enum parameter for the oper/proxy name
763 */
764
765 /* Allocate enum table based on max number of objects. Will be compacted in the end */
766 cmd_parms = bcmos_calloc(sizeof(bcmcli_cmd_parm) * (num_cmd_parms + 1));
767 if (!cmd_parms)
768 return BCM_ERR_NOMEM;
769
770 /* Allocate enough space for all object entries as well as a terminator entry (which is left NULL) */
771 obj_selector = bcmos_calloc(sizeof(bcmcli_enum_val) * (BCMBAL_OBJ_ID__NUM_OF + 1));
772 if (!obj_selector)
773 goto nomem_cleanup;
774
775 /* Allocate parameter table */
776 n_obj = 0;
777 for (o = 0; o < BCMBAL_OBJ_ID__NUM_OF; o++)
778 {
779 uint32_t nkeyfields = 0;
780 uint32_t nfields = 0;
781 uint32_t nfilterfields = 0;
782 uint32_t size;
783 uint16_t s;
784 uint16_t subgroup_count = bcmbal_apicli_get_subgroup_count(o, group);
785 bcmcli_enum_val *sub_selector;
786
787 if (subgroup_count == 0)
788 continue;
789
790 obj_selector[n_obj].val = o;
791 rc = bcmbal_apicli_object_name(o, &obj_selector[n_obj].name, NULL);
792 if (rc)
793 continue;
794
795 /* Get number of key fields and save it */
796 if (group == BCMBAL_MGT_GROUP_AUTO_CFG)
797 {
798 nkeyfields = 0;
799 }
800 else
801 {
802 bcmbal_apicli_get_num_fields_in_group(
803 o, BCMBAL_MGT_GROUP_KEY, 0, BCMBAL_APICLI_PROP_ACCESS_ID_W, &nkeyfields);
804 }
805
806 /* Allocate subgroup enum table */
807 sub_selector = bcmos_calloc(sizeof(bcmcli_enum_val) * (subgroup_count + 1));
808 if (!sub_selector)
809 goto nomem_cleanup;
810
811 /* Allocate single subgroup command parameter */
812 size = sizeof(bcmcli_cmd_parm) * 2;
813 obj_selector[n_obj].parms = bcmos_calloc(size);
814 if (!obj_selector[n_obj].parms)
815 {
816 bcmos_free(sub_selector);
817 goto nomem_cleanup;
818 }
819
820 /* Setup single subgroup command parameter */
821 obj_selector[n_obj].parms[0].type = BCMCLI_PARM_ENUM;
822 obj_selector[n_obj].parms[0].flags = BCMCLI_PARM_FLAG_SELECTOR;
823 obj_selector[n_obj].parms[0].enum_table = sub_selector;
824 rc = bcmbal_apicli_copy_parm_name(&obj_selector[n_obj].parms[0],
825 "sub",
826 "Subgroup (specific operation / proxy msg)");
827 if (rc)
828 goto nomem_cleanup;
829
830 for (s = 0; s < subgroup_count; ++s)
831 {
832 const char *sub_name;
833 bcmcli_cmd_parm *parm_ptr;
834
835 /* Get name of specific subgroup */
836 rc = bcmbal_apicli_object_subgroup_name(o, group, s, &sub_name, NULL);
837 if (rc)
838 continue;
839
840 /* Setup entry in subgroup enum table */
841 sub_selector[s].name = sub_name;
842 sub_selector[s].val = s;
843
844 /* Get number of group fields */
845 rc = bcmbal_apicli_get_num_fields_in_group(o, group, s, access_level, &nfields);
846 if (rc)
847 continue;
848
849 if ((flags & BCMBAL_APICLI_FLAGS_IGNORE_FIELDS) != BCMBAL_APICLI_FLAGS_NONE)
850 {
851 nfilterfields = 0;
852 nfields = 0;
853 }
854
855 /* Allocate parameter table and populate it */
856 sub_selector[s].parms = bcmbal_apicli_parm_alloc(nfields + nkeyfields + nfilterfields);
857 if (!sub_selector[s].parms)
858 {
859 rc = BCM_ERR_NOMEM;
860 goto nomem_cleanup;
861 }
862 for (i = 0; i < nkeyfields + nfields + nfilterfields; i++)
863 {
864 bcmbal_apicli_parm_data *parm_data = sub_selector[s].parms[i].user_data;
865 parm_data->group = (i < nkeyfields) ? BCMBAL_MGT_GROUP_KEY : group;
866 }
867
868 parm_ptr = sub_selector[s].parms;
869 if (nkeyfields)
870 {
871 rc = bcmbal_apicli_populate_parms(
872 o, BCMBAL_MGT_GROUP_KEY, 0, BCMBAL_APICLI_PROP_ACCESS_ID_W, parm_ptr, 0, "");
873 if (rc < 0)
874 goto nomem_cleanup;
875 parm_ptr += rc;
876 }
877 if (nfilterfields)
878 {
879 rc = bcmbal_apicli_populate_parms(
880 o, group, s, BCMBAL_APICLI_PROP_ACCESS_ID_RW, parm_ptr, cmd_flags, "filter.");
881 if (rc < 0)
882 goto nomem_cleanup;
883 parm_ptr += rc;
884 }
885 if (nfields)
886 {
887 rc = bcmbal_apicli_populate_parms(o, group, s, access_level, parm_ptr, cmd_flags, "");
888 if (rc < 0)
889 goto nomem_cleanup;
890 parm_ptr += rc;
891 }
892 }
893
894 /* Compact sub_selector enum. Removes holes (values without parameter table) */
895 bcmbal_apicli_compact_selector(sub_selector, subgroup_count);
896
897 /* If the group type doesn't support subgroups, remove the subgroup param entry */
898 if (group == BCMBAL_MGT_GROUP_CFG || group == BCMBAL_MGT_GROUP_STAT || group == BCMBAL_MGT_GROUP_AUTO_CFG)
899 {
900 /* Free the memory associated with the (single) subgroup param */
901 bcmos_free(BCMBAL_APICLI_CAST_DISCARD_CONST(obj_selector[n_obj].parms[0].name, void *));
902 bcmos_free(BCMBAL_APICLI_CAST_DISCARD_CONST(obj_selector[n_obj].parms[0].description, void *));
903 bcmos_free(obj_selector[n_obj].parms);
904 /* Assign the subgroup params to the root object params */
905 obj_selector[n_obj].parms = sub_selector[0].parms;
906 bcmos_free(sub_selector);
907 }
908
909 ++n_obj; /* number of configured objects */
910 }
911
912 /* Compact obj_selector enum. Removes holes (values without parameter table) */
913 bcmbal_apicli_compact_selector(obj_selector, BCMBAL_OBJ_ID__NUM_OF);
914
915 /* Add a 'clear on read' to stats group */
916 if (group == BCMBAL_MGT_GROUP_STAT)
917 {
918 cmd_parms[0].type = BCMCLI_PARM_ENUM;
919 cmd_parms[0].enum_table = bool_enum;
920 rc = bcmbal_apicli_copy_parm_name(&cmd_parms[0], "clear", "clear on read");
921 if (rc)
922 goto nomem_cleanup;
923 }
924
925 /* We are ready to add this command */
926 cmd_parms[num_cmd_parms - 1].type = BCMCLI_PARM_ENUM;
927 cmd_parms[num_cmd_parms - 1].flags = BCMCLI_PARM_FLAG_SELECTOR;
928 cmd_parms[num_cmd_parms - 1].enum_table = obj_selector;
929 rc = bcmbal_apicli_copy_parm_name(&cmd_parms[num_cmd_parms - 1], "object", "Object Type");
930 if (rc)
931 goto nomem_cleanup;
932 rc = bcmcli_cmd_add(dir, cmd_name, cmd_handler, cmd_descr,
933 (access_level == BCMBAL_APICLI_PROP_ACCESS_ID_W) ? BCMCLI_ACCESS_ADMIN : BCMCLI_ACCESS_GUEST,
934 &cmd_extras, cmd_parms);
935 if (rc)
936 goto nomem_cleanup;
937 return 0;
938
939nomem_cleanup:
940 if (obj_selector)
941 {
942 for (o = 0; o < BCMBAL_OBJ_ID__NUM_OF; o++)
943 {
944 if (obj_selector[o].parms)
945 bcmbal_apicli_free_parms(obj_selector[o].parms);
946 }
947 bcmos_free(obj_selector);
948 }
949 bcmos_free(cmd_parms);
950 return rc;
951}
952
953static bcmcli_session *bcmbal_apicli_log;
954static FILE *bcmbal_apicli_log_file;
955
956static int bcmbal_apicli_log_write_cb(bcmcli_session *session, const char *buf, uint32_t size)
957{
958 if (bcmbal_apicli_log_file == NULL || buf == NULL)
959 return BCM_ERR_INTERNAL;
960 fwrite(buf, 1, size, bcmbal_apicli_log_file);
961 fflush(bcmbal_apicli_log_file);
962 return BCM_ERR_OK;
963}
964
965/* Enable/disable API logging
966 * BCMCLI_MAKE_PARM("file", "Log file. Use \"-\" to disable logging", BCMCLI_PARM_STRING, 0));
967 */
968static bcmos_errno bcmbal_apicli_log_handler(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
969{
970 const char *fname = parm[0].value.string;
971 bcmcli_session_parm session_params =
972 {
973 .write = bcmbal_apicli_log_write_cb,
974 .name = "api_log"
975 };
976 bcmos_errno rc;
977 time_t start_time;
978
979 /* Close existing log session if any */
980 if (bcmbal_apicli_log)
981 {
982 bcmcli_log_set(BCMCLI_LOG_NONE, NULL);
983 bcmcli_session_close(bcmbal_apicli_log);
984 fclose(bcmbal_apicli_log_file);
985 bcmbal_apicli_log = NULL;
986 bcmbal_apicli_log_file = NULL;
987 }
988
989 if (!strcmp(fname, "-"))
990 return BCM_ERR_OK;
991
992 /* Starting a new log session */
993 bcmbal_apicli_log_file = fopen(fname, "a");
994 if (bcmbal_apicli_log_file == NULL)
995 {
996 bcmcli_print(session, "Can't open file %s for logging\n", fname);
997 return BCM_ERR_PARM;
998 }
999 rc = bcmcli_session_open_user(&session_params, &bcmbal_apicli_log);
1000 if (rc)
1001 {
1002 fclose(bcmbal_apicli_log_file);
1003 bcmbal_apicli_log_file = NULL;
1004 bcmcli_print(session, "Can't open log session. Error %s\n", bcmos_strerror(rc));
1005 return rc;
1006 }
1007 time(&start_time);
1008 bcmcli_log_set(BCMCLI_LOG_C_COMMENT, bcmbal_apicli_log);
1009 bcmcli_log("/* API logging session started. %s */\n", ctime(&start_time));
1010 return BCM_ERR_OK;
1011}
1012
1013static void bcmbal_apicli_find_del_cmd(bcmcli_entry *dir, const char *cmd_name)
1014{
1015 bcmcli_entry *cmd;
1016 cmd = bcmcli_cmd_find(dir, cmd_name);
1017 if (cmd)
1018 {
1019 bcmcli_token_destroy(cmd);
1020 }
1021}
1022
1023/* Unregisters commands and directories */
1024void bcmbal_apicli_del_commands(bcmcli_session *session, bcmcli_entry *api_dir)
1025{
1026 bcmbal_apicli_find_del_cmd(api_dir, "set");
1027 bcmbal_apicli_find_del_cmd(api_dir, "get");
1028 bcmbal_apicli_find_del_cmd(api_dir, "clear");
1029 bcmbal_apicli_find_del_cmd(api_dir, "stat");
1030 bcmbal_apicli_find_del_cmd(api_dir, "objects");
1031 bcmbal_apicli_find_del_cmd(api_dir, "log");
1032}
1033
1034/* Registers commands and directories */
1035bcmos_errno bcmbal_apicli_add_commands(bcmcli_session *session, bcmcli_entry *api_dir)
1036{
1037 bcmos_errno rc;
1038
1039 current_session = session;
1040
1041 /* Now generate and add commands */
1042 rc = bcmbal_apicli_add(api_dir, "set", "Set object configuration", BCMBAL_MGT_GROUP_CFG,
1043 BCMBAL_APICLI_PROP_ACCESS_ID_W, bcmbal_apicli_set_handler, BCMBAL_APICLI_FLAGS_NONE);
1044 rc = rc ? rc : bcmbal_apicli_add(api_dir, "get", "Get object configuration", BCMBAL_MGT_GROUP_CFG,
1045 BCMBAL_APICLI_PROP_ACCESS_ID_R, bcmbal_apicli_get_handler, BCMBAL_APICLI_FLAGS_NONE);
1046 rc = rc ? rc : bcmbal_apicli_add(api_dir, "clear", "Clear object configuration", BCMBAL_MGT_GROUP_CFG,
1047 BCMBAL_APICLI_PROP_ACCESS_ID_R, bcmbal_apicli_clear_handler, BCMBAL_APICLI_FLAGS_IGNORE_FIELDS);
1048 rc = rc ? rc : bcmbal_apicli_add(api_dir, "stat", "Get statistics", BCMBAL_MGT_GROUP_STAT,
1049 BCMBAL_APICLI_PROP_ACCESS_ID_R, bcmbal_apicli_stat_handler, BCMBAL_APICLI_FLAGS_NONE);
1050
1051 /* List all system objects */
1052 rc = rc ? rc : bcmcli_cmd_add(api_dir, "objects", bcmbal_apicli_objects_handler,
1053 "Object Types", BCMCLI_ACCESS_GUEST, NULL, NULL);
1054
1055 BCMCLI_MAKE_CMD(api_dir, "log", "Log API calls", bcmbal_apicli_log_handler,
1056 BCMCLI_MAKE_PARM("file", "Log file. Use \"-\" to disable logging", BCMCLI_PARM_STRING, 0));
1057
1058 return rc;
1059}