vppinfra: use count_trailing_zeros in sparse_vec_index
[vpp.git] / src / plugins / dpdk / device / cli.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <unistd.h>
17 #include <fcntl.h>
18
19 #include <vnet/vnet.h>
20 #include <vppinfra/vec.h>
21 #include <vppinfra/error.h>
22 #include <vppinfra/format.h>
23 #include <vppinfra/xxhash.h>
24 #include <vppinfra/linux/sysfs.c>
25
26 #include <vnet/ethernet/ethernet.h>
27 #include <dpdk/device/dpdk.h>
28 #include <vnet/classify/vnet_classify.h>
29 #include <vnet/mpls/packet.h>
30
31 #include <dpdk/device/dpdk_priv.h>
32
33 /**
34  * @file
35  * @brief CLI for DPDK Abstraction Layer and pcap Tx Trace.
36  *
37  * This file contains the source code for CLI for DPDK
38  * Abstraction Layer and pcap Tx Trace.
39  */
40
41
42 static clib_error_t *
43 get_hqos (u32 hw_if_index, u32 subport_id, dpdk_device_t ** xd,
44           dpdk_device_config_t ** devconf)
45 {
46   dpdk_main_t *dm = &dpdk_main;
47   vnet_hw_interface_t *hw;
48   struct rte_eth_dev_info dev_info;
49   uword *p = 0;
50   clib_error_t *error = NULL;
51
52
53   if (hw_if_index == (u32) ~ 0)
54     {
55       error = clib_error_return (0, "please specify valid interface name");
56       goto done;
57     }
58
59   if (subport_id != 0)
60     {
61       error = clib_error_return (0, "Invalid subport");
62       goto done;
63     }
64
65   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
66   *xd = vec_elt_at_index (dm->devices, hw->dev_instance);
67
68   rte_eth_dev_info_get ((*xd)->device_index, &dev_info);
69   if (dev_info.pci_dev)
70     {                           /* bonded interface has no pci info */
71       vlib_pci_addr_t pci_addr;
72
73       pci_addr.domain = dev_info.pci_dev->addr.domain;
74       pci_addr.bus = dev_info.pci_dev->addr.bus;
75       pci_addr.slot = dev_info.pci_dev->addr.devid;
76       pci_addr.function = dev_info.pci_dev->addr.function;
77
78       p =
79         hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
80     }
81
82   if (p)
83     (*devconf) = pool_elt_at_index (dm->conf->dev_confs, p[0]);
84   else
85     (*devconf) = &dm->conf->default_devconf;
86
87 done:
88   return error;
89 }
90
91 static clib_error_t *
92 pcap_trace_command_fn (vlib_main_t * vm,
93                        unformat_input_t * input, vlib_cli_command_t * cmd)
94 {
95 #define PCAP_DEF_PKT_TO_CAPTURE (100)
96
97   unformat_input_t _line_input, *line_input = &_line_input;
98   dpdk_main_t *dm = &dpdk_main;
99   u8 *filename;
100   u8 *chroot_filename = 0;
101   u32 max = 0;
102   int enabled = 0;
103   int errorFlag = 0;
104   clib_error_t *error = 0;
105
106   /* Get a line of input. */
107   if (!unformat_user (input, unformat_line_input, line_input))
108     return 0;
109
110   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
111     {
112       if (unformat (line_input, "on"))
113         {
114           if (dm->tx_pcap_enable == 0)
115             {
116               enabled = 1;
117             }
118           else
119             {
120               vlib_cli_output (vm, "pcap tx capture already on...");
121               errorFlag = 1;
122               break;
123             }
124         }
125       else if (unformat (line_input, "off"))
126         {
127           if (dm->tx_pcap_enable)
128             {
129               vlib_cli_output (vm, "captured %d pkts...",
130                                dm->pcap_main.n_packets_captured + 1);
131               if (dm->pcap_main.n_packets_captured)
132                 {
133                   dm->pcap_main.n_packets_to_capture =
134                     dm->pcap_main.n_packets_captured;
135                   error = pcap_write (&dm->pcap_main);
136                   if (error)
137                     clib_error_report (error);
138                   else
139                     vlib_cli_output (vm, "saved to %s...", dm->pcap_filename);
140                 }
141
142               dm->tx_pcap_enable = 0;
143             }
144           else
145             {
146               vlib_cli_output (vm, "pcap tx capture already off...");
147               errorFlag = 1;
148               break;
149             }
150         }
151       else if (unformat (line_input, "max %d", &max))
152         {
153           if (dm->tx_pcap_enable)
154             {
155               vlib_cli_output (vm,
156                                "can't change max value while pcap tx capture active...");
157               errorFlag = 1;
158               break;
159             }
160         }
161       else if (unformat (line_input, "intfc %U",
162                          unformat_vnet_sw_interface, dm->vnet_main,
163                          &dm->pcap_sw_if_index))
164         ;
165
166       else if (unformat (line_input, "intfc any"))
167         {
168           dm->pcap_sw_if_index = 0;
169         }
170       else if (unformat (line_input, "file %s", &filename))
171         {
172           if (dm->tx_pcap_enable)
173             {
174               vlib_cli_output (vm,
175                                "can't change file while pcap tx capture active...");
176               errorFlag = 1;
177               break;
178             }
179
180           /* Brain-police user path input */
181           if (strstr ((char *) filename, "..")
182               || index ((char *) filename, '/'))
183             {
184               vlib_cli_output (vm, "illegal characters in filename '%s'",
185                                filename);
186               vlib_cli_output (vm,
187                                "Hint: Only filename, do not enter directory structure.");
188               vec_free (filename);
189               errorFlag = 1;
190               break;
191             }
192
193           chroot_filename = format (0, "/tmp/%s%c", filename, 0);
194           vec_free (filename);
195         }
196       else if (unformat (line_input, "status"))
197         {
198           if (dm->pcap_sw_if_index == 0)
199             {
200               vlib_cli_output (vm, "max is %d for any interface to file %s",
201                                dm->
202                                pcap_pkts_to_capture ? dm->pcap_pkts_to_capture
203                                : PCAP_DEF_PKT_TO_CAPTURE,
204                                dm->
205                                pcap_filename ? dm->pcap_filename : (u8 *)
206                                "/tmp/vpe.pcap");
207             }
208           else
209             {
210               vlib_cli_output (vm, "max is %d for interface %U to file %s",
211                                dm->
212                                pcap_pkts_to_capture ? dm->pcap_pkts_to_capture
213                                : PCAP_DEF_PKT_TO_CAPTURE,
214                                format_vnet_sw_if_index_name, dm->vnet_main,
215                                dm->pcap_sw_if_index,
216                                dm->
217                                pcap_filename ? dm->pcap_filename : (u8 *)
218                                "/tmp/vpe.pcap");
219             }
220
221           if (dm->tx_pcap_enable == 0)
222             {
223               vlib_cli_output (vm, "pcap tx capture is off...");
224             }
225           else
226             {
227               vlib_cli_output (vm, "pcap tx capture is on: %d of %d pkts...",
228                                dm->pcap_main.n_packets_captured,
229                                dm->pcap_main.n_packets_to_capture);
230             }
231           break;
232         }
233
234       else
235         {
236           error = clib_error_return (0, "unknown input `%U'",
237                                      format_unformat_error, line_input);
238           errorFlag = 1;
239           break;
240         }
241     }
242   unformat_free (line_input);
243
244
245   if (errorFlag == 0)
246     {
247       /* Since no error, save configured values. */
248       if (chroot_filename)
249         {
250           if (dm->pcap_filename)
251             vec_free (dm->pcap_filename);
252           vec_add1 (chroot_filename, 0);
253           dm->pcap_filename = chroot_filename;
254         }
255
256       if (max)
257         dm->pcap_pkts_to_capture = max;
258
259
260       if (enabled)
261         {
262           if (dm->pcap_filename == 0)
263             dm->pcap_filename = format (0, "/tmp/vpe.pcap%c", 0);
264
265           memset (&dm->pcap_main, 0, sizeof (dm->pcap_main));
266           dm->pcap_main.file_name = (char *) dm->pcap_filename;
267           dm->pcap_main.n_packets_to_capture = PCAP_DEF_PKT_TO_CAPTURE;
268           if (dm->pcap_pkts_to_capture)
269             dm->pcap_main.n_packets_to_capture = dm->pcap_pkts_to_capture;
270
271           dm->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
272           dm->tx_pcap_enable = 1;
273           vlib_cli_output (vm, "pcap tx capture on...");
274         }
275     }
276   else if (chroot_filename)
277     vec_free (chroot_filename);
278
279
280   return error;
281 }
282
283 /*?
284  * This command is used to start or stop a packet capture, or show
285  * the status of packet capture.
286  *
287  * This command has the following optional parameters:
288  *
289  * - <b>on|off</b> - Used to start or stop a packet capture.
290  *
291  * - <b>max <nn></b> - Depth of local buffer. Once '<em>nn</em>' number
292  *   of packets have been received, buffer is flushed to file. Once another
293  *   '<em>nn</em>' number of packets have been received, buffer is flushed
294  *   to file, overwriting previous write. If not entered, value defaults
295  *   to 100. Can only be updated if packet capture is off.
296  *
297  * - <b>intfc <interface>|any</b> - Used to specify a given interface,
298  *   or use '<em>any</em>' to run packet capture on all interfaces.
299  *   '<em>any</em>' is the default if not provided. Settings from a previous
300  *   packet capture are preserved, so '<em>any</em>' can be used to reset
301  *   the interface setting.
302  *
303  * - <b>file <name></b> - Used to specify the output filename. The file will
304  *   be placed in the '<em>/tmp</em>' directory, so only the filename is
305  *   supported. Directory should not be entered. If file already exists, file
306  *   will be overwritten. If no filename is provided, '<em>/tmp/vpe.pcap</em>'
307  *   will be used. Can only be updated if packet capture is off.
308  *
309  * - <b>status</b> - Displays the current status and configured attributes
310  *   associated with a packet capture. If packet capture is in progress,
311  *   '<em>status</em>' also will return the number of packets currently in
312  *   the local buffer. All additional attributes entered on command line
313  *   with '<em>status</em>' will be ingnored and not applied.
314  *
315  * @cliexpar
316  * Example of how to display the status of a tx packet capture when off:
317  * @cliexstart{pcap tx trace status}
318  * max is 100, for any interface to file /tmp/vpe.pcap
319  * pcap tx capture is off...
320  * @cliexend
321  * Example of how to start a tx packet capture:
322  * @cliexstart{pcap tx trace on max 35 intfc GigabitEthernet0/8/0 file vppTest.pcap}
323  * pcap tx capture on...
324  * @cliexend
325  * Example of how to display the status of a tx packet capture in progress:
326  * @cliexstart{pcap tx trace status}
327  * max is 35, for interface GigabitEthernet0/8/0 to file /tmp/vppTest.pcap
328  * pcap tx capture is on: 20 of 35 pkts...
329  * @cliexend
330  * Example of how to stop a tx packet capture:
331  * @cliexstart{vppctl pcap tx trace off}
332  * captured 21 pkts...
333  * saved to /tmp/vppTest.pcap...
334  * @cliexend
335 ?*/
336 /* *INDENT-OFF* */
337 VLIB_CLI_COMMAND (pcap_trace_command, static) = {
338     .path = "pcap tx trace",
339     .short_help =
340     "pcap tx trace [on|off] [max <nn>] [intfc <interface>|any] [file <name>] [status]",
341     .function = pcap_trace_command_fn,
342 };
343 /* *INDENT-ON* */
344
345
346 static clib_error_t *
347 show_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input,
348                   vlib_cli_command_t * cmd)
349 {
350   struct rte_mempool *rmp;
351   int i;
352
353   for (i = 0; i < vec_len (dpdk_main.pktmbuf_pools); i++)
354     {
355       rmp = dpdk_main.pktmbuf_pools[i];
356       if (rmp)
357         {
358           unsigned count = rte_mempool_avail_count (rmp);
359           unsigned free_count = rte_mempool_in_use_count (rmp);
360
361           vlib_cli_output (vm,
362                            "name=\"%s\"  available = %7d allocated = %7d total = %7d\n",
363                            rmp->name, (u32) count, (u32) free_count,
364                            (u32) (count + free_count));
365         }
366       else
367         {
368           vlib_cli_output (vm, "rte_mempool is NULL (!)\n");
369         }
370     }
371   return 0;
372 }
373
374 /*?
375  * This command displays statistics of each DPDK mempool.
376  *
377  * @cliexpar
378  * Example of how to display DPDK buffer data:
379  * @cliexstart{show dpdk buffer}
380  * name="mbuf_pool_socket0"  available =   15104 allocated =    1280 total =   16384
381  * @cliexend
382 ?*/
383 /* *INDENT-OFF* */
384 VLIB_CLI_COMMAND (cmd_show_dpdk_buffer,static) = {
385     .path = "show dpdk buffer",
386     .short_help = "show dpdk buffer",
387     .function = show_dpdk_buffer,
388     .is_mp_safe = 1,
389 };
390 /* *INDENT-ON* */
391
392 static clib_error_t *
393 show_dpdk_physmem (vlib_main_t * vm, unformat_input_t * input,
394                    vlib_cli_command_t * cmd)
395 {
396   clib_error_t *err = 0;
397   u32 pipe_max_size;
398   int fds[2];
399   u8 *s = 0;
400   int n, n_try;
401   FILE *f;
402
403   err = clib_sysfs_read ("/proc/sys/fs/pipe-max-size", "%u", &pipe_max_size);
404
405   if (err)
406     return err;
407
408   if (pipe (fds) == -1)
409     return clib_error_return_unix (0, "pipe");
410
411 #ifndef F_SETPIPE_SZ
412 #define F_SETPIPE_SZ    (1024 + 7)
413 #endif
414
415   if (fcntl (fds[1], F_SETPIPE_SZ, pipe_max_size) == -1)
416     {
417       err = clib_error_return_unix (0, "fcntl(F_SETPIPE_SZ)");
418       goto error;
419     }
420
421   if (fcntl (fds[0], F_SETFL, O_NONBLOCK) == -1)
422     {
423       err = clib_error_return_unix (0, "fcntl(F_SETFL)");
424       goto error;
425     }
426
427   if ((f = fdopen (fds[1], "a")) == 0)
428     {
429       err = clib_error_return_unix (0, "fdopen");
430       goto error;
431     }
432
433   rte_dump_physmem_layout (f);
434   fflush (f);
435
436   n = n_try = 4096;
437   while (n == n_try)
438     {
439       uword len = vec_len (s);
440       vec_resize (s, len + n_try);
441
442       n = read (fds[0], s + len, n_try);
443       if (n < 0 && errno != EAGAIN)
444         {
445           err = clib_error_return_unix (0, "read");
446           goto error;
447         }
448       _vec_len (s) = len + (n < 0 ? 0 : n);
449     }
450
451   vlib_cli_output (vm, "%v", s);
452
453 error:
454   close (fds[0]);
455   close (fds[1]);
456   vec_free (s);
457   return err;
458 }
459
460 /*?
461  * This command displays DPDK physmem layout
462  *
463  * @cliexpar
464  * Example of how to display DPDK physmem layout:
465  * @cliexstart{show dpdk physmem}
466  * @cliexend
467 ?*/
468 /* *INDENT-OFF* */
469 VLIB_CLI_COMMAND (cmd_show_dpdk_physmem,static) = {
470     .path = "show dpdk physmem",
471     .short_help = "show dpdk physmem",
472     .function = show_dpdk_physmem,
473     .is_mp_safe = 1,
474 };
475 /* *INDENT-ON* */
476
477 static clib_error_t *
478 test_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input,
479                   vlib_cli_command_t * cmd)
480 {
481   static u32 *allocated_buffers;
482   u32 n_alloc = 0;
483   u32 n_free = 0;
484   u32 first, actual_alloc;
485
486   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
487     {
488       if (unformat (input, "allocate %d", &n_alloc))
489         ;
490       else if (unformat (input, "free %d", &n_free))
491         ;
492       else
493         break;
494     }
495
496   if (n_free)
497     {
498       if (vec_len (allocated_buffers) < n_free)
499         return clib_error_return (0, "Can't free %d, only %d allocated",
500                                   n_free, vec_len (allocated_buffers));
501
502       first = vec_len (allocated_buffers) - n_free;
503       vlib_buffer_free (vm, allocated_buffers + first, n_free);
504       _vec_len (allocated_buffers) = first;
505     }
506   if (n_alloc)
507     {
508       first = vec_len (allocated_buffers);
509       vec_validate (allocated_buffers,
510                     vec_len (allocated_buffers) + n_alloc - 1);
511
512       actual_alloc = vlib_buffer_alloc (vm, allocated_buffers + first,
513                                         n_alloc);
514       _vec_len (allocated_buffers) = first + actual_alloc;
515
516       if (actual_alloc < n_alloc)
517         vlib_cli_output (vm, "WARNING: only allocated %d buffers",
518                          actual_alloc);
519     }
520
521   vlib_cli_output (vm, "Currently %d buffers allocated",
522                    vec_len (allocated_buffers));
523
524   if (allocated_buffers && vec_len (allocated_buffers) == 0)
525     vec_free (allocated_buffers);
526
527   return 0;
528 }
529
530 /*?
531  * This command tests the allocation and freeing of DPDK buffers.
532  * If both '<em>allocate</em>' and '<em>free</em>' are entered on the
533  * same command, the '<em>free</em>' is executed first. If no
534  * parameters are provided, this command display how many DPDK buffers
535  * the test command has allocated.
536  *
537  * @cliexpar
538  * @parblock
539  *
540  * Example of how to display how many DPDK buffer test command has allcoated:
541  * @cliexstart{test dpdk buffer}
542  * Currently 0 buffers allocated
543  * @cliexend
544  *
545  * Example of how to allocate DPDK buffers using the test command:
546  * @cliexstart{test dpdk buffer allocate 10}
547  * Currently 10 buffers allocated
548  * @cliexend
549  *
550  * Example of how to free DPDK buffers allocated by the test command:
551  * @cliexstart{test dpdk buffer free 10}
552  * Currently 0 buffers allocated
553  * @cliexend
554  * @endparblock
555 ?*/
556 /* *INDENT-OFF* */
557 VLIB_CLI_COMMAND (cmd_test_dpdk_buffer,static) = {
558     .path = "test dpdk buffer",
559     .short_help = "test dpdk buffer [allocate <nn>] [free <nn>]",
560     .function = test_dpdk_buffer,
561     .is_mp_safe = 1,
562 };
563 /* *INDENT-ON* */
564
565 static clib_error_t *
566 set_dpdk_if_desc (vlib_main_t * vm, unformat_input_t * input,
567                   vlib_cli_command_t * cmd)
568 {
569   unformat_input_t _line_input, *line_input = &_line_input;
570   dpdk_main_t *dm = &dpdk_main;
571   vnet_hw_interface_t *hw;
572   dpdk_device_t *xd;
573   u32 hw_if_index = (u32) ~ 0;
574   u32 nb_rx_desc = (u32) ~ 0;
575   u32 nb_tx_desc = (u32) ~ 0;
576   clib_error_t *error = NULL;
577
578   if (!unformat_user (input, unformat_line_input, line_input))
579     return 0;
580
581   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
582     {
583       if (unformat
584           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
585            &hw_if_index))
586         ;
587       else if (unformat (line_input, "tx %d", &nb_tx_desc))
588         ;
589       else if (unformat (line_input, "rx %d", &nb_rx_desc))
590         ;
591       else
592         {
593           error = clib_error_return (0, "parse error: '%U'",
594                                      format_unformat_error, line_input);
595           goto done;
596         }
597     }
598
599   if (hw_if_index == (u32) ~ 0)
600     {
601       error = clib_error_return (0, "please specify valid interface name");
602       goto done;
603     }
604
605   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
606   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
607
608   if ((xd->flags & DPDK_DEVICE_FLAG_PMD) == 0)
609     {
610       error =
611         clib_error_return (0,
612                            "number of descriptors can be set only for "
613                            "physical devices");
614       goto done;
615     }
616
617   if ((nb_rx_desc == (u32) ~ 0 || nb_rx_desc == xd->nb_rx_desc) &&
618       (nb_tx_desc == (u32) ~ 0 || nb_tx_desc == xd->nb_tx_desc))
619     {
620       error = clib_error_return (0, "nothing changed");
621       goto done;
622     }
623
624   if (nb_rx_desc != (u32) ~ 0)
625     xd->nb_rx_desc = nb_rx_desc;
626
627   if (nb_tx_desc != (u32) ~ 0)
628     xd->nb_tx_desc = nb_tx_desc;
629
630   dpdk_device_setup (xd);
631
632   if (vec_len (xd->errors))
633     return clib_error_return (0, "%U", format_dpdk_device_errors, xd);
634
635 done:
636   unformat_free (line_input);
637
638   return error;
639 }
640
641 /*?
642  * This command sets the number of DPDK '<em>rx</em>' and
643  * '<em>tx</em>' descriptors for the given physical interface. Use
644  * the command '<em>show hardware-interface</em>' to display the
645  * current descriptor allocation.
646  *
647  * @cliexpar
648  * Example of how to set the DPDK interface descriptors:
649  * @cliexcmd{set dpdk interface descriptors GigabitEthernet0/8/0 rx 512 tx 512}
650 ?*/
651 /* *INDENT-OFF* */
652 VLIB_CLI_COMMAND (cmd_set_dpdk_if_desc,static) = {
653     .path = "set dpdk interface descriptors",
654     .short_help = "set dpdk interface descriptors <interface> [rx <nn>] [tx <nn>]",
655     .function = set_dpdk_if_desc,
656 };
657 /* *INDENT-ON* */
658
659 static int
660 dpdk_device_queue_sort (void *a1, void *a2)
661 {
662   dpdk_device_and_queue_t *dq1 = a1;
663   dpdk_device_and_queue_t *dq2 = a2;
664
665   if (dq1->device > dq2->device)
666     return 1;
667   else if (dq1->device < dq2->device)
668     return -1;
669   else if (dq1->queue_id > dq2->queue_id)
670     return 1;
671   else if (dq1->queue_id < dq2->queue_id)
672     return -1;
673   else
674     return 0;
675 }
676
677
678 static clib_error_t *
679 show_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input,
680                              vlib_cli_command_t * cmd)
681 {
682   vlib_thread_main_t *tm = vlib_get_thread_main ();
683   dpdk_main_t *dm = &dpdk_main;
684   dpdk_device_and_queue_t *dq;
685   int cpu;
686
687   if (tm->n_vlib_mains == 1)
688     vlib_cli_output (vm, "All interfaces are handled by main thread");
689
690   for (cpu = 0; cpu < vec_len (dm->devices_by_hqos_cpu); cpu++)
691     {
692       if (cpu >= dm->hqos_cpu_first_index &&
693           cpu < (dm->hqos_cpu_first_index + dm->hqos_cpu_count))
694         vlib_cli_output (vm, "Thread %u (%s at lcore %u):", cpu,
695                          vlib_worker_threads[cpu].name,
696                          vlib_worker_threads[cpu].lcore_id);
697
698       vec_foreach (dq, dm->devices_by_hqos_cpu[cpu])
699       {
700         u32 hw_if_index = dm->devices[dq->device].hw_if_index;
701         vnet_hw_interface_t *hi =
702           vnet_get_hw_interface (dm->vnet_main, hw_if_index);
703         vlib_cli_output (vm, "  %v queue %u", hi->name, dq->queue_id);
704       }
705     }
706   return 0;
707 }
708
709 /*?
710  * This command is used to display the thread and core each
711  * DPDK output interface and HQoS queue is assigned too.
712  *
713  * @cliexpar
714  * Example of how to display the DPDK output interface and HQoS queue placement:
715  * @cliexstart{show dpdk interface hqos placement}
716  * Thread 1 (vpp_hqos-threads_0 at lcore 3):
717  *   GigabitEthernet0/8/0 queue 0
718  * Thread 2 (vpp_hqos-threads_1 at lcore 4):
719  *   GigabitEthernet0/9/0 queue 0
720  * @cliexend
721 ?*/
722 /* *INDENT-OFF* */
723 VLIB_CLI_COMMAND (cmd_show_dpdk_if_hqos_placement, static) = {
724   .path = "show dpdk interface hqos placement",
725   .short_help = "show dpdk interface hqos placement",
726   .function = show_dpdk_if_hqos_placement,
727 };
728 /* *INDENT-ON* */
729
730 static clib_error_t *
731 set_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input,
732                             vlib_cli_command_t * cmd)
733 {
734   unformat_input_t _line_input, *line_input = &_line_input;
735   dpdk_main_t *dm = &dpdk_main;
736   dpdk_device_and_queue_t *dq;
737   vnet_hw_interface_t *hw;
738   dpdk_device_t *xd;
739   u32 hw_if_index = (u32) ~ 0;
740   u32 cpu = (u32) ~ 0;
741   int i;
742   clib_error_t *error = NULL;
743
744   if (!unformat_user (input, unformat_line_input, line_input))
745     return 0;
746
747   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
748     {
749       if (unformat
750           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
751            &hw_if_index))
752         ;
753       else if (unformat (line_input, "thread %d", &cpu))
754         ;
755       else
756         {
757           error = clib_error_return (0, "parse error: '%U'",
758                                      format_unformat_error, line_input);
759           goto done;
760         }
761     }
762
763   if (hw_if_index == (u32) ~ 0)
764     return clib_error_return (0, "please specify valid interface name");
765
766   if (cpu < dm->hqos_cpu_first_index ||
767       cpu >= (dm->hqos_cpu_first_index + dm->hqos_cpu_count))
768     {
769       error = clib_error_return (0, "please specify valid thread id");
770       goto done;
771     }
772
773   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
774   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
775
776   for (i = 0; i < vec_len (dm->devices_by_hqos_cpu); i++)
777     {
778       vec_foreach (dq, dm->devices_by_hqos_cpu[i])
779       {
780         if (hw_if_index == dm->devices[dq->device].hw_if_index)
781           {
782             if (cpu == i)       /* nothing to do */
783               goto done;
784
785             vec_del1 (dm->devices_by_hqos_cpu[i],
786                       dq - dm->devices_by_hqos_cpu[i]);
787             vec_add2 (dm->devices_by_hqos_cpu[cpu], dq, 1);
788             dq->queue_id = 0;
789             dq->device = xd->device_index;
790
791             vec_sort_with_function (dm->devices_by_hqos_cpu[i],
792                                     dpdk_device_queue_sort);
793
794             vec_sort_with_function (dm->devices_by_hqos_cpu[cpu],
795                                     dpdk_device_queue_sort);
796
797             goto done;
798           }
799       }
800     }
801
802   error = clib_error_return (0, "not found");
803
804 done:
805   unformat_free (line_input);
806
807   return error;
808 }
809
810 /*?
811  * This command is used to assign a given DPDK output interface and
812  * HQoS queue to a different thread. This will not create a thread,
813  * so the thread must already exist. Use '<em>/etc/vpp/startup.conf</em>'
814  * for the initial thread creation. See @ref qos_doc for more details.
815  *
816  * @cliexpar
817  * Example of how to display the DPDK output interface and HQoS queue placement:
818  * @cliexstart{show dpdk interface hqos placement}
819  * Thread 1 (vpp_hqos-threads_0 at lcore 3):
820  *   GigabitEthernet0/8/0 queue 0
821  * Thread 2 (vpp_hqos-threads_1 at lcore 4):
822  *   GigabitEthernet0/9/0 queue 0
823  * @cliexend
824  * Example of how to assign a DPDK output interface and HQoS queue to a thread:
825  * @cliexcmd{set dpdk interface hqos placement GigabitEthernet0/8/0 thread 2}
826 ?*/
827 /* *INDENT-OFF* */
828 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_placement, static) = {
829   .path = "set dpdk interface hqos placement",
830   .short_help = "set dpdk interface hqos placement <interface> thread <n>",
831   .function = set_dpdk_if_hqos_placement,
832 };
833 /* *INDENT-ON* */
834
835 static clib_error_t *
836 set_dpdk_if_hqos_pipe (vlib_main_t * vm, unformat_input_t * input,
837                        vlib_cli_command_t * cmd)
838 {
839   unformat_input_t _line_input, *line_input = &_line_input;
840   dpdk_main_t *dm = &dpdk_main;
841   vnet_hw_interface_t *hw;
842   dpdk_device_t *xd;
843   u32 hw_if_index = (u32) ~ 0;
844   u32 subport_id = (u32) ~ 0;
845   u32 pipe_id = (u32) ~ 0;
846   u32 profile_id = (u32) ~ 0;
847   int rv;
848   clib_error_t *error = NULL;
849
850   if (!unformat_user (input, unformat_line_input, line_input))
851     return 0;
852
853   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
854     {
855       if (unformat
856           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
857            &hw_if_index))
858         ;
859       else if (unformat (line_input, "subport %d", &subport_id))
860         ;
861       else if (unformat (line_input, "pipe %d", &pipe_id))
862         ;
863       else if (unformat (line_input, "profile %d", &profile_id))
864         ;
865       else
866         {
867           error = clib_error_return (0, "parse error: '%U'",
868                                      format_unformat_error, line_input);
869           goto done;
870         }
871     }
872
873   if (hw_if_index == (u32) ~ 0)
874     {
875       error = clib_error_return (0, "please specify valid interface name");
876       goto done;
877     }
878
879   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
880   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
881
882   rv =
883     rte_sched_pipe_config (xd->hqos_ht->hqos, subport_id, pipe_id,
884                            profile_id);
885   if (rv)
886     {
887       error = clib_error_return (0, "pipe configuration failed");
888       goto done;
889     }
890
891 done:
892   unformat_free (line_input);
893
894   return error;
895 }
896
897 /*?
898  * This command is used to change the profile associate with a HQoS pipe. The
899  * '<em><profile_id></em>' is zero based. Use the command
900  * '<em>show dpdk interface hqos</em>' to display the content of each profile.
901  * See @ref qos_doc for more details.
902  *
903  * @note
904  * Currently there is not an API to create a new HQoS pipe profile. One is
905  * created by default in the code (search for '<em>hqos_pipe_params_default</em>'').
906  * Additional profiles can be created in code and code recompiled. Then use this
907  * command to assign it.
908  *
909  * @cliexpar
910  * Example of how to assign a new profile to a HQoS pipe:
911  * @cliexcmd{set dpdk interface hqos pipe GigabitEthernet0/8/0 subport 0 pipe 2 profile 1}
912 ?*/
913 /* *INDENT-OFF* */
914 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_pipe, static) =
915 {
916   .path = "set dpdk interface hqos pipe",
917   .short_help = "set dpdk interface hqos pipe <interface> subport <subport_id> pipe <pipe_id> "
918                   "profile <profile_id>",
919   .function = set_dpdk_if_hqos_pipe,
920 };
921 /* *INDENT-ON* */
922
923 static clib_error_t *
924 set_dpdk_if_hqos_subport (vlib_main_t * vm, unformat_input_t * input,
925                           vlib_cli_command_t * cmd)
926 {
927   unformat_input_t _line_input, *line_input = &_line_input;
928   dpdk_main_t *dm = &dpdk_main;
929   dpdk_device_t *xd = NULL;
930   u32 hw_if_index = (u32) ~ 0;
931   u32 subport_id = (u32) ~ 0;
932   struct rte_sched_subport_params p;
933   int rv;
934   clib_error_t *error = NULL;
935   u32 tb_rate = (u32) ~ 0;
936   u32 tb_size = (u32) ~ 0;
937   u32 tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE] =
938     { (u32) ~ 0, (u32) ~ 0, (u32) ~ 0, (u32) ~ 0 };
939   u32 tc_period = (u32) ~ 0;
940   dpdk_device_config_t *devconf = NULL;
941
942   if (!unformat_user (input, unformat_line_input, line_input))
943     return 0;
944
945   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
946     {
947       if (unformat
948           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
949            &hw_if_index))
950         ;
951       else if (unformat (line_input, "subport %d", &subport_id))
952         ;
953       else if (unformat (line_input, "rate %d", &tb_rate))
954         ;
955       else if (unformat (line_input, "bktsize %d", &tb_size))
956         ;
957       else if (unformat (line_input, "tc0 %d", &tc_rate[0]))
958         ;
959       else if (unformat (line_input, "tc1 %d", &tc_rate[1]))
960         ;
961       else if (unformat (line_input, "tc2 %d", &tc_rate[2]))
962         ;
963       else if (unformat (line_input, "tc3 %d", &tc_rate[3]))
964         ;
965       else if (unformat (line_input, "period %d", &tc_period))
966         ;
967       else
968         {
969           error = clib_error_return (0, "parse error: '%U'",
970                                      format_unformat_error, line_input);
971           goto done;
972         }
973     }
974
975   error = get_hqos (hw_if_index, subport_id, &xd, &devconf);
976
977   if (error == NULL)
978     {
979       /* Copy the current values over to local structure. */
980       memcpy (&p, &devconf->hqos.subport[subport_id], sizeof (p));
981
982       /* Update local structure with input values. */
983       if (tb_rate != (u32) ~ 0)
984         {
985           p.tb_rate = tb_rate;
986           p.tc_rate[0] = tb_rate;
987           p.tc_rate[1] = tb_rate;
988           p.tc_rate[2] = tb_rate;
989           p.tc_rate[3] = tb_rate;
990         }
991       if (tb_size != (u32) ~ 0)
992         {
993           p.tb_size = tb_size;
994         }
995       if (tc_rate[0] != (u32) ~ 0)
996         {
997           p.tc_rate[0] = tc_rate[0];
998         }
999       if (tc_rate[1] != (u32) ~ 0)
1000         {
1001           p.tc_rate[1] = tc_rate[1];
1002         }
1003       if (tc_rate[2] != (u32) ~ 0)
1004         {
1005           p.tc_rate[2] = tc_rate[2];
1006         }
1007       if (tc_rate[3] != (u32) ~ 0)
1008         {
1009           p.tc_rate[3] = tc_rate[3];
1010         }
1011       if (tc_period != (u32) ~ 0)
1012         {
1013           p.tc_period = tc_period;
1014         }
1015
1016       /* Apply changes. */
1017       rv = rte_sched_subport_config (xd->hqos_ht->hqos, subport_id, &p);
1018       if (rv)
1019         {
1020           error = clib_error_return (0, "subport configuration failed");
1021           goto done;
1022         }
1023       else
1024         {
1025           /* Successfully applied, so save of the input values. */
1026           memcpy (&devconf->hqos.subport[subport_id], &p, sizeof (p));
1027         }
1028     }
1029
1030 done:
1031   unformat_free (line_input);
1032
1033   return error;
1034 }
1035
1036 /*?
1037  * This command is used to set the subport level parameters such as token
1038  * bucket rate (bytes per seconds), token bucket size (bytes), traffic class
1039  * rates (bytes per seconds) and token update period (Milliseconds).
1040  *
1041  * By default, the '<em>rate</em>' is set to 1250000000 bytes/second (10GbE
1042  * rate) and each of the four traffic classes is set to 100% of the port rate.
1043  * If the '<em>rate</em>' is updated by this command, all four traffic classes
1044  * are assigned the same value. Each of the four traffic classes can be updated
1045  * individually.
1046  *
1047  * @cliexpar
1048  * Example of how modify the subport attributes for a 1GbE link:
1049  * @cliexcmd{set dpdk interface hqos subport GigabitEthernet0/8/0 subport 0 rate 125000000}
1050 ?*/
1051 /* *INDENT-OFF* */
1052 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_subport, static) = {
1053   .path = "set dpdk interface hqos subport",
1054   .short_help = "set dpdk interface hqos subport <interface> subport <subport_id> "
1055                  "[rate <n>] [bktsize <n>] [tc0 <n>] [tc1 <n>] [tc2 <n>] [tc3 <n>] "
1056                  "[period <n>]",
1057   .function = set_dpdk_if_hqos_subport,
1058 };
1059 /* *INDENT-ON* */
1060
1061 static clib_error_t *
1062 set_dpdk_if_hqos_tctbl (vlib_main_t * vm, unformat_input_t * input,
1063                         vlib_cli_command_t * cmd)
1064 {
1065   unformat_input_t _line_input, *line_input = &_line_input;
1066   vlib_thread_main_t *tm = vlib_get_thread_main ();
1067   dpdk_main_t *dm = &dpdk_main;
1068   vnet_hw_interface_t *hw;
1069   dpdk_device_t *xd;
1070   u32 hw_if_index = (u32) ~ 0;
1071   u32 tc = (u32) ~ 0;
1072   u32 queue = (u32) ~ 0;
1073   u32 entry = (u32) ~ 0;
1074   u32 val, i;
1075   clib_error_t *error = NULL;
1076
1077   if (!unformat_user (input, unformat_line_input, line_input))
1078     return 0;
1079
1080   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1081     {
1082       if (unformat
1083           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
1084            &hw_if_index))
1085         ;
1086       else if (unformat (line_input, "entry %d", &entry))
1087         ;
1088       else if (unformat (line_input, "tc %d", &tc))
1089         ;
1090       else if (unformat (line_input, "queue %d", &queue))
1091         ;
1092       else
1093         {
1094           error = clib_error_return (0, "parse error: '%U'",
1095                                      format_unformat_error, line_input);
1096           goto done;
1097         }
1098     }
1099
1100   if (hw_if_index == (u32) ~ 0)
1101     {
1102       error = clib_error_return (0, "please specify valid interface name");
1103       goto done;
1104     }
1105   if (entry >= 64)
1106     {
1107       error = clib_error_return (0, "invalid entry");
1108       goto done;
1109     }
1110   if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE)
1111     {
1112       error = clib_error_return (0, "invalid traffic class");
1113       goto done;
1114     }
1115   if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS)
1116     {
1117       error = clib_error_return (0, "invalid traffic class queue");
1118       goto done;
1119     }
1120
1121   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
1122   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
1123
1124   /* Detect the set of worker threads */
1125   uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1126   /* Should never happen, shut up Coverity warning */
1127   if (p == 0)
1128     {
1129       error = clib_error_return (0, "no worker registrations?");
1130       goto done;
1131     }
1132
1133   vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0];
1134   int worker_thread_first = tr->first_index;
1135   int worker_thread_count = tr->count;
1136
1137   val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue;
1138   for (i = 0; i < worker_thread_count; i++)
1139     xd->hqos_wt[worker_thread_first + i].hqos_tc_table[entry] = val;
1140
1141 done:
1142   unformat_free (line_input);
1143
1144   return error;
1145 }
1146
1147 /*?
1148  * This command is used to set the traffic class translation table. The
1149  * traffic class translation table is used to map 64 values (0-63) to one of
1150  * four traffic class and one of four HQoS input queue. Use the '<em>show
1151  * dpdk interface hqos</em>' command to display the traffic class translation
1152  * table. See @ref qos_doc for more details.
1153  *
1154  * This command has the following parameters:
1155  *
1156  * - <b><interface></b> - Used to specify the output interface.
1157  *
1158  * - <b>entry <map_val></b> - Mapped value (0-63) to assign traffic class and queue to.
1159  *
1160  * - <b>tc <tc_id></b> - Traffic class (0-3) to be used by the provided mapped value.
1161  *
1162  * - <b>queue <queue_id></b> - HQoS input queue (0-3) to be used by the provided mapped value.
1163  *
1164  * @cliexpar
1165  * Example of how modify the traffic class translation table:
1166  * @cliexcmd{set dpdk interface hqos tctbl GigabitEthernet0/8/0 entry 16 tc 2 queue 2}
1167 ?*/
1168 /* *INDENT-OFF* */
1169 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_tctbl, static) = {
1170   .path = "set dpdk interface hqos tctbl",
1171   .short_help = "set dpdk interface hqos tctbl <interface> entry <map_val> tc <tc_id> queue <queue_id>",
1172   .function = set_dpdk_if_hqos_tctbl,
1173 };
1174 /* *INDENT-ON* */
1175
1176 static clib_error_t *
1177 set_dpdk_if_hqos_pktfield (vlib_main_t * vm, unformat_input_t * input,
1178                            vlib_cli_command_t * cmd)
1179 {
1180   unformat_input_t _line_input, *line_input = &_line_input;
1181   vlib_thread_main_t *tm = vlib_get_thread_main ();
1182   dpdk_main_t *dm = &dpdk_main;
1183   clib_error_t *error = NULL;
1184
1185   /* Device specific data */
1186   struct rte_eth_dev_info dev_info;
1187   dpdk_device_config_t *devconf = 0;
1188   vnet_hw_interface_t *hw;
1189   dpdk_device_t *xd;
1190   u32 hw_if_index = (u32) ~ 0;
1191
1192   /* Detect the set of worker threads */
1193   uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1194   /* Should never happen, shut up Coverity warning */
1195   if (p == 0)
1196     return clib_error_return (0, "no worker registrations?");
1197
1198   vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0];
1199   int worker_thread_first = tr->first_index;
1200   int worker_thread_count = tr->count;
1201
1202   /* Packet field configuration */
1203   u64 mask = (u64) ~ 0;
1204   u32 id = (u32) ~ 0;
1205   u32 offset = (u32) ~ 0;
1206
1207   /* HQoS params */
1208   u32 n_subports_per_port, n_pipes_per_subport, tctbl_size;
1209
1210   u32 i;
1211
1212   /* Parse input arguments */
1213   if (!unformat_user (input, unformat_line_input, line_input))
1214     return 0;
1215
1216   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1217     {
1218       if (unformat
1219           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
1220            &hw_if_index))
1221         ;
1222       else if (unformat (line_input, "id subport"))
1223         id = 0;
1224       else if (unformat (line_input, "id pipe"))
1225         id = 1;
1226       else if (unformat (line_input, "id tc"))
1227         id = 2;
1228       else if (unformat (line_input, "id %d", &id))
1229         ;
1230       else if (unformat (line_input, "offset %d", &offset))
1231         ;
1232       else if (unformat (line_input, "mask %llx", &mask))
1233         ;
1234       else
1235         {
1236           error = clib_error_return (0, "parse error: '%U'",
1237                                      format_unformat_error, line_input);
1238           goto done;
1239         }
1240     }
1241
1242   /* Get interface */
1243   if (hw_if_index == (u32) ~ 0)
1244     {
1245       error = clib_error_return (0, "please specify valid interface name");
1246       goto done;
1247     }
1248
1249   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
1250   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
1251
1252   rte_eth_dev_info_get (xd->device_index, &dev_info);
1253   if (dev_info.pci_dev)
1254     {                           /* bonded interface has no pci info */
1255       vlib_pci_addr_t pci_addr;
1256
1257       pci_addr.domain = dev_info.pci_dev->addr.domain;
1258       pci_addr.bus = dev_info.pci_dev->addr.bus;
1259       pci_addr.slot = dev_info.pci_dev->addr.devid;
1260       pci_addr.function = dev_info.pci_dev->addr.function;
1261
1262       p =
1263         hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
1264     }
1265
1266   if (p)
1267     devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]);
1268   else
1269     devconf = &dm->conf->default_devconf;
1270
1271   if (devconf->hqos_enabled == 0)
1272     {
1273       vlib_cli_output (vm, "HQoS disabled for this interface");
1274       goto done;
1275     }
1276
1277   n_subports_per_port = devconf->hqos.port.n_subports_per_port;
1278   n_pipes_per_subport = devconf->hqos.port.n_pipes_per_subport;
1279   tctbl_size = RTE_DIM (devconf->hqos.tc_table);
1280
1281   /* Validate packet field configuration: id, offset and mask */
1282   if (id >= 3)
1283     {
1284       error = clib_error_return (0, "invalid packet field id");
1285       goto done;
1286     }
1287
1288   switch (id)
1289     {
1290     case 0:
1291       if (dpdk_hqos_validate_mask (mask, n_subports_per_port) != 0)
1292         {
1293           error = clib_error_return (0, "invalid subport ID mask "
1294                                      "(n_subports_per_port = %u)",
1295                                      n_subports_per_port);
1296           goto done;
1297         }
1298       break;
1299     case 1:
1300       if (dpdk_hqos_validate_mask (mask, n_pipes_per_subport) != 0)
1301         {
1302           error = clib_error_return (0, "invalid pipe ID mask "
1303                                      "(n_pipes_per_subport = %u)",
1304                                      n_pipes_per_subport);
1305           goto done;
1306         }
1307       break;
1308     case 2:
1309     default:
1310       if (dpdk_hqos_validate_mask (mask, tctbl_size) != 0)
1311         {
1312           error = clib_error_return (0, "invalid TC table index mask "
1313                                      "(TC table size = %u)", tctbl_size);
1314           goto done;
1315         }
1316     }
1317
1318   /* Propagate packet field configuration to all workers */
1319   for (i = 0; i < worker_thread_count; i++)
1320     switch (id)
1321       {
1322       case 0:
1323         xd->hqos_wt[worker_thread_first + i].hqos_field0_slabpos = offset;
1324         xd->hqos_wt[worker_thread_first + i].hqos_field0_slabmask = mask;
1325         xd->hqos_wt[worker_thread_first + i].hqos_field0_slabshr =
1326           count_trailing_zeros (mask);
1327         break;
1328       case 1:
1329         xd->hqos_wt[worker_thread_first + i].hqos_field1_slabpos = offset;
1330         xd->hqos_wt[worker_thread_first + i].hqos_field1_slabmask = mask;
1331         xd->hqos_wt[worker_thread_first + i].hqos_field1_slabshr =
1332           count_trailing_zeros (mask);
1333         break;
1334       case 2:
1335       default:
1336         xd->hqos_wt[worker_thread_first + i].hqos_field2_slabpos = offset;
1337         xd->hqos_wt[worker_thread_first + i].hqos_field2_slabmask = mask;
1338         xd->hqos_wt[worker_thread_first + i].hqos_field2_slabshr =
1339           count_trailing_zeros (mask);
1340       }
1341
1342 done:
1343   unformat_free (line_input);
1344
1345   return error;
1346 }
1347
1348 /*?
1349  * This command is used to set the packet fields required for classifiying the
1350  * incoming packet. As a result of classification process, packet field
1351  * information will be mapped to 5 tuples (subport, pipe, traffic class, pipe,
1352  * color) and stored in packet mbuf.
1353  *
1354  * This command has the following parameters:
1355  *
1356  * - <b><interface></b> - Used to specify the output interface.
1357  *
1358  * - <b>id subport|pipe|tc</b> - Classification occurs across three fields.
1359  * This parameter indicates which of the three masks are being configured. Legacy
1360  * code used 0-2 to represent these three fields, so 0-2 is still accepted.
1361  *   - <b>subport|0</b> - Currently only one subport is supported, so only
1362  * an empty mask is supported for the subport classification.
1363  *   - <b>pipe|1</b> - Currently, 4096 pipes per subport are supported, so a
1364  * 12-bit mask should be configure to map to the 0-4095 pipes.
1365  *   - <b>tc|2</b> - The translation table (see '<em>set dpdk interface hqos
1366  * tctbl</em>' command) maps each value (0-63) into one of the 4 traffic classes
1367  * per pipe. A 6-bit mask should be configure to map this field to a traffic class.
1368  *
1369  * - <b>offset <n></b> - Offset in the packet to apply the 64-bit mask for classification.
1370  * The offset should be on an 8-byte boundary (0,8,16,24..).
1371  *
1372  * - <b>mask <hex-mask></b> - 64-bit mask to apply to packet at the given '<em>offset</em>'.
1373  * Bits must be contiguous and should not include '<em>0x</em>'.
1374  *
1375  * The default values for the '<em>pktfield</em>' assumes Ethernet/IPv4/UDP packets with
1376  * no VLAN. Adjust based on expected packet format and desired classification field.
1377  * - '<em>subport</em>' is always empty (offset 0 mask 0000000000000000)
1378  * - By default, '<em>pipe</em>' maps to the UDP payload bits 12 .. 23 (offset 40
1379  * mask 0000000fff000000)
1380  * - By default, '<em>tc</em>' maps to the DSCP field in IP header (offset 48 mask
1381  * 00000000000000fc)
1382  *
1383  * @cliexpar
1384  * Example of how modify the '<em>pipe</em>' classification filter to match VLAN:
1385  * @cliexcmd{set dpdk interface hqos pktfield GigabitEthernet0/8/0 id pipe offset 8 mask 0000000000000FFF}
1386 ?*/
1387 /* *INDENT-OFF* */
1388 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_pktfield, static) = {
1389   .path = "set dpdk interface hqos pktfield",
1390   .short_help = "set dpdk interface hqos pktfield <interface> id subport|pipe|tc offset <n> "
1391                  "mask <hex-mask>",
1392   .function = set_dpdk_if_hqos_pktfield,
1393 };
1394 /* *INDENT-ON* */
1395
1396 static clib_error_t *
1397 show_dpdk_if_hqos (vlib_main_t * vm, unformat_input_t * input,
1398                    vlib_cli_command_t * cmd)
1399 {
1400   unformat_input_t _line_input, *line_input = &_line_input;
1401   vlib_thread_main_t *tm = vlib_get_thread_main ();
1402   dpdk_main_t *dm = &dpdk_main;
1403   vnet_hw_interface_t *hw;
1404   dpdk_device_t *xd;
1405   dpdk_device_config_hqos_t *cfg;
1406   dpdk_device_hqos_per_hqos_thread_t *ht;
1407   dpdk_device_hqos_per_worker_thread_t *wk;
1408   u32 *tctbl;
1409   u32 hw_if_index = (u32) ~ 0;
1410   u32 profile_id, subport_id, i;
1411   struct rte_eth_dev_info dev_info;
1412   dpdk_device_config_t *devconf = 0;
1413   vlib_thread_registration_t *tr;
1414   uword *p = 0;
1415   clib_error_t *error = NULL;
1416
1417   if (!unformat_user (input, unformat_line_input, line_input))
1418     return 0;
1419
1420   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1421     {
1422       if (unformat
1423           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
1424            &hw_if_index))
1425         ;
1426       else
1427         {
1428           error = clib_error_return (0, "parse error: '%U'",
1429                                      format_unformat_error, line_input);
1430           goto done;
1431         }
1432     }
1433
1434   if (hw_if_index == (u32) ~ 0)
1435     {
1436       error = clib_error_return (0, "please specify interface name!!");
1437       goto done;
1438     }
1439
1440   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
1441   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
1442
1443   rte_eth_dev_info_get (xd->device_index, &dev_info);
1444   if (dev_info.pci_dev)
1445     {                           /* bonded interface has no pci info */
1446       vlib_pci_addr_t pci_addr;
1447
1448       pci_addr.domain = dev_info.pci_dev->addr.domain;
1449       pci_addr.bus = dev_info.pci_dev->addr.bus;
1450       pci_addr.slot = dev_info.pci_dev->addr.devid;
1451       pci_addr.function = dev_info.pci_dev->addr.function;
1452
1453       p =
1454         hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
1455     }
1456
1457   if (p)
1458     devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]);
1459   else
1460     devconf = &dm->conf->default_devconf;
1461
1462   if (devconf->hqos_enabled == 0)
1463     {
1464       vlib_cli_output (vm, "HQoS disabled for this interface");
1465       goto done;
1466     }
1467
1468   /* Detect the set of worker threads */
1469   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1470
1471   /* Should never happen, shut up Coverity warning */
1472   if (p == 0)
1473     {
1474       error = clib_error_return (0, "no worker registrations?");
1475       goto done;
1476     }
1477
1478   tr = (vlib_thread_registration_t *) p[0];
1479
1480   cfg = &devconf->hqos;
1481   ht = xd->hqos_ht;
1482   wk = &xd->hqos_wt[tr->first_index];
1483   tctbl = wk->hqos_tc_table;
1484
1485   vlib_cli_output (vm, " Thread:");
1486   vlib_cli_output (vm, "   Input SWQ size = %u packets", cfg->swq_size);
1487   vlib_cli_output (vm, "   Enqueue burst size = %u packets",
1488                    ht->hqos_burst_enq);
1489   vlib_cli_output (vm, "   Dequeue burst size = %u packets",
1490                    ht->hqos_burst_deq);
1491
1492   vlib_cli_output (vm,
1493                    "   Packet field 0: slab position = %4u, slab bitmask = 0x%016llx   (subport)",
1494                    wk->hqos_field0_slabpos, wk->hqos_field0_slabmask);
1495   vlib_cli_output (vm,
1496                    "   Packet field 1: slab position = %4u, slab bitmask = 0x%016llx   (pipe)",
1497                    wk->hqos_field1_slabpos, wk->hqos_field1_slabmask);
1498   vlib_cli_output (vm,
1499                    "   Packet field 2: slab position = %4u, slab bitmask = 0x%016llx   (tc)",
1500                    wk->hqos_field2_slabpos, wk->hqos_field2_slabmask);
1501   vlib_cli_output (vm,
1502                    "   Packet field 2  tc translation table: ([Mapped Value Range]: tc/queue tc/queue ...)");
1503   vlib_cli_output (vm,
1504                    "     [ 0 .. 15]: "
1505                    "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u",
1506                    tctbl[0] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1507                    tctbl[0] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1508                    tctbl[1] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1509                    tctbl[1] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1510                    tctbl[2] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1511                    tctbl[2] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1512                    tctbl[3] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1513                    tctbl[3] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1514                    tctbl[4] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1515                    tctbl[4] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1516                    tctbl[5] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1517                    tctbl[5] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1518                    tctbl[6] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1519                    tctbl[6] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1520                    tctbl[7] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1521                    tctbl[7] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1522                    tctbl[8] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1523                    tctbl[8] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1524                    tctbl[9] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1525                    tctbl[9] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1526                    tctbl[10] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1527                    tctbl[10] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1528                    tctbl[11] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1529                    tctbl[11] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1530                    tctbl[12] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1531                    tctbl[12] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1532                    tctbl[13] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1533                    tctbl[13] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1534                    tctbl[14] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1535                    tctbl[14] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1536                    tctbl[15] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1537                    tctbl[15] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS);
1538   vlib_cli_output (vm,
1539                    "     [16 .. 31]: "
1540                    "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u",
1541                    tctbl[16] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1542                    tctbl[16] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1543                    tctbl[17] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1544                    tctbl[17] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1545                    tctbl[18] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1546                    tctbl[18] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1547                    tctbl[19] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1548                    tctbl[19] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1549                    tctbl[20] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1550                    tctbl[20] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1551                    tctbl[21] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1552                    tctbl[21] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1553                    tctbl[22] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1554                    tctbl[22] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1555                    tctbl[23] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1556                    tctbl[23] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1557                    tctbl[24] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1558                    tctbl[24] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1559                    tctbl[25] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1560                    tctbl[25] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1561                    tctbl[26] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1562                    tctbl[26] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1563                    tctbl[27] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1564                    tctbl[27] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1565                    tctbl[28] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1566                    tctbl[28] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1567                    tctbl[29] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1568                    tctbl[29] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1569                    tctbl[30] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1570                    tctbl[30] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1571                    tctbl[31] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1572                    tctbl[31] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS);
1573   vlib_cli_output (vm,
1574                    "     [32 .. 47]: "
1575                    "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u",
1576                    tctbl[32] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1577                    tctbl[32] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1578                    tctbl[33] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1579                    tctbl[33] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1580                    tctbl[34] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1581                    tctbl[34] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1582                    tctbl[35] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1583                    tctbl[35] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1584                    tctbl[36] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1585                    tctbl[36] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1586                    tctbl[37] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1587                    tctbl[37] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1588                    tctbl[38] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1589                    tctbl[38] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1590                    tctbl[39] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1591                    tctbl[39] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1592                    tctbl[40] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1593                    tctbl[40] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1594                    tctbl[41] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1595                    tctbl[41] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1596                    tctbl[42] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1597                    tctbl[42] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1598                    tctbl[43] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1599                    tctbl[43] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1600                    tctbl[44] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1601                    tctbl[44] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1602                    tctbl[45] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1603                    tctbl[45] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1604                    tctbl[46] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1605                    tctbl[46] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1606                    tctbl[47] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1607                    tctbl[47] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS);
1608   vlib_cli_output (vm,
1609                    "     [48 .. 63]: "
1610                    "%u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u %u/%u",
1611                    tctbl[48] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1612                    tctbl[48] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1613                    tctbl[49] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1614                    tctbl[49] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1615                    tctbl[50] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1616                    tctbl[50] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1617                    tctbl[51] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1618                    tctbl[51] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1619                    tctbl[52] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1620                    tctbl[52] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1621                    tctbl[53] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1622                    tctbl[53] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1623                    tctbl[54] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1624                    tctbl[54] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1625                    tctbl[55] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1626                    tctbl[55] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1627                    tctbl[56] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1628                    tctbl[56] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1629                    tctbl[57] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1630                    tctbl[57] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1631                    tctbl[58] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1632                    tctbl[58] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1633                    tctbl[59] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1634                    tctbl[59] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1635                    tctbl[60] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1636                    tctbl[60] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1637                    tctbl[61] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1638                    tctbl[61] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1639                    tctbl[62] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1640                    tctbl[62] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1641                    tctbl[63] / RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS,
1642                    tctbl[63] % RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS);
1643   vlib_cli_output (vm, " Port:");
1644   vlib_cli_output (vm, "   Rate = %u bytes/second", cfg->port.rate);
1645   vlib_cli_output (vm, "   MTU = %u bytes", cfg->port.mtu);
1646   vlib_cli_output (vm, "   Frame overhead = %u bytes",
1647                    cfg->port.frame_overhead);
1648   vlib_cli_output (vm, "   Number of subports = %u",
1649                    cfg->port.n_subports_per_port);
1650   vlib_cli_output (vm, "   Number of pipes per subport = %u",
1651                    cfg->port.n_pipes_per_subport);
1652   vlib_cli_output (vm,
1653                    "   Packet queue size: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u packets",
1654                    cfg->port.qsize[0], cfg->port.qsize[1], cfg->port.qsize[2],
1655                    cfg->port.qsize[3]);
1656   vlib_cli_output (vm, "   Number of pipe profiles = %u",
1657                    cfg->port.n_pipe_profiles);
1658
1659   for (subport_id = 0; subport_id < vec_len (cfg->subport); subport_id++)
1660     {
1661       vlib_cli_output (vm, " Subport %u:", subport_id);
1662       vlib_cli_output (vm, "   Rate = %u bytes/second",
1663                        cfg->subport[subport_id].tb_rate);
1664       vlib_cli_output (vm, "   Token bucket size = %u bytes",
1665                        cfg->subport[subport_id].tb_size);
1666       vlib_cli_output (vm,
1667                        "   Traffic class rate: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u bytes/second",
1668                        cfg->subport[subport_id].tc_rate[0],
1669                        cfg->subport[subport_id].tc_rate[1],
1670                        cfg->subport[subport_id].tc_rate[2],
1671                        cfg->subport[subport_id].tc_rate[3]);
1672       vlib_cli_output (vm, "   TC period = %u milliseconds",
1673                        cfg->subport[subport_id].tc_period);
1674     }
1675
1676   for (profile_id = 0; profile_id < vec_len (cfg->pipe); profile_id++)
1677     {
1678       vlib_cli_output (vm, " Pipe profile %u:", profile_id);
1679       vlib_cli_output (vm, "   Rate = %u bytes/second",
1680                        cfg->pipe[profile_id].tb_rate);
1681       vlib_cli_output (vm, "   Token bucket size = %u bytes",
1682                        cfg->pipe[profile_id].tb_size);
1683       vlib_cli_output (vm,
1684                        "   Traffic class rate: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u bytes/second",
1685                        cfg->pipe[profile_id].tc_rate[0],
1686                        cfg->pipe[profile_id].tc_rate[1],
1687                        cfg->pipe[profile_id].tc_rate[2],
1688                        cfg->pipe[profile_id].tc_rate[3]);
1689       vlib_cli_output (vm, "   TC period = %u milliseconds",
1690                        cfg->pipe[profile_id].tc_period);
1691 #ifdef RTE_SCHED_SUBPORT_TC_OV
1692       vlib_cli_output (vm, "   TC3 oversubscription_weight = %u",
1693                        cfg->pipe[profile_id].tc_ov_weight);
1694 #endif
1695
1696       for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
1697         {
1698           vlib_cli_output (vm,
1699                            "   TC%u WRR weights: Q0 = %u, Q1 = %u, Q2 = %u, Q3 = %u",
1700                            i, cfg->pipe[profile_id].wrr_weights[i * 4],
1701                            cfg->pipe[profile_id].wrr_weights[i * 4 + 1],
1702                            cfg->pipe[profile_id].wrr_weights[i * 4 + 2],
1703                            cfg->pipe[profile_id].wrr_weights[i * 4 + 3]);
1704         }
1705     }
1706
1707 #ifdef RTE_SCHED_RED
1708   vlib_cli_output (vm, " Weighted Random Early Detection (WRED):");
1709   for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
1710     {
1711       vlib_cli_output (vm, "   TC%u min: G = %u, Y = %u, R = %u", i,
1712                        cfg->port.red_params[i][e_RTE_METER_GREEN].min_th,
1713                        cfg->port.red_params[i][e_RTE_METER_YELLOW].min_th,
1714                        cfg->port.red_params[i][e_RTE_METER_RED].min_th);
1715
1716       vlib_cli_output (vm, "   TC%u max: G = %u, Y = %u, R = %u", i,
1717                        cfg->port.red_params[i][e_RTE_METER_GREEN].max_th,
1718                        cfg->port.red_params[i][e_RTE_METER_YELLOW].max_th,
1719                        cfg->port.red_params[i][e_RTE_METER_RED].max_th);
1720
1721       vlib_cli_output (vm,
1722                        "   TC%u inverted probability: G = %u, Y = %u, R = %u",
1723                        i, cfg->port.red_params[i][e_RTE_METER_GREEN].maxp_inv,
1724                        cfg->port.red_params[i][e_RTE_METER_YELLOW].maxp_inv,
1725                        cfg->port.red_params[i][e_RTE_METER_RED].maxp_inv);
1726
1727       vlib_cli_output (vm, "   TC%u weight: R = %u, Y = %u, R = %u", i,
1728                        cfg->port.red_params[i][e_RTE_METER_GREEN].wq_log2,
1729                        cfg->port.red_params[i][e_RTE_METER_YELLOW].wq_log2,
1730                        cfg->port.red_params[i][e_RTE_METER_RED].wq_log2);
1731     }
1732 #endif
1733
1734 done:
1735   unformat_free (line_input);
1736
1737   return error;
1738 }
1739
1740 /*?
1741  * This command is used to display details of an output interface's HQoS
1742  * settings.
1743  *
1744  * @cliexpar
1745  * Example of how to display HQoS settings for an interfaces:
1746  * @cliexstart{show dpdk interface hqos GigabitEthernet0/8/0}
1747  *  Thread:
1748  *    Input SWQ size = 4096 packets
1749  *    Enqueue burst size = 256 packets
1750  *    Dequeue burst size = 220 packets
1751  *    Packet field 0: slab position =    0, slab bitmask = 0x0000000000000000   (subport)
1752  *    Packet field 1: slab position =   40, slab bitmask = 0x0000000fff000000   (pipe)
1753  *    Packet field 2: slab position =    8, slab bitmask = 0x00000000000000fc   (tc)
1754  *    Packet field 2  tc translation table: ([Mapped Value Range]: tc/queue tc/queue ...)
1755  *      [ 0 .. 15]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3
1756  *      [16 .. 31]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3
1757  *      [32 .. 47]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3
1758  *      [48 .. 63]: 0/0 0/1 0/2 0/3 1/0 1/1 1/2 1/3 2/0 2/1 2/2 2/3 3/0 3/1 3/2 3/3
1759  *  Port:
1760  *    Rate = 1250000000 bytes/second
1761  *    MTU = 1514 bytes
1762  *    Frame overhead = 24 bytes
1763  *    Number of subports = 1
1764  *    Number of pipes per subport = 4096
1765  *    Packet queue size: TC0 = 64, TC1 = 64, TC2 = 64, TC3 = 64 packets
1766  *    Number of pipe profiles = 2
1767  *  Subport 0:
1768  *    Rate = 1250000000 bytes/second
1769  *    Token bucket size = 1000000 bytes
1770  *    Traffic class rate: TC0 = 1250000000, TC1 = 1250000000, TC2 = 1250000000, TC3 = 1250000000 bytes/second
1771  *    TC period = 10 milliseconds
1772  *  Pipe profile 0:
1773  *    Rate = 305175 bytes/second
1774  *    Token bucket size = 1000000 bytes
1775  *    Traffic class rate: TC0 = 305175, TC1 = 305175, TC2 = 305175, TC3 = 305175 bytes/second
1776  *    TC period = 40 milliseconds
1777  *    TC0 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1
1778  *    TC1 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1
1779  *    TC2 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1
1780  *    TC3 WRR weights: Q0 = 1, Q1 = 1, Q2 = 1, Q3 = 1
1781  * @cliexend
1782 ?*/
1783 /* *INDENT-OFF* */
1784 VLIB_CLI_COMMAND (cmd_show_dpdk_if_hqos, static) = {
1785   .path = "show dpdk interface hqos",
1786   .short_help = "show dpdk interface hqos <interface>",
1787   .function = show_dpdk_if_hqos,
1788 };
1789
1790 /* *INDENT-ON* */
1791
1792 static clib_error_t *
1793 show_dpdk_hqos_queue_stats (vlib_main_t * vm, unformat_input_t * input,
1794                             vlib_cli_command_t * cmd)
1795 {
1796   unformat_input_t _line_input, *line_input = &_line_input;
1797   clib_error_t *error = NULL;
1798 #ifdef RTE_SCHED_COLLECT_STATS
1799   dpdk_main_t *dm = &dpdk_main;
1800   u32 hw_if_index = (u32) ~ 0;
1801   u32 subport = (u32) ~ 0;
1802   u32 pipe = (u32) ~ 0;
1803   u32 tc = (u32) ~ 0;
1804   u32 tc_q = (u32) ~ 0;
1805   vnet_hw_interface_t *hw;
1806   dpdk_device_t *xd;
1807   uword *p = 0;
1808   struct rte_eth_dev_info dev_info;
1809   dpdk_device_config_t *devconf = 0;
1810   u32 qindex;
1811   struct rte_sched_queue_stats stats;
1812   u16 qlen;
1813
1814   if (!unformat_user (input, unformat_line_input, line_input))
1815     return 0;
1816
1817   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1818     {
1819       if (unformat
1820           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
1821            &hw_if_index))
1822         ;
1823
1824       else if (unformat (line_input, "subport %d", &subport))
1825         ;
1826
1827       else if (unformat (line_input, "pipe %d", &pipe))
1828         ;
1829
1830       else if (unformat (line_input, "tc %d", &tc))
1831         ;
1832
1833       else if (unformat (line_input, "tc_q %d", &tc_q))
1834         ;
1835
1836       else
1837         {
1838           error = clib_error_return (0, "parse error: '%U'",
1839                                      format_unformat_error, line_input);
1840           goto done;
1841         }
1842     }
1843
1844   if (hw_if_index == (u32) ~ 0)
1845     {
1846       error = clib_error_return (0, "please specify interface name!!");
1847       goto done;
1848     }
1849
1850   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
1851   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
1852
1853   rte_eth_dev_info_get (xd->device_index, &dev_info);
1854   if (dev_info.pci_dev)
1855     {                           /* bonded interface has no pci info */
1856       vlib_pci_addr_t pci_addr;
1857
1858       pci_addr.domain = dev_info.pci_dev->addr.domain;
1859       pci_addr.bus = dev_info.pci_dev->addr.bus;
1860       pci_addr.slot = dev_info.pci_dev->addr.devid;
1861       pci_addr.function = dev_info.pci_dev->addr.function;
1862
1863       p =
1864         hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
1865     }
1866
1867   if (p)
1868     devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]);
1869   else
1870     devconf = &dm->conf->default_devconf;
1871
1872   if (devconf->hqos_enabled == 0)
1873     {
1874       vlib_cli_output (vm, "HQoS disabled for this interface");
1875       goto done;
1876     }
1877
1878   /*
1879    * Figure out which queue to query.  cf rte_sched_port_qindex.  (Not sure why
1880    * that method isn't made public by DPDK - how _should_ we get the queue ID?)
1881    */
1882   qindex = subport * devconf->hqos.port.n_pipes_per_subport + pipe;
1883   qindex = qindex * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE + tc;
1884   qindex = qindex * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + tc_q;
1885
1886   if (rte_sched_queue_read_stats (xd->hqos_ht->hqos, qindex, &stats, &qlen) !=
1887       0)
1888     {
1889       error = clib_error_return (0, "failed to read stats");
1890       goto done;
1891     }
1892
1893   vlib_cli_output (vm, "%=24s%=16s", "Stats Parameter", "Value");
1894   vlib_cli_output (vm, "%=24s%=16d", "Packets", stats.n_pkts);
1895   vlib_cli_output (vm, "%=24s%=16d", "Packets dropped", stats.n_pkts_dropped);
1896 #ifdef RTE_SCHED_RED
1897   vlib_cli_output (vm, "%=24s%=16d", "Packets dropped (RED)",
1898                    stats.n_pkts_red_dropped);
1899 #endif
1900   vlib_cli_output (vm, "%=24s%=16d", "Bytes", stats.n_bytes);
1901   vlib_cli_output (vm, "%=24s%=16d", "Bytes dropped", stats.n_bytes_dropped);
1902
1903 #else
1904
1905   /* Get a line of input */
1906   if (!unformat_user (input, unformat_line_input, line_input))
1907     return 0;
1908
1909   vlib_cli_output (vm, "RTE_SCHED_COLLECT_STATS disabled in DPDK");
1910   goto done;
1911
1912 #endif
1913
1914 done:
1915   unformat_free (line_input);
1916
1917   return error;
1918 }
1919
1920 /*?
1921  * This command is used to display statistics associated with a HQoS traffic class
1922  * queue.
1923  *
1924  * @note
1925  * Statistic collection by the scheduler is disabled by default in DPDK. In order to
1926  * turn it on, add the following line to '<em>../vpp/dpdk/Makefile</em>':
1927  * - <b>$(call set,RTE_SCHED_COLLECT_STATS,y)</b>
1928  *
1929  * @cliexpar
1930  * Example of how to display statistics of HQoS a HQoS traffic class queue:
1931  * @cliexstart{show dpdk hqos queue GigabitEthernet0/9/0 subport 0 pipe 3181 tc 0 tc_q 0}
1932  *      Stats Parameter          Value
1933  *          Packets               140
1934  *      Packets dropped            0
1935  *           Bytes               8400
1936  *       Bytes dropped             0
1937  * @cliexend
1938 ?*/
1939 /* *INDENT-OFF* */
1940 VLIB_CLI_COMMAND (cmd_show_dpdk_hqos_queue_stats, static) = {
1941   .path = "show dpdk hqos queue",
1942   .short_help = "show dpdk hqos queue <interface> subport <subport_id> pipe <pipe_id> tc <tc_id> tc_q <queue_id>",
1943   .function = show_dpdk_hqos_queue_stats,
1944 };
1945 /* *INDENT-ON* */
1946
1947 static clib_error_t *
1948 show_dpdk_version_command_fn (vlib_main_t * vm,
1949                               unformat_input_t * input,
1950                               vlib_cli_command_t * cmd)
1951 {
1952 #define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c);
1953   _("DPDK Version", "%s", rte_version ());
1954   _("DPDK EAL init args", "%s", dpdk_config_main.eal_init_args_str);
1955 #undef _
1956   return 0;
1957 }
1958
1959 /*?
1960  * This command is used to display the current DPDK version and
1961  * the list of arguments passed to DPDK when started.
1962  *
1963  * @cliexpar
1964  * Example of how to display how many DPDK buffer test command has allcoated:
1965  * @cliexstart{show dpdk version}
1966  * DPDK Version:        DPDK 16.11.0
1967  * DPDK EAL init args:  -c 1 -n 4 --huge-dir /run/vpp/hugepages --file-prefix vpp -w 0000:00:08.0 -w 0000:00:09.0 --master-lcore 0 --socket-mem 256
1968  * @cliexend
1969 ?*/
1970 /* *INDENT-OFF* */
1971 VLIB_CLI_COMMAND (show_vpe_version_command, static) = {
1972   .path = "show dpdk version",
1973   .short_help = "show dpdk version",
1974   .function = show_dpdk_version_command_fn,
1975 };
1976 /* *INDENT-ON* */
1977
1978 #if CLI_DEBUG
1979
1980 static clib_error_t *
1981 dpdk_validate_buffers_fn (vlib_main_t * vm, unformat_input_t * input,
1982                           vlib_cli_command_t * cmd_arg)
1983 {
1984   u32 n_invalid_bufs = 0, uninitialized = 0;
1985   u32 is_poison = 0, is_test = 0;
1986   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1987     {
1988       if (unformat (input, "poison"))
1989         is_poison = 1;
1990       else if (unformat (input, "trajectory"))
1991         is_test = 1;
1992       else
1993         return clib_error_return (0, "unknown input `%U'",
1994                                   format_unformat_error, input);
1995     }
1996
1997   if (VLIB_BUFFER_TRACE_TRAJECTORY == 0)
1998     {
1999       vlib_cli_output (vm, "Trajectory not enabled. Recompile with "
2000                        "VLIB_BUFFER_TRACE_TRAJECTORY 1");
2001       return 0;
2002     }
2003   if (is_poison)
2004     {
2005       dpdk_buffer_poison_trajectory_all ();
2006     }
2007   if (is_test)
2008     {
2009       n_invalid_bufs = dpdk_buffer_validate_trajectory_all (&uninitialized);
2010       if (!n_invalid_bufs)
2011         vlib_cli_output (vm, "All buffers are valid %d uninitialized",
2012                          uninitialized);
2013       else
2014         vlib_cli_output (vm, "Found %d invalid buffers and %d uninitialized",
2015                          n_invalid_bufs, uninitialized);
2016     }
2017   return 0;
2018 }
2019
2020 /* *INDENT-OFF* */
2021 VLIB_CLI_COMMAND (test_dpdk_buffers_command, static) =
2022 {
2023   .path = "test dpdk buffers",
2024   .short_help = "test dpdk buffers [poison] [trajectory]",
2025   .function = dpdk_validate_buffers_fn,
2026 };
2027 /* *INDENT-ON* */
2028
2029 #endif
2030
2031 clib_error_t *
2032 dpdk_cli_init (vlib_main_t * vm)
2033 {
2034   return 0;
2035 }
2036
2037 VLIB_INIT_FUNCTION (dpdk_cli_init);
2038
2039 /*
2040  * fd.io coding-style-patch-verification: ON
2041  *
2042  * Local Variables:
2043  * eval: (c-set-style "gnu")
2044  * End:
2045  */