#endif
#define EXTMEM_HEAP_NAME "extmem"
+#define EXTBUF_ZONE_SIZE RTE_PGSIZE_2M
uint16_t verbose_level = 0; /**< Silent by default. */
int testpmd_logtype; /**< Log type for testpmd logs */
&csum_fwd_engine,
&icmp_echo_engine,
&noisy_vnf_engine,
-#if defined RTE_LIBRTE_PMD_SOFTNIC
- &softnic_fwd_engine,
-#endif
+ &five_tuple_swap_fwd_engine,
#ifdef RTE_LIBRTE_IEEE1588
&ieee1588_fwd_engine,
#endif
uint8_t txonly_multi_flow;
/**< Whether multiple flows are generated in TXONLY mode. */
+uint32_t tx_pkt_times_inter;
+/**< Timings for send scheduling in TXONLY mode, time between bursts. */
+
+uint32_t tx_pkt_times_intra;
+/**< Timings for send scheduling in TXONLY mode, time between packets. */
+
uint16_t nb_pkt_per_burst = DEF_PKT_BURST; /**< Number of packets per burst. */
uint16_t mb_mempool_cache = DEF_MBUF_CACHE; /**< Size of mbuf mempool cache. */
/* After attach, port setup is called on event or by iterator */
bool setup_on_probe_event = true;
+/* Clear ptypes on port initialization. */
+uint8_t clear_ptypes = true;
+
/* Pretty printing of ethdev events */
static const char * const eth_event_desc[] = {
[RTE_ETH_EVENT_UNKNOWN] = "unknown",
[RTE_ETH_EVENT_INTR_RMV] = "device removal",
[RTE_ETH_EVENT_NEW] = "device probed",
[RTE_ETH_EVENT_DESTROY] = "device released",
+ [RTE_ETH_EVENT_FLOW_AGED] = "flow aged",
[RTE_ETH_EVENT_MAX] = NULL,
};
(UINT32_C(1) << RTE_ETH_EVENT_INTR_RESET) |
(UINT32_C(1) << RTE_ETH_EVENT_IPSEC) |
(UINT32_C(1) << RTE_ETH_EVENT_MACSEC) |
- (UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV);
+ (UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV) |
+ (UINT32_C(1) << RTE_ETH_EVENT_FLOW_AGED);
/*
* Decide if all memory are locked for performance.
*/
struct gro_status gro_ports[RTE_MAX_ETHPORTS];
uint8_t gro_flush_cycles = GRO_DEFAULT_FLUSH_CYCLES;
+/*
+ * hexadecimal bitmask of RX mq mode can be enabled.
+ */
+enum rte_eth_rx_mq_mode rx_mq_mode = ETH_MQ_RX_VMDQ_DCB_RSS;
+
/* Forward function declarations */
static void setup_attached_port(portid_t pi);
static void map_port_queue_stats_mapping_registers(portid_t pi,
struct gso_status gso_ports[RTE_MAX_ETHPORTS];
uint16_t gso_max_segment_size = RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN;
+/* Holds the registered mbuf dynamic flags names. */
+char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
+
/*
* Helper function to check if socket is already discovered.
* If yes, return positive value. If not, return zero.
}
}
+static unsigned int
+setup_extbuf(uint32_t nb_mbufs, uint16_t mbuf_sz, unsigned int socket_id,
+ char *pool_name, struct rte_pktmbuf_extmem **ext_mem)
+{
+ struct rte_pktmbuf_extmem *xmem;
+ unsigned int ext_num, zone_num, elt_num;
+ uint16_t elt_size;
+
+ elt_size = RTE_ALIGN_CEIL(mbuf_sz, RTE_CACHE_LINE_SIZE);
+ elt_num = EXTBUF_ZONE_SIZE / elt_size;
+ zone_num = (nb_mbufs + elt_num - 1) / elt_num;
+
+ xmem = malloc(sizeof(struct rte_pktmbuf_extmem) * zone_num);
+ if (xmem == NULL) {
+ TESTPMD_LOG(ERR, "Cannot allocate memory for "
+ "external buffer descriptors\n");
+ *ext_mem = NULL;
+ return 0;
+ }
+ for (ext_num = 0; ext_num < zone_num; ext_num++) {
+ struct rte_pktmbuf_extmem *xseg = xmem + ext_num;
+ const struct rte_memzone *mz;
+ char mz_name[RTE_MEMZONE_NAMESIZE];
+ int ret;
+
+ ret = snprintf(mz_name, sizeof(mz_name),
+ RTE_MEMPOOL_MZ_FORMAT "_xb_%u", pool_name, ext_num);
+ if (ret < 0 || ret >= (int)sizeof(mz_name)) {
+ errno = ENAMETOOLONG;
+ ext_num = 0;
+ break;
+ }
+ mz = rte_memzone_reserve_aligned(mz_name, EXTBUF_ZONE_SIZE,
+ socket_id,
+ RTE_MEMZONE_IOVA_CONTIG |
+ RTE_MEMZONE_1GB |
+ RTE_MEMZONE_SIZE_HINT_ONLY,
+ EXTBUF_ZONE_SIZE);
+ if (mz == NULL) {
+ /*
+ * The caller exits on external buffer creation
+ * error, so there is no need to free memzones.
+ */
+ errno = ENOMEM;
+ ext_num = 0;
+ break;
+ }
+ xseg->buf_ptr = mz->addr;
+ xseg->buf_iova = mz->iova;
+ xseg->buf_len = EXTBUF_ZONE_SIZE;
+ xseg->elt_size = elt_size;
+ }
+ if (ext_num == 0 && xmem != NULL) {
+ free(xmem);
+ xmem = NULL;
+ }
+ *ext_mem = xmem;
+ return ext_num;
+}
+
/*
* Configuration initialisation done once at init time.
*/
heap_socket);
break;
}
+ case MP_ALLOC_XBUF:
+ {
+ struct rte_pktmbuf_extmem *ext_mem;
+ unsigned int ext_num;
+
+ ext_num = setup_extbuf(nb_mbuf, mbuf_seg_size,
+ socket_id, pool_name, &ext_mem);
+ if (ext_num == 0)
+ rte_exit(EXIT_FAILURE,
+ "Can't create pinned data buffers\n");
+
+ TESTPMD_LOG(INFO, "preferred mempool ops selected: %s\n",
+ rte_mbuf_best_mempool_ops());
+ rte_mp = rte_pktmbuf_pool_create_extbuf
+ (pool_name, nb_mbuf, mb_mempool_cache,
+ 0, mbuf_seg_size, socket_id,
+ ext_mem, ext_num);
+ free(ext_mem);
+ break;
+ }
default:
{
rte_exit(EXIT_FAILURE, "Invalid mempool creation mode\n");
queueid_t
get_allowed_max_nb_rxq(portid_t *pid)
{
- queueid_t allowed_max_rxq = MAX_QUEUE_ID;
+ queueid_t allowed_max_rxq = RTE_MAX_QUEUES_PER_PORT;
bool max_rxq_valid = false;
portid_t pi;
struct rte_eth_dev_info dev_info;
queueid_t
get_allowed_max_nb_txq(portid_t *pid)
{
- queueid_t allowed_max_txq = MAX_QUEUE_ID;
+ queueid_t allowed_max_txq = RTE_MAX_QUEUES_PER_PORT;
bool max_txq_valid = false;
portid_t pi;
struct rte_eth_dev_info dev_info;
return 0;
}
+/*
+ * Get the allowed maximum number of RXDs of every rx queue.
+ * *pid return the port id which has minimal value of
+ * max_rxd in all queues of all ports.
+ */
+static uint16_t
+get_allowed_max_nb_rxd(portid_t *pid)
+{
+ uint16_t allowed_max_rxd = UINT16_MAX;
+ portid_t pi;
+ struct rte_eth_dev_info dev_info;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (eth_dev_info_get_print_err(pi, &dev_info) != 0)
+ continue;
+
+ if (dev_info.rx_desc_lim.nb_max < allowed_max_rxd) {
+ allowed_max_rxd = dev_info.rx_desc_lim.nb_max;
+ *pid = pi;
+ }
+ }
+ return allowed_max_rxd;
+}
+
+/*
+ * Get the allowed minimal number of RXDs of every rx queue.
+ * *pid return the port id which has minimal value of
+ * min_rxd in all queues of all ports.
+ */
+static uint16_t
+get_allowed_min_nb_rxd(portid_t *pid)
+{
+ uint16_t allowed_min_rxd = 0;
+ portid_t pi;
+ struct rte_eth_dev_info dev_info;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (eth_dev_info_get_print_err(pi, &dev_info) != 0)
+ continue;
+
+ if (dev_info.rx_desc_lim.nb_min > allowed_min_rxd) {
+ allowed_min_rxd = dev_info.rx_desc_lim.nb_min;
+ *pid = pi;
+ }
+ }
+
+ return allowed_min_rxd;
+}
+
+/*
+ * Check input rxd is valid or not.
+ * If input rxd is not greater than any of maximum number
+ * of RXDs of every Rx queues and is not less than any of
+ * minimal number of RXDs of every Rx queues, it is valid.
+ * if valid, return 0, else return -1
+ */
+int
+check_nb_rxd(queueid_t rxd)
+{
+ uint16_t allowed_max_rxd;
+ uint16_t allowed_min_rxd;
+ portid_t pid = 0;
+
+ allowed_max_rxd = get_allowed_max_nb_rxd(&pid);
+ if (rxd > allowed_max_rxd) {
+ printf("Fail: input rxd (%u) can't be greater "
+ "than max_rxds (%u) of port %u\n",
+ rxd,
+ allowed_max_rxd,
+ pid);
+ return -1;
+ }
+
+ allowed_min_rxd = get_allowed_min_nb_rxd(&pid);
+ if (rxd < allowed_min_rxd) {
+ printf("Fail: input rxd (%u) can't be less "
+ "than min_rxds (%u) of port %u\n",
+ rxd,
+ allowed_min_rxd,
+ pid);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Get the allowed maximum number of TXDs of every rx queues.
+ * *pid return the port id which has minimal value of
+ * max_txd in every tx queue.
+ */
+static uint16_t
+get_allowed_max_nb_txd(portid_t *pid)
+{
+ uint16_t allowed_max_txd = UINT16_MAX;
+ portid_t pi;
+ struct rte_eth_dev_info dev_info;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (eth_dev_info_get_print_err(pi, &dev_info) != 0)
+ continue;
+
+ if (dev_info.tx_desc_lim.nb_max < allowed_max_txd) {
+ allowed_max_txd = dev_info.tx_desc_lim.nb_max;
+ *pid = pi;
+ }
+ }
+ return allowed_max_txd;
+}
+
+/*
+ * Get the allowed maximum number of TXDs of every tx queues.
+ * *pid return the port id which has minimal value of
+ * min_txd in every tx queue.
+ */
+static uint16_t
+get_allowed_min_nb_txd(portid_t *pid)
+{
+ uint16_t allowed_min_txd = 0;
+ portid_t pi;
+ struct rte_eth_dev_info dev_info;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (eth_dev_info_get_print_err(pi, &dev_info) != 0)
+ continue;
+
+ if (dev_info.tx_desc_lim.nb_min > allowed_min_txd) {
+ allowed_min_txd = dev_info.tx_desc_lim.nb_min;
+ *pid = pi;
+ }
+ }
+
+ return allowed_min_txd;
+}
+
+/*
+ * Check input txd is valid or not.
+ * If input txd is not greater than any of maximum number
+ * of TXDs of every Rx queues, it is valid.
+ * if valid, return 0, else return -1
+ */
+int
+check_nb_txd(queueid_t txd)
+{
+ uint16_t allowed_max_txd;
+ uint16_t allowed_min_txd;
+ portid_t pid = 0;
+
+ allowed_max_txd = get_allowed_max_nb_txd(&pid);
+ if (txd > allowed_max_txd) {
+ printf("Fail: input txd (%u) can't be greater "
+ "than max_txds (%u) of port %u\n",
+ txd,
+ allowed_max_txd,
+ pid);
+ return -1;
+ }
+
+ allowed_min_txd = get_allowed_min_nb_txd(&pid);
+ if (txd < allowed_min_txd) {
+ printf("Fail: input txd (%u) can't be less "
+ "than min_txds (%u) of port %u\n",
+ txd,
+ allowed_min_txd,
+ pid);
+ return -1;
+ }
+ return 0;
+}
+
+
/*
* Get the allowed maximum number of hairpin queues.
* *pid return the port id which has minimal value of
queueid_t
get_allowed_max_nb_hairpinq(portid_t *pid)
{
- queueid_t allowed_max_hairpinq = MAX_QUEUE_ID;
+ queueid_t allowed_max_hairpinq = RTE_MAX_QUEUES_PER_PORT;
portid_t pi;
struct rte_eth_hairpin_cap cap;
"rte_gro_ctx_create() failed\n");
}
}
-
-#if defined RTE_LIBRTE_PMD_SOFTNIC
- if (strcmp(cur_fwd_eng->fwd_mode_name, "softnic") == 0) {
- RTE_ETH_FOREACH_DEV(pid) {
- port = &ports[pid];
- const char *driver = port->dev_info.driver_name;
-
- if (strcmp(driver, "net_softnic") == 0)
- port->softport.fwd_lcore_arg = fwd_lcores;
- }
- }
-#endif
-
}
static void
pkt_burst_stats_display(const char *rx_tx, struct pkt_burst_stats *pbs)
{
- unsigned int total_burst;
- unsigned int nb_burst;
- unsigned int burst_stats[3];
- uint16_t pktnb_stats[3];
+ uint64_t total_burst, sburst;
+ uint64_t nb_burst;
+ uint64_t burst_stats[4];
+ uint16_t pktnb_stats[4];
uint16_t nb_pkt;
- int burst_percent[3];
+ int burst_percent[4], sburstp;
+ int i;
/*
* First compute the total number of packet bursts and the
* two highest numbers of bursts of the same number of packets.
*/
- total_burst = 0;
- burst_stats[0] = burst_stats[1] = burst_stats[2] = 0;
- pktnb_stats[0] = pktnb_stats[1] = pktnb_stats[2] = 0;
- for (nb_pkt = 0; nb_pkt < MAX_PKT_BURST; nb_pkt++) {
+ memset(&burst_stats, 0x0, sizeof(burst_stats));
+ memset(&pktnb_stats, 0x0, sizeof(pktnb_stats));
+
+ /* Show stats for 0 burst size always */
+ total_burst = pbs->pkt_burst_spread[0];
+ burst_stats[0] = pbs->pkt_burst_spread[0];
+ pktnb_stats[0] = 0;
+
+ /* Find the next 2 burst sizes with highest occurrences. */
+ for (nb_pkt = 1; nb_pkt < MAX_PKT_BURST; nb_pkt++) {
nb_burst = pbs->pkt_burst_spread[nb_pkt];
+
if (nb_burst == 0)
continue;
+
total_burst += nb_burst;
- if (nb_burst > burst_stats[0]) {
- burst_stats[1] = burst_stats[0];
- pktnb_stats[1] = pktnb_stats[0];
- burst_stats[0] = nb_burst;
- pktnb_stats[0] = nb_pkt;
- } else if (nb_burst > burst_stats[1]) {
+
+ if (nb_burst > burst_stats[1]) {
+ burst_stats[2] = burst_stats[1];
+ pktnb_stats[2] = pktnb_stats[1];
burst_stats[1] = nb_burst;
pktnb_stats[1] = nb_pkt;
+ } else if (nb_burst > burst_stats[2]) {
+ burst_stats[2] = nb_burst;
+ pktnb_stats[2] = nb_pkt;
}
}
if (total_burst == 0)
return;
- burst_percent[0] = (burst_stats[0] * 100) / total_burst;
- printf(" %s-bursts : %u [%d%% of %d pkts", rx_tx, total_burst,
- burst_percent[0], (int) pktnb_stats[0]);
- if (burst_stats[0] == total_burst) {
- printf("]\n");
- return;
- }
- if (burst_stats[0] + burst_stats[1] == total_burst) {
- printf(" + %d%% of %d pkts]\n",
- 100 - burst_percent[0], pktnb_stats[1]);
- return;
- }
- burst_percent[1] = (burst_stats[1] * 100) / total_burst;
- burst_percent[2] = 100 - (burst_percent[0] + burst_percent[1]);
- if ((burst_percent[1] == 0) || (burst_percent[2] == 0)) {
- printf(" + %d%% of others]\n", 100 - burst_percent[0]);
- return;
+
+ printf(" %s-bursts : %"PRIu64" [", rx_tx, total_burst);
+ for (i = 0, sburst = 0, sburstp = 0; i < 4; i++) {
+ if (i == 3) {
+ printf("%d%% of other]\n", 100 - sburstp);
+ return;
+ }
+
+ sburst += burst_stats[i];
+ if (sburst == total_burst) {
+ printf("%d%% of %d pkts]\n",
+ 100 - sburstp, (int) pktnb_stats[i]);
+ return;
+ }
+
+ burst_percent[i] =
+ (double)burst_stats[i] / total_burst * 100;
+ printf("%d%% of %d pkts + ",
+ burst_percent[i], (int) pktnb_stats[i]);
+ sburstp += burst_percent[i];
}
- printf(" + %d%% of %d pkts + %d%% of others]\n",
- burst_percent[1], (int) pktnb_stats[1], burst_percent[2]);
}
#endif /* RTE_TEST_PMD_RECORD_BURST_STATS */
"%s\n",
acc_stats_border, acc_stats_border);
#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
- if (total_recv > 0)
- printf("\n CPU cycles/packet=%u (total cycles="
- "%"PRIu64" / total RX packets=%"PRIu64")\n",
- (unsigned int)(fwd_cycles / total_recv),
- fwd_cycles, total_recv);
+#define CYC_PER_MHZ 1E6
+ if (total_recv > 0 || total_xmit > 0) {
+ uint64_t total_pkts = 0;
+ if (strcmp(cur_fwd_eng->fwd_mode_name, "txonly") == 0 ||
+ strcmp(cur_fwd_eng->fwd_mode_name, "flowgen") == 0)
+ total_pkts = total_xmit;
+ else
+ total_pkts = total_recv;
+
+ printf("\n CPU cycles/packet=%.2F (total cycles="
+ "%"PRIu64" / total %s packets=%"PRIu64") at %"PRIu64
+ " MHz Clock\n",
+ (double) fwd_cycles / total_pkts,
+ fwd_cycles, cur_fwd_eng->fwd_mode_name, total_pkts,
+ (uint64_t)(rte_get_tsc_hz() / CYC_PER_MHZ));
+ }
#endif
}
return -1;
}
configure_rxtx_dump_callbacks(verbose_level);
+ if (clear_ptypes) {
+ diag = rte_eth_dev_set_ptypes(pi, RTE_PTYPE_UNKNOWN,
+ NULL, 0);
+ if (diag < 0)
+ printf(
+ "Port %d: Failed to disable Ptype parsing\n",
+ pi);
+ }
+
/* start port */
if (rte_eth_dev_start(pi) < 0) {
printf("Fail to start port %d\n", pi);
printf("Done\n");
}
-void
-detach_port_device(portid_t port_id)
+static void
+detach_device(struct rte_device *dev)
{
- struct rte_device *dev;
portid_t sibling;
- printf("Removing a device...\n");
-
- dev = rte_eth_devices[port_id].device;
if (dev == NULL) {
printf("Device already removed\n");
return;
}
- if (ports[port_id].port_status != RTE_PORT_CLOSED) {
- if (ports[port_id].port_status != RTE_PORT_STOPPED) {
- printf("Port not stopped\n");
- return;
- }
- printf("Port was not closed\n");
- if (ports[port_id].flow_list)
- port_flow_flush(port_id);
- }
+ printf("Removing a device...\n");
if (rte_dev_remove(dev) < 0) {
TESTPMD_LOG(ERR, "Failed to detach device %s\n", dev->name);
remove_invalid_ports();
- printf("Device of port %u is detached\n", port_id);
+ printf("Device is detached\n");
printf("Now total ports is %d\n", nb_ports);
printf("Done\n");
return;
}
void
-detach_device(char *identifier)
+detach_port_device(portid_t port_id)
+{
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ if (ports[port_id].port_status != RTE_PORT_CLOSED) {
+ if (ports[port_id].port_status != RTE_PORT_STOPPED) {
+ printf("Port not stopped\n");
+ return;
+ }
+ printf("Port was not closed\n");
+ if (ports[port_id].flow_list)
+ port_flow_flush(port_id);
+ }
+
+ detach_device(rte_eth_devices[port_id].device);
+}
+
+void
+detach_devargs(char *identifier)
{
struct rte_dev_iterator iterator;
struct rte_devargs da;
if (ports[port_id].port_status != RTE_PORT_CLOSED) {
if (ports[port_id].port_status != RTE_PORT_STOPPED) {
printf("Port %u not stopped\n", port_id);
+ rte_eth_iterator_cleanup(&iterator);
return;
}
cmd_func_t cmd_func;
};
-#define PMD_TEST_CMD_NB (sizeof(pmd_test_menu) / sizeof(pmd_test_menu[0]))
-
/* Check the link status of all ports in up to 9s, and print them finally */
static void
check_all_ports_link_status(uint32_t port_mask)
"Port%d Link Up. speed %u Mbps- %s\n",
portid, link.link_speed,
(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
- ("full-duplex") : ("half-duplex\n"));
+ ("full-duplex") : ("half-duplex"));
else
printf("Port %d Link Down\n", portid);
continue;
int need_to_start = 0;
int org_no_link_check = no_link_check;
portid_t port_id = (intptr_t)arg;
+ struct rte_device *dev;
RTE_ETH_VALID_PORTID_OR_RET(port_id);
no_link_check = 1;
stop_port(port_id);
no_link_check = org_no_link_check;
+
+ /* Save rte_device pointer before closing ethdev port */
+ dev = rte_eth_devices[port_id].device;
close_port(port_id);
- detach_port_device(port_id);
+ detach_device(dev); /* might be already removed or have more ports */
+
if (need_to_start)
start_packet_forwarding(0);
}
if (port->dcb_flag == 0) {
if( port->dev_conf.rx_adv_conf.rss_conf.rss_hf != 0)
- port->dev_conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
+ port->dev_conf.rxmode.mq_mode =
+ (enum rte_eth_rx_mq_mode)
+ (rx_mq_mode & ETH_MQ_RX_RSS);
else
port->dev_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
}
}
/* set DCB mode of RX and TX of multiple queues */
- eth_conf->rxmode.mq_mode = ETH_MQ_RX_VMDQ_DCB;
+ eth_conf->rxmode.mq_mode =
+ (enum rte_eth_rx_mq_mode)
+ (rx_mq_mode & ETH_MQ_RX_VMDQ_DCB);
eth_conf->txmode.mq_mode = ETH_MQ_TX_VMDQ_DCB;
} else {
struct rte_eth_dcb_rx_conf *rx_conf =
struct rte_eth_dcb_tx_conf *tx_conf =
ð_conf->tx_adv_conf.dcb_tx_conf;
+ memset(&rss_conf, 0, sizeof(struct rte_eth_rss_conf));
+
rc = rte_eth_dev_rss_hash_conf_get(pid, &rss_conf);
if (rc != 0)
return rc;
tx_conf->dcb_tc[i] = i % num_tcs;
}
- eth_conf->rxmode.mq_mode = ETH_MQ_RX_DCB_RSS;
+ eth_conf->rxmode.mq_mode =
+ (enum rte_eth_rx_mq_mode)
+ (rx_mq_mode & ETH_MQ_RX_DCB_RSS);
eth_conf->rx_adv_conf.rss_conf = rss_conf;
eth_conf->txmode.mq_mode = ETH_MQ_TX_DCB;
}
return 1;
}
- return 0;
+ ret = rte_eal_cleanup();
+ if (ret != 0)
+ rte_exit(EXIT_FAILURE,
+ "EAL cleanup failed: %s\n", strerror(-ret));
+
+ return EXIT_SUCCESS;
}