app/testpmd: support hairpin

This commit introduce the hairpin queues to the testpmd.
the hairpin queue is configured using --hairpinq=<n>
the hairpin queue adds n queue objects for both the total number
of TX queues and RX queues.
The connection between the queues are 1 to 1, first Rx hairpin queue
will be connected to the first Tx hairpin queue

Signed-off-by: Ori Kam <orika@mellanox.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
This commit is contained in:
Ori Kam 2019-11-05 19:05:19 +00:00 committed by Ferruh Yigit
parent 653b285ff1
commit 1c69df45f8
4 changed files with 160 additions and 2 deletions

View File

@ -149,6 +149,8 @@ usage(char* progname)
printf(" --rxd=N: set the number of descriptors in RX rings to N.\n");
printf(" --txq=N: set the number of TX queues per port to N.\n");
printf(" --txd=N: set the number of descriptors in TX rings to N.\n");
printf(" --hairpinq=N: set the number of hairpin queues per port to "
"N.\n");
printf(" --burst=N: set the number of packets per burst to N.\n");
printf(" --mbcache=N: set the cache of mbuf memory pool to N.\n");
printf(" --rxpt=N: set prefetch threshold register of RX rings to N.\n");
@ -622,6 +624,7 @@ launch_args_parse(int argc, char** argv)
{ "txq", 1, 0, 0 },
{ "rxd", 1, 0, 0 },
{ "txd", 1, 0, 0 },
{ "hairpinq", 1, 0, 0 },
{ "burst", 1, 0, 0 },
{ "mbcache", 1, 0, 0 },
{ "txpt", 1, 0, 0 },
@ -1045,6 +1048,31 @@ launch_args_parse(int argc, char** argv)
" >= 0 && <= %u\n", n,
get_allowed_max_nb_txq(&pid));
}
if (!strcmp(lgopts[opt_idx].name, "hairpinq")) {
n = atoi(optarg);
if (n >= 0 &&
check_nb_hairpinq((queueid_t)n) == 0)
nb_hairpinq = (queueid_t) n;
else
rte_exit(EXIT_FAILURE, "txq %d invalid - must be"
" >= 0 && <= %u\n", n,
get_allowed_max_nb_hairpinq
(&pid));
if ((n + nb_txq) < 0 ||
check_nb_txq((queueid_t)(n + nb_txq)) != 0)
rte_exit(EXIT_FAILURE, "txq + hairpinq "
"%d invalid - must be"
" >= 0 && <= %u\n",
n + nb_txq,
get_allowed_max_nb_txq(&pid));
if ((n + nb_rxq) < 0 ||
check_nb_rxq((queueid_t)(n + nb_rxq)) != 0)
rte_exit(EXIT_FAILURE, "rxq + hairpinq "
"%d invalid - must be"
" >= 0 && <= %u\n",
n + nb_rxq,
get_allowed_max_nb_rxq(&pid));
}
if (!nb_rxq && !nb_txq) {
rte_exit(EXIT_FAILURE, "Either rx or tx queues should "
"be non-zero\n");

View File

@ -234,6 +234,7 @@ uint8_t dcb_test = 0;
/*
* Configurable number of RX/TX queues.
*/
queueid_t nb_hairpinq; /**< Number of hairpin queues per port. */
queueid_t nb_rxq = 1; /**< Number of RX queues per port. */
queueid_t nb_txq = 1; /**< Number of TX queues per port. */
@ -1067,6 +1068,53 @@ check_nb_txq(queueid_t txq)
return 0;
}
/*
* Get the allowed maximum number of hairpin queues.
* *pid return the port id which has minimal value of
* max_hairpin_queues in all ports.
*/
queueid_t
get_allowed_max_nb_hairpinq(portid_t *pid)
{
queueid_t allowed_max_hairpinq = MAX_QUEUE_ID;
portid_t pi;
struct rte_eth_hairpin_cap cap;
RTE_ETH_FOREACH_DEV(pi) {
if (rte_eth_dev_hairpin_capability_get(pi, &cap) != 0) {
*pid = pi;
return 0;
}
if (cap.max_nb_queues < allowed_max_hairpinq) {
allowed_max_hairpinq = cap.max_nb_queues;
*pid = pi;
}
}
return allowed_max_hairpinq;
}
/*
* Check input hairpin is valid or not.
* If input hairpin is not greater than any of maximum number
* of hairpin queues of all ports, it is valid.
* if valid, return 0, else return -1
*/
int
check_nb_hairpinq(queueid_t hairpinq)
{
queueid_t allowed_max_hairpinq;
portid_t pid = 0;
allowed_max_hairpinq = get_allowed_max_nb_hairpinq(&pid);
if (hairpinq > allowed_max_hairpinq) {
printf("Fail: input hairpin (%u) can't be greater "
"than max_hairpin_queues (%u) of port %u\n",
hairpinq, allowed_max_hairpinq, pid);
return -1;
}
return 0;
}
static void
init_config(void)
{
@ -2016,6 +2064,63 @@ port_is_started(portid_t port_id)
return 1;
}
/* Configure the Rx and Tx hairpin queues for the selected port. */
static int
setup_hairpin_queues(portid_t pi)
{
queueid_t qi;
struct rte_eth_hairpin_conf hairpin_conf = {
.peer_count = 1,
};
int i;
int diag;
struct rte_port *port = &ports[pi];
for (qi = nb_txq, i = 0; qi < nb_hairpinq + nb_txq; qi++) {
hairpin_conf.peers[0].port = pi;
hairpin_conf.peers[0].queue = i + nb_rxq;
diag = rte_eth_tx_hairpin_queue_setup
(pi, qi, nb_txd, &hairpin_conf);
i++;
if (diag == 0)
continue;
/* Fail to setup rx queue, return */
if (rte_atomic16_cmpset(&(port->port_status),
RTE_PORT_HANDLING,
RTE_PORT_STOPPED) == 0)
printf("Port %d can not be set back "
"to stopped\n", pi);
printf("Fail to configure port %d hairpin "
"queues\n", pi);
/* try to reconfigure queues next time */
port->need_reconfig_queues = 1;
return -1;
}
for (qi = nb_rxq, i = 0; qi < nb_hairpinq + nb_rxq; qi++) {
hairpin_conf.peers[0].port = pi;
hairpin_conf.peers[0].queue = i + nb_txq;
diag = rte_eth_rx_hairpin_queue_setup
(pi, qi, nb_rxd, &hairpin_conf);
i++;
if (diag == 0)
continue;
/* Fail to setup rx queue, return */
if (rte_atomic16_cmpset(&(port->port_status),
RTE_PORT_HANDLING,
RTE_PORT_STOPPED) == 0)
printf("Port %d can not be set back "
"to stopped\n", pi);
printf("Fail to configure port %d hairpin "
"queues\n", pi);
/* try to reconfigure queues next time */
port->need_reconfig_queues = 1;
return -1;
}
return 0;
}
int
start_port(portid_t pid)
{
@ -2024,6 +2129,7 @@ start_port(portid_t pid)
queueid_t qi;
struct rte_port *port;
struct rte_ether_addr mac_addr;
struct rte_eth_hairpin_cap cap;
if (port_id_is_invalid(pid, ENABLED_WARN))
return 0;
@ -2056,9 +2162,16 @@ start_port(portid_t pid)
configure_rxtx_dump_callbacks(0);
printf("Configuring Port %d (socket %u)\n", pi,
port->socket_id);
if (nb_hairpinq > 0 &&
rte_eth_dev_hairpin_capability_get(pi, &cap)) {
printf("Port %d doesn't support hairpin "
"queues\n", pi);
return -1;
}
/* configure port */
diag = rte_eth_dev_configure(pi, nb_rxq, nb_txq,
&(port->dev_conf));
diag = rte_eth_dev_configure(pi, nb_rxq + nb_hairpinq,
nb_txq + nb_hairpinq,
&(port->dev_conf));
if (diag != 0) {
if (rte_atomic16_cmpset(&(port->port_status),
RTE_PORT_HANDLING, RTE_PORT_STOPPED) == 0)
@ -2151,6 +2264,9 @@ start_port(portid_t pid)
port->need_reconfig_queues = 1;
return -1;
}
/* setup hairpin queues */
if (setup_hairpin_queues(pi) != 0)
return -1;
}
configure_rxtx_dump_callbacks(verbose_level);
/* start port */

View File

@ -385,6 +385,7 @@ extern struct rte_eth_txmode tx_mode;
extern uint64_t rss_hf;
extern queueid_t nb_hairpinq;
extern queueid_t nb_rxq;
extern queueid_t nb_txq;
@ -859,6 +860,8 @@ queueid_t get_allowed_max_nb_rxq(portid_t *pid);
int check_nb_rxq(queueid_t rxq);
queueid_t get_allowed_max_nb_txq(portid_t *pid);
int check_nb_txq(queueid_t txq);
queueid_t get_allowed_max_nb_hairpinq(portid_t *pid);
int check_nb_hairpinq(queueid_t hairpinq);
uint16_t dump_rx_pkts(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
uint16_t nb_pkts, __rte_unused uint16_t max_pkts,

View File

@ -266,6 +266,17 @@ The command line options are:
Set the number of descriptors in the TX rings to N, where N > 0.
The default value is 512.
* ``--hairpinq=N``
Set the number of hairpin queues per port to N, where 1 <= N <= 65535.
The default value is 0. The number of hairpin queues are added to the
number of TX queues and to the number of RX queues. then the first
RX hairpin is binded to the first TX hairpin, the second RX hairpin is
binded to the second TX hairpin and so on. The index of the first
RX hairpin queue is the number of RX queues as configured using --rxq.
The index of the first TX hairpin queue is the number of TX queues
as configured using --txq.
* ``--burst=N``
Set the number of packets per burst to N, where 1 <= N <= 512.