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