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