574d86fe2200823db1f23f114903f4a99e499d31
[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 size;
36
37   /* Get a line of input. */
38   if (!unformat_user (input, unformat_line_input, line_input))
39     return 0;
40
41   clib_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, "gso"))
47         args.enable_gso = 1;
48       else if (unformat (line_input, "elog"))
49         args.enable_elog = 1;
50       else if (unformat (line_input, "bind"))
51         args.bind = 1;
52       else if (unformat (line_input, "rx-queue-size %u", &size))
53         args.rxq_size = size;
54       else if (unformat (line_input, "tx-queue-size %u", &size))
55         args.txq_size = size;
56       else if (unformat (line_input, "num-tx-queues %u", &size))
57         args.txq_num = size;
58       else if (unformat (line_input, "num-rx-queues %u", &size))
59         args.rxq_num = size;
60       else
61         return clib_error_return (0, "unknown input `%U'",
62                                   format_unformat_error, input);
63     }
64   unformat_free (line_input);
65
66
67   vmxnet3_create_if (vm, &args);
68   if (args.error == 0)
69     vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
70                      vnet_get_main (), args.sw_if_index);
71
72   return args.error;
73 }
74
75 /* *INDENT-OFF* */
76 VLIB_CLI_COMMAND (vmxnet3_create_command, static) = {
77   .path = "create interface vmxnet3",
78   .short_help = "create interface vmxnet3 <pci-address>"
79                 " [rx-queue-size <size>] [tx-queue-size <size>]"
80                 " [num-tx-queues <number>] [num-rx-queues <number>] [bind]"
81                 " [gso]",
82   .function = vmxnet3_create_command_fn,
83 };
84 /* *INDENT-ON* */
85
86 static clib_error_t *
87 vmxnet3_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
88                            vlib_cli_command_t * cmd)
89 {
90   unformat_input_t _line_input, *line_input = &_line_input;
91   u32 sw_if_index = ~0;
92   vnet_hw_interface_t *hw;
93   vmxnet3_main_t *vmxm = &vmxnet3_main;
94   vmxnet3_device_t *vd;
95   vnet_main_t *vnm = vnet_get_main ();
96
97   /* Get a line of input. */
98   if (!unformat_user (input, unformat_line_input, line_input))
99     return 0;
100
101   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
102     {
103       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
104         ;
105       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
106                          vnm, &sw_if_index))
107         ;
108       else
109         return clib_error_return (0, "unknown input `%U'",
110                                   format_unformat_error, input);
111     }
112   unformat_free (line_input);
113
114   if (sw_if_index == ~0)
115     return clib_error_return (0,
116                               "please specify interface name or sw_if_index");
117
118   hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
119   if (hw == NULL || vmxnet3_device_class.index != hw->dev_class_index)
120     return clib_error_return (0, "not a vmxnet3 interface");
121
122   vd = pool_elt_at_index (vmxm->devices, hw->dev_instance);
123
124   vmxnet3_delete_if (vm, vd);
125
126   return 0;
127 }
128
129 /* *INDENT-OFF* */
130 VLIB_CLI_COMMAND (vmxnet3_delete_command, static) = {
131   .path = "delete interface vmxnet3",
132   .short_help = "delete interface vmxnet3 "
133     "{<interface> | sw_if_index <sw_idx>}",
134   .function = vmxnet3_delete_command_fn,
135 };
136 /* *INDENT-ON* */
137
138 static clib_error_t *
139 vmxnet3_test_command_fn (vlib_main_t * vm, unformat_input_t * input,
140                          vlib_cli_command_t * cmd)
141 {
142   unformat_input_t _line_input, *line_input = &_line_input;
143   u32 sw_if_index = ~0;
144   vnet_hw_interface_t *hw;
145   vmxnet3_main_t *vmxm = &vmxnet3_main;
146   vmxnet3_device_t *vd;
147   vnet_main_t *vnm = vnet_get_main ();
148   int enable_elog = 0, disable_elog = 0;
149
150   /* Get a line of input. */
151   if (!unformat_user (input, unformat_line_input, line_input))
152     return 0;
153
154   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
155     {
156       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
157         ;
158       else if (unformat (line_input, "elog-on"))
159         enable_elog = 1;
160       else if (unformat (line_input, "elog-off"))
161         disable_elog = 1;
162       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
163                          vnm, &sw_if_index))
164         ;
165       else
166         return clib_error_return (0, "unknown input `%U'",
167                                   format_unformat_error, input);
168     }
169   unformat_free (line_input);
170
171   if (sw_if_index == ~0)
172     return clib_error_return (0,
173                               "please specify interface name or sw_if_index");
174
175   hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
176   if (hw == NULL || vmxnet3_device_class.index != hw->dev_class_index)
177     return clib_error_return (0, "not a vmxnet3 interface");
178
179   vd = pool_elt_at_index (vmxm->devices, hw->dev_instance);
180
181   if (enable_elog)
182     vd->flags |= VMXNET3_DEVICE_F_ELOG;
183
184   if (disable_elog)
185     vd->flags &= ~VMXNET3_DEVICE_F_ELOG;
186
187   return 0;
188 }
189
190 /* *INDENT-OFF* */
191 VLIB_CLI_COMMAND (vmxnet3_test_command, static) = {
192   .path = "test vmxnet3",
193   .short_help = "test vmxnet3 <interface> | sw_if_index <sw_idx> [irq] "
194     "[elog-on] [elog-off]",
195   .function = vmxnet3_test_command_fn,
196 };
197 /* *INDENT-ON* */
198
199 static void
200 show_vmxnet3 (vlib_main_t * vm, u32 * hw_if_indices, u8 show_descr,
201               u8 show_one_table, u32 which, u8 show_one_slot, u32 slot)
202 {
203   u32 i, desc_idx;
204   vmxnet3_device_t *vd;
205   vnet_main_t *vnm = &vnet_main;
206   vmxnet3_main_t *vmxm = &vmxnet3_main;
207   vnet_hw_interface_t *hi;
208   vmxnet3_rxq_t *rxq;
209   vmxnet3_rx_desc *rxd;
210   vmxnet3_rx_comp *rx_comp;
211   vmxnet3_txq_t *txq;
212   vmxnet3_tx_desc *txd;
213   vmxnet3_tx_comp *tx_comp;
214   u16 qid;
215
216   vlib_cli_output (vm, "Global:");
217   for (u32 tid = 0; tid <= vlib_num_workers (); tid++)
218     {
219       vmxnet3_per_thread_data_t *ptd =
220         vec_elt_at_index (vmxm->per_thread_data, tid);
221       vlib_cli_output (vm, "  Thread %u: polling queue count %u", tid,
222                        ptd->polling_q_count);
223     }
224
225   if (!hw_if_indices)
226     return;
227
228   for (i = 0; i < vec_len (hw_if_indices); i++)
229     {
230       hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
231       vd = vec_elt_at_index (vmxm->devices, hi->dev_instance);
232       vlib_cli_output (vm, "Interface: %U (ifindex %d)",
233                        format_vnet_hw_if_index_name, vnm, hw_if_indices[i],
234                        hw_if_indices[i]);
235       vlib_cli_output (vm, "  Version: %u", vd->version);
236       vlib_cli_output (vm, "  GSO enable: %u", vd->gso_enable);
237       vlib_cli_output (vm, "  PCI Address: %U", format_vlib_pci_addr,
238                        &vd->pci_addr);
239       vlib_cli_output (vm, "  Mac Address: %U", format_ethernet_address,
240                        vd->mac_addr);
241       vlib_cli_output (vm, "  hw if index: %u", vd->hw_if_index);
242       vlib_cli_output (vm, "  Device instance: %u", vd->dev_instance);
243       vlib_cli_output (vm, "  Number of interrupts: %u", vd->num_intrs);
244
245       vec_foreach_index (qid, vd->rxqs)
246       {
247         rxq = vec_elt_at_index (vd->rxqs, qid);
248         u16 rid;
249
250         vlib_cli_output (vm, "  Queue %u (RX)", qid);
251         vlib_cli_output (vm, "    RX completion next index %u",
252                          rxq->rx_comp_ring.next);
253         vlib_cli_output (vm, "    RX completion generation flag 0x%x",
254                          rxq->rx_comp_ring.gen);
255
256         /* RX descriptors tables */
257         for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
258           {
259             vmxnet3_rx_ring *ring = &rxq->rx_ring[rid];
260
261             vlib_cli_output (vm,
262                              "    ring %u size %u fill %u "
263                              "consume %u produce %u", rid,
264                              rxq->size, ring->fill, ring->consume,
265                              ring->produce);
266             if (show_descr)
267               {
268                 vlib_cli_output (vm, "RX descriptors table");
269                 vlib_cli_output (vm, "  %5s  %18s  %10s",
270                                  "slot", "address", "flags");
271                 for (desc_idx = 0; desc_idx < rxq->size; desc_idx++)
272                   {
273                     rxd = &rxq->rx_desc[rid][desc_idx];
274                     vlib_cli_output (vm, "  %5u  0x%016llx  0x%08x",
275                                      desc_idx, rxd->address, rxd->flags);
276                   }
277               }
278             else if (show_one_table)
279               {
280                 if (((which == VMXNET3_SHOW_RX_DESC0) && (rid == 0)) ||
281                     ((which == VMXNET3_SHOW_RX_DESC1) && (rid == 1)))
282                   {
283                     vlib_cli_output (vm, "RX descriptors table");
284                     vlib_cli_output (vm, "  %5s  %18s  %10s",
285                                      "slot", "address", "flags");
286                     if (show_one_slot)
287                       {
288                         rxd = &rxq->rx_desc[rid][slot];
289                         vlib_cli_output (vm, "  %5u  0x%016llx  0x%08x",
290                                          slot, rxd->address, rxd->flags);
291                       }
292                     else
293                       for (desc_idx = 0; desc_idx < rxq->size; desc_idx++)
294                         {
295                           rxd = &rxq->rx_desc[rid][desc_idx];
296                           vlib_cli_output (vm, "  %5u  0x%016llx  0x%08x",
297                                            desc_idx, rxd->address,
298                                            rxd->flags);
299                         }
300                   }
301               }
302           }
303
304         /* RX completion table */
305         if (show_descr)
306           {
307             vlib_cli_output (vm, "RX completion descriptors table");
308             vlib_cli_output (vm, "  %5s  %10s  %10s  %10s  %10s",
309                              "slot", "index", "rss", "len", "flags");
310             for (desc_idx = 0; desc_idx < rxq->size; desc_idx++)
311               {
312                 rx_comp = &rxq->rx_comp[desc_idx];
313                 vlib_cli_output (vm, "  %5u  0x%08x  %10u  %10u  0x%08x",
314                                  desc_idx, rx_comp->index, rx_comp->rss,
315                                  rx_comp->len, rx_comp->flags);
316               }
317           }
318         else if (show_one_table)
319           {
320             if (which == VMXNET3_SHOW_RX_COMP)
321               {
322                 vlib_cli_output (vm, "RX completion descriptors table");
323                 vlib_cli_output (vm, "  %5s  %10s  %10s  %10s  %10s",
324                                  "slot", "index", "rss", "len", "flags");
325                 if (show_one_slot)
326                   {
327                     rx_comp = &rxq->rx_comp[slot];
328                     vlib_cli_output (vm, "  %5u  0x%08x  %10u  %10u  0x%08x",
329                                      slot, rx_comp->index, rx_comp->rss,
330                                      rx_comp->len, rx_comp->flags);
331                   }
332                 else
333                   for (desc_idx = 0; desc_idx < rxq->size; desc_idx++)
334                     {
335                       rx_comp = &rxq->rx_comp[desc_idx];
336                       vlib_cli_output (vm,
337                                        "  %5u  0x%08x  %10u  %10u  0x%08x",
338                                        desc_idx, rx_comp->index, rx_comp->rss,
339                                        rx_comp->len, rx_comp->flags);
340                     }
341               }
342           }
343       }
344
345       vec_foreach_index (qid, vd->txqs)
346       {
347         txq = vec_elt_at_index (vd->txqs, qid);
348         vlib_cli_output (vm, "  Queue %u (TX)", qid);
349         vlib_cli_output (vm, "    TX completion next index %u",
350                          txq->tx_comp_ring.next);
351         vlib_cli_output (vm, "    TX completion generation flag 0x%x",
352                          txq->tx_comp_ring.gen);
353         vlib_cli_output (vm, "    size %u consume %u produce %u",
354                          txq->size, txq->tx_ring.consume,
355                          txq->tx_ring.produce);
356         if (show_descr)
357           {
358             vlib_cli_output (vm, "TX descriptors table");
359             vlib_cli_output (vm, "  %5s  %18s  %10s  %10s",
360                              "slot", "address", "flags0", "flags1");
361             for (desc_idx = 0; desc_idx < txq->size; desc_idx++)
362               {
363                 txd = &txq->tx_desc[desc_idx];
364                 vlib_cli_output (vm, "  %5u  0x%016llx  0x%08x  0x%08x",
365                                  desc_idx, txd->address, txd->flags[0],
366                                  txd->flags[1]);
367               }
368
369             vlib_cli_output (vm, "TX completion descriptors table");
370             vlib_cli_output (vm, "  %5s  %10s  %10s",
371                              "slot", "index", "flags");
372             for (desc_idx = 0; desc_idx < txq->size; desc_idx++)
373               {
374                 tx_comp = &txq->tx_comp[desc_idx];
375                 vlib_cli_output (vm, "  %5u  0x%08x  0x%08x",
376                                  desc_idx, tx_comp->index, tx_comp->flags);
377               }
378           }
379         else if (show_one_table)
380           {
381             if (which == VMXNET3_SHOW_TX_DESC)
382               {
383                 vlib_cli_output (vm, "TX descriptors table");
384                 vlib_cli_output (vm, "  %5s  %18s  %10s  %10s",
385                                  "slot", "address", "flags0", "flags1");
386                 if (show_one_slot)
387                   {
388                     txd = &txq->tx_desc[slot];
389                     vlib_cli_output (vm, "  %5u  0x%016llx  0x%08x  0x%08x",
390                                      slot, txd->address, txd->flags[0],
391                                      txd->flags[1]);
392                   }
393                 else
394                   for (desc_idx = 0; desc_idx < txq->size; desc_idx++)
395                     {
396                       txd = &txq->tx_desc[desc_idx];
397                       vlib_cli_output (vm, "  %5u  0x%016llx  0x%08x  0x%08x",
398                                        desc_idx, txd->address, txd->flags[0],
399                                        txd->flags[1]);
400                     }
401               }
402             else if (which == VMXNET3_SHOW_TX_COMP)
403               {
404                 vlib_cli_output (vm, "TX completion descriptors table");
405                 vlib_cli_output (vm, "  %5s  %10s  %10s",
406                                  "slot", "index", "flags");
407                 if (show_one_slot)
408                   {
409                     tx_comp = &txq->tx_comp[slot];
410                     vlib_cli_output (vm, "  %5u  0x%08x  0x%08x",
411                                      slot, tx_comp->index, tx_comp->flags);
412                   }
413                 else
414                   for (desc_idx = 0; desc_idx < txq->size; desc_idx++)
415                     {
416                       tx_comp = &txq->tx_comp[desc_idx];
417                       vlib_cli_output (vm, "  %5u  0x%08x  0x%08x",
418                                        desc_idx, tx_comp->index,
419                                        tx_comp->flags);
420                     }
421               }
422           }
423       }
424     }
425 }
426
427 static clib_error_t *
428 show_vmxnet3_fn (vlib_main_t * vm, unformat_input_t * input,
429                  vlib_cli_command_t * cmd)
430 {
431   vmxnet3_main_t *vmxm = &vmxnet3_main;
432   vnet_main_t *vnm = &vnet_main;
433   vmxnet3_device_t *vd;
434   clib_error_t *error = 0;
435   u32 hw_if_index, *hw_if_indices = 0;
436   vnet_hw_interface_t *hi = 0;
437   u8 show_descr = 0, show_one_table = 0, show_one_slot = 0;
438   u32 which = ~0, slot;
439
440   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
441     {
442       if (unformat
443           (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
444         {
445           hi = vnet_get_hw_interface (vnm, hw_if_index);
446           if (vmxnet3_device_class.index != hi->dev_class_index)
447             {
448               error = clib_error_return (0, "unknown input `%U'",
449                                          format_unformat_error, input);
450               goto done;
451             }
452           vec_add1 (hw_if_indices, hw_if_index);
453         }
454       else if (unformat (input, "desc"))
455         show_descr = 1;
456       else if (hi)
457         {
458           vmxnet3_device_t *vd =
459             vec_elt_at_index (vmxm->devices, hi->dev_instance);
460
461           if (unformat (input, "rx-comp"))
462             {
463               show_one_table = 1;
464               which = VMXNET3_SHOW_RX_COMP;
465               if (unformat (input, "%u", &slot))
466                 {
467                   vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, 0);
468
469                   if (slot >= rxq->size)
470                     {
471                       error = clib_error_return (0,
472                                                  "slot size must be < rx queue "
473                                                  "size %u", rxq->size);
474                       goto done;
475                     }
476                   show_one_slot = 1;
477                 }
478             }
479           else if (unformat (input, "rx-desc-0"))
480             {
481               show_one_table = 1;
482               which = VMXNET3_SHOW_RX_DESC0;
483               if (unformat (input, "%u", &slot))
484                 {
485                   vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, 0);
486
487                   if (slot >= rxq->size)
488                     {
489                       error = clib_error_return (0,
490                                                  "slot size must be < rx queue "
491                                                  "size %u", rxq->size);
492                       goto done;
493                     }
494                   show_one_slot = 1;
495                 }
496             }
497           else if (unformat (input, "rx-desc-1"))
498             {
499               show_one_table = 1;
500               which = VMXNET3_SHOW_RX_DESC1;
501               if (unformat (input, "%u", &slot))
502                 {
503                   vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, 0);
504
505                   if (slot >= rxq->size)
506                     {
507                       error = clib_error_return (0,
508                                                  "slot size must be < rx queue "
509                                                  "size %u", rxq->size);
510                       goto done;
511                     }
512                   show_one_slot = 1;
513                 }
514             }
515           else if (unformat (input, "tx-comp"))
516             {
517               show_one_table = 1;
518               which = VMXNET3_SHOW_TX_COMP;
519               if (unformat (input, "%u", &slot))
520                 {
521                   vmxnet3_txq_t *txq = vec_elt_at_index (vd->txqs, 0);
522
523                   if (slot >= txq->size)
524                     {
525                       error = clib_error_return (0,
526                                                  "slot size must be < tx queue "
527                                                  "size %u", txq->size);
528                       goto done;
529                     }
530                   show_one_slot = 1;
531                 }
532             }
533           else if (unformat (input, "tx-desc"))
534             {
535               show_one_table = 1;
536               which = VMXNET3_SHOW_TX_DESC;
537               if (unformat (input, "%u", &slot))
538                 {
539                   vmxnet3_txq_t *txq = vec_elt_at_index (vd->txqs, 0);
540
541                   if (slot >= txq->size)
542                     {
543                       error = clib_error_return (0,
544                                                  "slot size must be < tx queue "
545                                                  "size %u", txq->size);
546                       goto done;
547                     }
548                   show_one_slot = 1;
549                 }
550             }
551           else
552             {
553               error = clib_error_return (0, "unknown input `%U'",
554                                          format_unformat_error, input);
555               goto done;
556             }
557         }
558       else
559         {
560           error = clib_error_return (0, "unknown input `%U'",
561                                      format_unformat_error, input);
562           goto done;
563         }
564     }
565
566   if (vec_len (hw_if_indices) == 0)
567     {
568       pool_foreach (vd, vmxm->devices)
569         vec_add1 (hw_if_indices, vd->hw_if_index);
570     }
571
572   show_vmxnet3 (vm, hw_if_indices, show_descr, show_one_table, which,
573                 show_one_slot, slot);
574
575 done:
576   vec_free (hw_if_indices);
577   return error;
578 }
579
580 /* *INDENT-OFF* */
581 VLIB_CLI_COMMAND (show_vmxnet3_command, static) = {
582   .path = "show vmxnet3",
583   .short_help = "show vmxnet3 [[<interface>] ([desc] | ([rx-comp] | "
584   "[rx-desc-0] | [rx-desc-1] | [tx-comp] | [tx-desc]) [<slot>])]",
585   .function = show_vmxnet3_fn,
586 };
587 /* *INDENT-ON* */
588
589 clib_error_t *
590 vmxnet3_cli_init (vlib_main_t * vm)
591 {
592   vmxnet3_main_t *vmxm = &vmxnet3_main;
593   vlib_thread_main_t *tm = vlib_get_thread_main ();
594
595   /* initialize binary API */
596   vmxnet3_plugin_api_hookup (vm);
597
598   vmxm->log_default = vlib_log_register_class ("vmxnet3", 0);
599
600   vec_validate (vmxm->per_thread_data, tm->n_vlib_mains - 1);
601   return 0;
602 }
603
604 VLIB_INIT_FUNCTION (vmxnet3_cli_init);
605
606 /*
607  * fd.io coding-style-patch-verification: ON
608  *
609  * Local Variables:
610  * eval: (c-set-style "gnu")
611  * End:
612  */