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