Reorganize source tree to use single autotools instance
[vpp.git] / src / vnet / devices / dpdk / 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 #include <vnet/vnet.h>
16 #include <vppinfra/vec.h>
17 #include <vppinfra/error.h>
18 #include <vppinfra/format.h>
19 #include <vppinfra/xxhash.h>
20
21 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/devices/dpdk/dpdk.h>
23 #include <vnet/classify/vnet_classify.h>
24 #include <vnet/mpls/packet.h>
25
26 #include "dpdk_priv.h"
27
28 static clib_error_t *
29 pcap_trace_command_fn (vlib_main_t * vm,
30                        unformat_input_t * input, vlib_cli_command_t * cmd)
31 {
32   dpdk_main_t *dm = &dpdk_main;
33   u8 *filename;
34   u32 max;
35   int matched = 0;
36   clib_error_t *error = 0;
37
38   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
39     {
40       if (unformat (input, "on"))
41         {
42           if (dm->tx_pcap_enable == 0)
43             {
44               if (dm->pcap_filename == 0)
45                 dm->pcap_filename = format (0, "/tmp/vpe.pcap%c", 0);
46
47               memset (&dm->pcap_main, 0, sizeof (dm->pcap_main));
48               dm->pcap_main.file_name = (char *) dm->pcap_filename;
49               dm->pcap_main.n_packets_to_capture = 100;
50               if (dm->pcap_pkts_to_capture)
51                 dm->pcap_main.n_packets_to_capture = dm->pcap_pkts_to_capture;
52
53               dm->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
54               dm->tx_pcap_enable = 1;
55               matched = 1;
56               vlib_cli_output (vm, "pcap tx capture on...");
57             }
58           else
59             {
60               vlib_cli_output (vm, "pcap tx capture already on...");
61             }
62           matched = 1;
63         }
64       else if (unformat (input, "off"))
65         {
66           if (dm->tx_pcap_enable)
67             {
68               vlib_cli_output (vm, "captured %d pkts...",
69                                dm->pcap_main.n_packets_captured + 1);
70               if (dm->pcap_main.n_packets_captured)
71                 {
72                   dm->pcap_main.n_packets_to_capture =
73                     dm->pcap_main.n_packets_captured;
74                   error = pcap_write (&dm->pcap_main);
75                   if (error)
76                     clib_error_report (error);
77                   else
78                     vlib_cli_output (vm, "saved to %s...", dm->pcap_filename);
79                 }
80             }
81           else
82             {
83               vlib_cli_output (vm, "pcap tx capture already off...");
84             }
85
86           dm->tx_pcap_enable = 0;
87           matched = 1;
88         }
89       else if (unformat (input, "max %d", &max))
90         {
91           dm->pcap_pkts_to_capture = max;
92           matched = 1;
93         }
94
95       else if (unformat (input, "intfc %U",
96                          unformat_vnet_sw_interface, dm->vnet_main,
97                          &dm->pcap_sw_if_index))
98         matched = 1;
99       else if (unformat (input, "intfc any"))
100         {
101           dm->pcap_sw_if_index = 0;
102           matched = 1;
103         }
104       else if (unformat (input, "file %s", &filename))
105         {
106           u8 *chroot_filename;
107           /* Brain-police user path input */
108           if (strstr ((char *) filename, "..")
109               || index ((char *) filename, '/'))
110             {
111               vlib_cli_output (vm, "illegal characters in filename '%s'",
112                                filename);
113               continue;
114             }
115
116           chroot_filename = format (0, "/tmp/%s%c", filename, 0);
117           vec_free (filename);
118
119           if (dm->pcap_filename)
120             vec_free (dm->pcap_filename);
121           vec_add1 (filename, 0);
122           dm->pcap_filename = chroot_filename;
123           matched = 1;
124         }
125       else if (unformat (input, "status"))
126         {
127           if (dm->tx_pcap_enable == 0)
128             {
129               vlib_cli_output (vm, "pcap tx capture is off...");
130               continue;
131             }
132
133           vlib_cli_output (vm, "pcap tx capture: %d of %d pkts...",
134                            dm->pcap_main.n_packets_captured,
135                            dm->pcap_main.n_packets_to_capture);
136           matched = 1;
137         }
138
139       else
140         break;
141     }
142
143   if (matched == 0)
144     return clib_error_return (0, "unknown input `%U'",
145                               format_unformat_error, input);
146
147   return 0;
148 }
149
150 /* *INDENT-OFF* */
151 VLIB_CLI_COMMAND (pcap_trace_command, static) = {
152     .path = "pcap tx trace",
153     .short_help =
154     "pcap tx trace on off max <nn> intfc <intfc> file <name> status",
155     .function = pcap_trace_command_fn,
156 };
157 /* *INDENT-ON* */
158
159
160 static clib_error_t *
161 show_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input,
162                   vlib_cli_command_t * cmd)
163 {
164   struct rte_mempool *rmp;
165   int i;
166
167   for (i = 0; i < vec_len (vm->buffer_main->pktmbuf_pools); i++)
168     {
169       rmp = vm->buffer_main->pktmbuf_pools[i];
170       if (rmp)
171         {
172           unsigned count = rte_mempool_avail_count (rmp);
173           unsigned free_count = rte_mempool_in_use_count (rmp);
174
175           vlib_cli_output (vm,
176                            "name=\"%s\"  available = %7d allocated = %7d total = %7d\n",
177                            rmp->name, (u32) count, (u32) free_count,
178                            (u32) (count + free_count));
179         }
180       else
181         {
182           vlib_cli_output (vm, "rte_mempool is NULL (!)\n");
183         }
184     }
185   return 0;
186 }
187
188 /* *INDENT-OFF* */
189 VLIB_CLI_COMMAND (cmd_show_dpdk_bufferr,static) = {
190     .path = "show dpdk buffer",
191     .short_help = "show dpdk buffer state",
192     .function = show_dpdk_buffer,
193     .is_mp_safe = 1,
194 };
195 /* *INDENT-ON* */
196
197 static clib_error_t *
198 test_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input,
199                   vlib_cli_command_t * cmd)
200 {
201   static u32 *allocated_buffers;
202   u32 n_alloc = 0;
203   u32 n_free = 0;
204   u32 first, actual_alloc;
205
206   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
207     {
208       if (unformat (input, "allocate %d", &n_alloc))
209         ;
210       else if (unformat (input, "free %d", &n_free))
211         ;
212       else
213         break;
214     }
215
216   if (n_free)
217     {
218       if (vec_len (allocated_buffers) < n_free)
219         return clib_error_return (0, "Can't free %d, only %d allocated",
220                                   n_free, vec_len (allocated_buffers));
221
222       first = vec_len (allocated_buffers) - n_free;
223       vlib_buffer_free (vm, allocated_buffers + first, n_free);
224       _vec_len (allocated_buffers) = first;
225     }
226   if (n_alloc)
227     {
228       first = vec_len (allocated_buffers);
229       vec_validate (allocated_buffers,
230                     vec_len (allocated_buffers) + n_alloc - 1);
231
232       actual_alloc = vlib_buffer_alloc (vm, allocated_buffers + first,
233                                         n_alloc);
234       _vec_len (allocated_buffers) = first + actual_alloc;
235
236       if (actual_alloc < n_alloc)
237         vlib_cli_output (vm, "WARNING: only allocated %d buffers",
238                          actual_alloc);
239     }
240
241   vlib_cli_output (vm, "Currently %d buffers allocated",
242                    vec_len (allocated_buffers));
243
244   if (allocated_buffers && vec_len (allocated_buffers) == 0)
245     vec_free (allocated_buffers);
246
247   return 0;
248 }
249
250 /* *INDENT-OFF* */
251 VLIB_CLI_COMMAND (cmd_test_dpdk_buffer,static) = {
252     .path = "test dpdk buffer",
253     .short_help = "test dpdk buffer [allocate <nn>][free <nn>]",
254     .function = test_dpdk_buffer,
255     .is_mp_safe = 1,
256 };
257 /* *INDENT-ON* */
258
259 static clib_error_t *
260 set_dpdk_if_desc (vlib_main_t * vm, unformat_input_t * input,
261                   vlib_cli_command_t * cmd)
262 {
263   unformat_input_t _line_input, *line_input = &_line_input;
264   dpdk_main_t *dm = &dpdk_main;
265   vnet_hw_interface_t *hw;
266   dpdk_device_t *xd;
267   u32 hw_if_index = (u32) ~ 0;
268   u32 nb_rx_desc = (u32) ~ 0;
269   u32 nb_tx_desc = (u32) ~ 0;
270   clib_error_t *rv;
271
272   if (!unformat_user (input, unformat_line_input, line_input))
273     return 0;
274
275   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
276     {
277       if (unformat
278           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
279            &hw_if_index))
280         ;
281       else if (unformat (line_input, "tx %d", &nb_tx_desc))
282         ;
283       else if (unformat (line_input, "rx %d", &nb_rx_desc))
284         ;
285       else
286         return clib_error_return (0, "parse error: '%U'",
287                                   format_unformat_error, line_input);
288     }
289
290   unformat_free (line_input);
291
292   if (hw_if_index == (u32) ~ 0)
293     return clib_error_return (0, "please specify valid interface name");
294
295   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
296   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
297
298   if ((xd->flags & DPDK_DEVICE_FLAG_PMD) == 0)
299     return clib_error_return (0, "number of descriptors can be set only for "
300                               "physical devices");
301
302   if ((nb_rx_desc == (u32) ~ 0 || nb_rx_desc == xd->nb_rx_desc) &&
303       (nb_tx_desc == (u32) ~ 0 || nb_tx_desc == xd->nb_tx_desc))
304     return clib_error_return (0, "nothing changed");
305
306   if (nb_rx_desc != (u32) ~ 0)
307     xd->nb_rx_desc = nb_rx_desc;
308
309   if (nb_tx_desc != (u32) ~ 0)
310     xd->nb_tx_desc = nb_tx_desc;
311
312   rv = dpdk_port_setup (dm, xd);
313
314   return rv;
315 }
316
317 /* *INDENT-OFF* */
318 VLIB_CLI_COMMAND (cmd_set_dpdk_if_desc,static) = {
319     .path = "set dpdk interface descriptors",
320     .short_help = "set dpdk interface descriptors <if-name> [rx <n>] [tx <n>]",
321     .function = set_dpdk_if_desc,
322 };
323 /* *INDENT-ON* */
324
325 static clib_error_t *
326 show_dpdk_if_placement (vlib_main_t * vm, unformat_input_t * input,
327                         vlib_cli_command_t * cmd)
328 {
329   vlib_thread_main_t *tm = vlib_get_thread_main ();
330   dpdk_main_t *dm = &dpdk_main;
331   dpdk_device_and_queue_t *dq;
332   int cpu;
333
334   if (tm->n_vlib_mains == 1)
335     vlib_cli_output (vm, "All interfaces are handled by main thread");
336
337   for (cpu = 0; cpu < vec_len (dm->devices_by_cpu); cpu++)
338     {
339       if (vec_len (dm->devices_by_cpu[cpu]))
340         vlib_cli_output (vm, "Thread %u (%s at lcore %u):", cpu,
341                          vlib_worker_threads[cpu].name,
342                          vlib_worker_threads[cpu].lcore_id);
343
344       /* *INDENT-OFF* */
345       vec_foreach(dq, dm->devices_by_cpu[cpu])
346         {
347           u32 hw_if_index = dm->devices[dq->device].vlib_hw_if_index;
348           vnet_hw_interface_t * hi =  vnet_get_hw_interface(dm->vnet_main, hw_if_index);
349           vlib_cli_output(vm, "  %v queue %u", hi->name, dq->queue_id);
350         }
351       /* *INDENT-ON* */
352     }
353   return 0;
354 }
355
356 /* *INDENT-OFF* */
357 VLIB_CLI_COMMAND (cmd_show_dpdk_if_placement,static) = {
358     .path = "show dpdk interface placement",
359     .short_help = "show dpdk interface placement",
360     .function = show_dpdk_if_placement,
361 };
362 /* *INDENT-ON* */
363
364 static int
365 dpdk_device_queue_sort (void *a1, void *a2)
366 {
367   dpdk_device_and_queue_t *dq1 = a1;
368   dpdk_device_and_queue_t *dq2 = a2;
369
370   if (dq1->device > dq2->device)
371     return 1;
372   else if (dq1->device < dq2->device)
373     return -1;
374   else if (dq1->queue_id > dq2->queue_id)
375     return 1;
376   else if (dq1->queue_id < dq2->queue_id)
377     return -1;
378   else
379     return 0;
380 }
381
382 static clib_error_t *
383 set_dpdk_if_placement (vlib_main_t * vm, unformat_input_t * input,
384                        vlib_cli_command_t * cmd)
385 {
386   unformat_input_t _line_input, *line_input = &_line_input;
387   dpdk_main_t *dm = &dpdk_main;
388   dpdk_device_and_queue_t *dq;
389   vnet_hw_interface_t *hw;
390   dpdk_device_t *xd;
391   u32 hw_if_index = (u32) ~ 0;
392   u32 queue = (u32) 0;
393   u32 cpu = (u32) ~ 0;
394   int i;
395
396   if (!unformat_user (input, unformat_line_input, line_input))
397     return 0;
398
399   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
400     {
401       if (unformat
402           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
403            &hw_if_index))
404         ;
405       else if (unformat (line_input, "queue %d", &queue))
406         ;
407       else if (unformat (line_input, "thread %d", &cpu))
408         ;
409       else
410         return clib_error_return (0, "parse error: '%U'",
411                                   format_unformat_error, line_input);
412     }
413
414   unformat_free (line_input);
415
416   if (hw_if_index == (u32) ~ 0)
417     return clib_error_return (0, "please specify valid interface name");
418
419   if (cpu < dm->input_cpu_first_index ||
420       cpu >= (dm->input_cpu_first_index + dm->input_cpu_count))
421     return clib_error_return (0, "please specify valid thread id");
422
423   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
424   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
425
426   for (i = 0; i < vec_len (dm->devices_by_cpu); i++)
427     {
428       /* *INDENT-OFF* */
429       vec_foreach(dq, dm->devices_by_cpu[i])
430         {
431           if (hw_if_index == dm->devices[dq->device].vlib_hw_if_index &&
432               queue == dq->queue_id)
433             {
434               if (cpu == i) /* nothing to do */
435                 return 0;
436
437               vec_del1(dm->devices_by_cpu[i], dq - dm->devices_by_cpu[i]);
438               vec_add2(dm->devices_by_cpu[cpu], dq, 1);
439               dq->queue_id = queue;
440               dq->device = xd->device_index;
441               xd->cpu_socket_id_by_queue[queue] =
442                 rte_lcore_to_socket_id(vlib_worker_threads[cpu].lcore_id);
443
444               vec_sort_with_function(dm->devices_by_cpu[i],
445                                      dpdk_device_queue_sort);
446
447               vec_sort_with_function(dm->devices_by_cpu[cpu],
448                                      dpdk_device_queue_sort);
449
450               if (vec_len(dm->devices_by_cpu[i]) == 0)
451                 vlib_node_set_state (vlib_mains[i], dpdk_input_node.index,
452                                      VLIB_NODE_STATE_DISABLED);
453
454               if (vec_len(dm->devices_by_cpu[cpu]) == 1)
455                 vlib_node_set_state (vlib_mains[cpu], dpdk_input_node.index,
456                                      VLIB_NODE_STATE_POLLING);
457
458               return 0;
459             }
460         }
461       /* *INDENT-ON* */
462     }
463
464   return clib_error_return (0, "not found");
465 }
466
467 /* *INDENT-OFF* */
468 VLIB_CLI_COMMAND (cmd_set_dpdk_if_placement,static) = {
469     .path = "set dpdk interface placement",
470     .short_help = "set dpdk interface placement <if-name> [queue <n>]  thread <n>",
471     .function = set_dpdk_if_placement,
472 };
473 /* *INDENT-ON* */
474
475 static clib_error_t *
476 show_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input,
477                              vlib_cli_command_t * cmd)
478 {
479   vlib_thread_main_t *tm = vlib_get_thread_main ();
480   dpdk_main_t *dm = &dpdk_main;
481   dpdk_device_and_queue_t *dq;
482   int cpu;
483
484   if (tm->n_vlib_mains == 1)
485     vlib_cli_output (vm, "All interfaces are handled by main thread");
486
487   for (cpu = 0; cpu < vec_len (dm->devices_by_hqos_cpu); cpu++)
488     {
489       if (vec_len (dm->devices_by_hqos_cpu[cpu]))
490         vlib_cli_output (vm, "Thread %u (%s at lcore %u):", cpu,
491                          vlib_worker_threads[cpu].name,
492                          vlib_worker_threads[cpu].lcore_id);
493
494       vec_foreach (dq, dm->devices_by_hqos_cpu[cpu])
495       {
496         u32 hw_if_index = dm->devices[dq->device].vlib_hw_if_index;
497         vnet_hw_interface_t *hi =
498           vnet_get_hw_interface (dm->vnet_main, hw_if_index);
499         vlib_cli_output (vm, "  %v queue %u", hi->name, dq->queue_id);
500       }
501     }
502   return 0;
503 }
504
505 /* *INDENT-OFF* */
506 VLIB_CLI_COMMAND (cmd_show_dpdk_if_hqos_placement, static) = {
507   .path = "show dpdk interface hqos placement",
508   .short_help = "show dpdk interface hqos placement",
509   .function = show_dpdk_if_hqos_placement,
510 };
511 /* *INDENT-ON* */
512
513 static clib_error_t *
514 set_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input,
515                             vlib_cli_command_t * cmd)
516 {
517   unformat_input_t _line_input, *line_input = &_line_input;
518   dpdk_main_t *dm = &dpdk_main;
519   dpdk_device_and_queue_t *dq;
520   vnet_hw_interface_t *hw;
521   dpdk_device_t *xd;
522   u32 hw_if_index = (u32) ~ 0;
523   u32 cpu = (u32) ~ 0;
524   int i;
525
526   if (!unformat_user (input, unformat_line_input, line_input))
527     return 0;
528
529   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
530     {
531       if (unformat
532           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
533            &hw_if_index))
534         ;
535       else if (unformat (line_input, "thread %d", &cpu))
536         ;
537       else
538         return clib_error_return (0, "parse error: '%U'",
539                                   format_unformat_error, line_input);
540     }
541
542   unformat_free (line_input);
543
544   if (hw_if_index == (u32) ~ 0)
545     return clib_error_return (0, "please specify valid interface name");
546
547   if (cpu < dm->hqos_cpu_first_index ||
548       cpu >= (dm->hqos_cpu_first_index + dm->hqos_cpu_count))
549     return clib_error_return (0, "please specify valid thread id");
550
551   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
552   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
553
554   for (i = 0; i < vec_len (dm->devices_by_hqos_cpu); i++)
555     {
556       vec_foreach (dq, dm->devices_by_hqos_cpu[i])
557       {
558         if (hw_if_index == dm->devices[dq->device].vlib_hw_if_index)
559           {
560             if (cpu == i)       /* nothing to do */
561               return 0;
562
563             vec_del1 (dm->devices_by_hqos_cpu[i],
564                       dq - dm->devices_by_hqos_cpu[i]);
565             vec_add2 (dm->devices_by_hqos_cpu[cpu], dq, 1);
566             dq->queue_id = 0;
567             dq->device = xd->device_index;
568
569             vec_sort_with_function (dm->devices_by_hqos_cpu[i],
570                                     dpdk_device_queue_sort);
571
572             vec_sort_with_function (dm->devices_by_hqos_cpu[cpu],
573                                     dpdk_device_queue_sort);
574
575             return 0;
576           }
577       }
578     }
579
580   return clib_error_return (0, "not found");
581 }
582
583 /* *INDENT-OFF* */
584 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_placement, static) = {
585   .path = "set dpdk interface hqos placement",
586   .short_help = "set dpdk interface hqos placement <if-name> thread <n>",
587   .function = set_dpdk_if_hqos_placement,
588 };
589 /* *INDENT-ON* */
590
591 static clib_error_t *
592 set_dpdk_if_hqos_pipe (vlib_main_t * vm, unformat_input_t * input,
593                        vlib_cli_command_t * cmd)
594 {
595   unformat_input_t _line_input, *line_input = &_line_input;
596   dpdk_main_t *dm = &dpdk_main;
597   vnet_hw_interface_t *hw;
598   dpdk_device_t *xd;
599   u32 hw_if_index = (u32) ~ 0;
600   u32 subport_id = (u32) ~ 0;
601   u32 pipe_id = (u32) ~ 0;
602   u32 profile_id = (u32) ~ 0;
603   int rv;
604
605   if (!unformat_user (input, unformat_line_input, line_input))
606     return 0;
607
608   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
609     {
610       if (unformat
611           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
612            &hw_if_index))
613         ;
614       else if (unformat (line_input, "subport %d", &subport_id))
615         ;
616       else if (unformat (line_input, "pipe %d", &pipe_id))
617         ;
618       else if (unformat (line_input, "profile %d", &profile_id))
619         ;
620       else
621         return clib_error_return (0, "parse error: '%U'",
622                                   format_unformat_error, line_input);
623     }
624
625   unformat_free (line_input);
626
627   if (hw_if_index == (u32) ~ 0)
628     return clib_error_return (0, "please specify valid interface name");
629
630   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
631   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
632
633   rv =
634     rte_sched_pipe_config (xd->hqos_ht->hqos, subport_id, pipe_id,
635                            profile_id);
636   if (rv)
637     return clib_error_return (0, "pipe configuration failed");
638
639   return 0;
640 }
641
642 /* *INDENT-OFF* */
643 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_pipe, static) =
644 {
645   .path = "set dpdk interface hqos pipe",
646   .short_help = "set dpdk interface hqos pipe <if-name> subport <n> pipe <n> "
647                   "profile <n>",
648   .function = set_dpdk_if_hqos_pipe,
649 };
650 /* *INDENT-ON* */
651
652 static clib_error_t *
653 set_dpdk_if_hqos_subport (vlib_main_t * vm, unformat_input_t * input,
654                           vlib_cli_command_t * cmd)
655 {
656   unformat_input_t _line_input, *line_input = &_line_input;
657   dpdk_main_t *dm = &dpdk_main;
658   vnet_hw_interface_t *hw;
659   dpdk_device_t *xd;
660   u32 hw_if_index = (u32) ~ 0;
661   u32 subport_id = (u32) ~ 0;
662   struct rte_sched_subport_params p = {
663     .tb_rate = 1250000000,      /* 10GbE */
664     .tb_size = 1000000,
665     .tc_rate = {1250000000, 1250000000, 1250000000, 1250000000},
666     .tc_period = 10,
667   };
668   int rv;
669
670   if (!unformat_user (input, unformat_line_input, line_input))
671     return 0;
672
673   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
674     {
675       if (unformat
676           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
677            &hw_if_index))
678         ;
679       else if (unformat (line_input, "subport %d", &subport_id))
680         ;
681       else if (unformat (line_input, "rate %d", &p.tb_rate))
682         {
683           p.tc_rate[0] = p.tb_rate;
684           p.tc_rate[1] = p.tb_rate;
685           p.tc_rate[2] = p.tb_rate;
686           p.tc_rate[3] = p.tb_rate;
687         }
688       else if (unformat (line_input, "bktsize %d", &p.tb_size))
689         ;
690       else if (unformat (line_input, "tc0 %d", &p.tc_rate[0]))
691         ;
692       else if (unformat (line_input, "tc1 %d", &p.tc_rate[1]))
693         ;
694       else if (unformat (line_input, "tc2 %d", &p.tc_rate[2]))
695         ;
696       else if (unformat (line_input, "tc3 %d", &p.tc_rate[3]))
697         ;
698       else if (unformat (line_input, "period %d", &p.tc_period))
699         ;
700       else
701         return clib_error_return (0, "parse error: '%U'",
702                                   format_unformat_error, line_input);
703     }
704
705   unformat_free (line_input);
706
707   if (hw_if_index == (u32) ~ 0)
708     return clib_error_return (0, "please specify valid interface name");
709
710   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
711   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
712
713   rv = rte_sched_subport_config (xd->hqos_ht->hqos, subport_id, &p);
714   if (rv)
715     return clib_error_return (0, "subport configuration failed");
716
717   return 0;
718 }
719
720 /* *INDENT-OFF* */
721 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_subport, static) = {
722   .path = "set dpdk interface hqos subport",
723   .short_help = "set dpdk interface hqos subport <if-name> subport <n> "
724                  "[rate <n>] [bktsize <n>] [tc0 <n>] [tc1 <n>] [tc2 <n>] [tc3 <n>] "
725                  "[period <n>]",
726   .function = set_dpdk_if_hqos_subport,
727 };
728 /* *INDENT-ON* */
729
730 static clib_error_t *
731 set_dpdk_if_hqos_tctbl (vlib_main_t * vm, unformat_input_t * input,
732                         vlib_cli_command_t * cmd)
733 {
734   unformat_input_t _line_input, *line_input = &_line_input;
735   vlib_thread_main_t *tm = vlib_get_thread_main ();
736   dpdk_main_t *dm = &dpdk_main;
737   vnet_hw_interface_t *hw;
738   dpdk_device_t *xd;
739   u32 hw_if_index = (u32) ~ 0;
740   u32 tc = (u32) ~ 0;
741   u32 queue = (u32) ~ 0;
742   u32 entry = (u32) ~ 0;
743   u32 val, i;
744
745   if (!unformat_user (input, unformat_line_input, line_input))
746     return 0;
747
748   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
749     {
750       if (unformat
751           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
752            &hw_if_index))
753         ;
754       else if (unformat (line_input, "entry %d", &entry))
755         ;
756       else if (unformat (line_input, "tc %d", &tc))
757         ;
758       else if (unformat (line_input, "queue %d", &queue))
759         ;
760       else
761         return clib_error_return (0, "parse error: '%U'",
762                                   format_unformat_error, line_input);
763     }
764
765   unformat_free (line_input);
766
767   if (hw_if_index == (u32) ~ 0)
768     return clib_error_return (0, "please specify valid interface name");
769   if (entry >= 64)
770     return clib_error_return (0, "invalid entry");
771   if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE)
772     return clib_error_return (0, "invalid traffic class");
773   if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS)
774     return clib_error_return (0, "invalid traffic class");
775
776   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
777   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
778
779   /* Detect the set of worker threads */
780   uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers");
781   /* Should never happen, shut up Coverity warning */
782   if (p == 0)
783     return clib_error_return (0, "no worker registrations?");
784
785   vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0];
786   int worker_thread_first = tr->first_index;
787   int worker_thread_count = tr->count;
788
789   val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue;
790   for (i = 0; i < worker_thread_count; i++)
791     xd->hqos_wt[worker_thread_first + i].hqos_tc_table[entry] = val;
792
793   return 0;
794 }
795
796 /* *INDENT-OFF* */
797 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_tctbl, static) = {
798   .path = "set dpdk interface hqos tctbl",
799   .short_help = "set dpdk interface hqos tctbl <if-name> entry <n> tc <n> queue <n>",
800   .function = set_dpdk_if_hqos_tctbl,
801 };
802 /* *INDENT-ON* */
803
804 static clib_error_t *
805 set_dpdk_if_hqos_pktfield (vlib_main_t * vm, unformat_input_t * input,
806                            vlib_cli_command_t * cmd)
807 {
808   unformat_input_t _line_input, *line_input = &_line_input;
809   vlib_thread_main_t *tm = vlib_get_thread_main ();
810   dpdk_main_t *dm = &dpdk_main;
811
812   /* Device specific data */
813   struct rte_eth_dev_info dev_info;
814   dpdk_device_config_t *devconf = 0;
815   vnet_hw_interface_t *hw;
816   dpdk_device_t *xd;
817   u32 hw_if_index = (u32) ~ 0;
818
819   /* Detect the set of worker threads */
820   uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers");
821   /* Should never happen, shut up Coverity warning */
822   if (p == 0)
823     return clib_error_return (0, "no worker registrations?");
824
825   vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0];
826   int worker_thread_first = tr->first_index;
827   int worker_thread_count = tr->count;
828
829   /* Packet field configuration */
830   u64 mask = (u64) ~ 0;
831   u32 id = (u32) ~ 0;
832   u32 offset = (u32) ~ 0;
833
834   /* HQoS params */
835   u32 n_subports_per_port, n_pipes_per_subport, tctbl_size;
836
837   u32 i;
838
839   /* Parse input arguments */
840   if (!unformat_user (input, unformat_line_input, line_input))
841     return 0;
842
843   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
844     {
845       if (unformat
846           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
847            &hw_if_index))
848         ;
849       else if (unformat (line_input, "id %d", &id))
850         ;
851       else if (unformat (line_input, "offset %d", &offset))
852         ;
853       else if (unformat (line_input, "mask %llx", &mask))
854         ;
855       else
856         return clib_error_return (0, "parse error: '%U'",
857                                   format_unformat_error, line_input);
858     }
859
860   unformat_free (line_input);
861
862   /* Get interface */
863   if (hw_if_index == (u32) ~ 0)
864     return clib_error_return (0, "please specify valid interface name");
865
866   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
867   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
868
869   rte_eth_dev_info_get (xd->device_index, &dev_info);
870   if (dev_info.pci_dev)
871     {                           /* bonded interface has no pci info */
872       vlib_pci_addr_t pci_addr;
873
874       pci_addr.domain = dev_info.pci_dev->addr.domain;
875       pci_addr.bus = dev_info.pci_dev->addr.bus;
876       pci_addr.slot = dev_info.pci_dev->addr.devid;
877       pci_addr.function = dev_info.pci_dev->addr.function;
878
879       p =
880         hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
881     }
882
883   if (p)
884     devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]);
885   else
886     devconf = &dm->conf->default_devconf;
887
888   if (devconf->hqos_enabled == 0)
889     {
890       vlib_cli_output (vm, "HQoS disabled for this interface");
891       return 0;
892     }
893
894   n_subports_per_port = devconf->hqos.port.n_subports_per_port;
895   n_pipes_per_subport = devconf->hqos.port.n_pipes_per_subport;
896   tctbl_size = RTE_DIM (devconf->hqos.tc_table);
897
898   /* Validate packet field configuration: id, offset and mask */
899   if (id >= 3)
900     return clib_error_return (0, "invalid packet field id");
901
902   switch (id)
903     {
904     case 0:
905       if (dpdk_hqos_validate_mask (mask, n_subports_per_port) != 0)
906         return clib_error_return (0, "invalid subport ID mask "
907                                   "(n_subports_per_port = %u)",
908                                   n_subports_per_port);
909       break;
910     case 1:
911       if (dpdk_hqos_validate_mask (mask, n_pipes_per_subport) != 0)
912         return clib_error_return (0, "invalid pipe ID mask "
913                                   "(n_pipes_per_subport = %u)",
914                                   n_pipes_per_subport);
915       break;
916     case 2:
917     default:
918       if (dpdk_hqos_validate_mask (mask, tctbl_size) != 0)
919         return clib_error_return (0, "invalid TC table index mask "
920                                   "(TC table size = %u)", tctbl_size);
921     }
922
923   /* Propagate packet field configuration to all workers */
924   for (i = 0; i < worker_thread_count; i++)
925     switch (id)
926       {
927       case 0:
928         xd->hqos_wt[worker_thread_first + i].hqos_field0_slabpos = offset;
929         xd->hqos_wt[worker_thread_first + i].hqos_field0_slabmask = mask;
930         xd->hqos_wt[worker_thread_first + i].hqos_field0_slabshr =
931           __builtin_ctzll (mask);
932         break;
933       case 1:
934         xd->hqos_wt[worker_thread_first + i].hqos_field1_slabpos = offset;
935         xd->hqos_wt[worker_thread_first + i].hqos_field1_slabmask = mask;
936         xd->hqos_wt[worker_thread_first + i].hqos_field1_slabshr =
937           __builtin_ctzll (mask);
938         break;
939       case 2:
940       default:
941         xd->hqos_wt[worker_thread_first + i].hqos_field2_slabpos = offset;
942         xd->hqos_wt[worker_thread_first + i].hqos_field2_slabmask = mask;
943         xd->hqos_wt[worker_thread_first + i].hqos_field2_slabshr =
944           __builtin_ctzll (mask);
945       }
946
947   return 0;
948 }
949
950 /* *INDENT-OFF* */
951 VLIB_CLI_COMMAND (cmd_set_dpdk_if_hqos_pktfield, static) = {
952   .path = "set dpdk interface hqos pktfield",
953   .short_help = "set dpdk interface hqos pktfield <if-name> id <n> offset <n> "
954                  "mask <n>",
955   .function = set_dpdk_if_hqos_pktfield,
956 };
957 /* *INDENT-ON* */
958
959 static clib_error_t *
960 show_dpdk_if_hqos (vlib_main_t * vm, unformat_input_t * input,
961                    vlib_cli_command_t * cmd)
962 {
963   unformat_input_t _line_input, *line_input = &_line_input;
964   vlib_thread_main_t *tm = vlib_get_thread_main ();
965   dpdk_main_t *dm = &dpdk_main;
966   vnet_hw_interface_t *hw;
967   dpdk_device_t *xd;
968   dpdk_device_config_hqos_t *cfg;
969   dpdk_device_hqos_per_hqos_thread_t *ht;
970   dpdk_device_hqos_per_worker_thread_t *wk;
971   u32 *tctbl;
972   u32 hw_if_index = (u32) ~ 0;
973   u32 profile_id, i;
974   struct rte_eth_dev_info dev_info;
975   dpdk_device_config_t *devconf = 0;
976   vlib_thread_registration_t *tr;
977   uword *p = 0;
978
979   if (!unformat_user (input, unformat_line_input, line_input))
980     return 0;
981
982   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
983     {
984       if (unformat
985           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
986            &hw_if_index))
987         ;
988       else
989         return clib_error_return (0, "parse error: '%U'",
990                                   format_unformat_error, line_input);
991     }
992
993   unformat_free (line_input);
994
995   if (hw_if_index == (u32) ~ 0)
996     return clib_error_return (0, "please specify interface name!!");
997
998   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
999   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
1000
1001   rte_eth_dev_info_get (xd->device_index, &dev_info);
1002   if (dev_info.pci_dev)
1003     {                           /* bonded interface has no pci info */
1004       vlib_pci_addr_t pci_addr;
1005
1006       pci_addr.domain = dev_info.pci_dev->addr.domain;
1007       pci_addr.bus = dev_info.pci_dev->addr.bus;
1008       pci_addr.slot = dev_info.pci_dev->addr.devid;
1009       pci_addr.function = dev_info.pci_dev->addr.function;
1010
1011       p =
1012         hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
1013     }
1014
1015   if (p)
1016     devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]);
1017   else
1018     devconf = &dm->conf->default_devconf;
1019
1020   if (devconf->hqos_enabled == 0)
1021     {
1022       vlib_cli_output (vm, "HQoS disabled for this interface");
1023       return 0;
1024     }
1025
1026   /* Detect the set of worker threads */
1027   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1028
1029   /* Should never happen, shut up Coverity warning */
1030   if (p == 0)
1031     return clib_error_return (0, "no worker registrations?");
1032
1033   tr = (vlib_thread_registration_t *) p[0];
1034
1035   cfg = &devconf->hqos;
1036   ht = xd->hqos_ht;
1037   wk = &xd->hqos_wt[tr->first_index];
1038   tctbl = wk->hqos_tc_table;
1039
1040   vlib_cli_output (vm, " Thread:");
1041   vlib_cli_output (vm, "   Input SWQ size = %u packets", cfg->swq_size);
1042   vlib_cli_output (vm, "   Enqueue burst size = %u packets",
1043                    ht->hqos_burst_enq);
1044   vlib_cli_output (vm, "   Dequeue burst size = %u packets",
1045                    ht->hqos_burst_deq);
1046
1047   vlib_cli_output (vm,
1048                    "   Packet field 0: slab position = %4u, slab bitmask = 0x%016llx",
1049                    wk->hqos_field0_slabpos, wk->hqos_field0_slabmask);
1050   vlib_cli_output (vm,
1051                    "   Packet field 1: slab position = %4u, slab bitmask = 0x%016llx",
1052                    wk->hqos_field1_slabpos, wk->hqos_field1_slabmask);
1053   vlib_cli_output (vm,
1054                    "   Packet field 2: slab position = %4u, slab bitmask = 0x%016llx",
1055                    wk->hqos_field2_slabpos, wk->hqos_field2_slabmask);
1056   vlib_cli_output (vm, "   Packet field 2 translation table:");
1057   vlib_cli_output (vm, "     [ 0 .. 15]: "
1058                    "%2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u",
1059                    tctbl[0], tctbl[1], tctbl[2], tctbl[3],
1060                    tctbl[4], tctbl[5], tctbl[6], tctbl[7],
1061                    tctbl[8], tctbl[9], tctbl[10], tctbl[11],
1062                    tctbl[12], tctbl[13], tctbl[14], tctbl[15]);
1063   vlib_cli_output (vm, "     [16 .. 31]: "
1064                    "%2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u",
1065                    tctbl[16], tctbl[17], tctbl[18], tctbl[19],
1066                    tctbl[20], tctbl[21], tctbl[22], tctbl[23],
1067                    tctbl[24], tctbl[25], tctbl[26], tctbl[27],
1068                    tctbl[28], tctbl[29], tctbl[30], tctbl[31]);
1069   vlib_cli_output (vm, "     [32 .. 47]: "
1070                    "%2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u",
1071                    tctbl[32], tctbl[33], tctbl[34], tctbl[35],
1072                    tctbl[36], tctbl[37], tctbl[38], tctbl[39],
1073                    tctbl[40], tctbl[41], tctbl[42], tctbl[43],
1074                    tctbl[44], tctbl[45], tctbl[46], tctbl[47]);
1075   vlib_cli_output (vm, "     [48 .. 63]: "
1076                    "%2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u %2u",
1077                    tctbl[48], tctbl[49], tctbl[50], tctbl[51],
1078                    tctbl[52], tctbl[53], tctbl[54], tctbl[55],
1079                    tctbl[56], tctbl[57], tctbl[58], tctbl[59],
1080                    tctbl[60], tctbl[61], tctbl[62], tctbl[63]);
1081
1082   vlib_cli_output (vm, " Port:");
1083   vlib_cli_output (vm, "   Rate = %u bytes/second", cfg->port.rate);
1084   vlib_cli_output (vm, "   MTU = %u bytes", cfg->port.mtu);
1085   vlib_cli_output (vm, "   Frame overhead = %u bytes",
1086                    cfg->port.frame_overhead);
1087   vlib_cli_output (vm, "   Number of subports = %u",
1088                    cfg->port.n_subports_per_port);
1089   vlib_cli_output (vm, "   Number of pipes per subport = %u",
1090                    cfg->port.n_pipes_per_subport);
1091   vlib_cli_output (vm,
1092                    "   Packet queue size: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u packets",
1093                    cfg->port.qsize[0], cfg->port.qsize[1], cfg->port.qsize[2],
1094                    cfg->port.qsize[3]);
1095   vlib_cli_output (vm, "   Number of pipe profiles = %u",
1096                    cfg->port.n_pipe_profiles);
1097
1098   for (profile_id = 0; profile_id < vec_len (cfg->pipe); profile_id++)
1099     {
1100       vlib_cli_output (vm, " Pipe profile %u:", profile_id);
1101       vlib_cli_output (vm, "   Rate = %u bytes/second",
1102                        cfg->pipe[profile_id].tb_rate);
1103       vlib_cli_output (vm, "   Token bucket size = %u bytes",
1104                        cfg->pipe[profile_id].tb_size);
1105       vlib_cli_output (vm,
1106                        "   Traffic class rate: TC0 = %u, TC1 = %u, TC2 = %u, TC3 = %u bytes/second",
1107                        cfg->pipe[profile_id].tc_rate[0],
1108                        cfg->pipe[profile_id].tc_rate[1],
1109                        cfg->pipe[profile_id].tc_rate[2],
1110                        cfg->pipe[profile_id].tc_rate[3]);
1111       vlib_cli_output (vm, "   TC period = %u milliseconds",
1112                        cfg->pipe[profile_id].tc_period);
1113 #ifdef RTE_SCHED_SUBPORT_TC_OV
1114       vlib_cli_output (vm, "   TC3 oversubscription_weight = %u",
1115                        cfg->pipe[profile_id].tc_ov_weight);
1116 #endif
1117
1118       for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
1119         {
1120           vlib_cli_output (vm,
1121                            "   TC%u WRR weights: Q0 = %u, Q1 = %u, Q2 = %u, Q3 = %u",
1122                            i, cfg->pipe[profile_id].wrr_weights[i * 4],
1123                            cfg->pipe[profile_id].wrr_weights[i * 4 + 1],
1124                            cfg->pipe[profile_id].wrr_weights[i * 4 + 2],
1125                            cfg->pipe[profile_id].wrr_weights[i * 4 + 3]);
1126         }
1127     }
1128
1129 #ifdef RTE_SCHED_RED
1130   vlib_cli_output (vm, " Weighted Random Early Detection (WRED):");
1131   for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
1132     {
1133       vlib_cli_output (vm, "   TC%u min: G = %u, Y = %u, R = %u", i,
1134                        cfg->port.red_params[i][e_RTE_METER_GREEN].min_th,
1135                        cfg->port.red_params[i][e_RTE_METER_YELLOW].min_th,
1136                        cfg->port.red_params[i][e_RTE_METER_RED].min_th);
1137
1138       vlib_cli_output (vm, "   TC%u max: G = %u, Y = %u, R = %u", i,
1139                        cfg->port.red_params[i][e_RTE_METER_GREEN].max_th,
1140                        cfg->port.red_params[i][e_RTE_METER_YELLOW].max_th,
1141                        cfg->port.red_params[i][e_RTE_METER_RED].max_th);
1142
1143       vlib_cli_output (vm,
1144                        "   TC%u inverted probability: G = %u, Y = %u, R = %u",
1145                        i, cfg->port.red_params[i][e_RTE_METER_GREEN].maxp_inv,
1146                        cfg->port.red_params[i][e_RTE_METER_YELLOW].maxp_inv,
1147                        cfg->port.red_params[i][e_RTE_METER_RED].maxp_inv);
1148
1149       vlib_cli_output (vm, "   TC%u weight: R = %u, Y = %u, R = %u", i,
1150                        cfg->port.red_params[i][e_RTE_METER_GREEN].wq_log2,
1151                        cfg->port.red_params[i][e_RTE_METER_YELLOW].wq_log2,
1152                        cfg->port.red_params[i][e_RTE_METER_RED].wq_log2);
1153     }
1154 #endif
1155
1156   return 0;
1157 }
1158
1159 /* *INDENT-OFF* */
1160 VLIB_CLI_COMMAND (cmd_show_dpdk_if_hqos, static) = {
1161   .path = "show dpdk interface hqos",
1162   .short_help = "show dpdk interface hqos <if-name>",
1163   .function = show_dpdk_if_hqos,
1164 };
1165
1166 /* *INDENT-ON* */
1167
1168 static clib_error_t *
1169 show_dpdk_hqos_queue_stats (vlib_main_t * vm, unformat_input_t * input,
1170                             vlib_cli_command_t * cmd)
1171 {
1172   unformat_input_t _line_input, *line_input = &_line_input;
1173   dpdk_main_t *dm = &dpdk_main;
1174   u32 hw_if_index = (u32) ~ 0;
1175   u32 subport = (u32) ~ 0;
1176   u32 pipe = (u32) ~ 0;
1177   u32 tc = (u32) ~ 0;
1178   u32 tc_q = (u32) ~ 0;
1179   vnet_hw_interface_t *hw;
1180   dpdk_device_t *xd;
1181   uword *p = 0;
1182   struct rte_eth_dev_info dev_info;
1183   dpdk_device_config_t *devconf = 0;
1184   u32 qindex;
1185   struct rte_sched_queue_stats stats;
1186   u16 qlen;
1187
1188   if (!unformat_user (input, unformat_line_input, line_input))
1189     return 0;
1190
1191   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1192     {
1193       if (unformat
1194           (line_input, "%U", unformat_vnet_hw_interface, dm->vnet_main,
1195            &hw_if_index))
1196         ;
1197
1198       else if (unformat (line_input, "subport %d", &subport))
1199         ;
1200
1201       else if (unformat (line_input, "pipe %d", &pipe))
1202         ;
1203
1204       else if (unformat (line_input, "tc %d", &tc))
1205         ;
1206
1207       else if (unformat (line_input, "tc_q %d", &tc_q))
1208         ;
1209
1210       else
1211         return clib_error_return (0, "parse error: '%U'",
1212                                   format_unformat_error, line_input);
1213     }
1214
1215   unformat_free (line_input);
1216
1217   if (hw_if_index == (u32) ~ 0)
1218     return clib_error_return (0, "please specify interface name!!");
1219
1220   hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
1221   xd = vec_elt_at_index (dm->devices, hw->dev_instance);
1222
1223   rte_eth_dev_info_get (xd->device_index, &dev_info);
1224   if (dev_info.pci_dev)
1225     {                           /* bonded interface has no pci info */
1226       vlib_pci_addr_t pci_addr;
1227
1228       pci_addr.domain = dev_info.pci_dev->addr.domain;
1229       pci_addr.bus = dev_info.pci_dev->addr.bus;
1230       pci_addr.slot = dev_info.pci_dev->addr.devid;
1231       pci_addr.function = dev_info.pci_dev->addr.function;
1232
1233       p =
1234         hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
1235     }
1236
1237   if (p)
1238     devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]);
1239   else
1240     devconf = &dm->conf->default_devconf;
1241
1242   if (devconf->hqos_enabled == 0)
1243     {
1244       vlib_cli_output (vm, "HQoS disabled for this interface");
1245       return 0;
1246     }
1247
1248   /*
1249    * Figure out which queue to query.  cf rte_sched_port_qindex.  (Not sure why
1250    * that method isn't made public by DPDK - how _should_ we get the queue ID?)
1251    */
1252   qindex = subport * devconf->hqos.port.n_pipes_per_subport + pipe;
1253   qindex = qindex * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE + tc;
1254   qindex = qindex * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + tc_q;
1255
1256   if (rte_sched_queue_read_stats (xd->hqos_ht->hqos, qindex, &stats, &qlen) !=
1257       0)
1258     return clib_error_return (0, "failed to read stats");
1259
1260   vlib_cli_output (vm, "%=24s%=16s", "Stats Parameter", "Value");
1261   vlib_cli_output (vm, "%=24s%=16d", "Packets", stats.n_pkts);
1262   vlib_cli_output (vm, "%=24s%=16d", "Packets dropped", stats.n_pkts_dropped);
1263 #ifdef RTE_SCHED_RED
1264   vlib_cli_output (vm, "%=24s%=16d", "Packets dropped (RED)",
1265                    stats.n_pkts_red_dropped);
1266 #endif
1267   vlib_cli_output (vm, "%=24s%=16d", "Bytes", stats.n_bytes);
1268   vlib_cli_output (vm, "%=24s%=16d", "Bytes dropped", stats.n_bytes_dropped);
1269
1270
1271   return 0;
1272 }
1273
1274 /* *INDENT-OFF* */
1275 VLIB_CLI_COMMAND (cmd_show_dpdk_hqos_queue_stats, static) = {
1276   .path = "show dpdk hqos queue",
1277   .short_help = "show dpdk hqos queue <if-name> subport <subport> pipe <pipe> tc <tc> tc_q <tc_q>",
1278   .function = show_dpdk_hqos_queue_stats,
1279 };
1280 /* *INDENT-ON* */
1281
1282 clib_error_t *
1283 dpdk_cli_init (vlib_main_t * vm)
1284 {
1285   return 0;
1286 }
1287
1288 VLIB_INIT_FUNCTION (dpdk_cli_init);
1289
1290 /*
1291  * fd.io coding-style-patch-verification: ON
1292  *
1293  * Local Variables:
1294  * eval: (c-set-style "gnu")
1295  * End:
1296  */