* Copyright(C) 2019 Marvell International Ltd.
*/
+#include <rte_string_fns.h>
+
#include "l2fwd_event.h"
#include "l2fwd_poll.h"
" Default mode = eventdev\n"
" --eventq-sched: Event queue schedule type, ordered, atomic or parallel.\n"
" Default: atomic\n"
- " Valid only if --mode=eventdev\n\n",
+ " Valid only if --mode=eventdev\n"
+ " --event-vector: Enable event vectorization.\n"
+ " --event-vector-size: Max vector size if event vectorization is enabled.\n"
+ " --event-vector-tmo: Max timeout to form vector in nanoseconds if event vectorization is enabled\n"
+ " --config: Configure forwarding port pair mapping\n"
+ " Default: alternate port pairs\n\n",
prgname);
}
/* parse hexadecimal string */
pm = strtoul(portmask, &end, 16);
if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
- return -1;
-
- if (pm == 0)
- return -1;
+ return 0;
return pm;
}
rsrc->sched_type = RTE_SCHED_TYPE_PARALLEL;
}
+static int
+l2fwd_parse_port_pair_config(const char *q_arg, struct l2fwd_resources *rsrc)
+{
+ enum fieldnames {
+ FLD_PORT1 = 0,
+ FLD_PORT2,
+ _NUM_FLD
+ };
+ const char *p, *p0 = q_arg;
+ uint16_t int_fld[_NUM_FLD];
+ char *str_fld[_NUM_FLD];
+ uint16_t port_pair = 0;
+ unsigned int size;
+ char s[256];
+ char *end;
+ int i;
+
+ while ((p = strchr(p0, '(')) != NULL) {
+ ++p;
+ p0 = strchr(p, ')');
+ if (p0 == NULL)
+ return -1;
+
+ size = p0 - p;
+ if (size >= sizeof(s))
+ return -1;
+
+ memcpy(s, p, size);
+ if (rte_strsplit(s, sizeof(s), str_fld,
+ _NUM_FLD, ',') != _NUM_FLD)
+ return -1;
+
+ for (i = 0; i < _NUM_FLD; i++) {
+ errno = 0;
+ int_fld[i] = strtoul(str_fld[i], &end, 0);
+ if (errno != 0 || end == str_fld[i] ||
+ int_fld[i] >= RTE_MAX_ETHPORTS)
+ return -1;
+ }
+
+ if (port_pair >= RTE_MAX_ETHPORTS / 2) {
+ printf("exceeded max number of port pair params: Current %d Max = %d\n",
+ port_pair, RTE_MAX_ETHPORTS / 2);
+ return -1;
+ }
+
+ if ((rsrc->dst_ports[int_fld[FLD_PORT1]] != UINT32_MAX) ||
+ (rsrc->dst_ports[int_fld[FLD_PORT2]] != UINT32_MAX)) {
+ printf("Duplicate port pair (%d,%d) config\n",
+ int_fld[FLD_PORT1], int_fld[FLD_PORT2]);
+ return -1;
+ }
+
+ rsrc->dst_ports[int_fld[FLD_PORT1]] = int_fld[FLD_PORT2];
+ rsrc->dst_ports[int_fld[FLD_PORT2]] = int_fld[FLD_PORT1];
+
+ port_pair++;
+ }
+
+ rsrc->port_pairs = true;
+
+ return 0;
+}
+
static const char short_options[] =
"p:" /* portmask */
"q:" /* number of queues */
#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
#define CMD_LINE_OPT_MODE "mode"
#define CMD_LINE_OPT_EVENTQ_SCHED "eventq-sched"
+#define CMD_LINE_OPT_PORT_PAIR_CONF "config"
+#define CMD_LINE_OPT_ENABLE_VECTOR "event-vector"
+#define CMD_LINE_OPT_VECTOR_SIZE "event-vector-size"
+#define CMD_LINE_OPT_VECTOR_TMO_NS "event-vector-tmo"
enum {
/* long options mapped to a short option */
CMD_LINE_OPT_MIN_NUM = 256,
CMD_LINE_OPT_MODE_NUM,
CMD_LINE_OPT_EVENTQ_SCHED_NUM,
+ CMD_LINE_OPT_PORT_PAIR_CONF_NUM,
+ CMD_LINE_OPT_ENABLE_VECTOR_NUM,
+ CMD_LINE_OPT_VECTOR_SIZE_NUM,
+ CMD_LINE_OPT_VECTOR_TMO_NS_NUM
};
/* Parse the argument given in the command line of the application */
static int
-l2fwd_event_parse_args(int argc, char **argv,
- struct l2fwd_resources *rsrc)
+l2fwd_event_parse_args(int argc, char **argv, struct l2fwd_resources *rsrc)
{
int mac_updating = 1;
struct option lgopts[] = {
CMD_LINE_OPT_MODE_NUM},
{ CMD_LINE_OPT_EVENTQ_SCHED, required_argument, NULL,
CMD_LINE_OPT_EVENTQ_SCHED_NUM},
+ { CMD_LINE_OPT_PORT_PAIR_CONF, required_argument, NULL,
+ CMD_LINE_OPT_PORT_PAIR_CONF_NUM},
+ {CMD_LINE_OPT_ENABLE_VECTOR, no_argument, NULL,
+ CMD_LINE_OPT_ENABLE_VECTOR_NUM},
+ {CMD_LINE_OPT_VECTOR_SIZE, required_argument, NULL,
+ CMD_LINE_OPT_VECTOR_SIZE_NUM},
+ {CMD_LINE_OPT_VECTOR_TMO_NS, required_argument, NULL,
+ CMD_LINE_OPT_VECTOR_TMO_NS_NUM},
{NULL, 0, 0, 0}
};
int opt, ret, timer_secs;
char *prgname = argv[0];
- char **argvopt;
+ uint16_t port_id;
int option_index;
+ char **argvopt;
+
+ /* Reset l2fwd_dst_ports. 8< */
+ for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++)
+ rsrc->dst_ports[port_id] = UINT32_MAX;
argvopt = argv;
while ((opt = getopt_long(argc, argvopt, short_options,
l2fwd_event_parse_eventq_sched(optarg, rsrc);
break;
+ case CMD_LINE_OPT_PORT_PAIR_CONF_NUM:
+ ret = l2fwd_parse_port_pair_config(optarg, rsrc);
+ if (ret) {
+ printf("Invalid port pair config\n");
+ l2fwd_event_usage(prgname);
+ return -1;
+ }
+ break;
+ case CMD_LINE_OPT_ENABLE_VECTOR_NUM:
+ printf("event vectorization is enabled\n");
+ rsrc->evt_vec.enabled = 1;
+ break;
+ case CMD_LINE_OPT_VECTOR_SIZE_NUM:
+ rsrc->evt_vec.size = strtol(optarg, NULL, 10);
+ break;
+ case CMD_LINE_OPT_VECTOR_TMO_NS_NUM:
+ rsrc->evt_vec.timeout_ns = strtoull(optarg, NULL, 10);
+ break;
+
/* long options */
case 0:
break;
rsrc->mac_updating = mac_updating;
+ if (rsrc->evt_vec.enabled && !rsrc->evt_vec.size) {
+ rsrc->evt_vec.size = VECTOR_SIZE_DEFAULT;
+ printf("vector size set to default (%" PRIu16 ")\n",
+ rsrc->evt_vec.size);
+ }
+
+ if (rsrc->evt_vec.enabled && !rsrc->evt_vec.timeout_ns) {
+ rsrc->evt_vec.timeout_ns = VECTOR_TMO_NS_DEFAULT;
+ printf("vector timeout set to default (%" PRIu64 " ns)\n",
+ rsrc->evt_vec.timeout_ns);
+ }
+
if (optind >= 0)
argv[optind-1] = prgname;
ret = optind-1;
optind = 1; /* reset getopt lib */
return ret;
+ /* >8 End of reset l2fwd_dst_ports. */
+}
+
+/*
+ * Check port pair config with enabled port mask,
+ * and for valid port pair combinations.
+ */
+static int
+check_port_pair_config(struct l2fwd_resources *rsrc)
+{
+ uint32_t port_pair_mask = 0;
+ uint32_t portid;
+ uint16_t index;
+
+ for (index = 0; index < rte_eth_dev_count_avail(); index++) {
+ if ((rsrc->enabled_port_mask & (1 << index)) == 0 ||
+ (port_pair_mask & (1 << index)))
+ continue;
+
+ portid = rsrc->dst_ports[index];
+ if (portid == UINT32_MAX) {
+ printf("port %u is enabled in but no valid port pair\n",
+ index);
+ return -1;
+ }
+
+ if (!rte_eth_dev_is_valid_port(index)) {
+ printf("port %u is not valid\n", index);
+ return -1;
+ }
+
+ if (!rte_eth_dev_is_valid_port(portid)) {
+ printf("port %u is not valid\n", portid);
+ return -1;
+ }
+
+ if (port_pair_mask & (1 << portid) &&
+ rsrc->dst_ports[portid] != index) {
+ printf("port %u is used in other port pairs\n", portid);
+ return -1;
+ }
+
+ port_pair_mask |= (1 << portid);
+ port_pair_mask |= (1 << index);
+ }
+
+ return 0;
}
static int
{
struct l2fwd_resources *rsrc = args;
struct l2fwd_poll_resources *poll_rsrc = rsrc->poll_rsrc;
+ struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc;
- poll_rsrc->poll_main_loop(rsrc);
+ if (rsrc->event_mode)
+ evt_rsrc->ops.l2fwd_event_loop(rsrc);
+ else
+ poll_rsrc->poll_main_loop(rsrc);
return 0;
}
uint16_t port_id;
uint8_t count, all_ports_up, print_flag = 0;
struct rte_eth_link link;
+ int ret;
+ char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
printf("\nChecking link status...");
fflush(stdout);
if ((port_mask & (1 << port_id)) == 0)
continue;
memset(&link, 0, sizeof(link));
- rte_eth_link_get_nowait(port_id, &link);
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ if (ret < 0) {
+ all_ports_up = 0;
+ if (print_flag == 1)
+ printf("Port %u link get failed: %s\n",
+ port_id, rte_strerror(-ret));
+ continue;
+ }
/* print link status if flag set */
if (print_flag == 1) {
- if (link.link_status)
- printf(
- "Port%d Link Up. Speed %u Mbps - %s\n",
- port_id, link.link_speed,
- (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
- ("full-duplex") : ("half-duplex\n"));
- else
- printf("Port %d Link Down\n", port_id);
+ rte_eth_link_to_str(link_status_text,
+ sizeof(link_status_text), &link);
+ printf("Port %d %s\n", port_id,
+ link_status_text);
continue;
}
/* clear all_ports_up flag if any link down */
- if (link.link_status == ETH_LINK_DOWN) {
+ if (link.link_status == RTE_ETH_LINK_DOWN) {
all_ports_up = 0;
break;
}
if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
continue;
printf("\nStatistics for port %u ------------------------------"
- "\nPackets sent: %24"PRIu64
- "\nPackets received: %20"PRIu64
- "\nPackets dropped: %21"PRIu64,
+ "\nPackets sent: %29"PRIu64
+ "\nPackets received: %25"PRIu64
+ "\nPackets dropped: %26"PRIu64,
port_id,
rsrc->port_stats[port_id].tx,
rsrc->port_stats[port_id].rx,
total_packets_tx += rsrc->port_stats[port_id].tx;
total_packets_rx += rsrc->port_stats[port_id].rx;
}
- printf("\nAggregate statistics ==============================="
- "\nTotal packets sent: %18"PRIu64
- "\nTotal packets received: %14"PRIu64
- "\nTotal packets dropped: %15"PRIu64,
+
+ if (rsrc->event_mode) {
+ struct l2fwd_event_resources *evt_rsrc = rsrc->evt_rsrc;
+ struct rte_event_eth_rx_adapter_stats rx_adptr_stats;
+ struct rte_event_eth_tx_adapter_stats tx_adptr_stats;
+ int ret, i;
+
+ for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) {
+ ret = rte_event_eth_rx_adapter_stats_get(
+ evt_rsrc->rx_adptr.rx_adptr[i],
+ &rx_adptr_stats);
+ if (ret < 0)
+ continue;
+ printf("\nRx adapter[%d] statistics===================="
+ "\nReceive queue poll count: %17"PRIu64
+ "\nReceived packet count: %20"PRIu64
+ "\nEventdev enqueue count: %19"PRIu64
+ "\nEventdev enqueue retry count: %13"PRIu64
+ "\nReceived packet dropped count: %12"PRIu64
+ "\nRx enqueue start timestamp: %15"PRIu64
+ "\nRx enqueue block cycles: %18"PRIu64
+ "\nRx enqueue unblock timestamp: %13"PRIu64,
+ evt_rsrc->rx_adptr.rx_adptr[i],
+ rx_adptr_stats.rx_poll_count,
+ rx_adptr_stats.rx_packets,
+ rx_adptr_stats.rx_enq_count,
+ rx_adptr_stats.rx_enq_retry,
+ rx_adptr_stats.rx_dropped,
+ rx_adptr_stats.rx_enq_start_ts,
+ rx_adptr_stats.rx_enq_block_cycles,
+ rx_adptr_stats.rx_enq_end_ts);
+ }
+ for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++) {
+ ret = rte_event_eth_tx_adapter_stats_get(
+ evt_rsrc->tx_adptr.tx_adptr[i],
+ &tx_adptr_stats);
+ if (ret < 0)
+ continue;
+ printf("\nTx adapter[%d] statistics===================="
+ "\nNumber of transmit retries: %15"PRIu64
+ "\nNumber of packets transmitted: %12"PRIu64
+ "\nNumber of packets dropped: %16"PRIu64,
+ evt_rsrc->tx_adptr.tx_adptr[i],
+ tx_adptr_stats.tx_retry,
+ tx_adptr_stats.tx_packets,
+ tx_adptr_stats.tx_dropped);
+ }
+ }
+ printf("\nAggregate lcore statistics ========================="
+ "\nTotal packets sent: %23"PRIu64
+ "\nTotal packets received: %19"PRIu64
+ "\nTotal packets dropped: %20"PRIu64,
total_packets_tx,
total_packets_rx,
total_packets_dropped);
printf("\n====================================================\n");
+
+ fflush(stdout);
}
static void
uint16_t port_id, last_port;
uint32_t nb_mbufs;
uint16_t nb_ports;
- int ret;
+ int i, ret;
- /* init EAL */
+ /* Init EAL. 8< */
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_panic("Invalid EAL arguments\n");
ret = l2fwd_event_parse_args(argc, argv, rsrc);
if (ret < 0)
rte_panic("Invalid L2FWD arguments\n");
+ /* >8 End of init EAL. */
printf("MAC updating %s\n", rsrc->mac_updating ? "enabled" :
"disabled");
rte_panic("Invalid portmask; possible (0x%x)\n",
(1 << nb_ports) - 1);
- /* reset l2fwd_dst_ports */
- for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++)
- rsrc->dst_ports[port_id] = 0;
- last_port = 0;
+ if (!rsrc->port_pairs) {
+ last_port = 0;
+ /*
+ * Each logical core is assigned a dedicated TX queue on each
+ * port.
+ */
+ RTE_ETH_FOREACH_DEV(port_id) {
+ /* skip ports that are not enabled */
+ if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
+ continue;
- /*
- * Each logical core is assigned a dedicated TX queue on each port.
- */
- RTE_ETH_FOREACH_DEV(port_id) {
- /* skip ports that are not enabled */
- if ((rsrc->enabled_port_mask & (1 << port_id)) == 0)
- continue;
+ if (nb_ports_in_mask % 2) {
+ rsrc->dst_ports[port_id] = last_port;
+ rsrc->dst_ports[last_port] = port_id;
+ } else {
+ last_port = port_id;
+ }
+ nb_ports_in_mask++;
+ }
if (nb_ports_in_mask % 2) {
- rsrc->dst_ports[port_id] = last_port;
- rsrc->dst_ports[last_port] = port_id;
- } else {
- last_port = port_id;
+ printf("Notice: odd number of ports in portmask.\n");
+ rsrc->dst_ports[last_port] = last_port;
}
-
- nb_ports_in_mask++;
- }
- if (nb_ports_in_mask % 2) {
- printf("Notice: odd number of ports in portmask.\n");
- rsrc->dst_ports[last_port] = last_port;
+ } else {
+ if (check_port_pair_config(rsrc) < 0)
+ rte_panic("Invalid port pair config\n");
}
nb_mbufs = RTE_MAX(nb_ports * (RTE_TEST_RX_DESC_DEFAULT +
MAX_PKT_BURST + rte_lcore_count() *
MEMPOOL_CACHE_SIZE), 8192U);
- /* create the mbuf pool */
+ /* Create the mbuf pool. 8< */
rsrc->pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool",
nb_mbufs, MEMPOOL_CACHE_SIZE, 0,
RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (rsrc->pktmbuf_pool == NULL)
rte_panic("Cannot init mbuf pool\n");
+ /* >8 End of creation of mbuf pool. */
+
+ if (rsrc->evt_vec.enabled) {
+ unsigned int nb_vec, vec_size;
+
+ vec_size = rsrc->evt_vec.size;
+ nb_vec = (nb_mbufs + vec_size - 1) / vec_size;
+ rsrc->evt_vec_pool = rte_event_vector_pool_create(
+ "vector_pool", nb_vec, 0, vec_size, rte_socket_id());
+ if (rsrc->evt_vec_pool == NULL)
+ rte_panic("Cannot init event vector pool\n");
+ }
nb_ports_available = l2fwd_event_init_ports(rsrc);
if (!nb_ports_available)
port_id);
}
+ if (rsrc->event_mode)
+ l2fwd_event_service_setup(rsrc);
+
check_all_ports_link_status(rsrc, rsrc->enabled_port_mask);
/* launch per-lcore init on every lcore */
rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, rsrc,
- SKIP_MASTER);
+ SKIP_MAIN);
l2fwd_event_print_stats(rsrc);
- rte_eal_mp_wait_lcore();
+ if (rsrc->event_mode) {
+ struct l2fwd_event_resources *evt_rsrc =
+ rsrc->evt_rsrc;
+ for (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++)
+ rte_event_eth_rx_adapter_stop(
+ evt_rsrc->rx_adptr.rx_adptr[i]);
+ for (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++)
+ rte_event_eth_tx_adapter_stop(
+ evt_rsrc->tx_adptr.tx_adptr[i]);
- RTE_ETH_FOREACH_DEV(port_id) {
- if ((rsrc->enabled_port_mask &
- (1 << port_id)) == 0)
- continue;
- printf("Closing port %d...", port_id);
- rte_eth_dev_stop(port_id);
- rte_eth_dev_close(port_id);
- printf(" Done\n");
+ RTE_ETH_FOREACH_DEV(port_id) {
+ if ((rsrc->enabled_port_mask &
+ (1 << port_id)) == 0)
+ continue;
+ ret = rte_eth_dev_stop(port_id);
+ if (ret < 0)
+ printf("rte_eth_dev_stop:err=%d, port=%u\n",
+ ret, port_id);
+ }
+
+ rte_eal_mp_wait_lcore();
+ RTE_ETH_FOREACH_DEV(port_id) {
+ if ((rsrc->enabled_port_mask &
+ (1 << port_id)) == 0)
+ continue;
+ rte_eth_dev_close(port_id);
+ }
+
+ rte_event_dev_stop(evt_rsrc->event_d_id);
+ rte_event_dev_close(evt_rsrc->event_d_id);
+
+ } else {
+ rte_eal_mp_wait_lcore();
+
+ RTE_ETH_FOREACH_DEV(port_id) {
+ if ((rsrc->enabled_port_mask &
+ (1 << port_id)) == 0)
+ continue;
+ printf("Closing port %d...", port_id);
+ ret = rte_eth_dev_stop(port_id);
+ if (ret < 0)
+ printf("rte_eth_dev_stop:err=%d, port=%u\n",
+ ret, port_id);
+ rte_eth_dev_close(port_id);
+ printf(" Done\n");
+ }
}
+
+ /* clean up the EAL */
+ rte_eal_cleanup();
printf("Bye...\n");
return 0;