When doing benchmarking it is important to disable NIC
flow control. Testpmd can do this only from the interactive
command line, there was no option to do this from a script.

Add --flow-ctrl=none|rx|tx|full, applied each time a port
is started. Devices without flow control support are skipped.

Signed-off-by: Stephen Hemminger <[email protected]>
---
 app/test-pmd/parameters.c             | 18 +++++++++++++++++
 app/test-pmd/testpmd.c                | 28 +++++++++++++++++++++++++++
 app/test-pmd/testpmd.h                |  1 +
 doc/guides/testpmd_app_ug/run_app.rst |  5 +++++
 4 files changed, 52 insertions(+)

diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 833b14eda4..f031dd7445 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -207,6 +207,8 @@ enum {
        TESTPMD_OPT_NO_LSC_INTERRUPT_NUM,
 #define TESTPMD_OPT_NO_RMV_INTERRUPT "no-rmv-interrupt"
        TESTPMD_OPT_NO_RMV_INTERRUPT_NUM,
+#define TESTPMD_OPT_FLOW_CTRL "flow-ctrl"
+       TESTPMD_OPT_FLOW_CTRL_NUM,
 #define TESTPMD_OPT_PRINT_EVENT "print-event"
        TESTPMD_OPT_PRINT_EVENT_NUM,
 #define TESTPMD_OPT_MASK_EVENT "mask-event"
@@ -357,6 +359,7 @@ static const struct option long_options[] = {
        NO_ARG(TESTPMD_OPT_DISABLE_DEVICE_START),
        NO_ARG(TESTPMD_OPT_NO_LSC_INTERRUPT),
        NO_ARG(TESTPMD_OPT_NO_RMV_INTERRUPT),
+       REQUIRED_ARG(TESTPMD_OPT_FLOW_CTRL),
        REQUIRED_ARG(TESTPMD_OPT_PRINT_EVENT),
        REQUIRED_ARG(TESTPMD_OPT_MASK_EVENT),
        REQUIRED_ARG(TESTPMD_OPT_TX_OFFLOADS),
@@ -515,6 +518,8 @@ usage(char* progname)
        printf("  --disable-device-start: do not automatically start port\n");
        printf("  --no-lsc-interrupt: disable link status change interrupt.\n");
        printf("  --no-rmv-interrupt: disable device removal interrupt.\n");
+       printf("  --flow-ctrl=none|rx|tx|full: set Ethernet flow control"
+              " mode when ports are started.\n");
 #ifdef RTE_LIB_BITRATESTATS
        printf("  --bitrate-stats=N: set the logical core N to perform "
                "bit-rate calculation.\n");
@@ -1635,6 +1640,19 @@ launch_args_parse(int argc, char** argv)
                case TESTPMD_OPT_NO_RMV_INTERRUPT_NUM:
                        rmv_interrupt = 0;
                        break;
+               case TESTPMD_OPT_FLOW_CTRL_NUM:
+                       if (!strcmp(optarg, "none"))
+                               flow_ctrl_mode = RTE_ETH_FC_NONE;
+                       else if (!strcmp(optarg, "rx"))
+                               flow_ctrl_mode = RTE_ETH_FC_RX_PAUSE;
+                       else if (!strcmp(optarg, "tx"))
+                               flow_ctrl_mode = RTE_ETH_FC_TX_PAUSE;
+                       else if (!strcmp(optarg, "full"))
+                               flow_ctrl_mode = RTE_ETH_FC_FULL;
+                       else
+                               rte_exit(EXIT_FAILURE,
+                                        "flow-ctrl must be none, rx, tx or 
full\n");
+                       break;
                case TESTPMD_OPT_FLOW_ISOLATE_ALL_NUM:
                        flow_isolate_all = 1;
                        break;
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index d6211a9a8a..e1766eec72 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -446,6 +446,12 @@ uint8_t lsc_interrupt = 1; /* enabled by default */
  */
 uint8_t rmv_interrupt = 1; /* enabled by default */
 
+/*
+ * Ethernet flow control mode applied on port start.
+ * Negative means leave the device default.
+ */
+int flow_ctrl_mode = -1;
+
 uint8_t hot_plug = 0; /**< hotplug disabled by default. */
 
 /* After attach, port setup is called on event or by iterator */
@@ -2973,6 +2979,26 @@ update_bonding_port_dev_conf(portid_t bond_pid)
 #endif
 }
 
+static void
+port_flow_ctrl_apply(portid_t pi)
+{
+       struct rte_eth_fc_conf fc_conf;
+       int ret;
+
+       if (flow_ctrl_mode < 0 || !is_proc_primary())
+               return;
+
+       memset(&fc_conf, 0, sizeof(fc_conf));
+       ret = rte_eth_dev_flow_ctrl_get(pi, &fc_conf);
+       if (ret == 0) {
+               fc_conf.mode = flow_ctrl_mode;
+               ret = rte_eth_dev_flow_ctrl_set(pi, &fc_conf);
+       }
+       if (ret != 0 && ret != -ENOTSUP)
+               fprintf(stderr, "Port %u: failed to set flow control: %s\n",
+                       pi, rte_strerror(-ret));
+}
+
 int
 start_port(portid_t pid)
 {
@@ -3229,6 +3255,8 @@ start_port(portid_t pid)
                        fprintf(stderr, "Port %d can not be set into started\n",
                                pi);
 
+               port_flow_ctrl_apply(pi);
+
                if (eth_macaddr_get_print_err(pi, &port->eth_addr) == 0)
                        printf("Port %d: " RTE_ETHER_ADDR_PRT_FMT "\n", pi,
                                        RTE_ETHER_ADDR_BYTES(&port->eth_addr));
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 2ca4aaf086..6d4c3e8f84 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -541,6 +541,7 @@ extern uint8_t no_device_start; /**<set by 
"--disable-device-start" parameter */
 extern volatile int test_done; /* stop packet forwarding when set to 1. */
 extern uint8_t lsc_interrupt; /**< disabled by "--no-lsc-interrupt" parameter 
*/
 extern uint8_t rmv_interrupt; /**< disabled by "--no-rmv-interrupt" parameter 
*/
+extern int flow_ctrl_mode; /**< set by "--flow-ctrl" parameter */
 extern uint32_t event_print_mask;
 /**< set by "--print-event xxxx" and "--mask-event xxxx parameters */
 extern bool setup_on_probe_event; /**< disabled by port setup-on iterator */
diff --git a/doc/guides/testpmd_app_ug/run_app.rst 
b/doc/guides/testpmd_app_ug/run_app.rst
index bcfbf33f92..e678058b97 100644
--- a/doc/guides/testpmd_app_ug/run_app.rst
+++ b/doc/guides/testpmd_app_ug/run_app.rst
@@ -224,6 +224,11 @@ The command line options are:
 
     Disable RSS (Receive Side Scaling).
 
+*   ``--flow-ctrl=mode``
+
+    Set the Ethernet flow control mode of all ports each time they are started.
+    The possible values are ``none``, ``rx``, ``tx`` and ``full``.
+
 *   ``--port-topology=mode``
 
     Set port topology, where mode is ``paired`` (the default), ``chained`` or 
``loop``.
-- 
2.53.0

Reply via email to