* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#include <unistd.h>
+#include <fcntl.h>
+
#include <vnet/vnet.h>
#include <vppinfra/vec.h>
#include <vppinfra/error.h>
#include <vppinfra/format.h>
#include <vppinfra/xxhash.h>
+#include <vppinfra/linux/sysfs.c>
#include <vnet/ethernet/ethernet.h>
#include <dpdk/device/dpdk.h>
dpdk_main_t *dm = &dpdk_main;
vnet_hw_interface_t *hw;
struct rte_eth_dev_info dev_info;
+ struct rte_pci_device *pci_dev;
uword *p = 0;
clib_error_t *error = NULL;
hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
*xd = vec_elt_at_index (dm->devices, hw->dev_instance);
- rte_eth_dev_info_get ((*xd)->device_index, &dev_info);
- if (dev_info.pci_dev)
- { /* bonded interface has no pci info */
+ rte_eth_dev_info_get ((*xd)->port_id, &dev_info);
+
+ pci_dev = dpdk_get_pci_device (&dev_info);
+
+ if (pci_dev)
+ {
vlib_pci_addr_t pci_addr;
- pci_addr.domain = dev_info.pci_dev->addr.domain;
- pci_addr.bus = dev_info.pci_dev->addr.bus;
- pci_addr.slot = dev_info.pci_dev->addr.devid;
- pci_addr.function = dev_info.pci_dev->addr.function;
+ pci_addr.domain = pci_dev->addr.domain;
+ pci_addr.bus = pci_dev->addr.bus;
+ pci_addr.slot = pci_dev->addr.devid;
+ pci_addr.function = pci_dev->addr.function;
p =
hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
return error;
}
-static clib_error_t *
-pcap_trace_command_fn (vlib_main_t * vm,
- unformat_input_t * input, vlib_cli_command_t * cmd)
+static inline clib_error_t *
+pcap_trace_command_internal (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd, int rx_tx)
{
#define PCAP_DEF_PKT_TO_CAPTURE (100)
{
if (unformat (line_input, "on"))
{
- if (dm->tx_pcap_enable == 0)
+ if (dm->pcap[rx_tx].pcap_enable == 0)
{
enabled = 1;
}
}
else if (unformat (line_input, "off"))
{
- if (dm->tx_pcap_enable)
+ if (dm->pcap[rx_tx].pcap_enable)
{
- vlib_cli_output (vm, "captured %d pkts...",
- dm->pcap_main.n_packets_captured + 1);
- if (dm->pcap_main.n_packets_captured)
+ vlib_cli_output
+ (vm, "captured %d pkts...",
+ dm->pcap[rx_tx].pcap_main.n_packets_captured);
+ if (dm->pcap[rx_tx].pcap_main.n_packets_captured)
{
- dm->pcap_main.n_packets_to_capture =
- dm->pcap_main.n_packets_captured;
- error = pcap_write (&dm->pcap_main);
+ dm->pcap[rx_tx].pcap_main.n_packets_to_capture =
+ dm->pcap[rx_tx].pcap_main.n_packets_captured;
+ error = pcap_write (&dm->pcap[rx_tx].pcap_main);
if (error)
clib_error_report (error);
else
- vlib_cli_output (vm, "saved to %s...", dm->pcap_filename);
+ vlib_cli_output (vm, "saved to %s...",
+ dm->pcap[rx_tx].pcap_main.file_name);
}
- dm->tx_pcap_enable = 0;
+ dm->pcap[rx_tx].pcap_enable = 0;
}
else
{
}
else if (unformat (line_input, "max %d", &max))
{
- if (dm->tx_pcap_enable)
+ if (dm->pcap[rx_tx].pcap_enable)
{
- vlib_cli_output (vm,
- "can't change max value while pcap tx capture active...");
+ vlib_cli_output
+ (vm,
+ "can't change max value while pcap tx capture active...");
errorFlag = 1;
break;
}
+ dm->pcap[rx_tx].pcap_main.n_packets_to_capture = max;
}
else if (unformat (line_input, "intfc %U",
unformat_vnet_sw_interface, dm->vnet_main,
- &dm->pcap_sw_if_index))
+ &dm->pcap[rx_tx].pcap_sw_if_index))
;
else if (unformat (line_input, "intfc any"))
{
- dm->pcap_sw_if_index = 0;
+ dm->pcap[rx_tx].pcap_sw_if_index = 0;
}
else if (unformat (line_input, "file %s", &filename))
{
- if (dm->tx_pcap_enable)
+ if (dm->pcap[rx_tx].pcap_enable)
{
- vlib_cli_output (vm,
- "can't change file while pcap tx capture active...");
+ vlib_cli_output
+ (vm, "can't change file while pcap tx capture active...");
errorFlag = 1;
break;
}
{
vlib_cli_output (vm, "illegal characters in filename '%s'",
filename);
- vlib_cli_output (vm,
- "Hint: Only filename, do not enter directory structure.");
+ vlib_cli_output (vm, "Hint: .. and / are not allowed.");
vec_free (filename);
errorFlag = 1;
break;
}
else if (unformat (line_input, "status"))
{
- if (dm->pcap_sw_if_index == 0)
+ if (dm->pcap[rx_tx].pcap_sw_if_index == 0)
{
- vlib_cli_output (vm, "max is %d for any interface to file %s",
- dm->
- pcap_pkts_to_capture ? dm->pcap_pkts_to_capture
- : PCAP_DEF_PKT_TO_CAPTURE,
- dm->
- pcap_filename ? dm->pcap_filename : (u8 *)
- "/tmp/vpe.pcap");
+ vlib_cli_output
+ (vm, "max is %d for any interface to file %s",
+ dm->pcap[rx_tx].pcap_main.n_packets_to_capture ?
+ dm->pcap[rx_tx].pcap_main.n_packets_to_capture
+ : PCAP_DEF_PKT_TO_CAPTURE,
+ dm->pcap[rx_tx].pcap_main.file_name ?
+ (u8 *) dm->pcap[rx_tx].pcap_main.file_name :
+ (u8 *) "/tmp/vpe.pcap");
}
else
{
vlib_cli_output (vm, "max is %d for interface %U to file %s",
- dm->
- pcap_pkts_to_capture ? dm->pcap_pkts_to_capture
- : PCAP_DEF_PKT_TO_CAPTURE,
+ dm->pcap[rx_tx].pcap_main.n_packets_to_capture
+ ? dm->pcap[rx_tx].
+ pcap_main.n_packets_to_capture :
+ PCAP_DEF_PKT_TO_CAPTURE,
format_vnet_sw_if_index_name, dm->vnet_main,
dm->pcap_sw_if_index,
- dm->
- pcap_filename ? dm->pcap_filename : (u8 *)
- "/tmp/vpe.pcap");
+ dm->pcap[rx_tx].
+ pcap_main.file_name ? (u8 *) dm->pcap[rx_tx].
+ pcap_main.file_name : (u8 *) "/tmp/vpe.pcap");
}
- if (dm->tx_pcap_enable == 0)
+ if (dm->pcap[rx_tx].pcap_enable == 0)
{
- vlib_cli_output (vm, "pcap tx capture is off...");
+ vlib_cli_output (vm, "pcap %s capture is off...",
+ (rx_tx == VLIB_RX) ? "rx" : "tx");
}
else
{
- vlib_cli_output (vm, "pcap tx capture is on: %d of %d pkts...",
- dm->pcap_main.n_packets_captured,
- dm->pcap_main.n_packets_to_capture);
+ vlib_cli_output (vm, "pcap %s capture is on: %d of %d pkts...",
+ (rx_tx == VLIB_RX) ? "rx" : "tx",
+ dm->pcap[rx_tx].pcap_main.n_packets_captured,
+ dm->pcap[rx_tx].
+ pcap_main.n_packets_to_capture);
}
break;
}
/* Since no error, save configured values. */
if (chroot_filename)
{
- if (dm->pcap_filename)
- vec_free (dm->pcap_filename);
+ if (dm->pcap[rx_tx].pcap_main.file_name)
+ vec_free (dm->pcap[rx_tx].pcap_main.file_name);
vec_add1 (chroot_filename, 0);
- dm->pcap_filename = chroot_filename;
+ dm->pcap[rx_tx].pcap_main.file_name = (char *) chroot_filename;
}
if (max)
- dm->pcap_pkts_to_capture = max;
-
+ dm->pcap[rx_tx].pcap_main.n_packets_to_capture = max;
if (enabled)
{
- if (dm->pcap_filename == 0)
- dm->pcap_filename = format (0, "/tmp/vpe.pcap%c", 0);
-
- memset (&dm->pcap_main, 0, sizeof (dm->pcap_main));
- dm->pcap_main.file_name = (char *) dm->pcap_filename;
- dm->pcap_main.n_packets_to_capture = PCAP_DEF_PKT_TO_CAPTURE;
- if (dm->pcap_pkts_to_capture)
- dm->pcap_main.n_packets_to_capture = dm->pcap_pkts_to_capture;
-
- dm->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
- dm->tx_pcap_enable = 1;
- vlib_cli_output (vm, "pcap tx capture on...");
+ if (dm->pcap[rx_tx].pcap_main.file_name == 0)
+ dm->pcap[rx_tx].pcap_main.file_name
+ = (char *) format (0, "/tmp/vpe.pcap%c", 0);
+
+ dm->pcap[rx_tx].pcap_main.n_packets_captured = 0;
+ dm->pcap[rx_tx].pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
+ if (dm->pcap[rx_tx].pcap_main.lock == 0)
+ clib_spinlock_init (&(dm->pcap[rx_tx].pcap_main.lock));
+ dm->pcap[rx_tx].pcap_enable = 1;
+ vlib_cli_output (vm, "pcap %s capture on...",
+ rx_tx == VLIB_RX ? "rx" : "tx");
}
}
else if (chroot_filename)
vec_free (chroot_filename);
-
return error;
}
+static clib_error_t *
+pcap_rx_trace_command_fn (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ return pcap_trace_command_internal (vm, input, cmd, VLIB_RX);
+}
+
+static clib_error_t *
+pcap_tx_trace_command_fn (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ return pcap_trace_command_internal (vm, input, cmd, VLIB_TX);
+}
+
+
/*?
* This command is used to start or stop a packet capture, or show
- * the status of packet capture.
+ * the status of packet capture. Note that both "pcap rx trace" and
+ * "pcap tx trace" are implemented. The command syntax is identical,
+ * simply substitute rx for tx as needed.
*
* This command has the following optional parameters:
*
* associated with a packet capture. If packet capture is in progress,
* '<em>status</em>' also will return the number of packets currently in
* the local buffer. All additional attributes entered on command line
- * with '<em>status</em>' will be ingnored and not applied.
+ * with '<em>status</em>' will be ignored and not applied.
*
* @cliexpar
* Example of how to display the status of a tx packet capture when off:
* @cliexend
?*/
/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (pcap_trace_command, static) = {
+
+VLIB_CLI_COMMAND (pcap_tx_trace_command, static) = {
.path = "pcap tx trace",
.short_help =
"pcap tx trace [on|off] [max <nn>] [intfc <interface>|any] [file <name>] [status]",
- .function = pcap_trace_command_fn,
+ .function = pcap_tx_trace_command_fn,
+};
+VLIB_CLI_COMMAND (pcap_rx_trace_command, static) = {
+ .path = "pcap rx trace",
+ .short_help =
+ "pcap rx trace [on|off] [max <nn>] [intfc <interface>|any] [file <name>] [status]",
+ .function = pcap_rx_trace_command_fn,
};
/* *INDENT-ON* */
* @cliexend
?*/
/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (cmd_show_dpdk_bufferr,static) = {
+VLIB_CLI_COMMAND (cmd_show_dpdk_buffer,static) = {
.path = "show dpdk buffer",
.short_help = "show dpdk buffer",
.function = show_dpdk_buffer,
};
/* *INDENT-ON* */
+static clib_error_t *
+show_dpdk_physmem (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ clib_error_t *err = 0;
+ u32 pipe_max_size;
+ int fds[2];
+ u8 *s = 0;
+ int n, n_try;
+ FILE *f;
+
+ err = clib_sysfs_read ("/proc/sys/fs/pipe-max-size", "%u", &pipe_max_size);
+
+ if (err)
+ return err;
+
+ if (pipe (fds) == -1)
+ return clib_error_return_unix (0, "pipe");
+
+#ifndef F_SETPIPE_SZ
+#define F_SETPIPE_SZ (1024 + 7)
+#endif
+
+ if (fcntl (fds[1], F_SETPIPE_SZ, pipe_max_size) == -1)
+ {
+ err = clib_error_return_unix (0, "fcntl(F_SETPIPE_SZ)");
+ goto error;
+ }
+
+ if (fcntl (fds[0], F_SETFL, O_NONBLOCK) == -1)
+ {
+ err = clib_error_return_unix (0, "fcntl(F_SETFL)");
+ goto error;
+ }
+
+ if ((f = fdopen (fds[1], "a")) == 0)
+ {
+ err = clib_error_return_unix (0, "fdopen");
+ goto error;
+ }
+
+ rte_dump_physmem_layout (f);
+ fflush (f);
+
+ n = n_try = 4096;
+ while (n == n_try)
+ {
+ uword len = vec_len (s);
+ vec_resize (s, len + n_try);
+
+ n = read (fds[0], s + len, n_try);
+ if (n < 0 && errno != EAGAIN)
+ {
+ err = clib_error_return_unix (0, "read");
+ goto error;
+ }
+ _vec_len (s) = len + (n < 0 ? 0 : n);
+ }
+
+ vlib_cli_output (vm, "%v", s);
+
+error:
+ close (fds[0]);
+ close (fds[1]);
+ vec_free (s);
+ return err;
+}
+
+/*?
+ * This command displays DPDK physmem layout
+ *
+ * @cliexpar
+ * Example of how to display DPDK physmem layout:
+ * @cliexstart{show dpdk physmem}
+ * @cliexend
+?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (cmd_show_dpdk_physmem,static) = {
+ .path = "show dpdk physmem",
+ .short_help = "show dpdk physmem",
+ .function = show_dpdk_physmem,
+ .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
+
static clib_error_t *
test_dpdk_buffer (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
* @cliexpar
* @parblock
*
- * Example of how to display how many DPDK buffer test command has allcoated:
+ * Example of how to display how many DPDK buffer test command has allocated:
* @cliexstart{test dpdk buffer}
* Currently 0 buffers allocated
* @cliexend
cpu < (dm->hqos_cpu_first_index + dm->hqos_cpu_count))
vlib_cli_output (vm, "Thread %u (%s at lcore %u):", cpu,
vlib_worker_threads[cpu].name,
- vlib_worker_threads[cpu].lcore_id);
+ vlib_worker_threads[cpu].cpu_id);
vec_foreach (dq, dm->devices_by_hqos_cpu[cpu])
{
/* Device specific data */
struct rte_eth_dev_info dev_info;
+ struct rte_pci_device *pci_dev;
dpdk_device_config_t *devconf = 0;
vnet_hw_interface_t *hw;
dpdk_device_t *xd;
hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
xd = vec_elt_at_index (dm->devices, hw->dev_instance);
- rte_eth_dev_info_get (xd->device_index, &dev_info);
- if (dev_info.pci_dev)
+ rte_eth_dev_info_get (xd->port_id, &dev_info);
+
+ pci_dev = dpdk_get_pci_device (&dev_info);
+
+ if (pci_dev)
{ /* bonded interface has no pci info */
vlib_pci_addr_t pci_addr;
- pci_addr.domain = dev_info.pci_dev->addr.domain;
- pci_addr.bus = dev_info.pci_dev->addr.bus;
- pci_addr.slot = dev_info.pci_dev->addr.devid;
- pci_addr.function = dev_info.pci_dev->addr.function;
+ pci_addr.domain = pci_dev->addr.domain;
+ pci_addr.bus = pci_dev->addr.bus;
+ pci_addr.slot = pci_dev->addr.devid;
+ pci_addr.function = pci_dev->addr.function;
p =
hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
xd->hqos_wt[worker_thread_first + i].hqos_field0_slabpos = offset;
xd->hqos_wt[worker_thread_first + i].hqos_field0_slabmask = mask;
xd->hqos_wt[worker_thread_first + i].hqos_field0_slabshr =
- __builtin_ctzll (mask);
+ count_trailing_zeros (mask);
break;
case 1:
xd->hqos_wt[worker_thread_first + i].hqos_field1_slabpos = offset;
xd->hqos_wt[worker_thread_first + i].hqos_field1_slabmask = mask;
xd->hqos_wt[worker_thread_first + i].hqos_field1_slabshr =
- __builtin_ctzll (mask);
+ count_trailing_zeros (mask);
break;
case 2:
default:
xd->hqos_wt[worker_thread_first + i].hqos_field2_slabpos = offset;
xd->hqos_wt[worker_thread_first + i].hqos_field2_slabmask = mask;
xd->hqos_wt[worker_thread_first + i].hqos_field2_slabshr =
- __builtin_ctzll (mask);
+ count_trailing_zeros (mask);
}
done:
}
/*?
- * This command is used to set the packet fields required for classifiying the
+ * This command is used to set the packet fields required for classifying the
* incoming packet. As a result of classification process, packet field
* information will be mapped to 5 tuples (subport, pipe, traffic class, pipe,
* color) and stored in packet mbuf.
u32 hw_if_index = (u32) ~ 0;
u32 profile_id, subport_id, i;
struct rte_eth_dev_info dev_info;
+ struct rte_pci_device *pci_dev;
dpdk_device_config_t *devconf = 0;
vlib_thread_registration_t *tr;
uword *p = 0;
hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
xd = vec_elt_at_index (dm->devices, hw->dev_instance);
- rte_eth_dev_info_get (xd->device_index, &dev_info);
- if (dev_info.pci_dev)
+ rte_eth_dev_info_get (xd->port_id, &dev_info);
+
+ pci_dev = dpdk_get_pci_device (&dev_info);
+
+ if (pci_dev)
{ /* bonded interface has no pci info */
vlib_pci_addr_t pci_addr;
- pci_addr.domain = dev_info.pci_dev->addr.domain;
- pci_addr.bus = dev_info.pci_dev->addr.bus;
- pci_addr.slot = dev_info.pci_dev->addr.devid;
- pci_addr.function = dev_info.pci_dev->addr.function;
+ pci_addr.domain = pci_dev->addr.domain;
+ pci_addr.bus = pci_dev->addr.bus;
+ pci_addr.slot = pci_dev->addr.devid;
+ pci_addr.function = pci_dev->addr.function;
p =
hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32);
hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index);
xd = vec_elt_at_index (dm->devices, hw->dev_instance);
- rte_eth_dev_info_get (xd->device_index, &dev_info);
+ rte_eth_dev_info_get (xd->port_id, &dev_info);
if (dev_info.pci_dev)
{ /* bonded interface has no pci info */
vlib_pci_addr_t pci_addr;
* the list of arguments passed to DPDK when started.
*
* @cliexpar
- * Example of how to display how many DPDK buffer test command has allcoated:
+ * Example of how to display how many DPDK buffer test command has allocated:
* @cliexstart{show dpdk version}
* DPDK Version: DPDK 16.11.0
* 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
};
/* *INDENT-ON* */
+#if CLI_DEBUG
+
+static clib_error_t *
+dpdk_validate_buffers_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd_arg)
+{
+ u32 n_invalid_bufs = 0, uninitialized = 0;
+ u32 is_poison = 0, is_test = 0;
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "poison"))
+ is_poison = 1;
+ else if (unformat (input, "trajectory"))
+ is_test = 1;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+
+ if (VLIB_BUFFER_TRACE_TRAJECTORY == 0)
+ {
+ vlib_cli_output (vm, "Trajectory not enabled. Recompile with "
+ "VLIB_BUFFER_TRACE_TRAJECTORY 1");
+ return 0;
+ }
+ if (is_poison)
+ {
+ dpdk_buffer_poison_trajectory_all ();
+ }
+ if (is_test)
+ {
+ n_invalid_bufs = dpdk_buffer_validate_trajectory_all (&uninitialized);
+ if (!n_invalid_bufs)
+ vlib_cli_output (vm, "All buffers are valid %d uninitialized",
+ uninitialized);
+ else
+ vlib_cli_output (vm, "Found %d invalid buffers and %d uninitialized",
+ n_invalid_bufs, uninitialized);
+ }
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (test_dpdk_buffers_command, static) =
+{
+ .path = "test dpdk buffers",
+ .short_help = "test dpdk buffers [poison] [trajectory]",
+ .function = dpdk_validate_buffers_fn,
+};
+/* *INDENT-ON* */
+
+#endif
+
clib_error_t *
dpdk_cli_init (vlib_main_t * vm)
{