@@ -222,6 +222,9 @@
"enabled\n");
printf(" --record-core-cycles: enable measurement of CPU cycles.\n");
printf(" --record-burst-stats: enable display of RX and TX bursts.\n");
+ printf(" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n "
+ " 0x10 - explicit tx rule, 0x02 - hairpin ports paired\n"
+ " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n");
}
#ifdef RTE_LIBRTE_CMDLINE
@@ -645,6 +648,7 @@
{ "rxd", 1, 0, 0 },
{ "txd", 1, 0, 0 },
{ "hairpinq", 1, 0, 0 },
+ { "hairpin-mode", 1, 0, 0 },
{ "burst", 1, 0, 0 },
{ "mbcache", 1, 0, 0 },
{ "txpt", 1, 0, 0 },
@@ -1113,6 +1117,17 @@
rte_exit(EXIT_FAILURE, "Either rx or tx queues should "
"be non-zero\n");
}
+ if (!strcmp(lgopts[opt_idx].name, "hairpin-mode")) {
+ char *end = NULL;
+ unsigned int n;
+
+ errno = 0;
+ n = strtoul(optarg, &end, 0);
+ if (errno != 0 || end == optarg)
+ rte_exit(EXIT_FAILURE, "hairpin mode invalid\n");
+ else
+ hairpin_mode = (uint16_t)n;
+ }
if (!strcmp(lgopts[opt_idx].name, "burst")) {
n = atoi(optarg);
if (n == 0) {
@@ -367,6 +367,9 @@ struct fwd_engine * fwd_engines[] = {
/* Clear ptypes on port initialization. */
uint8_t clear_ptypes = true;
+/* Hairpin ports configuration mode. */
+uint16_t hairpin_mode;
+
/* Pretty printing of ethdev events */
static const char * const eth_event_desc[] = {
[RTE_ETH_EVENT_UNKNOWN] = "unknown",
@@ -2345,7 +2348,7 @@ struct extmem_param {
/* Configure the Rx and Tx hairpin queues for the selected port. */
static int
-setup_hairpin_queues(portid_t pi)
+setup_hairpin_queues(portid_t pi, portid_t p_pi, uint16_t cnt_pi)
{
queueid_t qi;
struct rte_eth_hairpin_conf hairpin_conf = {
@@ -2354,10 +2357,49 @@ struct extmem_param {
int i;
int diag;
struct rte_port *port = &ports[pi];
+ uint16_t peer_rx_port = pi;
+ uint16_t peer_tx_port = pi;
+ uint32_t manual = 1;
+ uint32_t tx_exp = hairpin_mode & 0x10;
+
+ if (!(hairpin_mode & 0xf)) {
+ peer_rx_port = pi;
+ peer_tx_port = pi;
+ manual = 0;
+ } else if (hairpin_mode & 0x1) {
+ peer_tx_port = rte_eth_find_next_owned_by(pi + 1,
+ RTE_ETH_DEV_NO_OWNER);
+ if (peer_tx_port >= RTE_MAX_ETHPORTS)
+ peer_tx_port = rte_eth_find_next_owned_by(0,
+ RTE_ETH_DEV_NO_OWNER);
+ if (p_pi != RTE_MAX_ETHPORTS) {
+ peer_rx_port = p_pi;
+ } else {
+ uint16_t next_pi;
+
+ /* Last port will be the peer RX port of the first. */
+ RTE_ETH_FOREACH_DEV(next_pi)
+ peer_rx_port = next_pi;
+ }
+ manual = 1;
+ } else if (hairpin_mode & 0x2) {
+ if (cnt_pi & 0x1) {
+ peer_rx_port = p_pi;
+ } else {
+ peer_rx_port = rte_eth_find_next_owned_by(pi + 1,
+ RTE_ETH_DEV_NO_OWNER);
+ if (peer_rx_port >= RTE_MAX_ETHPORTS)
+ peer_rx_port = pi;
+ }
+ peer_tx_port = peer_rx_port;
+ manual = 1;
+ }
for (qi = nb_txq, i = 0; qi < nb_hairpinq + nb_txq; qi++) {
- hairpin_conf.peers[0].port = pi;
+ hairpin_conf.peers[0].port = peer_rx_port;
hairpin_conf.peers[0].queue = i + nb_rxq;
+ hairpin_conf.manual_bind = !!manual;
+ hairpin_conf.tx_explicit = !!tx_exp;
diag = rte_eth_tx_hairpin_queue_setup
(pi, qi, nb_txd, &hairpin_conf);
i++;
@@ -2377,8 +2419,10 @@ struct extmem_param {
return -1;
}
for (qi = nb_rxq, i = 0; qi < nb_hairpinq + nb_rxq; qi++) {
- hairpin_conf.peers[0].port = pi;
+ hairpin_conf.peers[0].port = peer_tx_port;
hairpin_conf.peers[0].queue = i + nb_txq;
+ hairpin_conf.manual_bind = !!manual;
+ hairpin_conf.tx_explicit = !!tx_exp;
diag = rte_eth_rx_hairpin_queue_setup
(pi, qi, nb_rxd, &hairpin_conf);
i++;
@@ -2405,6 +2449,12 @@ struct extmem_param {
{
int diag, need_check_link_status = -1;
portid_t pi;
+ portid_t p_pi = RTE_MAX_ETHPORTS;
+ portid_t pl[RTE_MAX_ETHPORTS];
+ portid_t peer_pl[RTE_MAX_ETHPORTS];
+ uint16_t cnt_pi = 0;
+ uint16_t cfg_pi = 0;
+ int peer_pi;
queueid_t qi;
struct rte_port *port;
struct rte_ether_addr mac_addr;
@@ -2544,7 +2594,7 @@ struct extmem_param {
return -1;
}
/* setup hairpin queues */
- if (setup_hairpin_queues(pi) != 0)
+ if (setup_hairpin_queues(pi, p_pi, cnt_pi) != 0)
return -1;
}
configure_rxtx_dump_callbacks(verbose_level);
@@ -2557,6 +2607,9 @@ struct extmem_param {
pi);
}
+ p_pi = pi;
+ cnt_pi++;
+
/* start port */
if (rte_eth_dev_start(pi) < 0) {
printf("Fail to start port %d\n", pi);
@@ -2581,6 +2634,8 @@ struct extmem_param {
/* at least one port started, need checking link status */
need_check_link_status = 1;
+
+ pl[cfg_pi++] = pi;
}
if (need_check_link_status == 1 && !no_link_check)
@@ -2588,6 +2643,50 @@ struct extmem_param {
else if (need_check_link_status == 0)
printf("Please stop the ports first\n");
+ if (hairpin_mode & 0xf) {
+ uint16_t i;
+ int j;
+
+ /* bind all started hairpin ports */
+ for (i = 0; i < cfg_pi; i++) {
+ pi = pl[i];
+ /* bind current TX to all peer RX */
+ peer_pi = rte_eth_hairpin_get_peer_ports(pi, peer_pl,
+ RTE_MAX_ETHPORTS, 1);
+ if (peer_pi < 0)
+ return peer_pi;
+ for (j = 0; j < peer_pi; j++) {
+ if (!port_is_started(peer_pl[j]))
+ continue;
+ diag = rte_eth_hairpin_bind(pi, peer_pl[j]);
+ if (diag < 0) {
+ printf("Error during binding "
+ "hairpin tx port %u to %u: %s",
+ pi, peer_pl[j],
+ rte_strerror(-diag));
+ return -1;
+ }
+ }
+ /* bind all peer TX to current RX */
+ peer_pi = rte_eth_hairpin_get_peer_ports(pi, peer_pl,
+ RTE_MAX_ETHPORTS, 0);
+ if (peer_pi < 0)
+ return peer_pi;
+ for (j = 0; j < peer_pi; j++) {
+ if (!port_is_started(peer_pl[j]))
+ continue;
+ diag = rte_eth_hairpin_bind(peer_pl[j], pi);
+ if (diag < 0) {
+ printf("Error during binding "
+ "hairpin tx port %u to %u: %s",
+ peer_pl[j], pi,
+ rte_strerror(-diag));
+ return -1;
+ }
+ }
+ }
+ }
+
printf("Done\n");
return 0;
}
@@ -2598,6 +2697,8 @@ struct extmem_param {
portid_t pi;
struct rte_port *port;
int need_check_link_status = 0;
+ portid_t peer_pl[RTE_MAX_ETHPORTS];
+ int peer_pi;
if (dcb_test) {
dcb_test = 0;
@@ -2628,6 +2729,22 @@ struct extmem_param {
RTE_PORT_HANDLING) == 0)
continue;
+ if (hairpin_mode & 0xf) {
+ int j;
+
+ rte_eth_hairpin_unbind(pi, RTE_MAX_ETHPORTS);
+ /* unbind all peer TX from current RX */
+ peer_pi = rte_eth_hairpin_get_peer_ports(pi, peer_pl,
+ RTE_MAX_ETHPORTS, 0);
+ if (peer_pi < 0)
+ continue;
+ for (j = 0; j < peer_pi; j++) {
+ if (!port_is_started(peer_pl[j]))
+ continue;
+ rte_eth_hairpin_unbind(peer_pl[j], pi);
+ }
+ }
+
rte_eth_dev_stop(pi);
if (rte_atomic16_cmpset(&(port->port_status),
@@ -398,6 +398,8 @@ struct queue_stats_mappings {
extern uint16_t stats_period;
+extern uint16_t hairpin_mode;
+
#ifdef RTE_LIBRTE_LATENCY_STATS
extern uint8_t latencystats_enabled;
extern lcoreid_t latencystats_lcore_id;
@@ -503,3 +503,11 @@ The command line options are:
* ``--record-burst-stats``
Enable display of RX and TX burst stats.
+
+* ``--hairpin-mode=0xXX``
+
+ Set the hairpin port mode with bitmask, only valid when hairpin queues number is set.
+ bit 4 - explicit TX flow rule
+ bit 1 - two hairpin ports paired
+ bit 0 - two hairpin ports loop
+ The default value is 0. Hairpin will use single port mode and implicit TX flow mode.