blob: e302517cc611b65fa36520746b4c6f0a6b44d222 [file] [log] [blame]
Damjan Marion69768d92023-11-13 17:33:32 +00001/* SPDX-License-Identifier: Apache-2.0
2 * Copyright (c) 2023 Cisco Systems, Inc.
3 */
4
5#include "vppinfra/pool.h"
6#include <vnet/vnet.h>
7#include <vnet/dev/dev.h>
8#include <vnet/dev/counters.h>
9#include <vnet/dev/log.h>
10#include <vnet/dev/types.h>
11#include <vppinfra/format_table.h>
12
13VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
14 .class_name = "dev",
15 .subclass_name = "args",
16};
17
18void
19vnet_dev_arg_clear_value (vnet_dev_arg_t *a)
20{
21 if (a->type == VNET_DEV_ARG_TYPE_STRING)
22 vec_free (a->val.string);
23 a->val = (typeof (a->val)){};
24 a->val_set = 0;
25}
26
27void
28vnet_dev_arg_free (vnet_dev_arg_t **vp)
29{
30 vnet_dev_arg_t *v;
31 vec_foreach (v, *vp)
32 vnet_dev_arg_clear_value (v);
33 vec_free (*vp);
34}
35
36vnet_dev_rv_t
37vnet_dev_arg_parse (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_arg_t *args,
38 u8 *str)
39{
40 vnet_dev_rv_t rv = VNET_DEV_OK;
41 unformat_input_t in;
42 u8 *name = 0;
43 u8 *err = 0;
44
45 log_debug (dev, "input '%v'", str);
46 if (args == 0)
47 return rv;
48
49 unformat_init_string (&in, (char *) str, vec_len (str));
50
51 while (unformat (&in, "%U=", unformat_token, "a-zA-Z0-9_", &name))
52 {
53 vnet_dev_arg_t *a = args;
54 vec_add1 (name, 0);
55 while (a < vec_end (args))
56 if (strcmp (a->name, (char *) name) == 0)
57 break;
58 else
59 a++;
60
61 if (a->type == VNET_DEV_ARG_TYPE_BOOL)
62 {
63
64 if (unformat (&in, "true") || unformat (&in, "1") ||
65 unformat (&in, "on") || unformat (&in, "yes"))
66 a->val.boolean = 1;
67 else if (unformat (&in, "false") || unformat (&in, "0") ||
68 unformat (&in, "off") || unformat (&in, "no"))
69 a->val.boolean = 0;
70 else
71 {
72 log_err (dev, "unable to parse args: %U", format_unformat_error,
73 &in);
74 err = format (
75 0,
76 "boolean value expected ('yes', 'no', '0', '1', 'on', "
77 "'off', 'true' or 'false') for argument '%s', found '%U'",
78 a->name, format_unformat_error, &in);
79 goto done;
80 }
81 }
82 else if (a->type == VNET_DEV_ARG_TYPE_UINT32)
83 {
84 u32 val, min = 0, max = CLIB_U32_MAX;
85 if (!unformat (&in, "%u", &val))
86 {
87 err = format (0,
88 "unsigned integer in range %u - %u expected for "
89 "argument '%s', found '%U'",
90 min, max, a->name, format_unformat_error, &in);
91 goto done;
92 }
93
94 if (a->min || a->max)
95 {
96 min = a->min;
97 max = a->max;
98 }
99
100 if (val < min || val > max)
101 {
102 err = format (0,
103 "unsigned integer in range %u - %u expected for "
104 "argument '%s', found '%u'",
105 min, max, a->name, val);
106 goto done;
107 }
108 a->val.uint32 = val;
109 }
110 else if (a->type == VNET_DEV_ARG_TYPE_STRING)
111 {
112 if (!unformat (&in, "%U", unformat_double_quoted_string,
113 &a->val.string))
114 {
115 err = format (
116 0,
117 "double quoted string expected for argument '%s', found '%U'",
118 a->name, format_unformat_error, &in);
119 goto done;
120 }
121
122 if (a->min && vec_len (a->val.string) < a->min)
123 {
124 err =
125 format (0, "string '%v' too short, must be at least %u chars",
126 a->val.string, a->min);
127 goto done;
128 }
129 if (a->max && vec_len (a->val.string) > a->max)
130 {
131 err = format (
132 0, "string '%v' too long, must be no longer than %u chars",
133 a->val.string, a->max);
134 goto done;
135 }
136 }
137 else
138 {
139 err = format (0, "unknown argument '%s'", name);
140 goto done;
141 }
142
143 a->val_set = 1;
144 log_debug (dev, "name '%s' type %U value %U", name,
145 format_vnet_dev_arg_type, a->type, format_vnet_dev_arg_value,
146 a->type, &a->val);
147 vec_free (name);
148 unformat (&in, ",");
149 }
150
151 if (unformat_check_input (&in) != UNFORMAT_END_OF_INPUT)
152 err = format (0, "unable to parse argument name '%U'",
153 format_unformat_error, &in);
154
155done:
156 if (err)
157 {
158 vnet_dev_arg_t *a = 0;
159 log_err (dev, "%v", err);
160 vec_free (err);
161 vec_foreach (a, args)
162 vnet_dev_arg_clear_value (a);
163 rv = VNET_DEV_ERR_INVALID_ARG;
164 }
165
166 vec_free (name);
167 unformat_free (&in);
168 return rv;
169}
170
171u8 *
172format_vnet_dev_arg_type (u8 *s, va_list *args)
173{
174 vnet_dev_arg_type_t t = va_arg (*args, u32);
175 switch (t)
176 {
177#define _(n, f, val) \
178 case VNET_DEV_ARG_TYPE_##n: \
179 return format (s, #n);
180 foreach_vnet_dev_arg_type
181#undef _
182 default : ASSERT (0);
183 break;
184 }
185 return s;
186}
187
188u8 *
189format_vnet_dev_arg_value (u8 *s, va_list *args)
190{
191 vnet_dev_arg_type_t t = va_arg (*args, u32);
192 vnet_dev_arg_value_t *v = va_arg (*args, vnet_dev_arg_value_t *);
193
194 switch (t)
195 {
196#define _(n, f, value) \
197 case VNET_DEV_ARG_TYPE_##n: \
198 s = format (s, f, v->value); \
199 break;
200 foreach_vnet_dev_arg_type
201#undef _
202 default : break;
203 }
204 return s;
205}
206
207u8 *
208format_vnet_dev_args (u8 *s, va_list *va)
209{
210 vnet_dev_arg_t *a, *args = va_arg (*va, vnet_dev_arg_t *);
211 table_t t = { .no_ansi = 1 };
212
213 table_add_header_col (&t, 4, "Name", "Value", "Default", "Description");
214 table_set_cell_align (&t, -1, 0, TTAA_LEFT);
215 table_set_cell_align (&t, -1, 3, TTAA_LEFT);
216 vec_foreach (a, args)
217 {
218 int r = a - args;
219 table_format_cell (&t, r, 0, "%s", a->name);
220 if (a->val_set)
221 table_format_cell (&t, r, 1, "%U", format_vnet_dev_arg_value, a->type,
222 &a->val);
223 else
224 table_format_cell (&t, r, 1, "<not set>");
225
226 table_format_cell (&t, r, 2, "%U", format_vnet_dev_arg_value, a->type,
227 &a->default_val);
228 table_format_cell (&t, r, 3, "%s", a->desc);
229 table_set_cell_align (&t, r, 0, TTAA_LEFT);
230 table_set_cell_align (&t, r, 3, TTAA_LEFT);
231 }
232
233 s = format (s, "%U", format_table, &t);
234
235 table_free (&t);
236 return s;
237}