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