app/testpmd: support hairpin
authorOri Kam <orika@mellanox.com>
Tue, 5 Nov 2019 19:05:19 +0000 (19:05 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 8 Nov 2019 22:15:05 +0000 (23:15 +0100)
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>
app/test-pmd/parameters.c
app/test-pmd/testpmd.c
app/test-pmd/testpmd.h
doc/guides/testpmd_app_ug/run_app.rst

index 9ea87c1..9b6e35b 100644 (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");
index 5ba9741..4444346 100644 (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 */
index 419997f..caabf32 100644 (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,
index 858cec7..8c7fe44 100644 (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.