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