"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
{ "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 },
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) {
/* 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",
/* 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 = {
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++;
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++;
{
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;
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);
pi);
}
+ p_pi = pi;
+ cnt_pi++;
+
/* start port */
if (rte_eth_dev_start(pi) < 0) {
printf("Fail to start port %d\n", pi);
/* 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)
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\n",
+ 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\n",
+ peer_pl[j], pi,
+ rte_strerror(-diag));
+ return -1;
+ }
+ }
+ }
+ }
+
printf("Done\n");
return 0;
}
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;
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),