vmxnet3: error handling
[vpp.git] / src / plugins / vmxnet3 / cli.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2018 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17 #include <stdint.h>
18 #include <net/if.h>
19 #include <sys/ioctl.h>
20 #include <inttypes.h>
21
22 #include <vlib/vlib.h>
23 #include <vlib/unix/unix.h>
24 #include <vlib/pci/pci.h>
25 #include <vnet/ethernet/ethernet.h>
26
27 #include <vmxnet3/vmxnet3.h>
28
29 static clib_error_t *
30 vmxnet3_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
31                            vlib_cli_command_t * cmd)
32 {
33   unformat_input_t _line_input, *line_input = &_line_input;
34   vmxnet3_create_if_args_t args;
35   u32 tmp;
36
37   /* Get a line of input. */
38   if (!unformat_user (input, unformat_line_input, line_input))
39     return 0;
40
41   memset (&args, 0, sizeof (args));
42   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
43     {
44       if (unformat (line_input, "%U", unformat_vlib_pci_addr, &args.addr))
45         ;
46       else if (unformat (line_input, "elog"))
47         args.enable_elog = 1;
48       else if (unformat (line_input, "rx-queue-size %u", &tmp))
49         args.rxq_size = tmp;
50       else if (unformat (line_input, "tx-queue-size %u", &tmp))
51         args.txq_size = tmp;
52       else
53         return clib_error_return (0, "unknown input `%U'",
54                                   format_unformat_error, input);
55     }
56   unformat_free (line_input);
57
58
59   vmxnet3_create_if (vm, &args);
60
61   return args.error;
62 }
63
64 /* *INDENT-OFF* */
65 VLIB_CLI_COMMAND (vmxnet3_create_command, static) = {
66   .path = "create interface vmxnet3",
67   .short_help = "create interface vmxnet3 <pci-address>"
68                 "[rx-queue-size <size>] [tx-queue-size <size>]",
69   .function = vmxnet3_create_command_fn,
70 };
71 /* *INDENT-ON* */
72
73 static clib_error_t *
74 vmxnet3_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
75                            vlib_cli_command_t * cmd)
76 {
77   unformat_input_t _line_input, *line_input = &_line_input;
78   u32 sw_if_index = ~0;
79   vnet_hw_interface_t *hw;
80   vmxnet3_main_t *vmxm = &vmxnet3_main;
81   vmxnet3_device_t *vd;
82   vnet_main_t *vnm = vnet_get_main ();
83
84   /* Get a line of input. */
85   if (!unformat_user (input, unformat_line_input, line_input))
86     return 0;
87
88   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
89     {
90       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
91         ;
92       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
93                          vnm, &sw_if_index))
94         ;
95       else
96         return clib_error_return (0, "unknown input `%U'",
97                                   format_unformat_error, input);
98     }
99   unformat_free (line_input);
100
101   if (sw_if_index == ~0)
102     return clib_error_return (0,
103                               "please specify interface name or sw_if_index");
104
105   hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
106   if (hw == NULL || vmxnet3_device_class.index != hw->dev_class_index)
107     return clib_error_return (0, "not a vmxnet3 interface");
108
109   vd = pool_elt_at_index (vmxm->devices, hw->dev_instance);
110
111   vmxnet3_delete_if (vm, vd);
112
113   return 0;
114 }
115
116 /* *INDENT-OFF* */
117 VLIB_CLI_COMMAND (vmxnet3_delete_command, static) = {
118   .path = "delete interface vmxnet3",
119   .short_help = "delete interface vmxnet3 "
120     "{<interface> | sw_if_index <sw_idx>}",
121   .function = vmxnet3_delete_command_fn,
122 };
123 /* *INDENT-ON* */
124
125 static clib_error_t *
126 vmxnet3_test_command_fn (vlib_main_t * vm, unformat_input_t * input,
127                          vlib_cli_command_t * cmd)
128 {
129   unformat_input_t _line_input, *line_input = &_line_input;
130   u32 sw_if_index = ~0;
131   vnet_hw_interface_t *hw;
132   vmxnet3_main_t *vmxm = &vmxnet3_main;
133   vmxnet3_device_t *vd;
134   vnet_main_t *vnm = vnet_get_main ();
135   int enable_elog = 0, disable_elog = 0;
136
137   /* Get a line of input. */
138   if (!unformat_user (input, unformat_line_input, line_input))
139     return 0;
140
141   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
142     {
143       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
144         ;
145       else if (unformat (line_input, "elog-on"))
146         enable_elog = 1;
147       else if (unformat (line_input, "elog-off"))
148         disable_elog = 1;
149       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
150                          vnm, &sw_if_index))
151         ;
152       else
153         return clib_error_return (0, "unknown input `%U'",
154                                   format_unformat_error, input);
155     }
156   unformat_free (line_input);
157
158   if (sw_if_index == ~0)
159     return clib_error_return (0,
160                               "please specify interface name or sw_if_index");
161
162   hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
163   if (hw == NULL || vmxnet3_device_class.index != hw->dev_class_index)
164     return clib_error_return (0, "not a vmxnet3 interface");
165
166   vd = pool_elt_at_index (vmxm->devices, hw->dev_instance);
167
168   if (enable_elog)
169     vd->flags |= VMXNET3_DEVICE_F_ELOG;
170
171   if (disable_elog)
172     vd->flags &= ~VMXNET3_DEVICE_F_ELOG;
173
174   return 0;
175 }
176
177 /* *INDENT-OFF* */
178 VLIB_CLI_COMMAND (vmxnet3_test_command, static) = {
179   .path = "test vmxnet3",
180   .short_help = "test vmxnet3 <interface> | sw_if_index <sw_idx> [irq] "
181     "[elog-on] [elog-off]",
182   .function = vmxnet3_test_command_fn,
183 };
184 /* *INDENT-ON* */
185
186 static void
187 show_vmxnet3 (vlib_main_t * vm, u32 * hw_if_indices, u8 show_descr)
188 {
189   u32 i, desc_idx;
190   vmxnet3_device_t *vd;
191   vnet_main_t *vnm = &vnet_main;
192   vmxnet3_main_t *vmxm = &vmxnet3_main;
193   vnet_hw_interface_t *hi;
194   vmxnet3_rxq_t *rxq;
195   vmxnet3_rx_desc *rxd;
196   vmxnet3_rx_comp *rx_comp;
197   vmxnet3_txq_t *txq;
198   vmxnet3_tx_desc *txd;
199   vmxnet3_tx_comp *tx_comp;
200   u16 qid;
201
202   if (!hw_if_indices)
203     return;
204
205   for (i = 0; i < vec_len (hw_if_indices); i++)
206     {
207       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
208       vd = vec_elt_at_index (vmxm->devices, hi->dev_instance);
209       vlib_cli_output (vm, "Interface: %U (ifindex %d)",
210                        format_vnet_hw_if_index_name, vnm, hw_if_indices[i],
211                        hw_if_indices[i]);
212       vlib_cli_output (vm, "  Version: %u", vd->version);
213       vlib_cli_output (vm, "  PCI Address: %U", format_vlib_pci_addr,
214                        &vd->pci_addr);
215       vlib_cli_output (vm, "  Mac Address: %U", format_ethernet_address,
216                        vd->mac_addr);
217       vlib_cli_output (vm, "  hw if index: %u", vd->hw_if_index);
218       vlib_cli_output (vm, "  Device instance: %u", vd->dev_instance);
219       vlib_cli_output (vm, "  Number of interrupts: %u", vd->num_intrs);
220
221       vec_foreach_index (qid, vd->rxqs)
222       {
223         rxq = vec_elt_at_index (vd->rxqs, qid);
224         u16 rid;
225
226         vlib_cli_output (vm, "  Queue %u (RX)", qid);
227         vlib_cli_output (vm, "    RX completion next index %u",
228                          rxq->rx_comp_ring.next);
229         vlib_cli_output (vm, "    RX completion generation flag 0x%x",
230                          rxq->rx_comp_ring.gen);
231         for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
232           {
233             vmxnet3_rx_ring *ring = &rxq->rx_ring[rid];
234
235             vlib_cli_output (vm,
236                              "    ring %u size %u fill %u "
237                              "consume %u produce %u", rid,
238                              rxq->size, ring->fill, ring->consume,
239                              ring->produce);
240             if (show_descr)
241               {
242                 vlib_cli_output (vm, "RX descriptors table");
243                 vlib_cli_output (vm, "  %5s  %18s  %10s",
244                                  "slot", "address", "flags");
245                 for (desc_idx = 0; desc_idx < rxq->size; desc_idx++)
246                   {
247                     rxd = &rxq->rx_desc[rid][desc_idx];
248                     vlib_cli_output (vm, "  %5u  0x%016llx  0x%08x",
249                                      desc_idx, rxd->address, rxd->flags);
250                   }
251                 vlib_cli_output (vm, "RX completion descriptors table");
252                 vlib_cli_output (vm, "  %5s  %10s  %10s  %10s  %10s",
253                                  "slot", "index", "rss", "len", "flags");
254                 for (desc_idx = 0; desc_idx < rxq->size; desc_idx++)
255                   {
256                     rx_comp = &rxq->rx_comp[desc_idx];
257                     vlib_cli_output (vm, "  %5u  0x%08x  %10u  %10u  0x%08x",
258                                      desc_idx, rx_comp->index, rx_comp->rss,
259                                      rx_comp->len, rx_comp->flags);
260                   }
261               }
262           }
263       }
264
265       vec_foreach_index (qid, vd->rxqs)
266       {
267         txq = vec_elt_at_index (vd->txqs, 0);
268         vlib_cli_output (vm, "  Queue %u (TX)", qid);
269         vlib_cli_output (vm, "    TX completion next index %u",
270                          txq->tx_comp_ring.next);
271         vlib_cli_output (vm, "    TX completion generation flag 0x%x",
272                          txq->tx_comp_ring.gen);
273         vlib_cli_output (vm, "    size %u consume %u produce %u",
274                          txq->size, txq->tx_ring.consume,
275                          txq->tx_ring.produce);
276         if (show_descr)
277           {
278             vlib_cli_output (vm, "TX descriptors table");
279             vlib_cli_output (vm, "  %5s  %18s  %10s  %10s",
280                              "slot", "address", "flags0", "flags1");
281             for (desc_idx = 0; desc_idx < txq->size; desc_idx++)
282               {
283                 txd = &txq->tx_desc[desc_idx];
284                 vlib_cli_output (vm, "  %5u  0x%016llx  0x%08x  0x%08x",
285                                  desc_idx, txd->address, txd->flags[0],
286                                  txd->flags[1]);
287               }
288             vlib_cli_output (vm, "TX completion descriptors table");
289             vlib_cli_output (vm, "  %5s  %10s  %10s",
290                              "slot", "index", "flags");
291             for (desc_idx = 0; desc_idx < txq->size; desc_idx++)
292               {
293                 tx_comp = &txq->tx_comp[desc_idx];
294                 vlib_cli_output (vm, "  %5u  0x%08x  0x%08x",
295                                  desc_idx, tx_comp->index, tx_comp->flags);
296               }
297           }
298       }
299     }
300 }
301
302 static clib_error_t *
303 show_vmxnet3_fn (vlib_main_t * vm, unformat_input_t * input,
304                  vlib_cli_command_t * cmd)
305 {
306   vmxnet3_main_t *vmxm = &vmxnet3_main;
307   vnet_main_t *vnm = &vnet_main;
308   vmxnet3_device_t *vd;
309   clib_error_t *error = 0;
310   u32 hw_if_index, *hw_if_indices = 0;
311   vnet_hw_interface_t *hi;
312   u8 show_descr = 0;
313
314   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
315     {
316       if (unformat
317           (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
318         {
319           hi = vnet_get_hw_interface (vnm, hw_if_index);
320           if (vmxnet3_device_class.index != hi->dev_class_index)
321             {
322               error = clib_error_return (0, "unknown input `%U'",
323                                          format_unformat_error, input);
324               goto done;
325             }
326           vec_add1 (hw_if_indices, hw_if_index);
327         }
328       else if (unformat (input, "descriptors") || unformat (input, "desc"))
329         show_descr = 1;
330       else
331         {
332           error = clib_error_return (0, "unknown input `%U'",
333                                      format_unformat_error, input);
334           goto done;
335         }
336     }
337
338   if (vec_len (hw_if_indices) == 0)
339     {
340       pool_foreach (vd, vmxm->devices,
341                     vec_add1 (hw_if_indices, vd->hw_if_index);
342         );
343     }
344
345   show_vmxnet3 (vm, hw_if_indices, show_descr);
346
347 done:
348   vec_free (hw_if_indices);
349   return error;
350 }
351
352 /* *INDENT-OFF* */
353 VLIB_CLI_COMMAND (show_vmxnet3_command, static) = {
354   .path = "show vmxnet3",
355   .short_help = "show vmxnet3 [<interface>]",
356   .function = show_vmxnet3_fn,
357 };
358 /* *INDENT-ON* */
359
360 clib_error_t *
361 vmxnet3_cli_init (vlib_main_t * vm)
362 {
363   /* initialize binary API */
364   vmxnet3_plugin_api_hookup (vm);
365
366   return 0;
367 }
368
369 VLIB_INIT_FUNCTION (vmxnet3_cli_init);
370
371 /*
372  * fd.io coding-style-patch-verification: ON
373  *
374  * Local Variables:
375  * eval: (c-set-style "gnu")
376  * End:
377  */