422 lines
12 KiB
Diff
422 lines
12 KiB
Diff
|
|
From c7a841ce328cda8338494640b103d5182268fd1e Mon Sep 17 00:00:00 2001
|
|||
|
|
From: "Min Hu (Connor)" <humin29@huawei.com>
|
|||
|
|
Date: Wed, 25 Aug 2021 10:06:38 +0800
|
|||
|
|
Subject: [PATCH] app/testpmd: support multi-process
|
|||
|
|
|
|||
|
|
This patch adds multi-process support for testpmd.
|
|||
|
|
For example the following commands run two testpmd
|
|||
|
|
processes:
|
|||
|
|
|
|||
|
|
* the primary process:
|
|||
|
|
|
|||
|
|
./dpdk-testpmd --proc-type=auto -l 0-1 -- -i \
|
|||
|
|
--rxq=4 --txq=4 --num-procs=2 --proc-id=0
|
|||
|
|
|
|||
|
|
* the secondary process:
|
|||
|
|
|
|||
|
|
./dpdk-testpmd --proc-type=auto -l 2-3 -- -i \
|
|||
|
|
--rxq=4 --txq=4 --num-procs=2 --proc-id=1
|
|||
|
|
|
|||
|
|
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
|
|||
|
|
Signed-off-by: Lijun Ou <oulijun@huawei.com>
|
|||
|
|
Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
|
|||
|
|
Acked-by: Xiaoyun Li <xiaoyun.li@intel.com>
|
|||
|
|
Acked-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
|
|||
|
|
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
|
|||
|
|
Acked-by: Aman Deep Singh <aman.deep.singh@intel.com>
|
|||
|
|
---
|
|||
|
|
app/test-pmd/cmdline.c | 6 ++
|
|||
|
|
app/test-pmd/config.c | 20 +++++-
|
|||
|
|
app/test-pmd/parameters.c | 9 +++
|
|||
|
|
app/test-pmd/testpmd.c | 92 +++++++++++++++++++++++----
|
|||
|
|
app/test-pmd/testpmd.h | 11 ++++
|
|||
|
|
doc/guides/testpmd_app_ug/run_app.rst | 84 ++++++++++++++++++++++++
|
|||
|
|
6 files changed, 210 insertions(+), 12 deletions(-)
|
|||
|
|
|
|||
|
|
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
|
|||
|
|
index 5691fab94..b701129d8 100644
|
|||
|
|
--- a/app/test-pmd/cmdline.c
|
|||
|
|
+++ b/app/test-pmd/cmdline.c
|
|||
|
|
@@ -5441,6 +5441,12 @@ cmd_set_flush_rx_parsed(void *parsed_result,
|
|||
|
|
__rte_unused void *data)
|
|||
|
|
{
|
|||
|
|
struct cmd_set_flush_rx *res = parsed_result;
|
|||
|
|
+
|
|||
|
|
+ if (num_procs > 1 && (strcmp(res->mode, "on") == 0)) {
|
|||
|
|
+ printf("multi-process doesn't support to flush Rx queues.\n");
|
|||
|
|
+ return;
|
|||
|
|
+ }
|
|||
|
|
+
|
|||
|
|
no_flush_rx = (uint8_t)((strcmp(res->mode, "on") == 0) ? 0 : 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
|
|||
|
|
index 7af13f65c..0d6639020 100644
|
|||
|
|
--- a/app/test-pmd/config.c
|
|||
|
|
+++ b/app/test-pmd/config.c
|
|||
|
|
@@ -3117,6 +3117,8 @@ rss_fwd_config_setup(void)
|
|||
|
|
queueid_t rxq;
|
|||
|
|
queueid_t nb_q;
|
|||
|
|
streamid_t sm_id;
|
|||
|
|
+ int start;
|
|||
|
|
+ int end;
|
|||
|
|
|
|||
|
|
nb_q = nb_rxq;
|
|||
|
|
if (nb_q > nb_txq)
|
|||
|
|
@@ -3134,7 +3136,21 @@ rss_fwd_config_setup(void)
|
|||
|
|
init_fwd_streams();
|
|||
|
|
|
|||
|
|
setup_fwd_config_of_each_lcore(&cur_fwd_config);
|
|||
|
|
- rxp = 0; rxq = 0;
|
|||
|
|
+
|
|||
|
|
+ if (proc_id > 0 && nb_q % num_procs != 0)
|
|||
|
|
+ printf("Warning! queue numbers should be multiple of processes, or packet loss will happen.\n");
|
|||
|
|
+
|
|||
|
|
+ /**
|
|||
|
|
+ * In multi-process, All queues are allocated to different
|
|||
|
|
+ * processes based on num_procs and proc_id. For example:
|
|||
|
|
+ * if supports 4 queues(nb_q), 2 processes(num_procs),
|
|||
|
|
+ * the 0~1 queue for primary process.
|
|||
|
|
+ * the 2~3 queue for secondary process.
|
|||
|
|
+ */
|
|||
|
|
+ start = proc_id * nb_q / num_procs;
|
|||
|
|
+ end = start + nb_q / num_procs;
|
|||
|
|
+ rxp = 0;
|
|||
|
|
+ rxq = start;
|
|||
|
|
for (sm_id = 0; sm_id < cur_fwd_config.nb_fwd_streams; sm_id++) {
|
|||
|
|
struct fwd_stream *fs;
|
|||
|
|
|
|||
|
|
@@ -3151,6 +3167,8 @@ rss_fwd_config_setup(void)
|
|||
|
|
continue;
|
|||
|
|
rxp = 0;
|
|||
|
|
rxq++;
|
|||
|
|
+ if (rxq >= end)
|
|||
|
|
+ rxq = start;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
|
|||
|
|
index 414a0068f..c464c42f6 100644
|
|||
|
|
--- a/app/test-pmd/parameters.c
|
|||
|
|
+++ b/app/test-pmd/parameters.c
|
|||
|
|
@@ -487,6 +487,9 @@ parse_event_printing_config(const char *optarg, int enable)
|
|||
|
|
void
|
|||
|
|
launch_args_parse(int argc, char** argv)
|
|||
|
|
{
|
|||
|
|
+#define PARAM_PROC_ID "proc-id"
|
|||
|
|
+#define PARAM_NUM_PROCS "num-procs"
|
|||
|
|
+
|
|||
|
|
int n, opt;
|
|||
|
|
char **argvopt;
|
|||
|
|
int opt_idx;
|
|||
|
|
@@ -603,6 +606,8 @@ launch_args_parse(int argc, char** argv)
|
|||
|
|
{ "rx-mq-mode", 1, 0, 0 },
|
|||
|
|
{ "record-core-cycles", 0, 0, 0 },
|
|||
|
|
{ "record-burst-stats", 0, 0, 0 },
|
|||
|
|
+ { PARAM_NUM_PROCS, 1, 0, 0 },
|
|||
|
|
+ { PARAM_PROC_ID, 1, 0, 0 },
|
|||
|
|
{ 0, 0, 0, 0 },
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
@@ -1359,6 +1364,10 @@ launch_args_parse(int argc, char** argv)
|
|||
|
|
record_core_cycles = 1;
|
|||
|
|
if (!strcmp(lgopts[opt_idx].name, "record-burst-stats"))
|
|||
|
|
record_burst_stats = 1;
|
|||
|
|
+ if (!strcmp(lgopts[opt_idx].name, PARAM_NUM_PROCS))
|
|||
|
|
+ num_procs = atoi(optarg);
|
|||
|
|
+ if (!strcmp(lgopts[opt_idx].name, PARAM_PROC_ID))
|
|||
|
|
+ proc_id = atoi(optarg);
|
|||
|
|
break;
|
|||
|
|
case 'h':
|
|||
|
|
usage(argv[0]);
|
|||
|
|
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
|
|||
|
|
index 0eaa4852d..983d8827d 100644
|
|||
|
|
--- a/app/test-pmd/testpmd.c
|
|||
|
|
+++ b/app/test-pmd/testpmd.c
|
|||
|
|
@@ -505,6 +505,61 @@ uint8_t gro_flush_cycles = GRO_DEFAULT_FLUSH_CYCLES;
|
|||
|
|
* hexadecimal bitmask of RX mq mode can be enabled.
|
|||
|
|
*/
|
|||
|
|
enum rte_eth_rx_mq_mode rx_mq_mode = ETH_MQ_RX_VMDQ_DCB_RSS;
|
|||
|
|
+/*
|
|||
|
|
+ * ID of the current process in multi-process, used to
|
|||
|
|
+ * configure the queues to be polled.
|
|||
|
|
+ */
|
|||
|
|
+int proc_id;
|
|||
|
|
+
|
|||
|
|
+/*
|
|||
|
|
+ * Number of processes in multi-process, used to
|
|||
|
|
+ * configure the queues to be polled.
|
|||
|
|
+ */
|
|||
|
|
+unsigned int num_procs = 1;
|
|||
|
|
+
|
|||
|
|
+static int
|
|||
|
|
+eth_dev_configure_mp(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
|
|||
|
|
+ const struct rte_eth_conf *dev_conf)
|
|||
|
|
+{
|
|||
|
|
+ if (is_proc_primary())
|
|||
|
|
+ return rte_eth_dev_configure(port_id, nb_rx_q, nb_tx_q,
|
|||
|
|
+ dev_conf);
|
|||
|
|
+ return 0;
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
+static int
|
|||
|
|
+eth_dev_start_mp(uint16_t port_id)
|
|||
|
|
+{
|
|||
|
|
+ if (is_proc_primary())
|
|||
|
|
+ return rte_eth_dev_start(port_id);
|
|||
|
|
+
|
|||
|
|
+ return 0;
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
+static int
|
|||
|
|
+eth_dev_stop_mp(uint16_t port_id)
|
|||
|
|
+{
|
|||
|
|
+ if (is_proc_primary())
|
|||
|
|
+ return rte_eth_dev_stop(port_id);
|
|||
|
|
+
|
|||
|
|
+ return 0;
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
+static void
|
|||
|
|
+mempool_free_mp(struct rte_mempool *mp)
|
|||
|
|
+{
|
|||
|
|
+ if (is_proc_primary())
|
|||
|
|
+ rte_mempool_free(mp);
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
+static int
|
|||
|
|
+eth_dev_set_mtu_mp(uint16_t port_id, uint16_t mtu)
|
|||
|
|
+{
|
|||
|
|
+ if (is_proc_primary())
|
|||
|
|
+ return rte_eth_dev_set_mtu(port_id, mtu);
|
|||
|
|
+
|
|||
|
|
+ return 0;
|
|||
|
|
+}
|
|||
|
|
|
|||
|
|
/* Forward function declarations */
|
|||
|
|
static void setup_attached_port(portid_t pi);
|
|||
|
|
@@ -964,6 +1019,14 @@ mbuf_pool_create(uint16_t mbuf_seg_size, unsigned nb_mbuf,
|
|||
|
|
|
|||
|
|
mb_size = sizeof(struct rte_mbuf) + mbuf_seg_size;
|
|||
|
|
mbuf_poolname_build(socket_id, pool_name, sizeof(pool_name), size_idx);
|
|||
|
|
+ if (!is_proc_primary()) {
|
|||
|
|
+ rte_mp = rte_mempool_lookup(pool_name);
|
|||
|
|
+ if (rte_mp == NULL)
|
|||
|
|
+ rte_exit(EXIT_FAILURE,
|
|||
|
|
+ "Get mbuf pool for socket %u failed: %s\n",
|
|||
|
|
+ socket_id, rte_strerror(rte_errno));
|
|||
|
|
+ return rte_mp;
|
|||
|
|
+ }
|
|||
|
|
|
|||
|
|
TESTPMD_LOG(INFO,
|
|||
|
|
"create a new mbuf pool <%s>: n=%u, size=%u, socket=%u\n",
|
|||
|
|
@@ -1969,6 +2032,11 @@ flush_fwd_rx_queues(void)
|
|||
|
|
uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0;
|
|||
|
|
uint64_t timer_period;
|
|||
|
|
|
|||
|
|
+ if (num_procs > 1) {
|
|||
|
|
+ printf("multi-process not support for flushing fwd Rx queues, skip the below lines and return.\n");
|
|||
|
|
+ return;
|
|||
|
|
+ }
|
|||
|
|
+
|
|||
|
|
/* convert to number of cycles */
|
|||
|
|
timer_period = rte_get_timer_hz(); /* 1 second timeout */
|
|||
|
|
|
|||
|
|
@@ -2456,7 +2524,7 @@ start_port(portid_t pid)
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
/* configure port */
|
|||
|
|
- diag = rte_eth_dev_configure(pi, nb_rxq + nb_hairpinq,
|
|||
|
|
+ diag = eth_dev_configure_mp(pi, nb_rxq + nb_hairpinq,
|
|||
|
|
nb_txq + nb_hairpinq,
|
|||
|
|
&(port->dev_conf));
|
|||
|
|
if (diag != 0) {
|
|||
|
|
@@ -2470,7 +2538,7 @@ start_port(portid_t pid)
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
- if (port->need_reconfig_queues > 0) {
|
|||
|
|
+ if (port->need_reconfig_queues > 0 && is_proc_primary()) {
|
|||
|
|
port->need_reconfig_queues = 0;
|
|||
|
|
/* setup tx queues */
|
|||
|
|
for (qi = 0; qi < nb_txq; qi++) {
|
|||
|
|
@@ -2571,7 +2639,7 @@ start_port(portid_t pid)
|
|||
|
|
cnt_pi++;
|
|||
|
|
|
|||
|
|
/* start port */
|
|||
|
|
- if (rte_eth_dev_start(pi) < 0) {
|
|||
|
|
+ if (eth_dev_start_mp(pi) < 0) {
|
|||
|
|
printf("Fail to start port %d\n", pi);
|
|||
|
|
|
|||
|
|
/* Fail to setup rx queue, return */
|
|||
|
|
@@ -2700,7 +2768,7 @@ stop_port(portid_t pid)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
- if (rte_eth_dev_stop(pi) != 0)
|
|||
|
|
+ if (eth_dev_stop_mp(pi) != 0)
|
|||
|
|
RTE_LOG(ERR, EAL, "rte_eth_dev_stop failed for port %u\n",
|
|||
|
|
pi);
|
|||
|
|
|
|||
|
|
@@ -2769,8 +2837,10 @@ close_port(portid_t pid)
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
- port_flow_flush(pi);
|
|||
|
|
- rte_eth_dev_close(pi);
|
|||
|
|
+ if (is_proc_primary()) {
|
|||
|
|
+ port_flow_flush(pi);
|
|||
|
|
+ rte_eth_dev_close(pi);
|
|||
|
|
+ }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
remove_invalid_ports();
|
|||
|
|
@@ -3035,7 +3105,7 @@ pmd_test_exit(void)
|
|||
|
|
}
|
|||
|
|
for (i = 0 ; i < RTE_DIM(mempools) ; i++) {
|
|||
|
|
if (mempools[i])
|
|||
|
|
- rte_mempool_free(mempools[i]);
|
|||
|
|
+ mempool_free_mp(mempools[i]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
printf("\nBye...\n");
|
|||
|
|
@@ -3482,6 +3552,10 @@ init_port_dcb_config(portid_t pid,
|
|||
|
|
int retval;
|
|||
|
|
uint16_t i;
|
|||
|
|
|
|||
|
|
+ if (num_procs > 1) {
|
|||
|
|
+ printf("The multi-process feature doesn't support dcb.\n");
|
|||
|
|
+ return -ENOTSUP;
|
|||
|
|
+ }
|
|||
|
|
rte_port = &ports[pid];
|
|||
|
|
|
|||
|
|
/* retain the original device configuration. */
|
|||
|
|
@@ -3646,10 +3720,6 @@ main(int argc, char** argv)
|
|||
|
|
rte_exit(EXIT_FAILURE, "Cannot init EAL: %s\n",
|
|||
|
|
rte_strerror(rte_errno));
|
|||
|
|
|
|||
|
|
- if (rte_eal_process_type() == RTE_PROC_SECONDARY)
|
|||
|
|
- rte_exit(EXIT_FAILURE,
|
|||
|
|
- "Secondary process type not supported.\n");
|
|||
|
|
-
|
|||
|
|
ret = register_eth_event_callback();
|
|||
|
|
if (ret != 0)
|
|||
|
|
rte_exit(EXIT_FAILURE, "Cannot register for ethdev events");
|
|||
|
|
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
|
|||
|
|
index 303bed830..122fca29c 100644
|
|||
|
|
--- a/app/test-pmd/testpmd.h
|
|||
|
|
+++ b/app/test-pmd/testpmd.h
|
|||
|
|
@@ -626,6 +626,17 @@ extern struct mplsoudp_decap_conf mplsoudp_decap_conf;
|
|||
|
|
|
|||
|
|
extern enum rte_eth_rx_mq_mode rx_mq_mode;
|
|||
|
|
|
|||
|
|
+extern struct rte_flow_action_conntrack conntrack_context;
|
|||
|
|
+
|
|||
|
|
+extern int proc_id;
|
|||
|
|
+extern unsigned int num_procs;
|
|||
|
|
+
|
|||
|
|
+static inline bool
|
|||
|
|
+is_proc_primary(void)
|
|||
|
|
+{
|
|||
|
|
+ return rte_eal_process_type() == RTE_PROC_PRIMARY;
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
static inline unsigned int
|
|||
|
|
lcore_num(void)
|
|||
|
|
{
|
|||
|
|
diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
|
|||
|
|
index ca67105b7..098cbbd43 100644
|
|||
|
|
--- a/doc/guides/testpmd_app_ug/run_app.rst
|
|||
|
|
+++ b/doc/guides/testpmd_app_ug/run_app.rst
|
|||
|
|
@@ -529,3 +529,87 @@ The command line options are:
|
|||
|
|
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.
|
|||
|
|
+
|
|||
|
|
+
|
|||
|
|
+Testpmd Multi-Process Command-line Options
|
|||
|
|
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
|
+
|
|||
|
|
+The following are the command-line options for testpmd multi-process support:
|
|||
|
|
+
|
|||
|
|
+* primary process:
|
|||
|
|
+
|
|||
|
|
+.. code-block:: console
|
|||
|
|
+
|
|||
|
|
+ sudo ./dpdk-testpmd -a xxx --proc-type=auto -l 0-1 -- -i --rxq=4 --txq=4 \
|
|||
|
|
+ --num-procs=2 --proc-id=0
|
|||
|
|
+
|
|||
|
|
+* secondary process:
|
|||
|
|
+
|
|||
|
|
+.. code-block:: console
|
|||
|
|
+
|
|||
|
|
+ sudo ./dpdk-testpmd -a xxx --proc-type=auto -l 2-3 -- -i --rxq=4 --txq=4 \
|
|||
|
|
+ --num-procs=2 --proc-id=1
|
|||
|
|
+
|
|||
|
|
+The command line options are:
|
|||
|
|
+
|
|||
|
|
+* ``--num-procs=N``
|
|||
|
|
+
|
|||
|
|
+ The number of processes which will be used.
|
|||
|
|
+
|
|||
|
|
+* ``--proc-id=ID``
|
|||
|
|
+
|
|||
|
|
+ The ID of the current process (ID < num-procs). ID should be different in
|
|||
|
|
+ primary process and secondary process, which starts from '0'.
|
|||
|
|
+
|
|||
|
|
+Calculation rule for queue:
|
|||
|
|
+All queues are allocated to different processes based on ``proc_num`` and
|
|||
|
|
+``proc_id``.
|
|||
|
|
+Calculation rule for the testpmd to allocate queues to each process:
|
|||
|
|
+* start(queue start id) = proc_id * nb_q / num_procs<63><73>
|
|||
|
|
+
|
|||
|
|
+* end(queue end id) = start + nb_q / num_procs<63><73>
|
|||
|
|
+
|
|||
|
|
+For example, if testpmd is configured to have 4 Tx and Rx queues,
|
|||
|
|
+queues 0 and 1 will be used by the primary process and
|
|||
|
|
+queues 2 and 3 will be used by the secondary process.
|
|||
|
|
+
|
|||
|
|
+The number of queues should be a multiple of the number of processes. If not,
|
|||
|
|
+redundant queues will exist after queues are allocated to processes. If RSS
|
|||
|
|
+is enabled, packet loss occurs when traffic is sent to all processes at the same
|
|||
|
|
+time. Some traffic goes to redundant queues and cannot be forwarded.
|
|||
|
|
+
|
|||
|
|
+All the dev ops is supported in primary process. While secondary process is
|
|||
|
|
+not permitted to allocate or release shared memory, so some ops are not supported
|
|||
|
|
+as follows:
|
|||
|
|
+
|
|||
|
|
+- ``dev_configure``
|
|||
|
|
+- ``dev_start``
|
|||
|
|
+- ``dev_stop``
|
|||
|
|
+- ``rx_queue_setup``
|
|||
|
|
+- ``tx_queue_setup``
|
|||
|
|
+- ``rx_queue_release``
|
|||
|
|
+- ``tx_queue_release``
|
|||
|
|
+
|
|||
|
|
+So, any command from testpmd which calls those APIs will not be supported in
|
|||
|
|
+secondary process, like:
|
|||
|
|
+
|
|||
|
|
+.. code-block:: console
|
|||
|
|
+
|
|||
|
|
+ port config all rxq|txq|rxd|txd <value>
|
|||
|
|
+ port config <port_id> rx_offload xxx on/off
|
|||
|
|
+ port config <port_id> tx_offload xxx on/off
|
|||
|
|
+
|
|||
|
|
+etc.
|
|||
|
|
+
|
|||
|
|
+When secondary is running, port in primary is not permitted to be stopped.
|
|||
|
|
+Reconfigure operation is only valid in primary.
|
|||
|
|
+
|
|||
|
|
+Stats is supported, stats will not change when one quits and starts, as they
|
|||
|
|
+share the same buffer to store the stats. Flow rules are maintained in process
|
|||
|
|
+level: primary and secondary has its own flow list (but one flow list in HW).
|
|||
|
|
+The two can see all the queues, so setting the flow rules for the other is OK.
|
|||
|
|
+But in the testpmd primary process receiving or transmitting packets from the
|
|||
|
|
+queue allocated for secondary process is not permitted, and same for secondary
|
|||
|
|
+process.
|
|||
|
|
+
|
|||
|
|
+Flow API and RSS are supported.
|
|||
|
|
--
|
|||
|
|
2.23.0
|
|||
|
|
|