-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Type: improvement Change-Id: I26124a50d8e05d6f01a2e6dbc4bc8183fb5a09c4 Signed-off-by: Damjan Marion <damarion@cisco.com>
- Loading branch information
Showing
12 changed files
with
406 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
/* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright (c) 2023 Cisco Systems, Inc. | ||
*/ | ||
|
||
#include "vppinfra/pool.h" | ||
#include <vnet/vnet.h> | ||
#include <vnet/dev/dev.h> | ||
#include <vnet/dev/counters.h> | ||
#include <vnet/dev/log.h> | ||
#include <vnet/dev/types.h> | ||
#include <vppinfra/format_table.h> | ||
|
||
VLIB_REGISTER_LOG_CLASS (dev_log, static) = { | ||
.class_name = "dev", | ||
.subclass_name = "args", | ||
}; | ||
|
||
void | ||
vnet_dev_arg_clear_value (vnet_dev_arg_t *a) | ||
{ | ||
if (a->type == VNET_DEV_ARG_TYPE_STRING) | ||
vec_free (a->val.string); | ||
a->val = (typeof (a->val)){}; | ||
a->val_set = 0; | ||
} | ||
|
||
void | ||
vnet_dev_arg_free (vnet_dev_arg_t **vp) | ||
{ | ||
vnet_dev_arg_t *v; | ||
vec_foreach (v, *vp) | ||
vnet_dev_arg_clear_value (v); | ||
vec_free (*vp); | ||
} | ||
|
||
vnet_dev_rv_t | ||
vnet_dev_arg_parse (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_arg_t *args, | ||
u8 *str) | ||
{ | ||
vnet_dev_rv_t rv = VNET_DEV_OK; | ||
unformat_input_t in; | ||
u8 *name = 0; | ||
u8 *err = 0; | ||
|
||
log_debug (dev, "input '%v'", str); | ||
if (args == 0) | ||
return rv; | ||
|
||
unformat_init_string (&in, (char *) str, vec_len (str)); | ||
|
||
while (unformat (&in, "%U=", unformat_token, "a-zA-Z0-9_", &name)) | ||
{ | ||
vnet_dev_arg_t *a = args; | ||
vec_add1 (name, 0); | ||
while (a < vec_end (args)) | ||
if (strcmp (a->name, (char *) name) == 0) | ||
break; | ||
else | ||
a++; | ||
|
||
if (a->type == VNET_DEV_ARG_TYPE_BOOL) | ||
{ | ||
|
||
if (unformat (&in, "true") || unformat (&in, "1") || | ||
unformat (&in, "on") || unformat (&in, "yes")) | ||
a->val.boolean = 1; | ||
else if (unformat (&in, "false") || unformat (&in, "0") || | ||
unformat (&in, "off") || unformat (&in, "no")) | ||
a->val.boolean = 0; | ||
else | ||
{ | ||
log_err (dev, "unable to parse args: %U", format_unformat_error, | ||
&in); | ||
err = format ( | ||
0, | ||
"boolean value expected ('yes', 'no', '0', '1', 'on', " | ||
"'off', 'true' or 'false') for argument '%s', found '%U'", | ||
a->name, format_unformat_error, &in); | ||
goto done; | ||
} | ||
} | ||
else if (a->type == VNET_DEV_ARG_TYPE_UINT32) | ||
{ | ||
u32 val, min = 0, max = CLIB_U32_MAX; | ||
if (!unformat (&in, "%u", &val)) | ||
{ | ||
err = format (0, | ||
"unsigned integer in range %u - %u expected for " | ||
"argument '%s', found '%U'", | ||
min, max, a->name, format_unformat_error, &in); | ||
goto done; | ||
} | ||
|
||
if (a->min || a->max) | ||
{ | ||
min = a->min; | ||
max = a->max; | ||
} | ||
|
||
if (val < min || val > max) | ||
{ | ||
err = format (0, | ||
"unsigned integer in range %u - %u expected for " | ||
"argument '%s', found '%u'", | ||
min, max, a->name, val); | ||
goto done; | ||
} | ||
a->val.uint32 = val; | ||
} | ||
else if (a->type == VNET_DEV_ARG_TYPE_STRING) | ||
{ | ||
if (!unformat (&in, "%U", unformat_double_quoted_string, | ||
&a->val.string)) | ||
{ | ||
err = format ( | ||
0, | ||
"double quoted string expected for argument '%s', found '%U'", | ||
a->name, format_unformat_error, &in); | ||
goto done; | ||
} | ||
|
||
if (a->min && vec_len (a->val.string) < a->min) | ||
{ | ||
err = | ||
format (0, "string '%v' too short, must be at least %u chars", | ||
a->val.string, a->min); | ||
goto done; | ||
} | ||
if (a->max && vec_len (a->val.string) > a->max) | ||
{ | ||
err = format ( | ||
0, "string '%v' too long, must be no longer than %u chars", | ||
a->val.string, a->max); | ||
goto done; | ||
} | ||
} | ||
else | ||
{ | ||
err = format (0, "unknown argument '%s'", name); | ||
goto done; | ||
} | ||
|
||
a->val_set = 1; | ||
log_debug (dev, "name '%s' type %U value %U", name, | ||
format_vnet_dev_arg_type, a->type, format_vnet_dev_arg_value, | ||
a->type, &a->val); | ||
vec_free (name); | ||
unformat (&in, ","); | ||
} | ||
|
||
if (unformat_check_input (&in) != UNFORMAT_END_OF_INPUT) | ||
err = format (0, "unable to parse argument name '%U'", | ||
format_unformat_error, &in); | ||
|
||
done: | ||
if (err) | ||
{ | ||
vnet_dev_arg_t *a = 0; | ||
log_err (dev, "%v", err); | ||
vec_free (err); | ||
vec_foreach (a, args) | ||
vnet_dev_arg_clear_value (a); | ||
rv = VNET_DEV_ERR_INVALID_ARG; | ||
} | ||
|
||
vec_free (name); | ||
unformat_free (&in); | ||
return rv; | ||
} | ||
|
||
u8 * | ||
format_vnet_dev_arg_type (u8 *s, va_list *args) | ||
{ | ||
vnet_dev_arg_type_t t = va_arg (*args, u32); | ||
switch (t) | ||
{ | ||
#define _(n, f, val) \ | ||
case VNET_DEV_ARG_TYPE_##n: \ | ||
return format (s, #n); | ||
foreach_vnet_dev_arg_type | ||
#undef _ | ||
default : ASSERT (0); | ||
break; | ||
} | ||
return s; | ||
} | ||
|
||
u8 * | ||
format_vnet_dev_arg_value (u8 *s, va_list *args) | ||
{ | ||
vnet_dev_arg_type_t t = va_arg (*args, u32); | ||
vnet_dev_arg_value_t *v = va_arg (*args, vnet_dev_arg_value_t *); | ||
|
||
switch (t) | ||
{ | ||
#define _(n, f, value) \ | ||
case VNET_DEV_ARG_TYPE_##n: \ | ||
s = format (s, f, v->value); \ | ||
break; | ||
foreach_vnet_dev_arg_type | ||
#undef _ | ||
default : break; | ||
} | ||
return s; | ||
} | ||
|
||
u8 * | ||
format_vnet_dev_args (u8 *s, va_list *va) | ||
{ | ||
vnet_dev_arg_t *a, *args = va_arg (*va, vnet_dev_arg_t *); | ||
table_t t = { .no_ansi = 1 }; | ||
|
||
table_add_header_col (&t, 4, "Name", "Value", "Default", "Description"); | ||
table_set_cell_align (&t, -1, 0, TTAA_LEFT); | ||
table_set_cell_align (&t, -1, 3, TTAA_LEFT); | ||
vec_foreach (a, args) | ||
{ | ||
int r = a - args; | ||
table_format_cell (&t, r, 0, "%s", a->name); | ||
if (a->val_set) | ||
table_format_cell (&t, r, 1, "%U", format_vnet_dev_arg_value, a->type, | ||
&a->val); | ||
else | ||
table_format_cell (&t, r, 1, "<not set>"); | ||
|
||
table_format_cell (&t, r, 2, "%U", format_vnet_dev_arg_value, a->type, | ||
&a->default_val); | ||
table_format_cell (&t, r, 3, "%s", a->desc); | ||
table_set_cell_align (&t, r, 0, TTAA_LEFT); | ||
table_set_cell_align (&t, r, 3, TTAA_LEFT); | ||
} | ||
|
||
s = format (s, "%U", format_table, &t); | ||
|
||
table_free (&t); | ||
return s; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright (c) 2023 Cisco Systems, Inc. | ||
*/ | ||
|
||
#ifndef _VNET_DEV_ARGS_H_ | ||
#define _VNET_DEV_ARGS_H_ | ||
|
||
#include <vppinfra/clib.h> | ||
#include <vnet/dev/errors.h> | ||
|
||
#define foreach_vnet_dev_arg_type \ | ||
_ (BOOL, "%u", boolean) \ | ||
_ (UINT32, "%u", uint32) \ | ||
_ (STRING, "\'%v\'", string) | ||
|
||
typedef enum | ||
{ | ||
VNET_DEV_ARG_END, | ||
#define _(n, f, v) VNET_DEV_ARG_TYPE_##n, | ||
foreach_vnet_dev_arg_type | ||
#undef _ | ||
} __clib_packed vnet_dev_arg_type_t; | ||
|
||
typedef union | ||
{ | ||
u8 boolean; | ||
u8 uint32; | ||
u8 *string; | ||
} vnet_dev_arg_value_t; | ||
|
||
typedef struct | ||
{ | ||
char *name; | ||
char *desc; | ||
vnet_dev_arg_type_t type; | ||
u8 val_set; | ||
u32 min; | ||
u32 max; | ||
u64 id; | ||
vnet_dev_arg_value_t val; | ||
vnet_dev_arg_value_t default_val; | ||
} vnet_dev_arg_t; | ||
|
||
#define VNET_DEV_ARG_BOOL(ud, n, d, ...) \ | ||
{ \ | ||
.type = VNET_DEV_ARG_TYPE_BOOL, .id = ud, .name = n, .desc = d, \ | ||
__VA_ARGS__ \ | ||
} | ||
#define VNET_DEV_ARG_UINT32(ud, n, d, ...) \ | ||
{ \ | ||
.type = VNET_DEV_ARG_TYPE_UINT32, .id = ud, .name = n, .desc = d, \ | ||
__VA_ARGS__ \ | ||
} | ||
#define VNET_DEV_ARG_STRING(ud, n, d, ...) \ | ||
{ \ | ||
.type = VNET_DEV_ARG_TYPE_STRING, .id = ud, .name = n, .desc = d, \ | ||
__VA_ARGS__ \ | ||
} | ||
#define VNET_DEV_ARG_END() \ | ||
{ \ | ||
.type = VNET_DEV_ARG_END \ | ||
} | ||
|
||
#define VNET_DEV_ARGS(...) \ | ||
(vnet_dev_arg_t[]) { __VA_ARGS__, VNET_DEV_ARG_END () } | ||
|
||
#define foreach_vnet_dev_args(a, d) \ | ||
for (typeof ((d)->args[0]) *(a) = (d)->args; (a) < vec_end ((d)->args); \ | ||
(a)++) | ||
#define foreach_vnet_dev_port_args(a, p) \ | ||
for (typeof ((p)->args[0]) *(a) = (p)->args; (a) < vec_end ((p)->args); \ | ||
(a)++) | ||
|
||
#endif /* _VNET_DEV_ARGS_H_ */ |
Oops, something went wrong.