blob: 944da0698ea867a74a727ed95668ad7ac5337e2a [file] [log] [blame]
Damjan Marion38c61912023-10-17 16:06:26 +00001/* SPDX-License-Identifier: Apache-2.0
2 * Copyright (c) 2023 Cisco Systems, Inc.
3 */
4
Damjan Marion38c61912023-10-17 16:06:26 +00005#include <vnet/vnet.h>
6#include <vnet/dev/dev.h>
7#include <vnet/dev/counters.h>
8#include <vnet/ethernet/ethernet.h>
9
10u8 *
11format_vnet_dev_rv (u8 *s, va_list *args)
12{
13 vnet_dev_rv_t rv = va_arg (*args, vnet_dev_rv_t);
14 u32 index = -rv;
15
16 char *strings[] = { [0] = "OK",
17#define _(n, d) [-VNET_DEV_ERR_##n] = d,
18 foreach_vnet_dev_rv_type
19#undef _
20 };
21
22 if (index >= ARRAY_LEN (strings))
23 return format (s, "unknown return value (%d)", rv);
24 return format (s, "%s", strings[index]);
25}
26
27u8 *
28format_vnet_dev_addr (u8 *s, va_list *args)
29{
30 vnet_dev_main_t *dm = &vnet_dev_main;
31 vnet_dev_t *dev = va_arg (*args, vnet_dev_t *);
32 vnet_dev_bus_t *bus;
33
34 if (dev == 0)
35 return 0;
36
37 bus = pool_elt_at_index (dm->buses, dev->bus_index);
38 s = format (s, "%U", bus->ops.format_device_addr, dev);
39
40 return s;
41}
42
43u8 *
44format_vnet_dev_interface_name (u8 *s, va_list *args)
45{
46 u32 i = va_arg (*args, u32);
47 vnet_dev_port_t *port = vnet_dev_get_port_from_dev_instance (i);
48
49 return format (s, "%s", port->intf.name);
50}
51
52u8 *
53format_vnet_dev_info (u8 *s, va_list *args)
54{
55 vnet_dev_format_args_t *a = va_arg (*args, vnet_dev_format_args_t *);
56 vlib_main_t *vm = vlib_get_main ();
57 vnet_dev_main_t *dm = &vnet_dev_main;
58 vnet_dev_t *dev = va_arg (*args, vnet_dev_t *);
59 vnet_dev_driver_t *dr = pool_elt_at_index (dm->drivers, dev->driver_index);
60 vnet_dev_bus_t *bus = pool_elt_at_index (dm->buses, dev->bus_index);
61
62 u32 indent = format_get_indent (s);
63 s = format (s, "Driver is '%s', bus is '%s'", dr->registration->name,
64 bus->registration->name);
65
66 if (dev->description)
67 s = format (s, ", description is '%v'", dev->description);
68
69 if (bus->ops.format_device_info)
70 s = format (s, "\n%U%U", format_white_space, indent,
71 bus->ops.format_device_info, a, dev);
72
73 s = format (s, "\n%UAssigned process node is '%U'", format_white_space,
74 indent, format_vlib_node_name, vm, dev->process_node_index);
Damjan Marion69768d92023-11-13 17:33:32 +000075 if (dev->args)
76 s = format (s, "\n%UDevice Specific Arguments:\n%U%U", format_white_space,
77 indent, format_white_space, indent + 2, format_vnet_dev_args,
78 dev->args);
Damjan Marion38c61912023-10-17 16:06:26 +000079 if (dev->ops.format_info)
Damjan Marion69768d92023-11-13 17:33:32 +000080 s =
81 format (s, "\n%UDevice Specific Info:\n%U%U", format_white_space, indent,
82 format_white_space, indent + 2, dev->ops.format_info, a, dev);
Damjan Marion38c61912023-10-17 16:06:26 +000083 return s;
84}
85
86u8 *
87format_vnet_dev_hw_addr (u8 *s, va_list *args)
88{
89 vnet_dev_hw_addr_t *addr = va_arg (*args, vnet_dev_hw_addr_t *);
90 return format (s, "%U", format_ethernet_address, addr->eth_mac);
91}
92
93u8 *
94format_vnet_dev_port_info (u8 *s, va_list *args)
95{
96 vnet_dev_format_args_t *a = va_arg (*args, vnet_dev_format_args_t *);
97 vlib_main_t *vm = vlib_get_main ();
98 vnet_main_t *vnm = vnet_get_main ();
99 vnet_dev_port_t *port = va_arg (*args, vnet_dev_port_t *);
100
101 u32 indent = format_get_indent (s);
102
103 s = format (s, "Hardware Address is %U", format_vnet_dev_hw_addr,
104 &port->attr.hw_addr);
105 s = format (s, ", %u RX queues (max %u), %u TX queues (max %u)",
106 pool_elts (port->rx_queues), port->attr.max_rx_queues,
107 pool_elts (port->tx_queues), port->attr.max_tx_queues);
108 if (pool_elts (port->secondary_hw_addr))
109 {
110 u32 i = 0;
111 vnet_dev_hw_addr_t *a;
112 s = format (s, "\n%USecondary Hardware Address%s:", format_white_space,
113 indent,
114 pool_elts (port->secondary_hw_addr) > 1 ? "es are" : " is");
115 pool_foreach (a, port->secondary_hw_addr)
116 {
117 if (i++ % 6 == 0)
118 s = format (s, "\n%U", format_white_space, indent + 1);
119 s = format (s, " %U", format_vnet_dev_hw_addr, a);
120 }
121 }
Damjan Marione596ca12023-11-08 19:12:27 +0000122 s = format (s, "\n%UMax RX frame size is %u (max supported %u)",
123 format_white_space, indent, port->max_rx_frame_size,
124 port->attr.max_supported_rx_frame_size);
Damjan Marion38c61912023-10-17 16:06:26 +0000125 if (port->port_ops.format_status)
Damjan Marion69768d92023-11-13 17:33:32 +0000126 s = format (s, "\n%UDevice Specific Port Status:\n%U%U",
127 format_white_space, indent, format_white_space, indent + 2,
Damjan Marion38c61912023-10-17 16:06:26 +0000128 port->port_ops.format_status, a, port);
Damjan Marion69768d92023-11-13 17:33:32 +0000129 if (port->args)
130 s = format (s, "\n%UDevice Specific Port Arguments:\n%U%U",
131 format_white_space, indent, format_white_space, indent + 2,
132 format_vnet_dev_args, port->args);
Damjan Marion38c61912023-10-17 16:06:26 +0000133
134 s = format (s, "\n%UInterface ", format_white_space, indent);
135 if (port->interface_created)
136 {
137 s = format (s, "assigned, interface name is '%U', RX node is '%U'",
138 format_vnet_sw_if_index_name, vnm, port->intf.sw_if_index,
139 format_vlib_node_name, vm, port->intf.rx_node_index);
140 }
141 else
142 s = format (s, "not assigned");
143 return s;
144}
145
146u8 *
147format_vnet_dev_rx_queue_info (u8 *s, va_list *args)
148{
149 vnet_dev_format_args_t __clib_unused *a =
150 va_arg (*args, vnet_dev_format_args_t *);
151 vnet_dev_rx_queue_t *rxq = va_arg (*args, vnet_dev_rx_queue_t *);
152 u32 indent = format_get_indent (s);
153
154 s = format (s, "Size is %u, buffer pool index is %u", rxq->size,
155 vnet_dev_get_rx_queue_buffer_pool_index (rxq));
Damjan Marionb8dd9812023-11-03 13:47:05 +0000156 s = format (s, "\n%UPolling thread is %u, %sabled, %sstarted, %s mode",
Damjan Marion38c61912023-10-17 16:06:26 +0000157 format_white_space, indent, rxq->rx_thread_index,
Damjan Marionb8dd9812023-11-03 13:47:05 +0000158 rxq->enabled ? "en" : "dis", rxq->started ? "" : "not-",
159 rxq->interrupt_mode ? "interrupt" : "polling");
Damjan Marion38c61912023-10-17 16:06:26 +0000160
161 return s;
162}
163
164u8 *
165format_vnet_dev_tx_queue_info (u8 *s, va_list *args)
166{
167 vnet_dev_format_args_t __clib_unused *a =
168 va_arg (*args, vnet_dev_format_args_t *);
169 vnet_dev_tx_queue_t *txq = va_arg (*args, vnet_dev_tx_queue_t *);
170 u32 indent = format_get_indent (s);
171 u32 n;
172
173 s = format (s, "Size is %u", txq->size);
174 s = format (s, "\n%U", format_white_space, indent);
175 n = clib_bitmap_count_set_bits (txq->assigned_threads);
176 if (n == 0)
177 s = format (s, "Not used by any thread");
178 else
179 s = format (s, "Used by thread%s %U", n > 1 ? "s" : "", format_bitmap_list,
180 txq->assigned_threads);
181
182 return s;
183}
184
185u8 *
186format_vnet_dev_interface_info (u8 *s, va_list *args)
187{
188 u32 i = va_arg (*args, u32);
189 vnet_dev_format_args_t fa = {}, *a = &fa;
190 vnet_dev_port_t *port = vnet_dev_get_port_from_dev_instance (i);
191 vnet_dev_t *dev = port->dev;
192 u32 indent = format_get_indent (s);
193
194 s = format (s, "Device:");
195 s = format (s, "\n%U%U", format_white_space, indent + 2,
196 format_vnet_dev_info, a, dev);
197
198 s = format (s, "\n%UPort %u:", format_white_space, indent, port->port_id);
199 s = format (s, "\n%U%U", format_white_space, indent + 2,
200 format_vnet_dev_port_info, a, port);
201
202 foreach_vnet_dev_port_rx_queue (q, port)
203 {
204 s = format (s, "\n%URX queue %u:", format_white_space, indent + 2,
205 q->queue_id);
206 s = format (s, "\n%U%U", format_white_space, indent + 4,
207 format_vnet_dev_rx_queue_info, a, q);
208 }
209
210 foreach_vnet_dev_port_tx_queue (q, port)
211 {
212 s = format (s, "\n%UTX queue %u:", format_white_space, indent + 2,
213 q->queue_id);
214 s = format (s, "\n%U%U", format_white_space, indent + 4,
215 format_vnet_dev_tx_queue_info, a, q);
216 }
217 return s;
218}
219
220static u64
221unformat_flags (unformat_input_t *input, char *names[], u64 val[], u32 n_flags)
222{
223 u64 rv = 0;
224 uword c = 0;
225 u8 *s = 0;
226
227 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
228 {
229 switch (c)
230 {
231 case 'a' ... 'z':
232 c -= 'a' - 'A';
233 case '0' ... '9':
234 case 'A' ... 'Z':
235 vec_add1 (s, c);
236 break;
237 case '-':
238 vec_add1 (s, '_');
239 break;
240 case ',':
241 vec_add1 (s, 0);
242 break;
243 default:
244 goto end_of_string;
245 }
246 }
247end_of_string:
248
249 if (s == 0)
250 return 0;
251
252 vec_add1 (s, 0);
253
254 for (u8 *p = s, *end = vec_end (s); p < end; p += strlen ((char *) p) + 1)
255 {
256 for (c = 0; c < n_flags; c++)
257 if (strcmp (names[c], (char *) p) == 0)
258 {
259 rv |= val[c];
260 break;
261 }
262 if (c == n_flags)
263 goto done;
264 }
265
266done:
267 vec_free (s);
268 return rv;
269}
270
271uword
272unformat_vnet_dev_flags (unformat_input_t *input, va_list *args)
273{
274 vnet_dev_flags_t *fp = va_arg (*args, vnet_dev_flags_t *);
275 u64 val;
276
277 char *names[] = {
278#define _(b, n, d) #n,
279 foreach_vnet_dev_flag
280#undef _
281 };
282 u64 vals[] = {
283#define _(b, n, d) 1ull << (b)
284 foreach_vnet_dev_flag
285#undef _
286 };
287
288 val = unformat_flags (input, names, vals, ARRAY_LEN (names));
289
290 if (!val)
291 return 0;
292
293 fp->n = val;
294 return 1;
295}
296
297uword
298unformat_vnet_dev_port_flags (unformat_input_t *input, va_list *args)
299{
300 vnet_dev_port_flags_t *fp = va_arg (*args, vnet_dev_port_flags_t *);
301 u64 val;
302
303 char *flag_names[] = {
304#define _(b, n, d) #n,
305 foreach_vnet_dev_port_flag
306#undef _
307 };
308 u64 flag_values[] = {
309#define _(b, n, d) 1ull << (b)
310 foreach_vnet_dev_port_flag
311#undef _
312 };
313
314 val =
315 unformat_flags (input, flag_names, flag_values, ARRAY_LEN (flag_names));
316
317 if (!val)
318 return 0;
319
320 fp->n = val;
321 return 1;
322}
323
324static u8 *
325format_flags (u8 *s, u64 val, char *flag_names[], u64 flag_values[],
326 u32 n_flags)
327{
328 u32 n = 0;
329 for (int i = 0; i < n_flags; i++)
330 {
331 if ((val & flag_values[i]) == 0)
332 continue;
333
334 if (n++)
335 vec_add1 (s, ' ');
336
337 for (char *c = flag_names[i]; c[0] != 0; c++)
338 {
339 switch (c[0])
340 {
341 case 'A' ... 'Z':
342 vec_add1 (s, c[0] + 'a' - 'A');
343 break;
344 case '_':
345 vec_add1 (s, '-');
346 break;
347 default:
348 vec_add1 (s, c[0]);
349 }
350 }
351 }
352
353 return s;
354}
355
356u8 *
357format_vnet_dev_flags (u8 *s, va_list *args)
358{
359 vnet_dev_flags_t *fp = va_arg (*args, vnet_dev_flags_t *);
360 char *flag_names[] = {
361#define _(b, n, d) #n,
362 foreach_vnet_dev_flag
363#undef _
364 };
365 u64 flag_values[] = {
366#define _(b, n, d) 1ull << (b)
367 foreach_vnet_dev_flag
368#undef _
369 };
370
371 return format_flags (s, fp->n, flag_names, flag_values,
372 ARRAY_LEN (flag_names));
373}
374
375u8 *
376format_vnet_dev_port_flags (u8 *s, va_list *args)
377{
378 vnet_dev_port_flags_t *fp = va_arg (*args, vnet_dev_port_flags_t *);
379 char *flag_names[] = {
380#define _(b, n, d) #n,
381 foreach_vnet_dev_port_flag
382#undef _
383 };
384 u64 flag_values[] = {
385#define _(b, n, d) 1ull << (b)
386 foreach_vnet_dev_port_flag
387#undef _
388 };
389
390 return format_flags (s, fp->n, flag_names, flag_values,
391 ARRAY_LEN (flag_names));
392}
393
394u8 *
395format_vnet_dev_log (u8 *s, va_list *args)
396{
397 vnet_dev_t *dev = va_arg (*args, vnet_dev_t *);
398 char *func = va_arg (*args, char *);
399
400 if (dev)
401 s = format (s, "%U", format_vnet_dev_addr, dev);
402 if (dev && func)
403 vec_add1 (s, ' ');
404 if (func)
Damjan Marion6bd6c802023-11-02 18:40:32 +0000405 s = format (s, "%s", func);
Damjan Marion38c61912023-10-17 16:06:26 +0000406 vec_add1 (s, ':');
407 vec_add1 (s, ' ');
408 return s;
409}