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