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