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