vmxnet3: Add hardware link status 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         for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
230           {
231             vmxnet3_rx_ring *ring = &rxq->rx_ring[rid];
232
233             vlib_cli_output (vm,
234                              "    ring %u size %u fill %u "
235                              "consume %u produce %u", rid,
236                              rxq->size, ring->fill, ring->consume,
237                              ring->produce);
238             if (show_descr)
239               {
240                 vlib_cli_output (vm, "RX descriptors table");
241                 vlib_cli_output (vm, "  %5s  %18s  %10s",
242                                  "slot", "address", "flags");
243                 for (desc_idx = 0; desc_idx < rxq->size; desc_idx++)
244                   {
245                     rxd = &rxq->rx_desc[rid][desc_idx];
246                     vlib_cli_output (vm, "  %5u  0x%016llx  0x%08x",
247                                      desc_idx, rxd->address, rxd->flags);
248                   }
249                 vlib_cli_output (vm, "RX completion descriptors table");
250                 vlib_cli_output (vm, "  %5s  %10s  %10s  %10s  %10s",
251                                  "slot", "index", "rss", "len", "flags");
252                 for (desc_idx = 0; desc_idx < rxq->size; desc_idx++)
253                   {
254                     rx_comp = &rxq->rx_comp[desc_idx];
255                     vlib_cli_output (vm, "  %5u  0x%08x  %10u  %10u  0x%08x",
256                                      desc_idx, rx_comp->index, rx_comp->rss,
257                                      rx_comp->len, rx_comp->flags);
258                   }
259               }
260           }
261       }
262
263       vec_foreach_index (qid, vd->rxqs)
264       {
265         txq = vec_elt_at_index (vd->txqs, 0);
266         vlib_cli_output (vm, "  Queue %u (TX)", qid);
267         vlib_cli_output (vm, "    TX completion next index %u",
268                          txq->tx_comp_ring.next);
269         vlib_cli_output (vm, "    size %u consume %u produce %u",
270                          txq->size, txq->tx_ring.consume,
271                          txq->tx_ring.produce);
272         if (show_descr)
273           {
274             vlib_cli_output (vm, "TX descriptors table");
275             vlib_cli_output (vm, "  %5s  %18s  %10s  %10s",
276                              "slot", "address", "flags0", "flags1");
277             for (desc_idx = 0; desc_idx < txq->size; desc_idx++)
278               {
279                 txd = &txq->tx_desc[desc_idx];
280                 vlib_cli_output (vm, "  %5u  0x%016llx  0x%08x  0x%08x",
281                                  desc_idx, txd->address, txd->flags[0],
282                                  txd->flags[1]);
283               }
284             vlib_cli_output (vm, "TX completion descriptors table");
285             vlib_cli_output (vm, "  %5s  %10s  %10s",
286                              "slot", "index", "flags");
287             for (desc_idx = 0; desc_idx < txq->size; desc_idx++)
288               {
289                 tx_comp = &txq->tx_comp[desc_idx];
290                 vlib_cli_output (vm, "  %5u  0x%08x  0x%08x",
291                                  desc_idx, tx_comp->index, tx_comp->flags);
292               }
293           }
294       }
295     }
296 }
297
298 static clib_error_t *
299 show_vmxnet3_fn (vlib_main_t * vm, unformat_input_t * input,
300                  vlib_cli_command_t * cmd)
301 {
302   vmxnet3_main_t *vmxm = &vmxnet3_main;
303   vnet_main_t *vnm = &vnet_main;
304   vmxnet3_device_t *vd;
305   clib_error_t *error = 0;
306   u32 hw_if_index, *hw_if_indices = 0;
307   vnet_hw_interface_t *hi;
308   u8 show_descr = 0;
309
310   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
311     {
312       if (unformat
313           (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
314         {
315           hi = vnet_get_hw_interface (vnm, hw_if_index);
316           if (vmxnet3_device_class.index != hi->dev_class_index)
317             {
318               error = clib_error_return (0, "unknown input `%U'",
319                                          format_unformat_error, input);
320               goto done;
321             }
322           vec_add1 (hw_if_indices, hw_if_index);
323         }
324       else if (unformat (input, "descriptors") || unformat (input, "desc"))
325         show_descr = 1;
326       else
327         {
328           error = clib_error_return (0, "unknown input `%U'",
329                                      format_unformat_error, input);
330           goto done;
331         }
332     }
333
334   if (vec_len (hw_if_indices) == 0)
335     {
336       pool_foreach (vd, vmxm->devices,
337                     vec_add1 (hw_if_indices, vd->hw_if_index);
338         );
339     }
340
341   show_vmxnet3 (vm, hw_if_indices, show_descr);
342
343 done:
344   vec_free (hw_if_indices);
345   return error;
346 }
347
348 /* *INDENT-OFF* */
349 VLIB_CLI_COMMAND (show_vmxnet3_command, static) = {
350   .path = "show vmxnet3",
351   .short_help = "show vmxnet3 [<interface>]",
352   .function = show_vmxnet3_fn,
353 };
354 /* *INDENT-ON* */
355
356 clib_error_t *
357 vmxnet3_cli_init (vlib_main_t * vm)
358 {
359   /* initialize binary API */
360   vmxnet3_plugin_api_hookup (vm);
361
362   return 0;
363 }
364
365 VLIB_INIT_FUNCTION (vmxnet3_cli_init);
366
367 /*
368  * fd.io coding-style-patch-verification: ON
369  *
370  * Local Variables:
371  * eval: (c-set-style "gnu")
372  * End:
373  */