Skip to contentSkip to conversation

ethdev: introduce shared Rx queue

RFC In review Xueming Li 14 participants 266 messages Jul 27, 2021 – Nov 5, 2021 Page 2 of 3

Subsystems (2)
lore
Share & tools
lore
author
#66 lore raw

PATCH v2 14/15 app/testpmd: support shared Rx queue for 5tuple fwd

In reply to Xueming Li

From: Xiaoyu Min <[email protected]>

Add support of shared rxq.
If shared rxq is enabled, filter packet by stream according to mbuf->port value and then fwd it in stream basis (as before).

If shared rxq is not enabled, just fwd it as usual in stream basis.

---
 app/test-pmd/5tswap.c | 30 +++++++++++-------------------
 1 file changed, 11 insertions(+), 19 deletions(-)
app/test-pmd/5tswap.c +11 -19
index e8cef9623b..236a117ee3 100644
@@ -82,18 +82,16 @@ swap_udp(struct rte_udp_hdr *udp_hdr)
  * Parses each layer and swaps it. When the next layer doesn't match it stops.
  */
 static void
-pkt_burst_5tuple_swap(struct fwd_stream *fs)
+_5tuple_swap_stream(struct fwd_stream *fs, uint16_t nb_rx,
+		struct rte_mbuf **pkts_burst)
 {
-	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
 	struct rte_port  *txp;
 	struct rte_mbuf *mb;
 	uint16_t next_proto;
 	uint64_t ol_flags;
 	uint16_t proto;
-	uint16_t nb_rx;
 	uint16_t nb_tx;
 	uint32_t retry;
-
 	int i;
 	union {
 		struct rte_ether_hdr *eth;
@@ -105,20 +103,6 @@ pkt_burst_5tuple_swap(struct fwd_stream *fs)
 		uint8_t *byte;
 	} h;
 
-	uint64_t start_tsc = 0;
-
-	get_start_cycles(&start_tsc);
-
-	/*
-	 * Receive a burst of packets and forward them.
-	 */
-	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
-				 nb_pkt_per_burst);
-	inc_rx_burst_stats(fs, nb_rx);
-	if (unlikely(nb_rx == 0))
-		return;
-
-	fs->rx_packets += nb_rx;
 	txp = &ports[fs->tx_port];
 	ol_flags = ol_flags_init(txp->dev_conf.txmode.offloads);
 	vlan_qinq_set(pkts_burst, nb_rx, ol_flags,
@@ -182,7 +166,15 @@ pkt_burst_5tuple_swap(struct fwd_stream *fs)
 			rte_pktmbuf_free(pkts_burst[nb_tx]);
 		} while (++nb_tx < nb_rx);
 	}
-	get_end_cycles(fs, start_tsc);
+}
+
+/*
+ * Wrapper of real fwd engine.
+ */
+static void
+pkt_burst_5tuple_swap(struct fwd_stream *fs)
+{
+	return do_burst_fwd(fs, _5tuple_swap_stream);
 }
 
 struct fwd_engine five_tuple_swap_fwd_engine = {
Signature · 1 line
2.25.1
author
#67 lore raw

PATCH v2 15/15 app/testpmd: support shared Rx queue for ieee1588 fwd

In reply to Xueming Li

From: Xiaoyu Min <[email protected]>

Add support of shared rxq.
If shared rxq is enabled, filter packet by stream according to mbuf->port value and then fwd it in stream basis (as before).

If shared rxq is not enabled, just fwd it as usual in stream basis.

---
 app/test-pmd/ieee1588fwd.c | 30 ++++++++++++++++++++----------
 1 file changed, 20 insertions(+), 10 deletions(-)
app/test-pmd/ieee1588fwd.c +20 -10
index 034f238c34..dc6bf0e39d 100644
@@ -90,23 +90,17 @@ port_ieee1588_tx_timestamp_check(portid_t pi)
 }
 
 static void
-ieee1588_packet_fwd(struct fwd_stream *fs)
+ieee1588_fwd_stream(struct fwd_stream *fs, uint16_t nb_rx,
+		struct rte_mbuf **pkt)
 {
-	struct rte_mbuf  *mb;
+	struct rte_mbuf *mb = (*pkt);
 	struct rte_ether_hdr *eth_hdr;
 	struct rte_ether_addr addr;
 	struct ptpv2_msg *ptp_hdr;
 	uint16_t eth_type;
 	uint32_t timesync_index;
 
-	/*
-	 * Receive 1 packet at a time.
-	 */
-	if (rte_eth_rx_burst(fs->rx_port, fs->rx_queue, &mb, 1) == 0)
-		return;
-
-	fs->rx_packets += 1;
-
+	RTE_SET_USED(nb_rx);
 	/*
 	 * Check that the received packet is a PTP packet that was detected
 	 * by the hardware.
@@ -198,6 +192,22 @@ ieee1588_packet_fwd(struct fwd_stream *fs)
 	port_ieee1588_tx_timestamp_check(fs->rx_port);
 }
 
+/*
+ * Wrapper of real fwd ingine.
+ */
+static void
+ieee1588_packet_fwd(struct fwd_stream *fs)
+{
+	struct rte_mbuf *mb;
+
+	if (rte_eth_rx_burst(fs->rx_port, fs->rx_queue, &mb, 1) == 0)
+		return;
+	if (unlikely(rxq_share > 0))
+		forward_shared_rxq(fs, 1, &mb, ieee1588_fwd_stream);
+	else
+		ieee1588_fwd_stream(fs, 1, &mb);
+}
+
 static void
 port_ieee1588_fwd_begin(portid_t pi)
 {
Signature · 1 line
2.25.1
#68 lore raw
In reply to Xueming Li
Quoted 32 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

#undef RTE_RX_OFFLOAD_BIT2STR

lib/ethdev/rte_ethdev.h +0 -0
index d2b27c351f..a578c9db9d 100644

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1050

Quoted 4 lines
lib/ethdev/rte_ethdev.h +1 -0
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+       uint32_t shared_group; /**< Shared port group index in switch domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Quoted 19 lines
lib/ethdev/rte_ethdev.h +6 -1
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1373,6 +1374,12 @@ struct rte_eth_conf {
 #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM  0x00040000
 #define DEV_RX_OFFLOAD_RSS_HASH                0x00080000
 #define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000
+/**
+ * Rx queue is shared among ports in same switch domain to save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM | \
--

2.25.1

#69 lore raw
Quoted 38 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 26 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR

lib/ethdev/rte_ethdev.h index renamed from lib/ethdev/rte_ethdev.h +0 -0

d2b27c351f..a578c9db9d 100644

lib/ethdev/rte_ethdev.h +2 -0
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group index in switch
+ domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

To support more groups simultaneously, need to consider testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group number, but user must schedule stream affinity carefully - error prone.

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Quoted 22 lines
Quoted 22 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or

rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -1
+/**
+ * Rx queue is shared among ports in same switch domain to save
+memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM | \
--

2.25.1

#70 lore raw
Quoted 61 lines · Xueming(Steven) Li
Quoted 39 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 26 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR

lib/ethdev/rte_ethdev.h index renamed from lib/ethdev/rte_ethdev.h +0 -0

d2b27c351f..a578c9db9d 100644

lib/ethdev/rte_ethdev.h +2 -0
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group index in switch
+ domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

Quoted 7 lines

To support more groups simultaneously, need to consider testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group number, but user must schedule stream affinity carefully - error prone.

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Ack. One group is enough in testpmd.

My question was more about who and how this group is created, Should n't we need API to create shared_group? If we do the following, at least, I can think, how it
can be implemented in SW or other HW.

- Create aggregation queue group
- Attach multiple Rx queues to the aggregation queue group
- Pull the packets from the queue group(which internally fetch from the Rx queues _attached_)

Does the above kind of sequence, break your representor use case?

Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or

rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -1
+/**
+ * Rx queue is shared among ports in same switch domain to save
+memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM | \
--

2.25.1

#71 lore raw
Quoted 83 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 11:12 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 62 lines · Xueming(Steven) Li
Quoted 40 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 26 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same
configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives packets from
all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR

lib/ethdev/rte_ethdev.h +2 -0
index d2b27c351f..a578c9db9d 100644
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group index in
+ switch domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

Quoted 7 lines

To support more groups simultaneously, need to consider testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group number, but user must schedule stream affinity carefully - error prone.

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Ack. One group is enough in testpmd.

Quoted 8 lines

My question was more about who and how this group is created, Should n't we need API to create shared_group? If we do the following, at least, I can think, how it can be implemented in SW or other HW.

- Create aggregation queue group
- Attach multiple Rx queues to the aggregation queue group
- Pull the packets from the queue group(which internally fetch from the Rx queues _attached_)

Does the above kind of sequence, break your representor use case?

Seems more like a set of EAL wrapper. Current API tries to minimize the application efforts to adapt shared-rxq.
- step 1, not sure how important it is to create group with API, in rte_flow, group is created on demand.
- step 2, currently, the attaching is done in rte_eth_rx_queue_setup, specify offload and group in rx_conf struct.
- step 3, define a dedicate api to receive packets from shared rxq? Looks clear to receive packets from shared rxq. currently, rxq objects in share group is same - the shared rxq, so the eth callback eth_rx_burst_t(rxq_obj, mbufs, n) could be used to receive packets from any ports in group, normally the first port(PF) in group.
An alternative way is defining a vdev with same queue number and copy rxq objects will make the vdev a proxy of the shared rxq group - this could be an helper API.

Anyway the wrapper doesn't break use case, step 3 api is more clear, need to understand how to implement efficiently.

Quoted 25 lines
Quoted 25 lines
Quoted 25 lines
Quoted 25 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or

rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -1
+/**
+ * Rx queue is shared among ports in same switch domain to save
+memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM | \
--

2.25.1

#72 lore raw
Quoted 87 lines · Xueming(Steven) Li
Quoted 87 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 11:12 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 62 lines · Xueming(Steven) Li
Quoted 40 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 26 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same
configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives packets from
all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR

lib/ethdev/rte_ethdev.h +2 -0
index d2b27c351f..a578c9db9d 100644
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group index in
+ switch domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

Quoted 7 lines

To support more groups simultaneously, need to consider testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group number, but user must schedule stream affinity carefully - error prone.

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Ack. One group is enough in testpmd.

My question was more about who and how this group is created, Should n't we need API to create shared_group? If we do the following, at least, I can think, how it can be implemented in SW or other HW.

Quoted 8 lines
Quoted 5 lines

- Create aggregation queue group
- Attach multiple Rx queues to the aggregation queue group
- Pull the packets from the queue group(which internally fetch from the Rx queues _attached_)

Does the above kind of sequence, break your representor use case?

Seems more like a set of EAL wrapper. Current API tries to minimize the application efforts to adapt shared-rxq.
- step 1, not sure how important it is to create group with API, in rte_flow, group is created on demand.

Which rte_flow pattern/action for this?

Quoted 8 lines

- step 2, currently, the attaching is done in rte_eth_rx_queue_setup, specify offload and group in rx_conf struct.
- step 3, define a dedicate api to receive packets from shared rxq? Looks clear to receive packets from shared rxq. currently, rxq objects in share group is same - the shared rxq, so the eth callback eth_rx_burst_t(rxq_obj, mbufs, n) could be used to receive packets from any ports in group, normally the first port(PF) in group.
An alternative way is defining a vdev with same queue number and copy rxq objects will make the vdev a proxy of the shared rxq group - this could be an helper API.

Anyway the wrapper doesn't break use case, step 3 api is more clear, need to understand how to implement efficiently.

Are you doing this feature based on any HW support or it just pure SW thing, If it is SW, It is better to have
just new vdev for like drivers/net/bonding/. This we can help aggregate multiple Rxq across the multiple ports
of same the driver.

Quoted 26 lines
Quoted 26 lines
Quoted 26 lines
Quoted 26 lines
Quoted 26 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or

rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -1
+/**
+ * Rx queue is shared among ports in same switch domain to save
+memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM | \
--

2.25.1

#73 lore raw
Quoted 105 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 19, 2021 1:27 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 94 lines · Xueming(Steven) Li
Quoted 94 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 11:12 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 63 lines · Xueming(Steven) Li
Quoted 41 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 26 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same
configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives packets
from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR diff --git
a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h index d2b27c351f..a578c9db9d 100644

lib/ethdev/rte_ethdev.h +2 -0
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group index in
+ switch domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

Quoted 7 lines

To support more groups simultaneously, need to consider testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group number,
but user must schedule stream affinity carefully - error prone.

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Ack. One group is enough in testpmd.

My question was more about who and how this group is created, Should
n't we need API to create shared_group? If we do the following, at least, I can think, how it can be implemented in SW or other HW.

- Create aggregation queue group
- Attach multiple Rx queues to the aggregation queue group
- Pull the packets from the queue group(which internally fetch from the Rx queues _attached_)

Quoted 6 lines
Quoted 4 lines
Quoted 1 line

Does the above kind of sequence, break your representor use case?

Seems more like a set of EAL wrapper. Current API tries to minimize the application efforts to adapt shared-rxq.
- step 1, not sure how important it is to create group with API, in rte_flow, group is created on demand.

Which rte_flow pattern/action for this?

No rte_flow for this, just recalled that the group in rte_flow is not created along with flow, not via api. I don’t see anything else to create along with group, just double whether it valuable to introduce a new api set to manage group.

Quoted 8 lines
Quoted 8 lines

- step 2, currently, the attaching is done in rte_eth_rx_queue_setup, specify offload and group in rx_conf struct.
- step 3, define a dedicate api to receive packets from shared rxq? Looks clear to receive packets from shared rxq. currently, rxq objects in share group is same - the shared rxq, so the eth callback eth_rx_burst_t(rxq_obj, mbufs, n) could be used to receive packets from any ports in group, normally the first port(PF) in group.
An alternative way is defining a vdev with same queue number and copy rxq objects will make the vdev a proxy of the shared rxq group - this could be an helper API.

Quoted 4 lines
Quoted 1 line

Anyway the wrapper doesn't break use case, step 3 api is more clear, need to understand how to implement efficiently.

Are you doing this feature based on any HW support or it just pure SW thing, If it is SW, It is better to have just new vdev for like drivers/net/bonding/. This we can help aggregate multiple Rxq across the multiple ports of same the driver.

Based on HW support.

Most user might uses PF in group as the anchor port to rx burst, current definition should be easy for them to migrate. but some user might prefer grouping some hot plug/unpluggedrepresentors, EAL could provide wrappers, users could do that either due to the strategy not complex enough. Anyway, welcome any suggestion.

Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or

rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -1
+/**
+ * Rx queue is shared among ports in same switch domain to
+save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM | \
--

2.25.1

#74 lore raw
Quoted 108 lines · Xueming(Steven) Li
Quoted 108 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 19, 2021 1:27 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 96 lines · Xueming(Steven) Li
Quoted 95 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 11:12 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 63 lines · Xueming(Steven) Li
Quoted 41 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 26 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same
configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives packets
from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR diff --git
a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h index d2b27c351f..a578c9db9d 100644

lib/ethdev/rte_ethdev.h +2 -0
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group index in
+ switch domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

Quoted 7 lines

To support more groups simultaneously, need to consider testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group number,
but user must schedule stream affinity carefully - error prone.

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Ack. One group is enough in testpmd.

My question was more about who and how this group is created, Should
n't we need API to create shared_group? If we do the following, at least, I can think, how it can be implemented in SW or other HW.

- Create aggregation queue group
- Attach multiple Rx queues to the aggregation queue group
- Pull the packets from the queue group(which internally fetch from the Rx queues _attached_)

Does the above kind of sequence, break your representor use case?

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

Seems more like a set of EAL wrapper. Current API tries to minimize the application efforts to adapt shared-rxq.
- step 1, not sure how important it is to create group with API, in rte_flow, group is created on demand.

Which rte_flow pattern/action for this?

No rte_flow for this, just recalled that the group in rte_flow is not created along with flow, not via api. I don’t see anything else to create along with group, just double whether it valuable to introduce a new api set to manage group.

See below.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

- step 2, currently, the attaching is done in rte_eth_rx_queue_setup, specify offload and group in rx_conf struct.
- step 3, define a dedicate api to receive packets from shared rxq? Looks clear to receive packets from shared rxq. currently, rxq objects in share group is same - the shared rxq, so the eth callback eth_rx_burst_t(rxq_obj, mbufs, n) could be used to receive packets from any ports in group, normally the first port(PF) in group.
An alternative way is defining a vdev with same queue number and copy rxq objects will make the vdev a proxy of the shared rxq group - this could be an helper API.

Quoted 6 lines
Quoted 4 lines
Quoted 1 line

Anyway the wrapper doesn't break use case, step 3 api is more clear, need to understand how to implement efficiently.

Are you doing this feature based on any HW support or it just pure SW thing, If it is SW, It is better to have just new vdev for like drivers/net/bonding/. This we can help aggregate multiple Rxq across the multiple ports of same the driver.

Based on HW support.

In Marvel HW, we do some support, I will outline here and some queries on this.

# We need to create some new HW structure for aggregation # Connect each Rxq to the new HW structure for aggregation # Use rx_burst from the new HW structure.

Could you outline your HW support?

Also, I am not able to understand how this will reduce the memory, atleast in our HW need creating more memory now to deal this as we need to deal new HW structure.

How is in your HW it reduces the memory? Also, if memory is the constraint, why NOT reduce the number of queues.

# Also, I was thinking, one way to avoid the fast path or ABI change would like.

# Driver Initializes one more eth_dev_ops in driver as aggregator ethdev

# devargs of new ethdev or specific API like
drivers/net/bonding/rte_eth_bond.h can take the argument (port, queue)
tuples which needs to aggregate by new ethdev port
# No change in fastpath or ABI is required in this model.
Quoted 32 lines

Most user might uses PF in group as the anchor port to rx burst, current definition should be easy for them to migrate. but some user might prefer grouping some hot plug/unpluggedrepresentors, EAL could provide wrappers, users could do that either due to the strategy not complex enough. Anyway, welcome any suggestion.

Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or

rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -1
+/**
+ * Rx queue is shared among ports in same switch domain to
+save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM | \
--

2.25.1

#75 lore raw
Quoted 156 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 26, 2021 7:58 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 97 lines · Xueming(Steven) Li
Quoted 97 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 19, 2021 1:27 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 84 lines · Xueming(Steven) Li
Quoted 84 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 11:12 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 70 lines · Xueming(Steven) Li
Quoted 43 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 27 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same
configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives
packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object,
it's important to clear all queue control callback api that using queue object:

https://mails.dpdk.org/archives/dev/2021-July/215574.html

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR diff --git
a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h index d2b27c351f..a578c9db9d 100644

lib/ethdev/rte_ethdev.h +2 -0
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group
+ index in switch domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

To support more groups simultaneously, need to consider
testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group
number, but user must schedule stream affinity carefully - error prone.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Ack. One group is enough in testpmd.

My question was more about who and how this group is created,
Should n't we need API to create shared_group? If we do the following, at least, I can think, how it can be implemented in SW

or other HW.

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines

- Create aggregation queue group
- Attach multiple Rx queues to the aggregation queue group
- Pull the packets from the queue group(which internally fetch from the Rx queues _attached_)

Does the above kind of sequence, break your representor use case?

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

Seems more like a set of EAL wrapper. Current API tries to minimize the application efforts to adapt shared-rxq.
- step 1, not sure how important it is to create group with API, in rte_flow, group is created on demand.

Which rte_flow pattern/action for this?

No rte_flow for this, just recalled that the group in rte_flow is not created along with flow, not via api. I don’t see anything else to create along with group, just double whether it valuable to introduce a new api set to manage group.

See below.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

- step 2, currently, the attaching is done in rte_eth_rx_queue_setup, specify offload and group in rx_conf struct.
- step 3, define a dedicate api to receive packets from shared rxq? Looks clear to receive packets from shared rxq. currently, rxq objects in share group is same - the shared rxq, so the eth callback eth_rx_burst_t(rxq_obj, mbufs, n) could be used to receive packets from any ports in group, normally the first port(PF) in group.
An alternative way is defining a vdev with same queue number and copy rxq objects will make the vdev a proxy of the shared rxq group - this could be an helper API.

Quoted 4 lines
Quoted 4 lines
Quoted 1 line

Anyway the wrapper doesn't break use case, step 3 api is more clear, need to understand how to implement efficiently.

Are you doing this feature based on any HW support or it just pure
SW thing, If it is SW, It is better to have just new vdev for like drivers/net/bonding/. This we can help aggregate multiple Rxq across

the multiple ports of same the driver.

Quoted 2 lines

Based on HW support.

In Marvel HW, we do some support, I will outline here and some queries on this.

# We need to create some new HW structure for aggregation # Connect each Rxq to the new HW structure for aggregation # Use rx_burst from the new HW structure.

Quoted 7 lines

Could you outline your HW support?

Also, I am not able to understand how this will reduce the memory, atleast in our HW need creating more memory now to deal this as we need to deal new HW structure.

How is in your HW it reduces the memory? Also, if memory is the constraint, why NOT reduce the number of queues.

Glad to know that Marvel is working on this, what's the status of driver implementation?

In my PMD implementation, it's very similar, a new HW object shared memory pool is created to replace per rxq memory pool. Legacy rxq feed queue with allocated mbufs as number of descriptors, now shared rxqs share the same pool, no need to supply mbufs for each rxq, just feed the shared rxq.

So the memory saving reflects to mbuf per rxq, even 1000 representors in shared rxq group, the mbufs consumed is one rxq. In other words, new members in shared rxq doesn’t allocate new mbufs to feed rxq, just share with existing shared rxq(HW mempool). The memory required to setup each rxq doesn't change too much, agree.

Quoted 6 lines

# Also, I was thinking, one way to avoid the fast path or ABI change would like.

# Driver Initializes one more eth_dev_ops in driver as aggregator ethdev # devargs of new ethdev or specific API like drivers/net/bonding/rte_eth_bond.h can take the argument (port, queue) tuples which needs to aggregate by new ethdev port # No change in fastpath or ABI is required in this model.

This could be an option to access shared rxq. What's the difference of the new PMD? What's the difference of PMD driver to create the new device?

Is it important in your implementation? Does it work with existing rx_burst api?

Quoted 36 lines
Quoted 5 lines

Most user might uses PF in group as the anchor port to rx burst, current definition should be easy for them to migrate. but some user might prefer grouping some hot
plug/unpluggedrepresentors, EAL could provide wrappers, users could do that either due to the strategy not complex enough.

Anyway, welcome any suggestion.

Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or

rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -0
+/**
+ * Rx queue is shared among ports in same switch domain
+to save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM

| \
--
2.25.1

#76 lore raw
Quoted 167 lines · Xueming(Steven) Li
Quoted 157 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 26, 2021 7:58 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 97 lines · Xueming(Steven) Li
Quoted 97 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 19, 2021 1:27 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 84 lines · Xueming(Steven) Li
Quoted 84 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 11:12 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 70 lines · Xueming(Steven) Li
Quoted 43 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 27 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same
configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives
packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object,
it's important to clear all queue control callback api that using queue object:

https://mails.dpdk.org/archives/dev/2021-July/215574.html

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR diff --git
a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h index d2b27c351f..a578c9db9d 100644

lib/ethdev/rte_ethdev.h +2 -0
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group
+ index in switch domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

To support more groups simultaneously, need to consider
testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group
number, but user must schedule stream affinity carefully - error prone.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Ack. One group is enough in testpmd.

My question was more about who and how this group is created,
Should n't we need API to create shared_group? If we do the following, at least, I can think, how it can be implemented in SW

or other HW.

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines

- Create aggregation queue group
- Attach multiple Rx queues to the aggregation queue group
- Pull the packets from the queue group(which internally fetch from the Rx queues _attached_)

Does the above kind of sequence, break your representor use case?

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

Seems more like a set of EAL wrapper. Current API tries to minimize the application efforts to adapt shared-rxq.
- step 1, not sure how important it is to create group with API, in rte_flow, group is created on demand.

Which rte_flow pattern/action for this?

No rte_flow for this, just recalled that the group in rte_flow is not created along with flow, not via api. I don’t see anything else to create along with group, just double whether it valuable to introduce a new api set to manage group.

See below.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

- step 2, currently, the attaching is done in rte_eth_rx_queue_setup, specify offload and group in rx_conf struct.
- step 3, define a dedicate api to receive packets from shared rxq? Looks clear to receive packets from shared rxq. currently, rxq objects in share group is same - the shared rxq, so the eth callback eth_rx_burst_t(rxq_obj, mbufs, n) could be used to receive packets from any ports in group, normally the first port(PF) in group.
An alternative way is defining a vdev with same queue number and copy rxq objects will make the vdev a proxy of the shared rxq group - this could be an helper API.

Quoted 4 lines
Quoted 4 lines
Quoted 1 line

Anyway the wrapper doesn't break use case, step 3 api is more clear, need to understand how to implement efficiently.

Are you doing this feature based on any HW support or it just pure
SW thing, If it is SW, It is better to have just new vdev for like drivers/net/bonding/. This we can help aggregate multiple Rxq across

the multiple ports of same the driver.

Quoted 2 lines

Based on HW support.

In Marvel HW, we do some support, I will outline here and some queries on this.

# We need to create some new HW structure for aggregation # Connect each Rxq to the new HW structure for aggregation # Use rx_burst from the new HW structure.

Quoted 7 lines

Could you outline your HW support?

Also, I am not able to understand how this will reduce the memory, atleast in our HW need creating more memory now to deal this as we need to deal new HW structure.

How is in your HW it reduces the memory? Also, if memory is the constraint, why NOT reduce the number of queues.

Glad to know that Marvel is working on this, what's the status of driver implementation?

Quoted 7 lines

In my PMD implementation, it's very similar, a new HW object shared memory pool is created to replace per rxq memory pool. Legacy rxq feed queue with allocated mbufs as number of descriptors, now shared rxqs share the same pool, no need to supply mbufs for each rxq, just feed the shared rxq.

So the memory saving reflects to mbuf per rxq, even 1000 representors in shared rxq group, the mbufs consumed is one rxq. In other words, new members in shared rxq doesn’t allocate new mbufs to feed rxq, just share with existing shared rxq(HW mempool). The memory required to setup each rxq doesn't change too much, agree.

We can ask the application to configure the same mempool for multiple RQ too. RIght? If the saving is based on sharing the mempool with multiple RQs.

Quoted 9 lines
Quoted 7 lines

# Also, I was thinking, one way to avoid the fast path or ABI change would like.

# Driver Initializes one more eth_dev_ops in driver as aggregator ethdev # devargs of new ethdev or specific API like drivers/net/bonding/rte_eth_bond.h can take the argument (port, queue) tuples which needs to aggregate by new ethdev port # No change in fastpath or ABI is required in this model.

This could be an option to access shared rxq. What's the difference of the new PMD?

No ABI and fast change are required.

Quoted 3 lines

What's the difference of PMD driver to create the new device?

Is it important in your implementation? Does it work with existing rx_burst api?

Yes . It will work with the existing rx_burst API.

Quoted 37 lines
Quoted 37 lines
Quoted 6 lines

Most user might uses PF in group as the anchor port to rx burst, current definition should be easy for them to migrate. but some user might prefer grouping some hot
plug/unpluggedrepresentors, EAL could provide wrappers, users could do that either due to the strategy not complex enough.

Anyway, welcome any suggestion.

Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or

rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -0
+/**
+ * Rx queue is shared among ports in same switch domain
+to save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM

| \
--
2.25.1

#77 lore raw
Quoted 190 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Monday, August 30, 2021 5:31 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 179 lines · Xueming(Steven) Li
Quoted 165 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 26, 2021 7:58 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 103 lines · Xueming(Steven) Li
Quoted 103 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 19, 2021 1:27 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 89 lines · Xueming(Steven) Li
Quoted 89 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 11:12 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 73 lines · Xueming(Steven) Li
Quoted 44 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 28 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded
with mbufs for incoming packets. When number of
representors scale out in a switch domain, the memory consumption became significant. Most important,
polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same
configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives
packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue
object, it's important to clear all queue control callback api that using queue object:

https://mails.dpdk.org/archives/dev/2021-July/215574.h
tml

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR diff --git
a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h index d2b27c351f..a578c9db9d 100644

lib/ethdev/rte_ethdev.h +2 -0
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group
+ index in switch domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

To support more groups simultaneously, need to consider
testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group
number, but user must schedule stream affinity carefully - error prone.

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

Ack. One group is enough in testpmd.

My question was more about who and how this group is created, Should n't we need API to create shared_group? If we do the following, at least, I can think, how it can be implemented in SW

or other HW.

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines

- Create aggregation queue group
- Attach multiple Rx queues to the aggregation queue group
- Pull the packets from the queue group(which internally fetch from the Rx queues _attached_)

Does the above kind of sequence, break your representor use case?

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

Seems more like a set of EAL wrapper. Current API tries to minimize the application efforts to adapt shared-rxq.
- step 1, not sure how important it is to create group with API, in rte_flow, group is created on demand.

Which rte_flow pattern/action for this?

No rte_flow for this, just recalled that the group in rte_flow is not created along with flow, not via api. I don’t see anything else to create along with group, just double whether it valuable to introduce a new api set to manage group.

See below.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

- step 2, currently, the attaching is done in rte_eth_rx_queue_setup, specify offload and group in rx_conf struct.
- step 3, define a dedicate api to receive packets from shared rxq? Looks clear to receive packets from shared rxq. currently, rxq objects in share group is same - the shared rxq, so the eth callback eth_rx_burst_t(rxq_obj, mbufs, n) could be used to receive packets from any ports in group, normally the first port(PF) in group.
An alternative way is defining a vdev with same queue number and copy rxq objects will make the vdev a proxy of the shared rxq group - this could be an helper API.

Quoted 6 lines
Quoted 6 lines
Quoted 1 line

Anyway the wrapper doesn't break use case, step 3 api is more clear, need to understand how to implement efficiently.

Are you doing this feature based on any HW support or it just pure SW thing, If it is SW, It is better to have just new vdev for like drivers/net/bonding/. This we can help aggregate multiple Rxq across

the multiple ports of same the driver.

Quoted 2 lines

Based on HW support.

In Marvel HW, we do some support, I will outline here and some queries on this.

# We need to create some new HW structure for aggregation # Connect
each Rxq to the new HW structure for aggregation # Use rx_burst from the new HW structure.

Quoted 7 lines

Could you outline your HW support?

Also, I am not able to understand how this will reduce the memory,
atleast in our HW need creating more memory now to deal this as we need to deal new HW structure.

How is in your HW it reduces the memory? Also, if memory is the constraint, why NOT reduce the number of queues.

Glad to know that Marvel is working on this, what's the status of driver implementation?

In my PMD implementation, it's very similar, a new HW object shared memory pool is created to replace per rxq memory pool. Legacy rxq feed queue with allocated mbufs as number of descriptors,
now shared rxqs share the same pool, no need to supply mbufs for each rxq, just feed the shared rxq.

Quoted 7 lines
Quoted 2 lines

So the memory saving reflects to mbuf per rxq, even 1000 representors in shared rxq group, the mbufs consumed is one rxq. In other words, new members in shared rxq doesn’t allocate new mbufs to feed rxq, just share with existing shared rxq(HW

mempool).

Quoted 1 line

The memory required to setup each rxq doesn't change too much, agree.

We can ask the application to configure the same mempool for multiple RQ too. RIght? If the saving is based on sharing the mempool with multiple RQs.

Yes, using the same mempool is the fundamental. The difference is how many mbufs allocate from pool. Assuming 512 descriptors perf rxq and 4 rxqs per device, it's 2.3K(mbuf) * 512 * 4 = 4.6M / device To support 1000 representors, need a 4.6G mempool :)
For shared rxq, only 4.6M(one device) mbufs allocate from mempool, they are shared for all rxqs in group.

Quoted 58 lines
Quoted 7 lines
Quoted 7 lines

# Also, I was thinking, one way to avoid the fast path or ABI change would like.

# Driver Initializes one more eth_dev_ops in driver as aggregator
ethdev # devargs of new ethdev or specific API like
drivers/net/bonding/rte_eth_bond.h can take the argument (port, queue) tuples which needs to aggregate by new ethdev port #

No change in fastpath or ABI is required in this model.

Quoted 3 lines
Quoted 1 line

This could be an option to access shared rxq. What's the difference of the new PMD?

No ABI and fast change are required.

Quoted 3 lines

What's the difference of PMD driver to create the new device?

Is it important in your implementation? Does it work with existing rx_burst api?

Yes . It will work with the existing rx_burst API.

Quoted 38 lines
Quoted 38 lines
Quoted 6 lines

Most user might uses PF in group as the anchor port to rx burst, current definition should be easy for them to migrate. but some user might prefer grouping some hot
plug/unpluggedrepresentors, EAL could provide wrappers, users could do that either due to the strategy not complex enough.

Anyway, welcome any suggestion.

Quoted 31 lines
Quoted 31 lines
Quoted 31 lines
Quoted 31 lines
Quoted 31 lines
Quoted 31 lines
Quoted 31 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa

or rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -0
+/**
+ * Rx queue is shared among ports in same switch
+domain to save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \

DEV_RX_OFFLOAD_UDP_CKSUM
| \
--
2.25.1

#78 lore raw
In reply to Jerin Jacob

Hi Jerin,

Quoted 190 lines · Jerin Jacob
Quoted 167 lines · Xueming(Steven) Li
Quoted 157 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 26, 2021 7:58 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 97 lines · Xueming(Steven) Li
Quoted 97 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 19, 2021 1:27 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 84 lines · Xueming(Steven) Li
Quoted 84 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 11:12 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 70 lines · Xueming(Steven) Li
Quoted 43 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 27 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same
configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives
packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object,
it's important to clear all queue control callback api that using queue object:

https://mails.dpdk.org/archives/dev/2021-July/215574.html

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR diff --git
a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h index d2b27c351f..a578c9db9d 100644

lib/ethdev/rte_ethdev.h +2 -0
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group
+ index in switch domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

To support more groups simultaneously, need to consider
testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group
number, but user must schedule stream affinity carefully - error prone.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Ack. One group is enough in testpmd.

My question was more about who and how this group is created,
Should n't we need API to create shared_group? If we do the following, at least, I can think, how it can be implemented in SW

or other HW.

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines

- Create aggregation queue group
- Attach multiple Rx queues to the aggregation queue group
- Pull the packets from the queue group(which internally fetch from the Rx queues _attached_)

Does the above kind of sequence, break your representor use case?

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

Seems more like a set of EAL wrapper. Current API tries to minimize the application efforts to adapt shared-rxq.
- step 1, not sure how important it is to create group with API, in rte_flow, group is created on demand.

Which rte_flow pattern/action for this?

No rte_flow for this, just recalled that the group in rte_flow is not created along with flow, not via api. I don’t see anything else to create along with group, just double whether it valuable to introduce a new api set to manage group.

See below.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

- step 2, currently, the attaching is done in rte_eth_rx_queue_setup, specify offload and group in rx_conf struct.
- step 3, define a dedicate api to receive packets from shared rxq? Looks clear to receive packets from shared rxq. currently, rxq objects in share group is same - the shared rxq, so the eth callback eth_rx_burst_t(rxq_obj, mbufs, n) could be used to receive packets from any ports in group, normally the first port(PF) in group.
An alternative way is defining a vdev with same queue number and copy rxq objects will make the vdev a proxy of the shared rxq group - this could be an helper API.

Quoted 4 lines
Quoted 4 lines
Quoted 1 line

Anyway the wrapper doesn't break use case, step 3 api is more clear, need to understand how to implement efficiently.

Are you doing this feature based on any HW support or it just pure
SW thing, If it is SW, It is better to have just new vdev for like drivers/net/bonding/. This we can help aggregate multiple Rxq across

the multiple ports of same the driver.

Quoted 2 lines

Based on HW support.

In Marvel HW, we do some support, I will outline here and some queries on this.

# We need to create some new HW structure for aggregation # Connect each Rxq to the new HW structure for aggregation # Use rx_burst from the new HW structure.

Quoted 7 lines

Could you outline your HW support?

Also, I am not able to understand how this will reduce the memory, atleast in our HW need creating more memory now to deal this as we need to deal new HW structure.

How is in your HW it reduces the memory? Also, if memory is the constraint, why NOT reduce the number of queues.

Glad to know that Marvel is working on this, what's the status of driver implementation?

Quoted 7 lines

In my PMD implementation, it's very similar, a new HW object shared memory pool is created to replace per rxq memory pool. Legacy rxq feed queue with allocated mbufs as number of descriptors, now shared rxqs share the same pool, no need to supply mbufs for each rxq, just feed the shared rxq.

So the memory saving reflects to mbuf per rxq, even 1000 representors in shared rxq group, the mbufs consumed is one rxq. In other words, new members in shared rxq doesn’t allocate new mbufs to feed rxq, just share with existing shared rxq(HW mempool). The memory required to setup each rxq doesn't change too much, agree.

We can ask the application to configure the same mempool for multiple RQ too. RIght? If the saving is based on sharing the mempool with multiple RQs.

Quoted 9 lines
Quoted 7 lines

# Also, I was thinking, one way to avoid the fast path or ABI change would like.

# Driver Initializes one more eth_dev_ops in driver as aggregator ethdev # devargs of new ethdev or specific API like drivers/net/bonding/rte_eth_bond.h can take the argument (port, queue) tuples which needs to aggregate by new ethdev port # No change in fastpath or ABI is required in this model.

This could be an option to access shared rxq. What's the difference of the new PMD?

Quoted 8 lines

No ABI and fast change are required.

Quoted 3 lines

What's the difference of PMD driver to create the new device?

Is it important in your implementation? Does it work with existing rx_burst api?

Yes . It will work with the existing rx_burst API.

The aggregator ethdev required by user is a port, maybe it good to add a callback for PMD to prepare a complete ethdev just like creating representor ethdev - pmd register new port internally. If the PMD doens't provide the callback, ethdev api fallback to initialize an empty ethdev by copy rxq data(shared) and rx_burst api from source port and share group. Actually users can do this fallback themselves or with an util api.

IIUC, an aggregator ethdev not a must, do you think we can continue and leave that design in later stage?

Quoted 37 lines
Quoted 37 lines
Quoted 37 lines
Quoted 6 lines

Most user might uses PF in group as the anchor port to rx burst, current definition should be easy for them to migrate. but some user might prefer grouping some hot
plug/unpluggedrepresentors, EAL could provide wrappers, users could do that either due to the strategy not complex enough.

Anyway, welcome any suggestion.

Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or

rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -0
+/**
+ * Rx queue is shared among ports in same switch domain
+to save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM
Quoted 1 line

\

--
2.25.1

#79 lore raw
Quoted 211 lines · Xueming(Steven) Li

Hi Jerin,

Quoted 190 lines · Jerin Jacob
Quoted 167 lines · Xueming(Steven) Li
Quoted 157 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 26, 2021 7:58 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 97 lines · Xueming(Steven) Li
Quoted 97 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 19, 2021 1:27 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 84 lines · Xueming(Steven) Li
Quoted 84 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 11:12 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 70 lines · Xueming(Steven) Li
Quoted 43 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 27 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same
configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives
packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object,
it's important to clear all queue control callback api that using queue object:

https://mails.dpdk.org/archives/dev/2021-July/215574.html

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR diff --git
a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h index d2b27c351f..a578c9db9d 100644

lib/ethdev/rte_ethdev.h +2 -0
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group
+ index in switch domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

To support more groups simultaneously, need to consider
testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group
number, but user must schedule stream affinity carefully - error prone.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Ack. One group is enough in testpmd.

My question was more about who and how this group is created,
Should n't we need API to create shared_group? If we do the following, at least, I can think, how it can be implemented in SW

or other HW.

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines

- Create aggregation queue group
- Attach multiple Rx queues to the aggregation queue group
- Pull the packets from the queue group(which internally fetch from the Rx queues _attached_)

Does the above kind of sequence, break your representor use case?

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

Seems more like a set of EAL wrapper. Current API tries to minimize the application efforts to adapt shared-rxq.
- step 1, not sure how important it is to create group with API, in rte_flow, group is created on demand.

Which rte_flow pattern/action for this?

No rte_flow for this, just recalled that the group in rte_flow is not created along with flow, not via api. I don’t see anything else to create along with group, just double whether it valuable to introduce a new api set to manage group.

See below.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

- step 2, currently, the attaching is done in rte_eth_rx_queue_setup, specify offload and group in rx_conf struct.
- step 3, define a dedicate api to receive packets from shared rxq? Looks clear to receive packets from shared rxq. currently, rxq objects in share group is same - the shared rxq, so the eth callback eth_rx_burst_t(rxq_obj, mbufs, n) could be used to receive packets from any ports in group, normally the first port(PF) in group.
An alternative way is defining a vdev with same queue number and copy rxq objects will make the vdev a proxy of the shared rxq group - this could be an helper API.

Quoted 4 lines
Quoted 4 lines
Quoted 1 line

Anyway the wrapper doesn't break use case, step 3 api is more clear, need to understand how to implement efficiently.

Are you doing this feature based on any HW support or it just pure
SW thing, If it is SW, It is better to have just new vdev for like drivers/net/bonding/. This we can help aggregate multiple Rxq across

the multiple ports of same the driver.

Quoted 2 lines

Based on HW support.

In Marvel HW, we do some support, I will outline here and some queries on this.

# We need to create some new HW structure for aggregation # Connect each Rxq to the new HW structure for aggregation # Use rx_burst from the new HW structure.

Quoted 7 lines

Could you outline your HW support?

Also, I am not able to understand how this will reduce the memory, atleast in our HW need creating more memory now to deal this as we need to deal new HW structure.

How is in your HW it reduces the memory? Also, if memory is the constraint, why NOT reduce the number of queues.

Glad to know that Marvel is working on this, what's the status of driver implementation?

Quoted 7 lines

In my PMD implementation, it's very similar, a new HW object shared memory pool is created to replace per rxq memory pool. Legacy rxq feed queue with allocated mbufs as number of descriptors, now shared rxqs share the same pool, no need to supply mbufs for each rxq, just feed the shared rxq.

So the memory saving reflects to mbuf per rxq, even 1000 representors in shared rxq group, the mbufs consumed is one rxq. In other words, new members in shared rxq doesn’t allocate new mbufs to feed rxq, just share with existing shared rxq(HW mempool). The memory required to setup each rxq doesn't change too much, agree.

We can ask the application to configure the same mempool for multiple RQ too. RIght? If the saving is based on sharing the mempool with multiple RQs.

Quoted 9 lines
Quoted 7 lines

# Also, I was thinking, one way to avoid the fast path or ABI change would like.

# Driver Initializes one more eth_dev_ops in driver as aggregator ethdev # devargs of new ethdev or specific API like drivers/net/bonding/rte_eth_bond.h can take the argument (port, queue) tuples which needs to aggregate by new ethdev port # No change in fastpath or ABI is required in this model.

This could be an option to access shared rxq. What's the difference of the new PMD?

Quoted 8 lines

No ABI and fast change are required.

Quoted 3 lines

What's the difference of PMD driver to create the new device?

Is it important in your implementation? Does it work with existing rx_burst api?

Yes . It will work with the existing rx_burst API.

The aggregator ethdev required by user is a port, maybe it good to add a callback for PMD to prepare a complete ethdev just like creating representor ethdev - pmd register new port internally. If the PMD doens't provide the callback, ethdev api fallback to initialize an empty ethdev by copy rxq data(shared) and rx_burst api from source port and share group. Actually users can do this fallback themselves or with an util api.

Quoted 2 lines

IIUC, an aggregator ethdev not a must, do you think we can continue and leave that design in later stage?

IMO aggregator ethdev reduces the complexity for application hence avoid any change in
test application etc. IMO, I prefer to take that. I will leave the decision to ethdev maintainers.

Quoted 39 lines
Quoted 38 lines
Quoted 38 lines
Quoted 38 lines
Quoted 7 lines

Most user might uses PF in group as the anchor port to rx burst, current definition should be easy for them to migrate. but some user might prefer grouping some hot
plug/unpluggedrepresentors, EAL could provide wrappers, users could do that either due to the strategy not complex enough.

Anyway, welcome any suggestion.

Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or

rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -0
+/**
+ * Rx queue is shared among ports in same switch domain
+to save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM
Quoted 1 line

\

--
2.25.1

#80 lore raw
Quoted 212 lines · Jerin Jacob
Quoted 211 lines · Xueming(Steven) Li

Hi Jerin,

Quoted 190 lines · Jerin Jacob
Quoted 167 lines · Xueming(Steven) Li
Quoted 157 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 26, 2021 7:58 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 97 lines · Xueming(Steven) Li
Quoted 97 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Thursday, August 19, 2021 1:27 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 84 lines · Xueming(Steven) Li
Quoted 84 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 11:12 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 70 lines · Xueming(Steven) Li
Quoted 43 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, August 17, 2021 5:33 PM
To: Xueming(Steven) Li <[email protected]>
Cc: dpdk-dev <[email protected]>; Ferruh Yigit <[email protected]>; NBU-Contact-Thomas Monjalon <[email protected]>; Andrew Rybchenko <[email protected]>
Subject: Re: [PATCH v2 01/15] ethdev: introduce shared Rx queue

Quoted 27 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same
configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives
packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is
1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object,
it's important to clear all queue control callback api that using queue object:

https://mails.dpdk.org/archives/dev/2021-July/215574.html

Quoted 15 lines

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1052

Quoted 12 lines

#undef RTE_RX_OFFLOAD_BIT2STR diff --git
a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h index d2b27c351f..a578c9db9d 100644

lib/ethdev/rte_ethdev.h +2 -0
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array.
 */
+       uint32_t shared_group; /**< Shared port group
+ index in switch domain. */

Not to able to see anyone setting/creating this group ID test application. How this group is created?

Nice catch, the initial testpmd version only support one default group(0). All ports that supports shared-rxq assigned in same group.

We should be able to change "--rxq-shared" to "--rxq-shared-group" to support group other than default.

To support more groups simultaneously, need to consider
testpmd forwarding stream core assignment, all streams in same group need to stay on same core. It's possible to specify how many ports to increase group
number, but user must schedule stream affinity carefully - error prone.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

On the other hand, one group should be sufficient for most customer, the doubt is whether it valuable to support multiple groups test.

Ack. One group is enough in testpmd.

My question was more about who and how this group is created,
Should n't we need API to create shared_group? If we do the following, at least, I can think, how it can be implemented in SW

or other HW.

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines

- Create aggregation queue group
- Attach multiple Rx queues to the aggregation queue group
- Pull the packets from the queue group(which internally fetch from the Rx queues _attached_)

Does the above kind of sequence, break your representor use case?

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

Seems more like a set of EAL wrapper. Current API tries to minimize the application efforts to adapt shared-rxq.
- step 1, not sure how important it is to create group with API, in rte_flow, group is created on demand.

Which rte_flow pattern/action for this?

No rte_flow for this, just recalled that the group in rte_flow is not created along with flow, not via api. I don’t see anything else to create along with group, just double whether it valuable to introduce a new api set to manage group.

See below.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

- step 2, currently, the attaching is done in rte_eth_rx_queue_setup, specify offload and group in rx_conf struct.
- step 3, define a dedicate api to receive packets from shared rxq? Looks clear to receive packets from shared rxq. currently, rxq objects in share group is same - the shared rxq, so the eth callback eth_rx_burst_t(rxq_obj, mbufs, n) could be used to receive packets from any ports in group, normally the first port(PF) in group.
An alternative way is defining a vdev with same queue number and copy rxq objects will make the vdev a proxy of the shared rxq group - this could be an helper API.

Quoted 4 lines
Quoted 4 lines
Quoted 1 line

Anyway the wrapper doesn't break use case, step 3 api is more clear, need to understand how to implement efficiently.

Are you doing this feature based on any HW support or it just pure
SW thing, If it is SW, It is better to have just new vdev for like drivers/net/bonding/. This we can help aggregate multiple Rxq across

the multiple ports of same the driver.

Quoted 2 lines

Based on HW support.

In Marvel HW, we do some support, I will outline here and some queries on this.

# We need to create some new HW structure for aggregation # Connect each Rxq to the new HW structure for aggregation # Use rx_burst from the new HW structure.

Quoted 7 lines

Could you outline your HW support?

Also, I am not able to understand how this will reduce the memory, atleast in our HW need creating more memory now to deal this as we need to deal new HW structure.

How is in your HW it reduces the memory? Also, if memory is the constraint, why NOT reduce the number of queues.

Glad to know that Marvel is working on this, what's the status of driver implementation?

Quoted 7 lines

In my PMD implementation, it's very similar, a new HW object shared memory pool is created to replace per rxq memory pool. Legacy rxq feed queue with allocated mbufs as number of descriptors, now shared rxqs share the same pool, no need to supply mbufs for each rxq, just feed the shared rxq.

So the memory saving reflects to mbuf per rxq, even 1000 representors in shared rxq group, the mbufs consumed is one rxq. In other words, new members in shared rxq doesn’t allocate new mbufs to feed rxq, just share with existing shared rxq(HW mempool). The memory required to setup each rxq doesn't change too much, agree.

We can ask the application to configure the same mempool for multiple RQ too. RIght? If the saving is based on sharing the mempool with multiple RQs.

Quoted 9 lines
Quoted 7 lines

# Also, I was thinking, one way to avoid the fast path or ABI change would like.

# Driver Initializes one more eth_dev_ops in driver as aggregator ethdev # devargs of new ethdev or specific API like drivers/net/bonding/rte_eth_bond.h can take the argument (port, queue) tuples which needs to aggregate by new ethdev port # No change in fastpath or ABI is required in this model.

This could be an option to access shared rxq. What's the difference of the new PMD?

Quoted 8 lines

No ABI and fast change are required.

Quoted 3 lines

What's the difference of PMD driver to create the new device?

Is it important in your implementation? Does it work with existing rx_burst api?

Yes . It will work with the existing rx_burst API.

The aggregator ethdev required by user is a port, maybe it good to add a callback for PMD to prepare a complete ethdev just like creating representor ethdev - pmd register new port internally. If the PMD doens't provide the callback, ethdev api fallback to initialize an empty ethdev by copy rxq data(shared) and rx_burst api from source port and share group. Actually users can do this fallback themselves or with an util api.

Quoted 8 lines
Quoted 2 lines

IIUC, an aggregator ethdev not a must, do you think we can continue and leave that design in later stage?

IMO aggregator ethdev reduces the complexity for application hence avoid any change in
test application etc. IMO, I prefer to take that. I will leave the decision to ethdev maintainers.

Hi Jerin, new API added for aggregator, the last one in v3, thanks!

Quoted 41 lines
Quoted 41 lines
Quoted 40 lines
Quoted 40 lines
Quoted 40 lines
Quoted 9 lines

Most user might uses PF in group as the anchor port to rx burst, current definition should be easy for them to migrate. but some user might prefer grouping some hot
plug/unpluggedrepresentors, EAL could provide wrappers, users could do that either due to the strategy not complex enough.

Anyway, welcome any suggestion.

Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
lib/ethdev/rte_ethdev.h +0 -0
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or

rx_offload_capa @@ -1373,6 +1374,12 @@ struct rte_eth_conf { #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
#define DEV_RX_OFFLOAD_RSS_HASH 0x00080000
#define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000

lib/ethdev/rte_ethdev.h +7 -0
+/**
+ * Rx queue is shared among ports in same switch domain
+to save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM
Quoted 1 line

\

--
2.25.1

author
#81 lore raw

v3 cover ethdev: introduce shared Rx queue

In reply to Xueming Li

In current DPDK framework, all RX queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared RX queue. PF and representors with same configuration in same switch domain could share RX queue set by specifying shared Rx queue offloading flag and sharing group.

All ports that Shared Rx queue actually shares One Rx queue and only pre-load mbufs to one Rx queue, memory is saved.

Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of polling two share groups:
core group queue
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3

Shared RX queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

v1:
- initial version
v2:
- add testpmd patches
v3:
- change common forwarding api to macro for performance, thanks Jerin.
- save global variable accessed in forwarding to flowstream to minimize cache miss
- combined patches for each forwarding engine
- support multiple groups in testpmd "--share-rxq" parameter
- new api to aggerate shared rxq group

Xiaoyu Min (1):
app/testpmd: add common fwd wrapper

Xueming Li (7):
ethdev: introduce shared Rx queue
ethdev: new API to aggregate shared Rx queue group app/testpmd: dump port and queue info for each packet app/testpmd: new parameter to enable shared Rx queue app/testpmd: force shared Rx queue polled on same core app/testpmd: improve forwarding cache miss app/testpmd: support shared Rx queue forwarding

 app/test-pmd/5tswap.c                         |  25 +---
 app/test-pmd/config.c                         | 120 +++++++++++++++++-
 app/test-pmd/csumonly.c                       |  25 +---
 app/test-pmd/flowgen.c                        |  26 ++--
 app/test-pmd/icmpecho.c                       |  30 ++---
 app/test-pmd/ieee1588fwd.c                    |  30 +++--
 app/test-pmd/iofwd.c                          |  24 +---
 app/test-pmd/macfwd.c                         |  24 +---
 app/test-pmd/macswap.c                        |  23 +---
 app/test-pmd/noisy_vnf.c                      |   2 +-
 app/test-pmd/parameters.c                     |  13 ++
 app/test-pmd/rxonly.c                         |  32 ++---
 app/test-pmd/testpmd.c                        |  91 ++++++++++++-
 app/test-pmd/testpmd.h                        |  47 ++++++-
 app/test-pmd/txonly.c                         |   8 +-
 app/test-pmd/util.c                           |   1 +
 doc/guides/nics/features.rst                  |  11 ++
 doc/guides/nics/features/default.ini          |   1 +
 .../prog_guide/switch_representation.rst      |  10 ++
 doc/guides/testpmd_app_ug/run_app.rst         |   5 +
 lib/ethdev/ethdev_driver.h                    |  23 +++-
 lib/ethdev/rte_ethdev.c                       |  23 ++++
 lib/ethdev/rte_ethdev.h                       |  23 ++++
 lib/ethdev/version.map                        |   3 +
 24 files changed, 432 insertions(+), 188 deletions(-)
Signature · 1 line
2.33.0
author
#82 lore raw

PATCH v3 1/8 ethdev: introduce shared Rx queue

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

---
 doc/guides/nics/features.rst                    | 11 +++++++++++
 doc/guides/nics/features/default.ini            |  1 +
 doc/guides/prog_guide/switch_representation.rst | 10 ++++++++++
 lib/ethdev/rte_ethdev.c                         |  1 +
 lib/ethdev/rte_ethdev.h                         |  7 +++++++
 5 files changed, 30 insertions(+)
doc/guides/nics/features.rst +11 -0
index a96e12d155..2e2a9b1554 100644
@@ -624,6 +624,17 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same switch domain.
+
+* **[uses]     rte_eth_rxconf,rte_eth_rxmode**: ``offloads:RTE_ETH_RX_OFFLOAD_SHARED_RXQ``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index 754184ddd4..ebeb4c1851 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +10 -0
index ff6aa91c80..45bf5a3a10 100644
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- Memory usage of representors is huge when number of representor grows,
+  because PMD always allocate mbuf for each descriptor of Rx queue.
+  Polling the large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors in same switch domain. ``RTE_ETH_RX_OFFLOAD_SHARED_RXQ``
+  is present in Rx offloading capability of device info. Setting the
+  offloading flag in device Rx mode or Rx queue configuration to enable
+  shared Rx queue. Polling any member port of shared Rx queue can return
+  packets of all ports in group, port ID is saved in ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
lib/ethdev/rte_ethdev.c +1 -0
index a7c090ce79..b3a58d5e65 100644
@@ -127,6 +127,7 @@ static const struct {
 	RTE_RX_OFFLOAD_BIT2STR(OUTER_UDP_CKSUM),
 	RTE_RX_OFFLOAD_BIT2STR(RSS_HASH),
 	RTE_ETH_RX_OFFLOAD_BIT2STR(BUFFER_SPLIT),
+	RTE_ETH_RX_OFFLOAD_BIT2STR(SHARED_RXQ),
 };
 
 #undef RTE_RX_OFFLOAD_BIT2STR
lib/ethdev/rte_ethdev.h +7 -0
index d2b27c351f..a578c9db9d 100644
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
 	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	uint32_t shared_group; /**< Shared port group index in switch domain. */
 	/**
 	 * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
 	 * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1373,6 +1374,12 @@ struct rte_eth_conf {
 #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM  0x00040000
 #define DEV_RX_OFFLOAD_RSS_HASH		0x00080000
 #define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000
+/**
+ * Rx queue is shared among ports in same switch domain to save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
 				 DEV_RX_OFFLOAD_UDP_CKSUM | \
Signature · 1 line
2.33.0
#83 lore raw
Quoted 12 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Quoted 6 lines

Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

Can you clarify this a little more?

Apologies if this was already covered:
* Can't we do this for Tx also?

Couple of nits inline. Thanks

Quoted 54 lines

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

---
 doc/guides/nics/features.rst                    | 11 +++++++++++
 doc/guides/nics/features/default.ini            |  1 +
 doc/guides/prog_guide/switch_representation.rst | 10 ++++++++++
 lib/ethdev/rte_ethdev.c                         |  1 +
 lib/ethdev/rte_ethdev.h                         |  7 +++++++
 5 files changed, 30 insertions(+)
doc/guides/nics/features.rst +11 -0
index a96e12d155..2e2a9b1554 100644
@@ -624,6 +624,17 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same switch domain.
+
+* **[uses]     rte_eth_rxconf,rte_eth_rxmode**: ``offloads:RTE_ETH_RX_OFFLOAD_SHARED_RXQ``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index 754184ddd4..ebeb4c1851 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +0 -0
index ff6aa91c80..45bf5a3a10 100644

doc/guides/prog_guide/switch_representation.rst thought as a software "patch panel" front-end for applications. · line 130

Quoted 8 lines
doc/guides/prog_guide/switch_representation.rst +5 -0
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- Memory usage of representors is huge when number of representor grows,
+  because PMD always allocate mbuf for each descriptor of Rx queue.
+  Polling the large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors in same switch domain. ``RTE_ETH_RX_OFFLOAD_SHARED_RXQ``

"in the same switch"

doc/guides/prog_guide/switch_representation.rst thought as a software "patch panel" front-end for applications. · line 133

Quoted 3 lines
doc/guides/prog_guide/switch_representation.rst +3 -0
+  is present in Rx offloading capability of device info. Setting the
+  offloading flag in device Rx mode or Rx queue configuration to enable
+  shared Rx queue. Polling any member port of shared Rx queue can return

"of the shared Rx queue.."

doc/guides/prog_guide/switch_representation.rst thought as a software "patch panel" front-end for applications. · line 134

Quoted 1 line
doc/guides/prog_guide/switch_representation.rst +1 -0
+  packets of all ports in group, port ID is saved in ``mbuf.port``.

"ports in the group, "

Quoted 29 lines
doc/guides/prog_guide/switch_representation.rst +1 -0
+
 Basic SR-IOV
 ------------
 
lib/ethdev/rte_ethdev.c +1 -0
index a7c090ce79..b3a58d5e65 100644
@@ -127,6 +127,7 @@ static const struct {
        RTE_RX_OFFLOAD_BIT2STR(OUTER_UDP_CKSUM),
        RTE_RX_OFFLOAD_BIT2STR(RSS_HASH),
        RTE_ETH_RX_OFFLOAD_BIT2STR(BUFFER_SPLIT),
+       RTE_ETH_RX_OFFLOAD_BIT2STR(SHARED_RXQ),
 };
 
 #undef RTE_RX_OFFLOAD_BIT2STR
lib/ethdev/rte_ethdev.h +1 -0
index d2b27c351f..a578c9db9d 100644
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+       uint32_t shared_group; /**< Shared port group index in switch domain. */
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or rx_offload_capa

lib/ethdev/rte_ethdev.h struct rte_eth_conf { · line 1379

Quoted 6 lines
lib/ethdev/rte_ethdev.h +3 -0
@@ -1373,6 +1374,12 @@ struct rte_eth_conf {
 #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM  0x00040000
 #define DEV_RX_OFFLOAD_RSS_HASH                0x00080000
 #define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000
+/**
+ * Rx queue is shared among ports in same switch domain to save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.

"Any port in the group can"

Quoted 9 lines
lib/ethdev/rte_ethdev.h +3 -1
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM | \
--

2.33.0

#84 lore raw
Quoted 13 lines · Ajit Khaparde
Quoted 12 lines · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Quoted 7 lines
Quoted 6 lines

Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

Can you clarify this a little more?

Thanks for the review!

By using group ID, user can specify for example:
group 0: port 0-3, 2 queues per port, poll on core 0 and 1 group 1: port 4-127, 1 queue per port, poll on core 1.
Normally used for QoS and load balance.

Quoted 3 lines

Apologies if this was already covered:
* Can't we do this for Tx also?

Rx queue pre-fill mbufs for each queue, which consuming huge mbufs by default, most of them are less active, saving memory is the primary motatation for this feature.
Tx queue doesn't consume any mbuf by default until starting tx, no strong reason so far.

Quoted 125 lines

Couple of nits inline. Thanks

Quoted 54 lines

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

---
 doc/guides/nics/features.rst                    | 11 +++++++++++
 doc/guides/nics/features/default.ini            |  1 +
 doc/guides/prog_guide/switch_representation.rst | 10 ++++++++++
 lib/ethdev/rte_ethdev.c                         |  1 +
 lib/ethdev/rte_ethdev.h                         |  7 +++++++
 5 files changed, 30 insertions(+)
doc/guides/nics/features.rst +11 -0
index a96e12d155..2e2a9b1554 100644
@@ -624,6 +624,17 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same switch domain.
+
+* **[uses]     rte_eth_rxconf,rte_eth_rxmode**: ``offloads:RTE_ETH_RX_OFFLOAD_SHARED_RXQ``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index 754184ddd4..ebeb4c1851 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +0 -0
index ff6aa91c80..45bf5a3a10 100644

doc/guides/prog_guide/switch_representation.rst thought as a software "patch panel" front-end for applications. · line 130

Quoted 8 lines
doc/guides/prog_guide/switch_representation.rst +5 -0
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- Memory usage of representors is huge when number of representor grows,
+  because PMD always allocate mbuf for each descriptor of Rx queue.
+  Polling the large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors in same switch domain. ``RTE_ETH_RX_OFFLOAD_SHARED_RXQ``

"in the same switch"

doc/guides/prog_guide/switch_representation.rst thought as a software "patch panel" front-end for applications. · line 133

Quoted 3 lines
doc/guides/prog_guide/switch_representation.rst +3 -0
+  is present in Rx offloading capability of device info. Setting the
+  offloading flag in device Rx mode or Rx queue configuration to enable
+  shared Rx queue. Polling any member port of shared Rx queue can return

"of the shared Rx queue.."

doc/guides/prog_guide/switch_representation.rst thought as a software "patch panel" front-end for applications. · line 134

Quoted 1 line
doc/guides/prog_guide/switch_representation.rst +1 -0
+  packets of all ports in group, port ID is saved in ``mbuf.port``.

"ports in the group, "

Quoted 29 lines
doc/guides/prog_guide/switch_representation.rst +1 -0
+
 Basic SR-IOV
 ------------
 
lib/ethdev/rte_ethdev.c +1 -0
index a7c090ce79..b3a58d5e65 100644
@@ -127,6 +127,7 @@ static const struct {
        RTE_RX_OFFLOAD_BIT2STR(OUTER_UDP_CKSUM),
        RTE_RX_OFFLOAD_BIT2STR(RSS_HASH),
        RTE_ETH_RX_OFFLOAD_BIT2STR(BUFFER_SPLIT),
+       RTE_ETH_RX_OFFLOAD_BIT2STR(SHARED_RXQ),
 };
 
 #undef RTE_RX_OFFLOAD_BIT2STR
lib/ethdev/rte_ethdev.h +1 -0
index d2b27c351f..a578c9db9d 100644
@@ -1047,6 +1047,7 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+       uint32_t shared_group; /**< Shared port group index in switch domain. */
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or rx_offload_capa

lib/ethdev/rte_ethdev.h struct rte_eth_conf { · line 1379

Quoted 6 lines
lib/ethdev/rte_ethdev.h +3 -0
@@ -1373,6 +1374,12 @@ struct rte_eth_conf {
 #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM  0x00040000
 #define DEV_RX_OFFLOAD_RSS_HASH                0x00080000
 #define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000
+/**
+ * Rx queue is shared among ports in same switch domain to save memory,
+ * avoid polling each port. Any port in group can be used to receive packets.

"Any port in the group can"

Quoted 9 lines
lib/ethdev/rte_ethdev.h +3 -1
+ * Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
                                 DEV_RX_OFFLOAD_UDP_CKSUM | \
--

2.33.0

author
#85 lore raw

PATCH v3 2/8 ethdev: new API to aggregate shared Rx queue group

In reply to Xueming Li

This patch introduces new api to aggreated ports among same shared Rx queue group. Only queues with specified share group is aggregated. Rx burst and device close are expected to be supported by new device.

---
 lib/ethdev/ethdev_driver.h | 23 ++++++++++++++++++++++-
 lib/ethdev/rte_ethdev.c    | 22 ++++++++++++++++++++++
 lib/ethdev/rte_ethdev.h    | 16 ++++++++++++++++
 lib/ethdev/version.map     |  3 +++
 4 files changed, 63 insertions(+), 1 deletion(-)
lib/ethdev/ethdev_driver.h +22 -1
index 524757cf6f..72156a4153 100644
@@ -786,10 +786,28 @@ typedef int (*eth_get_monitor_addr_t)(void *rxq,
  * @return
  *   Negative errno value on error, number of info entries otherwise.
  */
-
 typedef int (*eth_representor_info_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_representor_info *info);
 
+/**
+ * @internal
+ * Aggregate shared Rx queue.
+ *
+ * Create a new port used for shared Rx queue polling.
+ *
+ * Only queues with specified share group are aggregated.
+ * At least Rx burst and device close should be supported.
+ *
+ * @param dev
+ *   Ethdev handle of port.
+ * @param group
+ *   Shared Rx queue group to aggregate.
+ * @return
+ *   UINT16_MAX if failed, otherwise aggregated port number.
+ */
+typedef int (*eth_shared_rxq_aggregate_t)(struct rte_eth_dev *dev,
+					  uint32_t group);
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -950,6 +968,9 @@ struct eth_dev_ops {
 
 	eth_representor_info_get_t representor_info_get;
 	/**< Get representor info. */
+
+	eth_shared_rxq_aggregate_t shared_rxq_aggregate;
+	/**< Aggregate shared Rx queue. */
 };
 
 /**
lib/ethdev/rte_ethdev.c +22 -0
index b3a58d5e65..9f2ef58309 100644
@@ -6301,6 +6301,28 @@ rte_eth_representor_info_get(uint16_t port_id,
 	return eth_err(port_id, (*dev->dev_ops->representor_info_get)(dev, info));
 }
 
+uint16_t
+rte_eth_shared_rxq_aggregate(uint16_t port_id, uint32_t group)
+{
+	struct rte_eth_dev *dev;
+	uint64_t offloads;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	dev = &rte_eth_devices[port_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->shared_rxq_aggregate,
+				UINT16_MAX);
+
+	offloads = dev->data->dev_conf.rxmode.offloads;
+	if ((offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ) == 0) {
+		RTE_ETHDEV_LOG(ERR, "port_id=%u doesn't support Rx offload\n",
+			       port_id);
+		return UINT16_MAX;
+	}
+
+	return (*dev->dev_ops->shared_rxq_aggregate)(dev, group);
+}
+
 RTE_LOG_REGISTER_DEFAULT(rte_eth_dev_logtype, INFO);
 
 RTE_INIT(ethdev_init_telemetry)
lib/ethdev/rte_ethdev.h +16 -0
index a578c9db9d..f15d2142b2 100644
@@ -4895,6 +4895,22 @@ __rte_experimental
 int rte_eth_representor_info_get(uint16_t port_id,
 				 struct rte_eth_representor_info *info);
 
+/**
+ * Aggregate shared Rx queue ports to one port for polling.
+ *
+ * Only queues with specified share group is aggregated.
+ * Any operation besides Rx burst and device close is unexpected.
+ *
+ * @param port_id
+ *   The port identifier of the device from shared Rx queue group.
+ * @param group
+ *   Shared Rx queue group to aggregate.
+ * @return
+ *   UINT16_MAX if failed, otherwise aggregated port number.
+ */
+__rte_experimental
+uint16_t rte_eth_shared_rxq_aggregate(uint16_t port_id, uint32_t group);
+
 #include <rte_ethdev_core.h>
 
 /**
lib/ethdev/version.map +3 -0
index 3eece75b72..97a2233508 100644
@@ -249,6 +249,9 @@ EXPERIMENTAL {
 	rte_mtr_meter_policy_delete;
 	rte_mtr_meter_policy_update;
 	rte_mtr_meter_policy_validate;
+
+	# added in 21.11
+	rte_eth_shared_rxq_aggregate;
 };
 
 INTERNAL {
Signature · 1 line
2.33.0
#86 lore raw

Re: [dpdk-dev] [PATCH v3 2/8] ethdev: new API to aggregate shared Rx queue group

Quoted 2 lines · Xueming Li

This patch introduces new api to aggreated ports among same shared Rx

s/aggregated/aggregate

Quoted 1 line

queue group. Only queues with specified share group is aggregated.

s/is/are

Quoted 3 lines

Rx burst and device close are expected to be supported by new device.

Minor nits - typos actually!

Quoted 89 lines
---
 lib/ethdev/ethdev_driver.h | 23 ++++++++++++++++++++++-
 lib/ethdev/rte_ethdev.c    | 22 ++++++++++++++++++++++
 lib/ethdev/rte_ethdev.h    | 16 ++++++++++++++++
 lib/ethdev/version.map     |  3 +++
 4 files changed, 63 insertions(+), 1 deletion(-)
lib/ethdev/ethdev_driver.h +22 -1
index 524757cf6f..72156a4153 100644
@@ -786,10 +786,28 @@ typedef int (*eth_get_monitor_addr_t)(void *rxq,
  * @return
  *   Negative errno value on error, number of info entries otherwise.
  */
-
 typedef int (*eth_representor_info_get_t)(struct rte_eth_dev *dev,
        struct rte_eth_representor_info *info);
 
+/**
+ * @internal
+ * Aggregate shared Rx queue.
+ *
+ * Create a new port used for shared Rx queue polling.
+ *
+ * Only queues with specified share group are aggregated.
+ * At least Rx burst and device close should be supported.
+ *
+ * @param dev
+ *   Ethdev handle of port.
+ * @param group
+ *   Shared Rx queue group to aggregate.
+ * @return
+ *   UINT16_MAX if failed, otherwise aggregated port number.
+ */
+typedef int (*eth_shared_rxq_aggregate_t)(struct rte_eth_dev *dev,
+                                         uint32_t group);
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -950,6 +968,9 @@ struct eth_dev_ops {
 
        eth_representor_info_get_t representor_info_get;
        /**< Get representor info. */
+
+       eth_shared_rxq_aggregate_t shared_rxq_aggregate;
+       /**< Aggregate shared Rx queue. */
 };
 
 /**
lib/ethdev/rte_ethdev.c +22 -0
index b3a58d5e65..9f2ef58309 100644
@@ -6301,6 +6301,28 @@ rte_eth_representor_info_get(uint16_t port_id,
        return eth_err(port_id, (*dev->dev_ops->representor_info_get)(dev, info));
 }
 
+uint16_t
+rte_eth_shared_rxq_aggregate(uint16_t port_id, uint32_t group)
+{
+       struct rte_eth_dev *dev;
+       uint64_t offloads;
+
+       RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+       dev = &rte_eth_devices[port_id];
+
+       RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->shared_rxq_aggregate,
+                               UINT16_MAX);
+
+       offloads = dev->data->dev_conf.rxmode.offloads;
+       if ((offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ) == 0) {
+               RTE_ETHDEV_LOG(ERR, "port_id=%u doesn't support Rx offload\n",
+                              port_id);
+               return UINT16_MAX;
+       }
+
+       return (*dev->dev_ops->shared_rxq_aggregate)(dev, group);
+}
+
 RTE_LOG_REGISTER_DEFAULT(rte_eth_dev_logtype, INFO);
 
 RTE_INIT(ethdev_init_telemetry)
lib/ethdev/rte_ethdev.h +0 -0
index a578c9db9d..f15d2142b2 100644

lib/ethdev/rte_ethdev.h __rte_experimental · line 4901

Quoted 7 lines
lib/ethdev/rte_ethdev.h +4 -0
@@ -4895,6 +4895,22 @@ __rte_experimental
 int rte_eth_representor_info_get(uint16_t port_id,
                                 struct rte_eth_representor_info *info);
 
+/**
+ * Aggregate shared Rx queue ports to one port for polling.
+ *
+ * Only queues with specified share group is aggregated.

s/is/are

Quoted 32 lines
lib/ethdev/rte_ethdev.h +12 -0
+ * Any operation besides Rx burst and device close is unexpected.
+ *
+ * @param port_id
+ *   The port identifier of the device from shared Rx queue group.
+ * @param group
+ *   Shared Rx queue group to aggregate.
+ * @return
+ *   UINT16_MAX if failed, otherwise aggregated port number.
+ */
+__rte_experimental
+uint16_t rte_eth_shared_rxq_aggregate(uint16_t port_id, uint32_t group);
+
 #include <rte_ethdev_core.h>
 
 /**
lib/ethdev/version.map +3 -1
index 3eece75b72..97a2233508 100644
@@ -249,6 +249,9 @@ EXPERIMENTAL {
        rte_mtr_meter_policy_delete;
        rte_mtr_meter_policy_update;
        rte_mtr_meter_policy_validate;
+
+       # added in 21.11
+       rte_eth_shared_rxq_aggregate;
 };
 
 INTERNAL {
--

2.33.0

author
#87 lore raw

PATCH v3 3/8 app/testpmd: dump port and queue info for each packet

In reply to Xueming Li

In case of shared Rx queue, port number of mbufs returned from one rx burst could be different.

To support shared Rx queue, this patch dumps mbuf->port and queue for each packet.

---
 app/test-pmd/util.c | 1 +
 1 file changed, 1 insertion(+)
app/test-pmd/util.c +1 -0
index 14a9a251fb..b85fbf75a5 100644
@@ -100,6 +100,7 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
 		struct rte_flow_restore_info info = { 0, };
 
 		mb = pkts[i];
+		MKDUMPSTR(print_buf, buf_size, cur_len, "port %u, ", mb->port);
 		eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
 		eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
 		packet_type = mb->packet_type;
Signature · 1 line
2.33.0
author
#88 lore raw

PATCH v3 4/8 app/testpmd: new parameter to enable shared Rx queue

In reply to Xueming Li

Adds "--rxq-share" parameter to enable shared rxq for each rxq.

Default shared rxq group 0 is used, RX queues in same switch domain shares same rxq according to queue index.

Shared Rx queue is enabled only if device support offloading flag RTE_ETH_RX_OFFLOAD_SHARED_RXQ.

---
 app/test-pmd/config.c                 |  6 +++++-
 app/test-pmd/parameters.c             | 13 +++++++++++++
 app/test-pmd/testpmd.c                | 18 ++++++++++++++++++
 app/test-pmd/testpmd.h                |  2 ++
 doc/guides/testpmd_app_ug/run_app.rst |  5 +++++
 5 files changed, 43 insertions(+), 1 deletion(-)
app/test-pmd/config.c +5 -1
index f5765b34f7..8ec5f87ef3 100644
@@ -2707,7 +2707,11 @@ rxtx_config_display(void)
 			printf("      RX threshold registers: pthresh=%d hthresh=%d "
 				" wthresh=%d\n",
 				pthresh_tmp, hthresh_tmp, wthresh_tmp);
-			printf("      RX Offloads=0x%"PRIx64"\n", offloads_tmp);
+			printf("      RX Offloads=0x%"PRIx64, offloads_tmp);
+			if (rx_conf->offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ)
+				printf(" share group=%u",
+				       rx_conf->shared_group);
+			printf("\n");
 		}
 
 		/* per tx queue config only for first queue to be less verbose */
app/test-pmd/parameters.c +13 -0
index 3f94a82e32..de0f1d28cc 100644
@@ -167,6 +167,7 @@ usage(char* progname)
 	printf("  --tx-ip=src,dst: IP addresses in Tx-only mode\n");
 	printf("  --tx-udp=src[,dst]: UDP ports in Tx-only mode\n");
 	printf("  --eth-link-speed: force link speed.\n");
+	printf("  --rxq-share: number of ports per shared rxq groups\n");
 	printf("  --disable-link-check: disable check on link status when "
 	       "starting/stopping ports.\n");
 	printf("  --disable-device-start: do not automatically start port\n");
@@ -607,6 +608,7 @@ launch_args_parse(int argc, char** argv)
 		{ "rxpkts",			1, 0, 0 },
 		{ "txpkts",			1, 0, 0 },
 		{ "txonly-multi-flow",		0, 0, 0 },
+		{ "rxq-share",			0, 0, 0 },
 		{ "eth-link-speed",		1, 0, 0 },
 		{ "disable-link-check",		0, 0, 0 },
 		{ "disable-device-start",	0, 0, 0 },
@@ -1271,6 +1273,17 @@ launch_args_parse(int argc, char** argv)
 			}
 			if (!strcmp(lgopts[opt_idx].name, "txonly-multi-flow"))
 				txonly_multi_flow = 1;
+			if (!strcmp(lgopts[opt_idx].name, "rxq-share")) {
+				if (optarg == NULL) {
+					rxq_share = UINT32_MAX;
+				} else {
+					n = atoi(optarg);
+					if (n >= 0)
+						rxq_share = (uint32_t)n;
+					else
+						rte_exit(EXIT_FAILURE, "rxq-share must be >= 0\n");
+				}
+			}
 			if (!strcmp(lgopts[opt_idx].name, "no-flush-rx"))
 				no_flush_rx = 1;
 			if (!strcmp(lgopts[opt_idx].name, "eth-link-speed")) {
app/test-pmd/testpmd.c +18 -0
index 97ae52e17e..417e92ade1 100644
@@ -498,6 +498,11 @@ uint8_t record_core_cycles;
  */
 uint8_t record_burst_stats;
 
+/*
+ * Number of ports per shared Rx queue group, 0 disable.
+ */
+uint32_t rxq_share;
+
 unsigned int num_sockets = 0;
 unsigned int socket_ids[RTE_MAX_NUMA_NODES];
 
@@ -1506,6 +1511,11 @@ init_config_port_offloads(portid_t pid, uint32_t socket_id)
 		port->dev_conf.txmode.offloads &=
 			~DEV_TX_OFFLOAD_MBUF_FAST_FREE;
 
+	if (rxq_share > 0 &&
+	    (port->dev_info.rx_offload_capa & RTE_ETH_RX_OFFLOAD_SHARED_RXQ))
+		port->dev_conf.rxmode.offloads |=
+				RTE_ETH_RX_OFFLOAD_SHARED_RXQ;
+
 	/* Apply Rx offloads configuration */
 	for (i = 0; i < port->dev_info.max_rx_queues; i++)
 		port->rx_conf[i].offloads = port->dev_conf.rxmode.offloads;
@@ -3401,6 +3411,14 @@ rxtx_port_config(struct rte_port *port)
 	for (qid = 0; qid < nb_rxq; qid++) {
 		offloads = port->rx_conf[qid].offloads;
 		port->rx_conf[qid] = port->dev_info.default_rxconf;
+
+		if (rxq_share > 0 &&
+		    (port->dev_info.rx_offload_capa &
+		     RTE_ETH_RX_OFFLOAD_SHARED_RXQ)) {
+			offloads |= RTE_ETH_RX_OFFLOAD_SHARED_RXQ;
+			port->rx_conf[qid].shared_group = nb_ports / rxq_share;
+		}
+
 		if (offloads != 0)
 			port->rx_conf[qid].offloads = offloads;
 
app/test-pmd/testpmd.h +2 -0
index 5863b2f43f..3dfaaad94c 100644
@@ -477,6 +477,8 @@ extern enum tx_pkt_split tx_pkt_split;
 
 extern uint8_t txonly_multi_flow;
 
+extern uint32_t rxq_share;
+
 extern uint16_t nb_pkt_per_burst;
 extern uint16_t nb_pkt_flowgen_clones;
 extern int nb_flows_flowgen;
doc/guides/testpmd_app_ug/run_app.rst +5 -0
index 640eadeff7..1b9f715608 100644
@@ -389,6 +389,11 @@ The command line options are:
 
     Generate multiple flows in txonly mode.
 
+*   ``--rxq-share=[X]``
+
+    Create all queues in shared RX queue mode if device supports.
+    Group number grows per X ports, default to group 0 if X not specified.
+
 *   ``--eth-link-speed``
 
     Set a forced link speed to the ethernet port::
Signature · 1 line
2.33.0
author
#89 lore raw

PATCH v3 5/8 app/testpmd: force shared Rx queue polled on same core

In reply to Xueming Li

Shared rxqs shares one set rx queue of groups zero. Shared Rx queue must must be polled from one core.

Checks and stops forwarding if shared rxq being scheduled on multiple cores.

---
 app/test-pmd/config.c  | 96 ++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.c |  4 +-
 app/test-pmd/testpmd.h |  2 +
 3 files changed, 101 insertions(+), 1 deletion(-)
app/test-pmd/config.c +96 -0
index 8ec5f87ef3..035247c33f 100644
@@ -2883,6 +2883,102 @@ port_rss_hash_key_update(portid_t port_id, char rss_type[], uint8_t *hash_key,
 	}
 }
 
+/*
+ * Check whether a shared rxq scheduled on other lcores.
+ */
+static bool
+fwd_stream_on_other_lcores(uint16_t domain_id, portid_t src_port,
+			   queueid_t src_rxq, lcoreid_t src_lc,
+			   uint32_t shared_group)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	struct rte_port *port;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	for (lc_id = src_lc + 1; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			port = &ports[fs->rx_port];
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((rxq_conf->offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			if (domain_id != port->dev_info.switch_info.domain_id)
+				continue;
+			if (fs->rx_queue != src_rxq)
+				continue;
+			if (rxq_conf->shared_group != shared_group)
+				continue;
+			printf("Shared RX queue group %u can't be scheduled on different cores:\n",
+			       shared_group);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       src_lc, src_port, src_rxq);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       lc_id, fs->rx_port, fs->rx_queue);
+			printf("  please use --nb-cores=%hu to limit forwarding cores\n",
+			       nb_rxq);
+			return true;
+		}
+	}
+	return false;
+}
+
+/*
+ * Check shared rxq configuration.
+ *
+ * Shared group must not being scheduled on different core.
+ */
+bool
+pkt_fwd_shared_rxq_check(void)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	uint16_t domain_id;
+	struct rte_port *port;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	/*
+	 * Check streams on each core, make sure the same switch domain +
+	 * group + queue doesn't get scheduled on other cores.
+	 */
+	for (lc_id = 0; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			/* Update lcore info stream being scheduled. */
+			fs->lcore = fwd_lcores[lc_id];
+			port = &ports[fs->rx_port];
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((rxq_conf->offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			/* Check shared rxq not scheduled on remaining cores. */
+			domain_id = port->dev_info.switch_info.domain_id;
+			if (fwd_stream_on_other_lcores(domain_id, fs->rx_port,
+						       fs->rx_queue, lc_id,
+						       rxq_conf->shared_group))
+				return false;
+		}
+	}
+	return true;
+}
+
 /*
  * Setup forwarding configuration for each logical core.
  */
app/test-pmd/testpmd.c +3 -1
index 417e92ade1..cab4b36b04 100644
@@ -2241,10 +2241,12 @@ start_packet_forwarding(int with_tx_first)
 
 	fwd_config_setup();
 
+	pkt_fwd_config_display(&cur_fwd_config);
+	if (!pkt_fwd_shared_rxq_check())
+		return;
 	if(!no_flush_rx)
 		flush_fwd_rx_queues();
 
-	pkt_fwd_config_display(&cur_fwd_config);
 	rxtx_config_display();
 
 	fwd_stats_reset();
app/test-pmd/testpmd.h +2 -0
index 3dfaaad94c..f121a2da90 100644
@@ -144,6 +144,7 @@ struct fwd_stream {
 	uint64_t     core_cycles; /**< used for RX and TX processing */
 	struct pkt_burst_stats rx_burst_stats;
 	struct pkt_burst_stats tx_burst_stats;
+	struct fwd_lcore *lcore; /**< Lcore being scheduled. */
 };
 
 /**
@@ -795,6 +796,7 @@ void port_summary_header_display(void);
 void rx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void tx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void fwd_lcores_config_display(void);
+bool pkt_fwd_shared_rxq_check(void);
 void pkt_fwd_config_display(struct fwd_config *cfg);
 void rxtx_config_display(void);
 void fwd_config_setup(void);
Signature · 1 line
2.33.0
author
#90 lore raw

PATCH v3 6/8 app/testpmd: add common fwd wrapper

In reply to Xueming Li

From: Xiaoyu Min <[email protected]>

Added common forwarding wrapper function for all fwd engines which do the following in common:

- record core cycles
- call rte_eth_rx_burst(...,nb_pkt_per_burst)
- update received packets
- handle received mbufs with callback function

For better performance, the function is defined as macro.

---
 app/test-pmd/5tswap.c   | 25 +++++--------------------
 app/test-pmd/csumonly.c | 25 ++++++-------------------
 app/test-pmd/flowgen.c  | 20 +++++---------------
 app/test-pmd/icmpecho.c | 30 ++++++++----------------------
 app/test-pmd/iofwd.c    | 24 +++++-------------------
 app/test-pmd/macfwd.c   | 24 +++++-------------------
 app/test-pmd/macswap.c  | 23 +++++------------------
 app/test-pmd/rxonly.c   | 32 ++++++++------------------------
 app/test-pmd/testpmd.h  | 19 +++++++++++++++++++
 9 files changed, 66 insertions(+), 156 deletions(-)
app/test-pmd/5tswap.c +5 -20
index e8cef9623b..8fe940294f 100644
@@ -82,18 +82,16 @@ swap_udp(struct rte_udp_hdr *udp_hdr)
  * Parses each layer and swaps it. When the next layer doesn't match it stops.
  */
 static void
-pkt_burst_5tuple_swap(struct fwd_stream *fs)
+_5tuple_swap_stream(struct fwd_stream *fs, uint16_t nb_rx,
+		struct rte_mbuf **pkts_burst)
 {
-	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
 	struct rte_port  *txp;
 	struct rte_mbuf *mb;
 	uint16_t next_proto;
 	uint64_t ol_flags;
 	uint16_t proto;
-	uint16_t nb_rx;
 	uint16_t nb_tx;
 	uint32_t retry;
-
 	int i;
 	union {
 		struct rte_ether_hdr *eth;
@@ -105,20 +103,6 @@ pkt_burst_5tuple_swap(struct fwd_stream *fs)
 		uint8_t *byte;
 	} h;
 
-	uint64_t start_tsc = 0;
-
-	get_start_cycles(&start_tsc);
-
-	/*
-	 * Receive a burst of packets and forward them.
-	 */
-	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
-				 nb_pkt_per_burst);
-	inc_rx_burst_stats(fs, nb_rx);
-	if (unlikely(nb_rx == 0))
-		return;
-
-	fs->rx_packets += nb_rx;
 	txp = &ports[fs->tx_port];
 	ol_flags = ol_flags_init(txp->dev_conf.txmode.offloads);
 	vlan_qinq_set(pkts_burst, nb_rx, ol_flags,
@@ -182,12 +166,13 @@ pkt_burst_5tuple_swap(struct fwd_stream *fs)
 			rte_pktmbuf_free(pkts_burst[nb_tx]);
 		} while (++nb_tx < nb_rx);
 	}
-	get_end_cycles(fs, start_tsc);
 }
 
+PKT_BURST_FWD(_5tuple_swap_stream);
+
 struct fwd_engine five_tuple_swap_fwd_engine = {
 	.fwd_mode_name  = "5tswap",
 	.port_fwd_begin = NULL,
 	.port_fwd_end   = NULL,
-	.packet_fwd     = pkt_burst_5tuple_swap,
+	.packet_fwd     = pkt_burst_fwd,
 };
app/test-pmd/csumonly.c +6 -19
index 38cc256533..9bfc7d10dc 100644
@@ -763,7 +763,7 @@ pkt_copy_split(const struct rte_mbuf *pkt)
 }
 
 /*
- * Receive a burst of packets, and for each packet:
+ * For each packet in received mbuf:
  *  - parse packet, and try to recognize a supported packet type (1)
  *  - if it's not a supported packet type, don't touch the packet, else:
  *  - reprocess the checksum of all supported layers. This is done in SW
@@ -792,9 +792,9 @@ pkt_copy_split(const struct rte_mbuf *pkt)
  * OUTER_IP is only useful for tunnel packets.
  */
 static void
-pkt_burst_checksum_forward(struct fwd_stream *fs)
+checksum_forward_stream(struct fwd_stream *fs, uint16_t nb_rx,
+		struct rte_mbuf **pkts_burst)
 {
-	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
 	struct rte_mbuf *gso_segments[GSO_MAX_PKT_BURST];
 	struct rte_gso_ctx *gso_ctx;
 	struct rte_mbuf **tx_pkts_burst;
@@ -805,7 +805,6 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
 	void **gro_ctx;
 	uint16_t gro_pkts_num;
 	uint8_t gro_enable;
-	uint16_t nb_rx;
 	uint16_t nb_tx;
 	uint16_t nb_prep;
 	uint16_t i;
@@ -820,18 +819,6 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
 	uint16_t nb_segments = 0;
 	int ret;
 
-	uint64_t start_tsc = 0;
-
-	get_start_cycles(&start_tsc);
-
-	/* receive a burst of packet */
-	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
-				 nb_pkt_per_burst);
-	inc_rx_burst_stats(fs, nb_rx);
-	if (unlikely(nb_rx == 0))
-		return;
-
-	fs->rx_packets += nb_rx;
 	rx_bad_ip_csum = 0;
 	rx_bad_l4_csum = 0;
 	rx_bad_outer_l4_csum = 0;
@@ -1138,13 +1125,13 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
 			rte_pktmbuf_free(tx_pkts_burst[nb_tx]);
 		} while (++nb_tx < nb_rx);
 	}
-
-	get_end_cycles(fs, start_tsc);
 }
 
+PKT_BURST_FWD(checksum_forward_stream);
+
 struct fwd_engine csum_fwd_engine = {
 	.fwd_mode_name  = "csum",
 	.port_fwd_begin = NULL,
 	.port_fwd_end   = NULL,
-	.packet_fwd     = pkt_burst_checksum_forward,
+	.packet_fwd     = pkt_burst_fwd,
 };
app/test-pmd/flowgen.c +5 -15
index 0d3664a64d..aa45948b4c 100644
@@ -61,10 +61,10 @@ RTE_DEFINE_PER_LCORE(int, _next_flow);
  * still do so in order to maintain traffic statistics.
  */
 static void
-pkt_burst_flow_gen(struct fwd_stream *fs)
+flow_gen_stream(struct fwd_stream *fs, uint16_t nb_rx,
+		struct rte_mbuf **pkts_burst)
 {
 	unsigned pkt_size = tx_pkt_length - 4;	/* Adjust FCS */
-	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
 	struct rte_mempool *mbp;
 	struct rte_mbuf  *pkt = NULL;
 	struct rte_ether_hdr *eth_hdr;
@@ -72,7 +72,6 @@ pkt_burst_flow_gen(struct fwd_stream *fs)
 	struct rte_udp_hdr *udp_hdr;
 	uint16_t vlan_tci, vlan_tci_outer;
 	uint64_t ol_flags = 0;
-	uint16_t nb_rx;
 	uint16_t nb_tx;
 	uint16_t nb_dropped;
 	uint16_t nb_pkt;
@@ -80,17 +79,9 @@ pkt_burst_flow_gen(struct fwd_stream *fs)
 	uint16_t i;
 	uint32_t retry;
 	uint64_t tx_offloads;
-	uint64_t start_tsc = 0;
 	int next_flow = RTE_PER_LCORE(_next_flow);
 
-	get_start_cycles(&start_tsc);
-
-	/* Receive a burst of packets and discard them. */
-	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
-				 nb_pkt_per_burst);
 	inc_rx_burst_stats(fs, nb_rx);
-	fs->rx_packets += nb_rx;
-
 	for (i = 0; i < nb_rx; i++)
 		rte_pktmbuf_free(pkts_burst[i]);
 
@@ -195,12 +186,11 @@ pkt_burst_flow_gen(struct fwd_stream *fs)
 			rte_pktmbuf_free(pkts_burst[nb_tx]);
 		} while (++nb_tx < nb_pkt);
 	}
-
 	RTE_PER_LCORE(_next_flow) = next_flow;
-
-	get_end_cycles(fs, start_tsc);
 }
 
+PKT_BURST_FWD(flow_gen_stream);
+
 static void
 flowgen_begin(portid_t pi)
 {
@@ -211,5 +201,5 @@ struct fwd_engine flow_gen_engine = {
 	.fwd_mode_name  = "flowgen",
 	.port_fwd_begin = flowgen_begin,
 	.port_fwd_end   = NULL,
-	.packet_fwd     = pkt_burst_flow_gen,
+	.packet_fwd     = pkt_burst_fwd,
 };
app/test-pmd/icmpecho.c +8 -22
index 8948f28eb5..467ba330aa 100644
@@ -267,13 +267,13 @@ ipv4_hdr_cksum(struct rte_ipv4_hdr *ip_h)
 	(((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0)
 
 /*
- * Receive a burst of packets, lookup for ICMP echo requests, and, if any,
- * send back ICMP echo replies.
+ * Lookup for ICMP echo requests in received mbuf and, if any,
+ * send back ICMP echo replies to corresponding Tx port.
  */
 static void
-reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
+reply_to_icmp_echo_rqsts_stream(struct fwd_stream *fs, uint16_t nb_rx,
+		struct rte_mbuf **pkts_burst)
 {
-	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
 	struct rte_mbuf *pkt;
 	struct rte_ether_hdr *eth_h;
 	struct rte_vlan_hdr *vlan_h;
@@ -283,7 +283,6 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
 	struct rte_ether_addr eth_addr;
 	uint32_t retry;
 	uint32_t ip_addr;
-	uint16_t nb_rx;
 	uint16_t nb_tx;
 	uint16_t nb_replies;
 	uint16_t eth_type;
@@ -291,22 +290,9 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
 	uint16_t arp_op;
 	uint16_t arp_pro;
 	uint32_t cksum;
-	uint8_t  i;
+	uint16_t  i;
 	int l2_len;
-	uint64_t start_tsc = 0;
 
-	get_start_cycles(&start_tsc);
-
-	/*
-	 * First, receive a burst of packets.
-	 */
-	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
-				 nb_pkt_per_burst);
-	inc_rx_burst_stats(fs, nb_rx);
-	if (unlikely(nb_rx == 0))
-		return;
-
-	fs->rx_packets += nb_rx;
 	nb_replies = 0;
 	for (i = 0; i < nb_rx; i++) {
 		if (likely(i < nb_rx - 1))
@@ -509,13 +495,13 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
 			} while (++nb_tx < nb_replies);
 		}
 	}
-
-	get_end_cycles(fs, start_tsc);
 }
 
+PKT_BURST_FWD(reply_to_icmp_echo_rqsts_stream);
+
 struct fwd_engine icmp_echo_engine = {
 	.fwd_mode_name  = "icmpecho",
 	.port_fwd_begin = NULL,
 	.port_fwd_end   = NULL,
-	.packet_fwd     = reply_to_icmp_echo_rqsts,
+	.packet_fwd     = pkt_burst_fwd,
 };
app/test-pmd/iofwd.c +5 -19
index 83d098adcb..dbd78167b4 100644
@@ -44,25 +44,11 @@
  * to packets data.
  */
 static void
-pkt_burst_io_forward(struct fwd_stream *fs)
+io_forward_stream(struct fwd_stream *fs, uint16_t nb_rx,
+		  struct rte_mbuf **pkts_burst)
 {
-	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
-	uint16_t nb_rx;
 	uint16_t nb_tx;
 	uint32_t retry;
-	uint64_t start_tsc = 0;
-
-	get_start_cycles(&start_tsc);
-
-	/*
-	 * Receive a burst of packets and forward them.
-	 */
-	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
-			pkts_burst, nb_pkt_per_burst);
-	inc_rx_burst_stats(fs, nb_rx);
-	if (unlikely(nb_rx == 0))
-		return;
-	fs->rx_packets += nb_rx;
 
 	nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
 			pkts_burst, nb_rx);
@@ -85,13 +71,13 @@ pkt_burst_io_forward(struct fwd_stream *fs)
 			rte_pktmbuf_free(pkts_burst[nb_tx]);
 		} while (++nb_tx < nb_rx);
 	}
-
-	get_end_cycles(fs, start_tsc);
 }
 
+PKT_BURST_FWD(io_forward_stream);
+
 struct fwd_engine io_fwd_engine = {
 	.fwd_mode_name  = "io",
 	.port_fwd_begin = NULL,
 	.port_fwd_end   = NULL,
-	.packet_fwd     = pkt_burst_io_forward,
+	.packet_fwd     = pkt_burst_fwd,
 };
app/test-pmd/macfwd.c +5 -19
index 0568ea794d..b0728c7597 100644
@@ -44,32 +44,18 @@
  * before forwarding them.
  */
 static void
-pkt_burst_mac_forward(struct fwd_stream *fs)
+mac_forward_stream(struct fwd_stream *fs, uint16_t nb_rx,
+		struct rte_mbuf **pkts_burst)
 {
-	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
 	struct rte_port  *txp;
 	struct rte_mbuf  *mb;
 	struct rte_ether_hdr *eth_hdr;
 	uint32_t retry;
-	uint16_t nb_rx;
 	uint16_t nb_tx;
 	uint16_t i;
 	uint64_t ol_flags = 0;
 	uint64_t tx_offloads;
-	uint64_t start_tsc = 0;
 
-	get_start_cycles(&start_tsc);
-
-	/*
-	 * Receive a burst of packets and forward them.
-	 */
-	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
-				 nb_pkt_per_burst);
-	inc_rx_burst_stats(fs, nb_rx);
-	if (unlikely(nb_rx == 0))
-		return;
-
-	fs->rx_packets += nb_rx;
 	txp = &ports[fs->tx_port];
 	tx_offloads = txp->dev_conf.txmode.offloads;
 	if (tx_offloads	& DEV_TX_OFFLOAD_VLAN_INSERT)
@@ -116,13 +102,13 @@ pkt_burst_mac_forward(struct fwd_stream *fs)
 			rte_pktmbuf_free(pkts_burst[nb_tx]);
 		} while (++nb_tx < nb_rx);
 	}
-
-	get_end_cycles(fs, start_tsc);
 }
 
+PKT_BURST_FWD(mac_forward_stream);
+
 struct fwd_engine mac_fwd_engine = {
 	.fwd_mode_name  = "mac",
 	.port_fwd_begin = NULL,
 	.port_fwd_end   = NULL,
-	.packet_fwd     = pkt_burst_mac_forward,
+	.packet_fwd     = pkt_burst_fwd,
 };
app/test-pmd/macswap.c +5 -18
index 310bca06af..cc208944d7 100644
@@ -50,27 +50,13 @@
  * addresses of packets before forwarding them.
  */
 static void
-pkt_burst_mac_swap(struct fwd_stream *fs)
+mac_swap_stream(struct fwd_stream *fs, uint16_t nb_rx,
+		struct rte_mbuf **pkts_burst)
 {
-	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
 	struct rte_port  *txp;
-	uint16_t nb_rx;
 	uint16_t nb_tx;
 	uint32_t retry;
-	uint64_t start_tsc = 0;
 
-	get_start_cycles(&start_tsc);
-
-	/*
-	 * Receive a burst of packets and forward them.
-	 */
-	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
-				 nb_pkt_per_burst);
-	inc_rx_burst_stats(fs, nb_rx);
-	if (unlikely(nb_rx == 0))
-		return;
-
-	fs->rx_packets += nb_rx;
 	txp = &ports[fs->tx_port];
 
 	do_macswap(pkts_burst, nb_rx, txp);
@@ -95,12 +81,13 @@ pkt_burst_mac_swap(struct fwd_stream *fs)
 			rte_pktmbuf_free(pkts_burst[nb_tx]);
 		} while (++nb_tx < nb_rx);
 	}
-	get_end_cycles(fs, start_tsc);
 }
 
+PKT_BURST_FWD(mac_swap_stream);
+
 struct fwd_engine mac_swap_engine = {
 	.fwd_mode_name  = "macswap",
 	.port_fwd_begin = NULL,
 	.port_fwd_end   = NULL,
-	.packet_fwd     = pkt_burst_mac_swap,
+	.packet_fwd     = pkt_burst_fwd,
 };
app/test-pmd/rxonly.c +8 -24
index c78fc4609a..a7354596b5 100644
@@ -41,37 +41,21 @@
 #include "testpmd.h"
 
 /*
- * Received a burst of packets.
+ * Process a burst of received packets from same stream.
  */
 static void
-pkt_burst_receive(struct fwd_stream *fs)
+rxonly_forward_stream(struct fwd_stream *fs, uint16_t nb_rx,
+		      struct rte_mbuf **pkts_burst)
 {
-	struct rte_mbuf  *pkts_burst[MAX_PKT_BURST];
-	uint16_t nb_rx;
-	uint16_t i;
-	uint64_t start_tsc = 0;
-
-	get_start_cycles(&start_tsc);
-
-	/*
-	 * Receive a burst of packets.
-	 */
-	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
-				 nb_pkt_per_burst);
-	inc_rx_burst_stats(fs, nb_rx);
-	if (unlikely(nb_rx == 0))
-		return;
-
-	fs->rx_packets += nb_rx;
-	for (i = 0; i < nb_rx; i++)
-		rte_pktmbuf_free(pkts_burst[i]);
-
-	get_end_cycles(fs, start_tsc);
+	RTE_SET_USED(fs);
+	rte_pktmbuf_free_bulk(pkts_burst, nb_rx);
 }
 
+PKT_BURST_FWD(rxonly_forward_stream)
+
 struct fwd_engine rx_only_engine = {
 	.fwd_mode_name  = "rxonly",
 	.port_fwd_begin = NULL,
 	.port_fwd_end   = NULL,
-	.packet_fwd     = pkt_burst_receive,
+	.packet_fwd     = pkt_burst_fwd,
 };
app/test-pmd/testpmd.h +19 -0
index f121a2da90..4792bef03b 100644
@@ -1028,6 +1028,25 @@ void add_tx_dynf_callback(portid_t portid);
 void remove_tx_dynf_callback(portid_t portid);
 int update_jumbo_frame_offload(portid_t portid);
 
+#define PKT_BURST_FWD(cb)                                       \
+static void                                                     \
+pkt_burst_fwd(struct fwd_stream *fs)                            \
+{                                                               \
+	struct rte_mbuf *pkts_burst[nb_pkt_per_burst];          \
+	uint16_t nb_rx;                                         \
+	uint64_t start_tsc = 0;                                 \
+								\
+	get_start_cycles(&start_tsc);                           \
+	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,     \
+			pkts_burst, nb_pkt_per_burst);          \
+	inc_rx_burst_stats(fs, nb_rx);                          \
+	if (unlikely(nb_rx == 0))                               \
+		return;                                         \
+	fs->rx_packets += nb_rx;                                \
+	cb(fs, nb_rx, pkts_burst);                              \
+	get_end_cycles(fs, start_tsc);                          \
+}
+
 /*
  * Work-around of a compilation error with ICC on invocations of the
  * rte_be_to_cpu_16() function.
Signature · 1 line
2.33.0
#91 lore raw

Re: [dpdk-dev] [PATCH v3 6/8] app/testpmd: add common fwd wrapper

Quoted 32 lines · Xueming Li

From: Xiaoyu Min <[email protected]>

Added common forwarding wrapper function for all fwd engines which do the following in common:

- record core cycles
- call rte_eth_rx_burst(...,nb_pkt_per_burst)
- update received packets
- handle received mbufs with callback function

For better performance, the function is defined as macro.

---
 app/test-pmd/5tswap.c   | 25 +++++--------------------
 app/test-pmd/csumonly.c | 25 ++++++-------------------
 app/test-pmd/flowgen.c  | 20 +++++---------------
 app/test-pmd/icmpecho.c | 30 ++++++++----------------------
 app/test-pmd/iofwd.c    | 24 +++++-------------------
 app/test-pmd/macfwd.c   | 24 +++++-------------------
 app/test-pmd/macswap.c  | 23 +++++------------------
 app/test-pmd/rxonly.c   | 32 ++++++++------------------------
 app/test-pmd/testpmd.h  | 19 +++++++++++++++++++
 9 files changed, 66 insertions(+), 156 deletions(-)
app/test-pmd/5tswap.c +0 -0
index e8cef9623b..8fe940294f 100644

app/test-pmd/5tswap.c swap_udp(struct rte_udp_hdr *udp_hdr) · line 85

Quoted 4 lines
app/test-pmd/5tswap.c +1 -0
@@ -82,18 +82,16 @@ swap_udp(struct rte_udp_hdr *udp_hdr)
  * Parses each layer and swaps it. When the next layer doesn't match it stops.
  */
 
+PKT_BURST_FWD(_5tuple_swap_stream);

Please make _5tuple_swap_stream aka "cb" as inline function to make sure compiler doesn't generate yet another function pointer.

app/test-pmd/5tswap.c swap_udp(struct rte_udp_hdr *udp_hdr) · line 89

Quoted 5 lines
app/test-pmd/5tswap.c +0 -1
 struct fwd_engine mac_swap_engine = {
        .fwd_mode_name  = "macswap",
        .port_fwd_begin = NULL,
        .port_fwd_end   = NULL,
-       .packet_fwd     = pkt_burst_mac_swap,

See below

app/test-pmd/5tswap.c swap_udp(struct rte_udp_hdr *udp_hdr) · line 92

Quoted 3 lines
app/test-pmd/5tswap.c +2 -0
+       .packet_fwd     = pkt_burst_fwd,
 
+#define PKT_BURST_FWD(cb)                                       \

Probably it can pass prefix too like PKT_BURST_FWD(cb, prefix) to make a unique function and call PKT_BURST_FWD(_5tuple_swap_stream, mac_swap) for better readability
and avoid diff above section.

app/test-pmd/5tswap.c swap_udp(struct rte_udp_hdr *udp_hdr) · line 94

Quoted 2 lines
app/test-pmd/5tswap.c +2 -0
+static void                                                     \
+pkt_burst_fwd(struct fwd_stream *fs)

pkt_burst_fwd##prefix(struct fwd_stream *fs)

                            \
Quoted 22 lines
app/test-pmd/5tswap.c +16 -1
+{                                                               \
+       struct rte_mbuf *pkts_burst[nb_pkt_per_burst];          \
+       uint16_t nb_rx;                                         \
+       uint64_t start_tsc = 0;                                 \
+                                                               \
+       get_start_cycles(&start_tsc);                           \
+       nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,     \
+                       pkts_burst, nb_pkt_per_burst);          \
+       inc_rx_burst_stats(fs, nb_rx);                          \
+       if (unlikely(nb_rx == 0))                               \
+               return;                                         \
+       fs->rx_packets += nb_rx;                                \
+       cb(fs, nb_rx, pkts_burst);                              \
+       get_end_cycles(fs, start_tsc);                          \
+}
+
 /*
  * Work-around of a compilation error with ICC on invocations of the
  * rte_be_to_cpu_16() function.
--

2.33.0

author
#92 lore raw

PATCH v3 7/8 app/testpmd: improve forwarding cache miss

In reply to Xueming Li

To minimize cache miss, adds flags and burst size used in forwarding to stream, moves condition tests in forwarding to flags in stream.

---
 app/test-pmd/config.c    | 18 ++++++++++++++----
 app/test-pmd/flowgen.c   |  6 +++---
 app/test-pmd/noisy_vnf.c |  2 +-
 app/test-pmd/testpmd.h   | 21 ++++++++++++---------
 app/test-pmd/txonly.c    |  8 ++++----
 5 files changed, 34 insertions(+), 21 deletions(-)
app/test-pmd/config.c +14 -4
index 035247c33f..5cdf8fa082 100644
@@ -3050,6 +3050,16 @@ fwd_topology_tx_port_get(portid_t rxp)
 	}
 }
 
+static void
+fwd_stream_set_common(struct fwd_stream *fs)
+{
+	fs->nb_pkt_per_burst = nb_pkt_per_burst;
+	fs->record_burst_stats = !!record_burst_stats;
+	fs->record_core_cycles = !!record_core_cycles;
+	fs->retry_enabled = !!retry_enabled;
+	fs->rxq_share = !!rxq_share;
+}
+
 static void
 simple_fwd_config_setup(void)
 {
@@ -3079,7 +3089,7 @@ simple_fwd_config_setup(void)
 				fwd_ports_ids[fwd_topology_tx_port_get(i)];
 		fwd_streams[i]->tx_queue  = 0;
 		fwd_streams[i]->peer_addr = fwd_streams[i]->tx_port;
-		fwd_streams[i]->retry_enabled = retry_enabled;
+		fwd_stream_set_common(fwd_streams[i]);
 	}
 }
 
@@ -3140,7 +3150,7 @@ rss_fwd_config_setup(void)
 		fs->tx_port = fwd_ports_ids[txp];
 		fs->tx_queue = rxq;
 		fs->peer_addr = fs->tx_port;
-		fs->retry_enabled = retry_enabled;
+		fwd_stream_set_common(fs);
 		rxp++;
 		if (rxp < nb_fwd_ports)
 			continue;
@@ -3255,7 +3265,7 @@ dcb_fwd_config_setup(void)
 				fs->tx_port = fwd_ports_ids[txp];
 				fs->tx_queue = txq + j % nb_tx_queue;
 				fs->peer_addr = fs->tx_port;
-				fs->retry_enabled = retry_enabled;
+				fwd_stream_set_common(fs);
 			}
 			fwd_lcores[lc_id]->stream_nb +=
 				rxp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue;
@@ -3326,7 +3336,7 @@ icmp_echo_config_setup(void)
 			fs->tx_port = fs->rx_port;
 			fs->tx_queue = rxq;
 			fs->peer_addr = fs->tx_port;
-			fs->retry_enabled = retry_enabled;
+			fwd_stream_set_common(fs);
 			if (verbose_level > 0)
 				printf("  stream=%d port=%d rxq=%d txq=%d\n",
 				       sm_id, fs->rx_port, fs->rx_queue,
app/test-pmd/flowgen.c +3 -3
index aa45948b4c..c282f3bcb1 100644
@@ -97,12 +97,12 @@ flow_gen_stream(struct fwd_stream *fs, uint16_t nb_rx,
 	if (tx_offloads	& DEV_TX_OFFLOAD_MACSEC_INSERT)
 		ol_flags |= PKT_TX_MACSEC;
 
-	for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
+	for (nb_pkt = 0; nb_pkt < fs->nb_pkt_per_burst; nb_pkt++) {
 		if (!nb_pkt || !nb_clones) {
 			nb_clones = nb_pkt_flowgen_clones;
 			/* Logic limitation */
-			if (nb_clones > nb_pkt_per_burst)
-				nb_clones = nb_pkt_per_burst;
+			if (nb_clones > fs->nb_pkt_per_burst)
+				nb_clones = fs->nb_pkt_per_burst;
 
 			pkt = rte_mbuf_raw_alloc(mbp);
 			if (!pkt)
app/test-pmd/noisy_vnf.c +1 -1
index 382a4c2aae..56bf6a4e70 100644
@@ -153,7 +153,7 @@ pkt_burst_noisy_vnf(struct fwd_stream *fs)
 	uint64_t now;
 
 	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
-			pkts_burst, nb_pkt_per_burst);
+			pkts_burst, fs->nb_pkt_per_burst);
 	inc_rx_burst_stats(fs, nb_rx);
 	if (unlikely(nb_rx == 0))
 		goto flush;
app/test-pmd/testpmd.h +12 -9
index 4792bef03b..3b8796a7a5 100644
@@ -128,12 +128,17 @@ struct fwd_stream {
 	queueid_t  tx_queue;  /**< TX queue to send forwarded packets */
 	streamid_t peer_addr; /**< index of peer ethernet address of packets */
 
-	unsigned int retry_enabled;
+	uint16_t nb_pkt_per_burst;
+	unsigned int record_burst_stats:1;
+	unsigned int record_core_cycles:1;
+	unsigned int retry_enabled:1;
+	unsigned int rxq_share:1;
 
 	/* "read-write" results */
 	uint64_t rx_packets;  /**< received packets */
 	uint64_t tx_packets;  /**< received packets transmitted */
 	uint64_t fwd_dropped; /**< received packets not forwarded */
+	uint64_t core_cycles; /**< used for RX and TX processing */
 	uint64_t rx_bad_ip_csum ; /**< received packets has bad ip checksum */
 	uint64_t rx_bad_l4_csum ; /**< received packets has bad l4 checksum */
 	uint64_t rx_bad_outer_l4_csum;
@@ -141,7 +146,6 @@ struct fwd_stream {
 	uint64_t rx_bad_outer_ip_csum;
 	/**< received packets having bad outer ip checksum */
 	unsigned int gro_times;	/**< GRO operation times */
-	uint64_t     core_cycles; /**< used for RX and TX processing */
 	struct pkt_burst_stats rx_burst_stats;
 	struct pkt_burst_stats tx_burst_stats;
 	struct fwd_lcore *lcore; /**< Lcore being scheduled. */
@@ -750,28 +754,27 @@ port_pci_reg_write(struct rte_port *port, uint32_t reg_off, uint32_t reg_v)
 static inline void
 get_start_cycles(uint64_t *start_tsc)
 {
-	if (record_core_cycles)
-		*start_tsc = rte_rdtsc();
+	*start_tsc = rte_rdtsc();
 }
 
 static inline void
 get_end_cycles(struct fwd_stream *fs, uint64_t start_tsc)
 {
-	if (record_core_cycles)
+	if (unlikely(fs->record_core_cycles))
 		fs->core_cycles += rte_rdtsc() - start_tsc;
 }
 
 static inline void
 inc_rx_burst_stats(struct fwd_stream *fs, uint16_t nb_rx)
 {
-	if (record_burst_stats)
+	if (unlikely(fs->record_burst_stats))
 		fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
 }
 
 static inline void
 inc_tx_burst_stats(struct fwd_stream *fs, uint16_t nb_tx)
 {
-	if (record_burst_stats)
+	if (unlikely(fs->record_burst_stats))
 		fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
 }
 
@@ -1032,13 +1035,13 @@ int update_jumbo_frame_offload(portid_t portid);
 static void                                                     \
 pkt_burst_fwd(struct fwd_stream *fs)                            \
 {                                                               \
-	struct rte_mbuf *pkts_burst[nb_pkt_per_burst];          \
+	struct rte_mbuf *pkts_burst[fs->nb_pkt_per_burst];      \
 	uint16_t nb_rx;                                         \
 	uint64_t start_tsc = 0;                                 \
 								\
 	get_start_cycles(&start_tsc);                           \
 	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,     \
-			pkts_burst, nb_pkt_per_burst);          \
+			pkts_burst, fs->nb_pkt_per_burst);      \
 	inc_rx_burst_stats(fs, nb_rx);                          \
 	if (unlikely(nb_rx == 0))                               \
 		return;                                         \
app/test-pmd/txonly.c +4 -4
index aed820f5d3..db6130421c 100644
@@ -367,8 +367,8 @@ pkt_burst_transmit(struct fwd_stream *fs)
 	eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
 
 	if (rte_mempool_get_bulk(mbp, (void **)pkts_burst,
-				nb_pkt_per_burst) == 0) {
-		for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
+				fs->nb_pkt_per_burst) == 0) {
+		for (nb_pkt = 0; nb_pkt < fs->nb_pkt_per_burst; nb_pkt++) {
 			if (unlikely(!pkt_burst_prepare(pkts_burst[nb_pkt], mbp,
 							&eth_hdr, vlan_tci,
 							vlan_tci_outer,
@@ -376,12 +376,12 @@ pkt_burst_transmit(struct fwd_stream *fs)
 							nb_pkt, fs))) {
 				rte_mempool_put_bulk(mbp,
 						(void **)&pkts_burst[nb_pkt],
-						nb_pkt_per_burst - nb_pkt);
+						fs->nb_pkt_per_burst - nb_pkt);
 				break;
 			}
 		}
 	} else {
-		for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
+		for (nb_pkt = 0; nb_pkt < fs->nb_pkt_per_burst; nb_pkt++) {
 			pkt = rte_mbuf_raw_alloc(mbp);
 			if (pkt == NULL)
 				break;
Signature · 1 line
2.33.0
author
#93 lore raw

PATCH v3 8/8 app/testpmd: support shared Rx queue forwarding

In reply to Xueming Li

By enabling shared Rx queue, received packets come from all member ports in same shared Rx queue.

This patch adds a common forwarding function for shared Rx queue, groups source forwarding stream by looking into local streams on current lcore with packet source port(mbuf->port) and queue, then invokes callback to handle received packets for each source stream.

---
 app/test-pmd/ieee1588fwd.c | 30 +++++++++++------
 app/test-pmd/testpmd.c     | 69 ++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.h     |  9 ++++-
 3 files changed, 97 insertions(+), 11 deletions(-)
app/test-pmd/ieee1588fwd.c +20 -10
index 034f238c34..0151d6de74 100644
@@ -90,23 +90,17 @@ port_ieee1588_tx_timestamp_check(portid_t pi)
 }
 
 static void
-ieee1588_packet_fwd(struct fwd_stream *fs)
+ieee1588_fwd_stream(struct fwd_stream *fs, uint16_t nb_rx,
+		struct rte_mbuf **pkt)
 {
-	struct rte_mbuf  *mb;
+	struct rte_mbuf *mb = (*pkt);
 	struct rte_ether_hdr *eth_hdr;
 	struct rte_ether_addr addr;
 	struct ptpv2_msg *ptp_hdr;
 	uint16_t eth_type;
 	uint32_t timesync_index;
 
-	/*
-	 * Receive 1 packet at a time.
-	 */
-	if (rte_eth_rx_burst(fs->rx_port, fs->rx_queue, &mb, 1) == 0)
-		return;
-
-	fs->rx_packets += 1;
-
+	RTE_SET_USED(nb_rx);
 	/*
 	 * Check that the received packet is a PTP packet that was detected
 	 * by the hardware.
@@ -198,6 +192,22 @@ ieee1588_packet_fwd(struct fwd_stream *fs)
 	port_ieee1588_tx_timestamp_check(fs->rx_port);
 }
 
+/*
+ * Wrapper of real fwd ingine.
+ */
+static void
+ieee1588_packet_fwd(struct fwd_stream *fs)
+{
+	struct rte_mbuf *mb;
+
+	if (rte_eth_rx_burst(fs->rx_port, fs->rx_queue, &mb, 1) == 0)
+		return;
+	if (unlikely(fs->rxq_share > 0))
+		forward_shared_rxq(fs, 1, &mb, ieee1588_fwd_stream);
+	else
+		ieee1588_fwd_stream(fs, 1, &mb);
+}
+
 static void
 port_ieee1588_fwd_begin(portid_t pi)
 {
app/test-pmd/testpmd.c +69 -0

75 lines not on this page · raw message

app/test-pmd/testpmd.h +8 -1
index 3b8796a7a5..7869f61f74 100644
@@ -276,6 +276,8 @@ struct fwd_lcore {
 typedef void (*port_fwd_begin_t)(portid_t pi);
 typedef void (*port_fwd_end_t)(portid_t pi);
 typedef void (*packet_fwd_t)(struct fwd_stream *fs);
+typedef void (*packet_fwd_cb)(struct fwd_stream *fs, uint16_t nb_rx,
+			      struct rte_mbuf **pkts);
 
 struct fwd_engine {
 	const char       *fwd_mode_name; /**< Forwarding mode name. */
@@ -910,6 +912,8 @@ char *list_pkt_forwarding_modes(void);
 char *list_pkt_forwarding_retry_modes(void);
 void set_pkt_forwarding_mode(const char *fwd_mode);
 void start_packet_forwarding(int with_tx_first);
+void forward_shared_rxq(struct fwd_stream *fs, uint16_t nb_rx,
+			struct rte_mbuf **pkts_burst, packet_fwd_cb fwd);
 void fwd_stats_display(void);
 void fwd_stats_reset(void);
 void stop_packet_forwarding(void);
@@ -1046,7 +1050,10 @@ pkt_burst_fwd(struct fwd_stream *fs)                            \
 	if (unlikely(nb_rx == 0))                               \
 		return;                                         \
 	fs->rx_packets += nb_rx;                                \
-	cb(fs, nb_rx, pkts_burst);                              \
+	if (fs->rxq_share)                                      \
+		forward_shared_rxq(fs, nb_rx, pkts_burst, cb);  \
+	else                                                    \
+		cb(fs, nb_rx, pkts_burst);                      \
 	get_end_cycles(fs, start_tsc);                          \
 }
 
Signature · 1 line
2.33.0
author
#94 lore raw

v4 cover ethdev: introduce shared Rx queue

In reply to Xueming Li

In current DPDK framework, all RX queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared RX queue. PF and representors with same configuration in same switch domain could share RX queue set by specifying shared Rx queue offloading flag and sharing group.

All ports that Shared Rx queue actually shares One Rx queue and only pre-load mbufs to one Rx queue, memory is saved.

Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of polling two share groups:
core group queue
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3

Shared RX queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

v1:
- initial version
v2:
- add testpmd patches
v3:
- change common forwarding api to macro for performance, thanks Jerin.
- save global variable accessed in forwarding to flowstream to minimize cache miss
- combined patches for each forwarding engine
- support multiple groups in testpmd "--share-rxq" parameter
- new api to aggerate shared rxq group
v4:
- spelling fixes
- remove shared-rxq support for all forwarding engines
- add dedicate shared-rxq forwarding engine

Xueming Li (6):
ethdev: introduce shared Rx queue
ethdev: new API to aggregate shared Rx queue group app/testpmd: new parameter to enable shared Rx queue app/testpmd: dump port info for shared Rx queue app/testpmd: force shared Rx queue polled on same core app/testpmd: add forwarding engine for shared Rx queue

 app/test-pmd/config.c                         | 102 +++++++++++-
 app/test-pmd/meson.build                      |   1 +
 app/test-pmd/parameters.c                     |  13 ++
 app/test-pmd/shared_rxq_fwd.c                 | 148 ++++++++++++++++++
 app/test-pmd/testpmd.c                        |  23 ++-
 app/test-pmd/testpmd.h                        |   5 +
 app/test-pmd/util.c                           |   3 +
 doc/guides/nics/features.rst                  |  11 ++
 doc/guides/nics/features/default.ini          |   1 +
 .../prog_guide/switch_representation.rst      |  10 ++
 doc/guides/testpmd_app_ug/run_app.rst         |   8 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst   |   5 +-
 lib/ethdev/ethdev_driver.h                    |  23 ++-
 lib/ethdev/rte_ethdev.c                       |  23 +++
 lib/ethdev/rte_ethdev.h                       |  23 +++
 lib/ethdev/version.map                        |   3 +
 16 files changed, 398 insertions(+), 4 deletions(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
Signature · 1 line
2.33.0
author
#95 lore raw

PATCH v4 1/6 ethdev: introduce shared Rx queue

In current DPDK framework, each RX queue is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

This patch introduces shared RX queue. Ports with same configuration in a switch domain could share RX queue set by specifying sharing group. Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

Multiple groups is supported by group ID.

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

---
 doc/guides/nics/features.rst                    | 11 +++++++++++
 doc/guides/nics/features/default.ini            |  1 +
 doc/guides/prog_guide/switch_representation.rst | 10 ++++++++++
 lib/ethdev/rte_ethdev.c                         |  1 +
 lib/ethdev/rte_ethdev.h                         |  7 +++++++
 5 files changed, 30 insertions(+)
doc/guides/nics/features.rst +11 -0
index 4fce8cd1c97..69bc1d5719c 100644
@@ -626,6 +626,17 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same switch domain.
+
+* **[uses]     rte_eth_rxconf,rte_eth_rxmode**: ``offloads:RTE_ETH_RX_OFFLOAD_SHARED_RXQ``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index 754184ddd4d..ebeb4c18512 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +10 -0
index ff6aa91c806..bc7ce65fa3d 100644
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- Memory usage of representors is huge when number of representor grows,
+  because PMD always allocate mbuf for each descriptor of Rx queue.
+  Polling the large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors in same switch. ``RTE_ETH_RX_OFFLOAD_SHARED_RXQ`` is
+  present in Rx offloading capability of device info. Setting the
+  offloading flag in device Rx mode or Rx queue configuration to enable
+  shared Rx queue. Polling any member port of the shared Rx queue can return
+  packets of all ports in the group, port ID is saved in ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
lib/ethdev/rte_ethdev.c +1 -0
index 61aa49efec6..73270c10492 100644
@@ -127,6 +127,7 @@ static const struct {
 	RTE_RX_OFFLOAD_BIT2STR(OUTER_UDP_CKSUM),
 	RTE_RX_OFFLOAD_BIT2STR(RSS_HASH),
 	RTE_ETH_RX_OFFLOAD_BIT2STR(BUFFER_SPLIT),
+	RTE_ETH_RX_OFFLOAD_BIT2STR(SHARED_RXQ),
 };
 
 #undef RTE_RX_OFFLOAD_BIT2STR
lib/ethdev/rte_ethdev.h +7 -0
index afdc53b674c..d7ac625ee74 100644
@@ -1077,6 +1077,7 @@ struct rte_eth_rxconf {
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
 	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	uint32_t shared_group; /**< Shared port group index in switch domain. */
 	/**
 	 * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
 	 * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1403,6 +1404,12 @@ struct rte_eth_conf {
 #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM  0x00040000
 #define DEV_RX_OFFLOAD_RSS_HASH		0x00080000
 #define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000
+/**
+ * Rx queue is shared among ports in same switch domain to save memory,
+ * avoid polling each port. Any port in the group can be used to receive
+ * packets. Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
 				 DEV_RX_OFFLOAD_UDP_CKSUM | \
Signature · 1 line
2.33.0
#96 lore raw
Quoted 1 line · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for

RX -> Rx

Quoted 4 lines

incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

It should be highlighted that it is a problem of some PMDs. Not all.

Quoted 2 lines

This patch introduces shared RX queue. Ports with same configuration in

"This patch introduces" -> "Introduce"

RX -> Rx

Quoted 1 line

a switch domain could share RX queue set by specifying sharing group.

RX -> Rx

Quoted 1 line

Polling any queue using same shared RX queue receives packets from all

RX -> Rx

Quoted 6 lines

member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

RX -> Rx

Quoted 2 lines

Multiple groups is supported by group ID.

is -> are

Quoted 3 lines

The patch should update release notes.

Quoted 51 lines

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

---
 doc/guides/nics/features.rst                    | 11 +++++++++++
 doc/guides/nics/features/default.ini            |  1 +
 doc/guides/prog_guide/switch_representation.rst | 10 ++++++++++
 lib/ethdev/rte_ethdev.c                         |  1 +
 lib/ethdev/rte_ethdev.h                         |  7 +++++++
 5 files changed, 30 insertions(+)
doc/guides/nics/features.rst +11 -0
index 4fce8cd1c97..69bc1d5719c 100644
@@ -626,6 +626,17 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same switch domain.
+
+* **[uses]     rte_eth_rxconf,rte_eth_rxmode**: ``offloads:RTE_ETH_RX_OFFLOAD_SHARED_RXQ``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index 754184ddd4d..ebeb4c18512 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +0 -0
index ff6aa91c806..bc7ce65fa3d 100644

doc/guides/prog_guide/switch_representation.rst thought as a software "patch panel" front-end for applications. · line 127

Quoted 5 lines
doc/guides/prog_guide/switch_representation.rst +2 -0
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- Memory usage of representors is huge when number of representor grows,
+  because PMD always allocate mbuf for each descriptor of Rx queue.

It is a problem of some PMDs only. So, it must be rewritten to highlight it.

Quoted 39 lines
doc/guides/prog_guide/switch_representation.rst +8 -0
+  Polling the large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors in same switch. ``RTE_ETH_RX_OFFLOAD_SHARED_RXQ`` is
+  present in Rx offloading capability of device info. Setting the
+  offloading flag in device Rx mode or Rx queue configuration to enable
+  shared Rx queue. Polling any member port of the shared Rx queue can return
+  packets of all ports in the group, port ID is saved in ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
lib/ethdev/rte_ethdev.c +1 -0
index 61aa49efec6..73270c10492 100644
@@ -127,6 +127,7 @@ static const struct {
 	RTE_RX_OFFLOAD_BIT2STR(OUTER_UDP_CKSUM),
 	RTE_RX_OFFLOAD_BIT2STR(RSS_HASH),
 	RTE_ETH_RX_OFFLOAD_BIT2STR(BUFFER_SPLIT),
+	RTE_ETH_RX_OFFLOAD_BIT2STR(SHARED_RXQ),
 };
 
 #undef RTE_RX_OFFLOAD_BIT2STR
lib/ethdev/rte_ethdev.h +1 -0
index afdc53b674c..d7ac625ee74 100644
@@ -1077,6 +1077,7 @@ struct rte_eth_rxconf {
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
 	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	uint32_t shared_group; /**< Shared port group index in switch domain. */
 	/**
 	 * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
 	 * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1403,6 +1404,12 @@ struct rte_eth_conf {
 #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM  0x00040000
 #define DEV_RX_OFFLOAD_RSS_HASH		0x00080000

lib/ethdev/rte_ethdev.h struct rte_eth_conf { · line 1415

Quoted 10 lines
lib/ethdev/rte_ethdev.h +6 -0
 #define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000
+/**
+ * Rx queue is shared among ports in same switch domain to save memory,
+ * avoid polling each port. Any port in the group can be used to receive
+ * packets. Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
 				 DEV_RX_OFFLOAD_UDP_CKSUM | \

IMHO it should be squashed with the second patch to make it easier to review. Otherwise it is hard to understand what is shared_group and the offlaod which are dead in the patch.

#97 lore raw
Quoted 154 lines · Andrew Rybchenko
Quoted 1 line · Xueming Li

In current DPDK framework, each RX queue is pre-loaded with mbufs for

RX -> Rx

Quoted 4 lines

incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Most important, polling all ports leads to high cache miss, high latency and low throughput.

It should be highlighted that it is a problem of some PMDs. Not all.

Quoted 2 lines

This patch introduces shared RX queue. Ports with same configuration in

"This patch introduces" -> "Introduce"

RX -> Rx

Quoted 1 line

a switch domain could share RX queue set by specifying sharing group.

RX -> Rx

Quoted 1 line

Polling any queue using same shared RX queue receives packets from all

RX -> Rx

Quoted 6 lines

member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group.

Share RX queue must be polled on single thread or core.

RX -> Rx

Quoted 2 lines

Multiple groups is supported by group ID.

is -> are

Quoted 3 lines

The patch should update release notes.

Quoted 51 lines

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

---
 doc/guides/nics/features.rst                    | 11 +++++++++++
 doc/guides/nics/features/default.ini            |  1 +
 doc/guides/prog_guide/switch_representation.rst | 10 ++++++++++
 lib/ethdev/rte_ethdev.c                         |  1 +
 lib/ethdev/rte_ethdev.h                         |  7 +++++++
 5 files changed, 30 insertions(+)
doc/guides/nics/features.rst +11 -0
index 4fce8cd1c97..69bc1d5719c 100644
@@ -626,6 +626,17 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same switch domain.
+
+* **[uses]     rte_eth_rxconf,rte_eth_rxmode**: ``offloads:RTE_ETH_RX_OFFLOAD_SHARED_RXQ``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index 754184ddd4d..ebeb4c18512 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +0 -0
index ff6aa91c806..bc7ce65fa3d 100644

doc/guides/prog_guide/switch_representation.rst thought as a software "patch panel" front-end for applications. · line 127

Quoted 5 lines
doc/guides/prog_guide/switch_representation.rst +2 -0
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- Memory usage of representors is huge when number of representor grows,
+  because PMD always allocate mbuf for each descriptor of Rx queue.

It is a problem of some PMDs only. So, it must be rewritten to highlight it.

Quoted 46 lines
doc/guides/prog_guide/switch_representation.rst +8 -0
+  Polling the large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors in same switch. ``RTE_ETH_RX_OFFLOAD_SHARED_RXQ`` is
+  present in Rx offloading capability of device info. Setting the
+  offloading flag in device Rx mode or Rx queue configuration to enable
+  shared Rx queue. Polling any member port of the shared Rx queue can return
+  packets of all ports in the group, port ID is saved in ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
lib/ethdev/rte_ethdev.c +1 -0
index 61aa49efec6..73270c10492 100644
@@ -127,6 +127,7 @@ static const struct {
 	RTE_RX_OFFLOAD_BIT2STR(OUTER_UDP_CKSUM),
 	RTE_RX_OFFLOAD_BIT2STR(RSS_HASH),
 	RTE_ETH_RX_OFFLOAD_BIT2STR(BUFFER_SPLIT),
+	RTE_ETH_RX_OFFLOAD_BIT2STR(SHARED_RXQ),
 };
 
 #undef RTE_RX_OFFLOAD_BIT2STR
lib/ethdev/rte_ethdev.h +7 -0
index afdc53b674c..d7ac625ee74 100644
@@ -1077,6 +1077,7 @@ struct rte_eth_rxconf {
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
 	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	uint32_t shared_group; /**< Shared port group index in switch domain. */
 	/**
 	 * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
 	 * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1403,6 +1404,12 @@ struct rte_eth_conf {
 #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM  0x00040000
 #define DEV_RX_OFFLOAD_RSS_HASH		0x00080000
 #define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000
+/**
+ * Rx queue is shared among ports in same switch domain to save memory,
+ * avoid polling each port. Any port in the group can be used to receive
+ * packets. Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
Quoted 7 lines

lib/ethdev/rte_ethdev.h struct rte_eth_conf { · line 1415

Quoted 3 lines
lib/ethdev/rte_ethdev.h +0 -0
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
 				 DEV_RX_OFFLOAD_UDP_CKSUM | \

IMHO it should be squashed with the second patch to make it easier to review. Otherwise it is hard to understand what is shared_group and the offlaod which are dead in the patch.

Hi Andrew,

Thanks for the review! With discussion with Jerin, we want to drop second patch and decide how to aggregate ports later by collecting more feedback and idea. To make the offload and group clear, I'll add an example in commit message. v5 sent w/o seeing your another review on 0/6, please ignore for now.

author
#98 lore raw

PATCH v4 2/6 ethdev: new API to aggregate shared Rx queue group

In reply to Xueming Li

This patch introduces new api to aggreate ports among same shared Rx queue group. Only queues with specified share group are aggregated. Rx burst and device close are expected to be supported by new device.

---
 lib/ethdev/ethdev_driver.h | 23 ++++++++++++++++++++++-
 lib/ethdev/rte_ethdev.c    | 22 ++++++++++++++++++++++
 lib/ethdev/rte_ethdev.h    | 16 ++++++++++++++++
 lib/ethdev/version.map     |  3 +++
 4 files changed, 63 insertions(+), 1 deletion(-)
lib/ethdev/ethdev_driver.h +22 -1
index 2f0fd3516d8..88c7bd3f698 100644
@@ -782,10 +782,28 @@ typedef int (*eth_get_monitor_addr_t)(void *rxq,
  * @return
  *   Negative errno value on error, number of info entries otherwise.
  */
-
 typedef int (*eth_representor_info_get_t)(struct rte_eth_dev *dev,
 	struct rte_eth_representor_info *info);
 
+/**
+ * @internal
+ * Aggregate shared Rx queue.
+ *
+ * Create a new port used for shared Rx queue polling.
+ *
+ * Only queues with specified share group are aggregated.
+ * At least Rx burst and device close should be supported.
+ *
+ * @param dev
+ *   Ethdev handle of port.
+ * @param group
+ *   Shared Rx queue group to aggregate.
+ * @return
+ *   UINT16_MAX if failed, otherwise aggregated port number.
+ */
+typedef uint16_t (*eth_shared_rxq_aggregate_t)(struct rte_eth_dev *dev,
+					       uint32_t group);
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -946,6 +964,9 @@ struct eth_dev_ops {
 
 	eth_representor_info_get_t representor_info_get;
 	/**< Get representor info. */
+
+	eth_shared_rxq_aggregate_t shared_rxq_aggregate;
+	/**< Aggregate shared Rx queue. */
 };
 
 /**
lib/ethdev/rte_ethdev.c +22 -0
index 73270c10492..d78b50e1fa7 100644
@@ -6297,6 +6297,28 @@ rte_eth_representor_info_get(uint16_t port_id,
 	return eth_err(port_id, (*dev->dev_ops->representor_info_get)(dev, info));
 }
 
+uint16_t
+rte_eth_shared_rxq_aggregate(uint16_t port_id, uint32_t group)
+{
+	struct rte_eth_dev *dev;
+	uint64_t offloads;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	dev = &rte_eth_devices[port_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->shared_rxq_aggregate,
+				UINT16_MAX);
+
+	offloads = dev->data->dev_conf.rxmode.offloads;
+	if ((offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ) == 0) {
+		RTE_ETHDEV_LOG(ERR, "port_id=%u doesn't support Rx offload\n",
+			       port_id);
+		return UINT16_MAX;
+	}
+
+	return (*dev->dev_ops->shared_rxq_aggregate)(dev, group);
+}
+
 RTE_LOG_REGISTER_DEFAULT(rte_eth_dev_logtype, INFO);
 
 RTE_INIT(ethdev_init_telemetry)
lib/ethdev/rte_ethdev.h +16 -0
index d7ac625ee74..b94f7ba5a3f 100644
@@ -4909,6 +4909,22 @@ __rte_experimental
 int rte_eth_representor_info_get(uint16_t port_id,
 				 struct rte_eth_representor_info *info);
 
+/**
+ * Aggregate shared Rx queue ports to one port for polling.
+ *
+ * Only queues with specified share group are aggregated.
+ * Any operation besides Rx burst and device close is unexpected.
+ *
+ * @param port_id
+ *   The port identifier of the device from shared Rx queue group.
+ * @param group
+ *   Shared Rx queue group to aggregate.
+ * @return
+ *   UINT16_MAX if failed, otherwise aggregated port number.
+ */
+__rte_experimental
+uint16_t rte_eth_shared_rxq_aggregate(uint16_t port_id, uint32_t group);
+
 #include <rte_ethdev_core.h>
 
 /**
lib/ethdev/version.map +3 -0
index 904bce6ea14..6f261bb923a 100644
@@ -247,6 +247,9 @@ EXPERIMENTAL {
 	rte_mtr_meter_policy_delete;
 	rte_mtr_meter_policy_update;
 	rte_mtr_meter_policy_validate;
+
+	# added in 21.11
+	rte_eth_shared_rxq_aggregate;
 };
 
 INTERNAL {
Signature · 1 line
2.33.0
author
#99 lore raw

PATCH v4 3/6 app/testpmd: new parameter to enable shared Rx queue

In reply to Xueming Li

Adds "--rxq-share" parameter to enable shared rxq for each rxq.

Default shared rxq group 0 is used, RX queues in same switch domain shares same rxq according to queue index.

Shared Rx queue is enabled only if device support offloading flag RTE_ETH_RX_OFFLOAD_SHARED_RXQ.

---
 app/test-pmd/config.c                 |  6 +++++-
 app/test-pmd/parameters.c             | 13 +++++++++++++
 app/test-pmd/testpmd.c                | 18 ++++++++++++++++++
 app/test-pmd/testpmd.h                |  2 ++
 doc/guides/testpmd_app_ug/run_app.rst |  7 +++++++
 5 files changed, 45 insertions(+), 1 deletion(-)
app/test-pmd/config.c +5 -1
index 9c66329e96e..6c7f9dee065 100644
@@ -2709,7 +2709,11 @@ rxtx_config_display(void)
 			printf("      RX threshold registers: pthresh=%d hthresh=%d "
 				" wthresh=%d\n",
 				pthresh_tmp, hthresh_tmp, wthresh_tmp);
-			printf("      RX Offloads=0x%"PRIx64"\n", offloads_tmp);
+			printf("      RX Offloads=0x%"PRIx64, offloads_tmp);
+			if (rx_conf->offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ)
+				printf(" share group=%u",
+				       rx_conf->shared_group);
+			printf("\n");
 		}
 
 		/* per tx queue config only for first queue to be less verbose */
app/test-pmd/parameters.c +13 -0
index 3f94a82e321..30dae326310 100644
@@ -167,6 +167,7 @@ usage(char* progname)
 	printf("  --tx-ip=src,dst: IP addresses in Tx-only mode\n");
 	printf("  --tx-udp=src[,dst]: UDP ports in Tx-only mode\n");
 	printf("  --eth-link-speed: force link speed.\n");
+	printf("  --rxq-share: number of ports per shared rxq groups, defaults to MAX(1 group)\n");
 	printf("  --disable-link-check: disable check on link status when "
 	       "starting/stopping ports.\n");
 	printf("  --disable-device-start: do not automatically start port\n");
@@ -607,6 +608,7 @@ launch_args_parse(int argc, char** argv)
 		{ "rxpkts",			1, 0, 0 },
 		{ "txpkts",			1, 0, 0 },
 		{ "txonly-multi-flow",		0, 0, 0 },
+		{ "rxq-share",			2, 0, 0 },
 		{ "eth-link-speed",		1, 0, 0 },
 		{ "disable-link-check",		0, 0, 0 },
 		{ "disable-device-start",	0, 0, 0 },
@@ -1271,6 +1273,17 @@ launch_args_parse(int argc, char** argv)
 			}
 			if (!strcmp(lgopts[opt_idx].name, "txonly-multi-flow"))
 				txonly_multi_flow = 1;
+			if (!strcmp(lgopts[opt_idx].name, "rxq-share")) {
+				if (optarg == NULL) {
+					rxq_share = UINT32_MAX;
+				} else {
+					n = atoi(optarg);
+					if (n >= 0)
+						rxq_share = (uint32_t)n;
+					else
+						rte_exit(EXIT_FAILURE, "rxq-share must be >= 0\n");
+				}
+			}
 			if (!strcmp(lgopts[opt_idx].name, "no-flush-rx"))
 				no_flush_rx = 1;
 			if (!strcmp(lgopts[opt_idx].name, "eth-link-speed")) {
app/test-pmd/testpmd.c +18 -0
index 97ae52e17ec..417e92ade11 100644
@@ -498,6 +498,11 @@ uint8_t record_core_cycles;
  */
 uint8_t record_burst_stats;
 
+/*
+ * Number of ports per shared Rx queue group, 0 disable.
+ */
+uint32_t rxq_share;
+
 unsigned int num_sockets = 0;
 unsigned int socket_ids[RTE_MAX_NUMA_NODES];
 
@@ -1506,6 +1511,11 @@ init_config_port_offloads(portid_t pid, uint32_t socket_id)
 		port->dev_conf.txmode.offloads &=
 			~DEV_TX_OFFLOAD_MBUF_FAST_FREE;
 
+	if (rxq_share > 0 &&
+	    (port->dev_info.rx_offload_capa & RTE_ETH_RX_OFFLOAD_SHARED_RXQ))
+		port->dev_conf.rxmode.offloads |=
+				RTE_ETH_RX_OFFLOAD_SHARED_RXQ;
+
 	/* Apply Rx offloads configuration */
 	for (i = 0; i < port->dev_info.max_rx_queues; i++)
 		port->rx_conf[i].offloads = port->dev_conf.rxmode.offloads;
@@ -3401,6 +3411,14 @@ rxtx_port_config(struct rte_port *port)
 	for (qid = 0; qid < nb_rxq; qid++) {
 		offloads = port->rx_conf[qid].offloads;
 		port->rx_conf[qid] = port->dev_info.default_rxconf;
+
+		if (rxq_share > 0 &&
+		    (port->dev_info.rx_offload_capa &
+		     RTE_ETH_RX_OFFLOAD_SHARED_RXQ)) {
+			offloads |= RTE_ETH_RX_OFFLOAD_SHARED_RXQ;
+			port->rx_conf[qid].shared_group = nb_ports / rxq_share;
+		}
+
 		if (offloads != 0)
 			port->rx_conf[qid].offloads = offloads;
 
app/test-pmd/testpmd.h +2 -0
index 5863b2f43f3..3dfaaad94c0 100644
@@ -477,6 +477,8 @@ extern enum tx_pkt_split tx_pkt_split;
 
 extern uint8_t txonly_multi_flow;
 
+extern uint32_t rxq_share;
+
 extern uint16_t nb_pkt_per_burst;
 extern uint16_t nb_pkt_flowgen_clones;
 extern int nb_flows_flowgen;
doc/guides/testpmd_app_ug/run_app.rst +7 -0
index 640eadeff73..43c85959e0b 100644
@@ -389,6 +389,13 @@ The command line options are:
 
     Generate multiple flows in txonly mode.
 
+*   ``--rxq-share=[X]``
+
+    Create queues in shared RX queue mode if device supports.
+    Group number grows per X ports, default to group 0 if X not specified.
+    Only "shared-rxq" forwarding engine suppose to resolve source stream
+    correctly.
+
 *   ``--eth-link-speed``
 
     Set a forced link speed to the ethernet port::
Signature · 1 line
2.33.0
author
#100 lore raw

PATCH v4 4/6 app/testpmd: dump port info for shared Rx queue

In reply to Xueming Li

In case of shared Rx queue, polling any member port returns mbufs for all members. This patch dumps mbuf->port for each packet.

---
 app/test-pmd/util.c | 3 +++
 1 file changed, 3 insertions(+)
app/test-pmd/util.c +3 -0
index 14a9a251fb9..4c07907c441 100644
@@ -100,6 +100,9 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
 		struct rte_flow_restore_info info = { 0, };
 
 		mb = pkts[i];
+		if (rxq_share > 0)
+			MKDUMPSTR(print_buf, buf_size, cur_len, "port %u, ",
+				  mb->port);
 		eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
 		eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
 		packet_type = mb->packet_type;
Signature · 1 line
2.33.0
author
#101 lore raw

PATCH v4 5/6 app/testpmd: force shared Rx queue polled on same core

In reply to Xueming Li

Shared rxqs shares one set rx queue of groups zero. Shared Rx queue must must be polled from one core.

Checks and stops forwarding if shared rxq being scheduled on multiple cores.

---
 app/test-pmd/config.c  | 96 ++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.c |  4 +-
 app/test-pmd/testpmd.h |  2 +
 3 files changed, 101 insertions(+), 1 deletion(-)
app/test-pmd/config.c +96 -0
index 6c7f9dee065..8bfa26570ba 100644
@@ -2885,6 +2885,102 @@ port_rss_hash_key_update(portid_t port_id, char rss_type[], uint8_t *hash_key,
 	}
 }
 
+/*
+ * Check whether a shared rxq scheduled on other lcores.
+ */
+static bool
+fwd_stream_on_other_lcores(uint16_t domain_id, portid_t src_port,
+			   queueid_t src_rxq, lcoreid_t src_lc,
+			   uint32_t shared_group)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	struct rte_port *port;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	for (lc_id = src_lc + 1; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			port = &ports[fs->rx_port];
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((rxq_conf->offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			if (domain_id != port->dev_info.switch_info.domain_id)
+				continue;
+			if (fs->rx_queue != src_rxq)
+				continue;
+			if (rxq_conf->shared_group != shared_group)
+				continue;
+			printf("Shared RX queue group %u can't be scheduled on different cores:\n",
+			       shared_group);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       src_lc, src_port, src_rxq);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       lc_id, fs->rx_port, fs->rx_queue);
+			printf("  please use --nb-cores=%hu to limit forwarding cores\n",
+			       nb_rxq);
+			return true;
+		}
+	}
+	return false;
+}
+
+/*
+ * Check shared rxq configuration.
+ *
+ * Shared group must not being scheduled on different core.
+ */
+bool
+pkt_fwd_shared_rxq_check(void)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	uint16_t domain_id;
+	struct rte_port *port;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	/*
+	 * Check streams on each core, make sure the same switch domain +
+	 * group + queue doesn't get scheduled on other cores.
+	 */
+	for (lc_id = 0; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			/* Update lcore info stream being scheduled. */
+			fs->lcore = fwd_lcores[lc_id];
+			port = &ports[fs->rx_port];
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((rxq_conf->offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			/* Check shared rxq not scheduled on remaining cores. */
+			domain_id = port->dev_info.switch_info.domain_id;
+			if (fwd_stream_on_other_lcores(domain_id, fs->rx_port,
+						       fs->rx_queue, lc_id,
+						       rxq_conf->shared_group))
+				return false;
+		}
+	}
+	return true;
+}
+
 /*
  * Setup forwarding configuration for each logical core.
  */
app/test-pmd/testpmd.c +3 -1
index 417e92ade11..cab4b36b046 100644
@@ -2241,10 +2241,12 @@ start_packet_forwarding(int with_tx_first)
 
 	fwd_config_setup();
 
+	pkt_fwd_config_display(&cur_fwd_config);
+	if (!pkt_fwd_shared_rxq_check())
+		return;
 	if(!no_flush_rx)
 		flush_fwd_rx_queues();
 
-	pkt_fwd_config_display(&cur_fwd_config);
 	rxtx_config_display();
 
 	fwd_stats_reset();
app/test-pmd/testpmd.h +2 -0
index 3dfaaad94c0..f121a2da90c 100644
@@ -144,6 +144,7 @@ struct fwd_stream {
 	uint64_t     core_cycles; /**< used for RX and TX processing */
 	struct pkt_burst_stats rx_burst_stats;
 	struct pkt_burst_stats tx_burst_stats;
+	struct fwd_lcore *lcore; /**< Lcore being scheduled. */
 };
 
 /**
@@ -795,6 +796,7 @@ void port_summary_header_display(void);
 void rx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void tx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void fwd_lcores_config_display(void);
+bool pkt_fwd_shared_rxq_check(void);
 void pkt_fwd_config_display(struct fwd_config *cfg);
 void rxtx_config_display(void);
 void fwd_config_setup(void);
Signature · 1 line
2.33.0
author
#102 lore raw

PATCH v4 6/6 app/testpmd: add forwarding engine for shared Rx queue

In reply to Xueming Li

To support shared Rx queue, this patch introduces dedicate forwarding engine. The engine groups received packets by mbuf->port into sub-group, updates stream statistics and simply frees packets.

---
 app/test-pmd/meson.build                    |   1 +
 app/test-pmd/shared_rxq_fwd.c               | 148 ++++++++++++++++++++
 app/test-pmd/testpmd.c                      |   1 +
 app/test-pmd/testpmd.h                      |   1 +
 doc/guides/testpmd_app_ug/run_app.rst       |   1 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |   5 +-
 6 files changed, 156 insertions(+), 1 deletion(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
app/test-pmd/meson.build +1 -0
index 98f3289bdfa..07042e45b12 100644
@@ -21,6 +21,7 @@ sources = files(
         'noisy_vnf.c',
         'parameters.c',
         'rxonly.c',
+        'shared_rxq_fwd.c',
         'testpmd.c',
         'txonly.c',
         'util.c',
app/test-pmd/shared_rxq_fwd.c new file +148 -0

148 lines not on this page · raw message

app/test-pmd/testpmd.c +1 -0
index cab4b36b046..681ea591871 100644
@@ -188,6 +188,7 @@ struct fwd_engine * fwd_engines[] = {
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
+	&shared_rxq_engine,
 	NULL,
 };
 
app/test-pmd/testpmd.h +1 -0
index f121a2da90c..f1fd607e365 100644
@@ -299,6 +299,7 @@ extern struct fwd_engine five_tuple_swap_fwd_engine;
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
+extern struct fwd_engine shared_rxq_engine;
 
 extern struct fwd_engine * fwd_engines[]; /**< NULL terminated array. */
 extern cmdline_parse_inst_t cmd_set_raw;
doc/guides/testpmd_app_ug/run_app.rst +1 -0
index 43c85959e0b..7b83d4b3944 100644
@@ -252,6 +252,7 @@ The command line options are:
        tm
        noisy
        5tswap
+       shared-rxq
 
 *   ``--rss-ip``
 
doc/guides/testpmd_app_ug/testpmd_funcs.rst +4 -1
index bbef7063741..a30e2f4dfae 100644
@@ -314,7 +314,7 @@ set fwd
 Set the packet forwarding mode::
 
    testpmd> set fwd (io|mac|macswap|flowgen| \
-                     rxonly|txonly|csum|icmpecho|noisy|5tswap) (""|retry)
+                     rxonly|txonly|csum|icmpecho|noisy|5tswap|shared-rxq) (""|retry)
 
 ``retry`` can be specified for forwarding engines except ``rx_only``.
 
@@ -357,6 +357,9 @@ The available information categories are:
 
   L4 swaps the source port and destination port of transport layer (TCP and UDP).
 
+* ``shared-rxq``: Receive only for shared Rx queue.
+  Resolve packet source port from mbuf and update stream statistics accrodingly.
+
 Example::
 
    testpmd> set fwd rxonly
Signature · 1 line
2.33.0
#103 lore raw
In reply to Xueming Li

Hi Xueming,

Quoted 29 lines · Xueming Li

In current DPDK framework, all RX queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared RX queue. PF and representors with same configuration in same switch domain could share RX queue set by specifying shared Rx queue offloading flag and sharing group.

All ports that Shared Rx queue actually shares One Rx queue and only pre-load mbufs to one Rx queue, memory is saved.

Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of polling two share groups:
core group queue
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3

Quoted 5 lines

Shared RX queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

I apologize that I jump in into the review process that late.

Frankly speaking I doubt that it is the best design to solve the problem. Yes, I confirm that the problem exists, but I think there is better and simpler way to solve it.

The problem of the suggested solution is that it puts all the headache about consistency to application and PMDs without any help from ethdev layer to guarantee the consistency. As the result I believe it will be either missing/lost consistency checks or huge duplication in each PMD which supports the feature. Shared RxQs must be equally configured including number of queues, offloads (taking device level Rx offloads into account), RSS settings etc. So, applications must care about it and PMDs (or ethdev layer) must check it.

The advantage of the solution is that any device may create group and subsequent devices join. Absence of primary device is nice. But do we really need it? Will the design work if some representors are configured to use shared RxQ, but some do not? Theoretically it is possible, but could require extra non-trivial code on fast path.

Also looking at the first two patch I don't understand how application will find out which devices may share RxQs. E.g. if we have two difference NICs which support sharing, we can try to setup only one group 0, but finally will have two devices (not one) which must be polled.

1. We need extra flag in dev_info->dev_capa RTE_ETH_DEV_CAPA_RX_SHARE to advertise that the device supports Rx sharing.

2. I think we need "rx_domain" in device info (which should be treated in boundaries of the switch_domain) if and only if RTE_ETH_DEV_CAPA_RX_SHARE is advertised. Otherwise rx_domain value does not make sense.

(1) and (2) will allow application to find out which devices can share Rx.

3. Primary device (representors backing device) should advertise shared RxQ offload. Enabling of the offload tells the device to provide packets to all device in the Rx domain with mbuf->port filled in appropriately. Also it allows app to identify primary device in the Rx domain. When application enables the offload, it must ensure that it does not treat used port_id as an input port_id, but always check mbuf->port for each packet.

4. A new Rx mode should be introduced for secondary devices. It should not allow to configure RSS, specify any Rx offloads etc. ethdev must ensure it. It is an open question right now if it should require to provide primary port_id. In theory representors have it. However, may be it is nice for consistency to ensure that application knows that it does. If shared Rx mode is specified for device, application does not need to setup RxQs and attempts to do it should be discarded in ethdev.
For consistency it is better to ensure that number of queues match.
It is an interesting question what should happen if primary device is reconfigured and shared Rx is disabled on reconfiguration.

5. If so, in theory implementation of the Rx burst in the secondary could simply call Rx burst on primary device.

Andrew.

#104 lore raw
Quoted 32 lines · Andrew Rybchenko

Hi Xueming,

Quoted 29 lines · Xueming Li

In current DPDK framework, all RX queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared RX queue. PF and representors with same configuration in same switch domain could share RX queue set by specifying shared Rx queue offloading flag and sharing group.

All ports that Shared Rx queue actually shares One Rx queue and only pre-load mbufs to one Rx queue, memory is saved.

Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of polling two share groups:
core group queue
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3

Quoted 7 lines
Quoted 5 lines

Shared RX queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

I apologize that I jump in into the review process that late.

Appreciate the bold suggestion, never too late :)

Quoted 5 lines

Frankly speaking I doubt that it is the best design to solve the problem. Yes, I confirm that the problem exists, but I think there is better and simpler way to solve it.

Quoted 10 lines

The problem of the suggested solution is that it puts all the headache about consistency to application and PMDs without any help from ethdev layer to guarantee the consistency. As the result I believe it will be either missing/lost consistency checks or huge duplication in each PMD which supports the feature. Shared RxQs must be equally configured including number of queues, offloads (taking device level Rx offloads into account), RSS settings etc. So, applications must care about it and PMDs (or ethdev layer) must check it.

The name might be confusing, here is my understanding:
1. NIC shares the buffer supply HW Q between shared RxQs - for memory
2. PMD polls one shared RxQ - for latency and performance
3. Most per queue features like offloads and RSS not impacted. That's why this not mentioned. Some offloading might not being supported due to PMD or hw limitation, need to add check in PMD case by case.
4. Multiple group is defined for service level flexibility. For example, PF and VIP customer's load distributed via queues and dedicate cores. Low priority customers share one core with one shared queue. multiple groups enables more combination.
5. One port could assign queues to different group for polling flexibility. For example first 4 queues in group 0 and next 4 queues in group1, each group have other member ports with 4 queues, so the port with 8 queues could be polled with 8 cores w/o non-shared rxq penalty, in other words, each core only poll one shared RxQ.

Quoted 8 lines

The advantage of the solution is that any device may create group and subsequent devices join. Absence of primary device is nice. But do we really need it? Will the design work if some representors are configured to use shared RxQ, but some do not? Theoretically it is possible, but could require extra non-trivial code on fast path.

If multiple groups, any device could be hot-unplugged.

Mixed configuration is supported, the only difference is how to set mbuf->port. Since group is per queue, mixed is better to be supported, didn't see any difficulty here.

PDM could select to support only group 0, same settings for each rxq, that fits most scenario.

Quoted 11 lines

Also looking at the first two patch I don't understand how application will find out which devices may share RxQs. E.g. if we have two difference NICs which support sharing, we can try to setup only one group 0, but finally will have two devices (not one) which must be polled.

1. We need extra flag in dev_info->dev_capa RTE_ETH_DEV_CAPA_RX_SHARE to advertise that the device supports Rx sharing.

dev_info->rx_queue_offload_capa could be used here, no?

Quoted 6 lines

2. I think we need "rx_domain" in device info (which should be treated in boundaries of the switch_domain) if and only if RTE_ETH_DEV_CAPA_RX_SHARE is advertised. Otherwise rx_domain value does not make sense.

I see, this will give flexibility of different hw, will add it.

Quoted 14 lines

(1) and (2) will allow application to find out which devices can share Rx.

3. Primary device (representors backing device) should advertise shared RxQ offload. Enabling of the offload tells the device to provide packets to all device in the Rx domain with mbuf->port filled in appropriately. Also it allows app to identify primary device in the Rx domain. When application enables the offload, it must ensure that it does not treat used port_id as an input port_id, but always check mbuf->port for each packet.

Quoted 12 lines

4. A new Rx mode should be introduced for secondary devices. It should not allow to configure RSS, specify any Rx offloads etc. ethdev must ensure it. It is an open question right now if it should require to provide primary port_id. In theory representors have it. However, may be it is nice for consistency to ensure that application knows that it does. If shared Rx mode is specified for device, application does not need to setup RxQs and attempts to do it should be discarded in ethdev.
For consistency it is better to ensure that number of queues match.

RSS and Rx offloads should be supported as individual, PMD needs to check if not supported.

Quoted 3 lines

It is an interesting question what should happen if primary device is reconfigured and shared Rx is disabled on reconfiguration.

I feel better no primary port/queue assumption in configuration, all members are equally treated, each queue can join or quit share group, that's important to support multiple groups.

Quoted 6 lines

5. If so, in theory implementation of the Rx burst in the secondary could simply call Rx burst on primary device.

Andrew.

#105 lore raw
Quoted 146 lines · Xueming Li
Quoted 32 lines · Andrew Rybchenko

Hi Xueming,

Quoted 29 lines · Xueming Li

In current DPDK framework, all RX queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared RX queue. PF and representors with same configuration in same switch domain could share RX queue set by specifying shared Rx queue offloading flag and sharing group.

All ports that Shared Rx queue actually shares One Rx queue and only pre-load mbufs to one Rx queue, memory is saved.

Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of polling two share groups:
core group queue
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3

Quoted 7 lines
Quoted 5 lines

Shared RX queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

I apologize that I jump in into the review process that late.

Appreciate the bold suggestion, never too late :)

Quoted 5 lines

Frankly speaking I doubt that it is the best design to solve the problem. Yes, I confirm that the problem exists, but I think there is better and simpler way to solve it.

Quoted 10 lines

The problem of the suggested solution is that it puts all the headache about consistency to application and PMDs without any help from ethdev layer to guarantee the consistency. As the result I believe it will be either missing/lost consistency checks or huge duplication in each PMD which supports the feature. Shared RxQs must be equally configured including number of queues, offloads (taking device level Rx offloads into account), RSS settings etc. So, applications must care about it and PMDs (or ethdev layer) must check it.

The name might be confusing, here is my understanding:
1. NIC shares the buffer supply HW Q between shared RxQs - for memory
2. PMD polls one shared RxQ - for latency and performance
3. Most per queue features like offloads and RSS not impacted. That's why this not mentioned. Some offloading might not being supported due to PMD or hw limitation, need to add check in PMD case by case.
4. Multiple group is defined for service level flexibility. For example, PF and VIP customer's load distributed via queues and dedicate cores. Low priority customers share one core with one shared queue. multiple groups enables more combination.
5. One port could assign queues to different group for polling flexibility. For example first 4 queues in group 0 and next 4 queues in group1, each group have other member ports with 4 queues, so the port with 8 queues could be polled with 8 cores w/o non-shared rxq penalty, in other words, each core only poll one shared RxQ.

Quoted 8 lines

The advantage of the solution is that any device may create group and subsequent devices join. Absence of primary device is nice. But do we really need it? Will the design work if some representors are configured to use shared RxQ, but some do not? Theoretically it is possible, but could require extra non-trivial code on fast path.

If multiple groups, any device could be hot-unplugged.

Mixed configuration is supported, the only difference is how to set mbuf->port. Since group is per queue, mixed is better to be supported, didn't see any difficulty here.

PDM could select to support only group 0, same settings for each rxq, that fits most scenario.

Quoted 11 lines

Also looking at the first two patch I don't understand how application will find out which devices may share RxQs. E.g. if we have two difference NICs which support sharing, we can try to setup only one group 0, but finally will have two devices (not one) which must be polled.

1. We need extra flag in dev_info->dev_capa RTE_ETH_DEV_CAPA_RX_SHARE to advertise that the device supports Rx sharing.

dev_info->rx_queue_offload_capa could be used here, no?

Quoted 6 lines

2. I think we need "rx_domain" in device info (which should be treated in boundaries of the switch_domain) if and only if RTE_ETH_DEV_CAPA_RX_SHARE is advertised. Otherwise rx_domain value does not make sense.

I see, this will give flexibility of different hw, will add it.

Quoted 14 lines

(1) and (2) will allow application to find out which devices can share Rx.

3. Primary device (representors backing device) should advertise shared RxQ offload. Enabling of the offload tells the device to provide packets to all device in the Rx domain with mbuf->port filled in appropriately. Also it allows app to identify primary device in the Rx domain. When application enables the offload, it must ensure that it does not treat used port_id as an input port_id, but always check mbuf->port for each packet.

Quoted 12 lines

4. A new Rx mode should be introduced for secondary devices. It should not allow to configure RSS, specify any Rx offloads etc. ethdev must ensure it. It is an open question right now if it should require to provide primary port_id. In theory representors have it. However, may be it is nice for consistency to ensure that application knows that it does. If shared Rx mode is specified for device, application does not need to setup RxQs and attempts to do it should be discarded in ethdev.
For consistency it is better to ensure that number of queues match.

RSS and Rx offloads should be supported as individual, PMD needs to check if not supported.

Quoted 15 lines
Quoted 3 lines

It is an interesting question what should happen if primary device is reconfigured and shared Rx is disabled on reconfiguration.

I feel better no primary port/queue assumption in configuration, all members are equally treated, each queue can join or quit share group, that's important to support multiple groups.

Quoted 6 lines

5. If so, in theory implementation of the Rx burst in the secondary could simply call Rx burst on primary device.

Andrew.

Hi Andrew,

I realized that we are talking different things, this feature introduced 2 RxQ share:
1. Share mempool to save memory
2. Share polling to save latency

What you suggested is reuse all RxQ configuration IIUC, maybe we should break the flag into 3, so application could learn PMD capability and configure accordingly, how do you think? RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POOL RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POLL RTE_ETH_RX_OFFLOAD_RXQ_SHARE_CFG //implies POOL and POLL

Regards,
Xueming

#106 lore raw
Quoted 102 lines · Xueming(Steven) Li
Quoted 101 lines · Xueming Li
Quoted 32 lines · Andrew Rybchenko

Hi Xueming,

Quoted 29 lines · Xueming Li

In current DPDK framework, all RX queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared RX queue. PF and representors with same configuration in same switch domain could share RX queue set by specifying shared Rx queue offloading flag and sharing group.

All ports that Shared Rx queue actually shares One Rx queue and only pre-load mbufs to one Rx queue, memory is saved.

Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of polling two share groups:
core group queue
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3

Quoted 7 lines
Quoted 5 lines

Shared RX queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

I apologize that I jump in into the review process that late.

Appreciate the bold suggestion, never too late :)

Quoted 5 lines

Frankly speaking I doubt that it is the best design to solve the problem. Yes, I confirm that the problem exists, but I think there is better and simpler way to solve it.

Quoted 10 lines

The problem of the suggested solution is that it puts all the headache about consistency to application and PMDs without any help from ethdev layer to guarantee the consistency. As the result I believe it will be either missing/lost consistency checks or huge duplication in each PMD which supports the feature. Shared RxQs must be equally configured including number of queues, offloads (taking device level Rx offloads into account), RSS settings etc. So, applications must care about it and PMDs (or ethdev layer) must check it.

The name might be confusing, here is my understanding:
1. NIC shares the buffer supply HW Q between shared RxQs - for memory
2. PMD polls one shared RxQ - for latency and performance
3. Most per queue features like offloads and RSS not impacted. That's why this not mentioned. Some offloading might not being supported due to PMD or hw limitation, need to add check in PMD case by case.
4. Multiple group is defined for service level flexibility. For example, PF and VIP customer's load distributed via queues and dedicate cores. Low priority customers share one core with one shared queue. multiple groups enables more combination.
5. One port could assign queues to different group for polling flexibility. For example first 4 queues in group 0 and next 4 queues in group1, each group have other member ports with 4 queues, so the port with 8 queues could be polled with 8 cores w/o non-shared rxq penalty, in other words, each core only poll one shared RxQ.

Quoted 8 lines

The advantage of the solution is that any device may create group and subsequent devices join. Absence of primary device is nice. But do we really need it? Will the design work if some representors are configured to use shared RxQ, but some do not? Theoretically it is possible, but could require extra non-trivial code on fast path.

If multiple groups, any device could be hot-unplugged.

Mixed configuration is supported, the only difference is how to set mbuf->port. Since group is per queue, mixed is better to be supported, didn't see any difficulty here.

PDM could select to support only group 0, same settings for each rxq, that fits most scenario.

Quoted 8 lines

Also looking at the first two patch I don't understand how application will find out which devices may share RxQs. E.g. if we have two difference NICs which support sharing, we can try to setup only one group 0, but finally will have two devices (not one) which must be polled.

Quoted 5 lines
Quoted 5 lines
Quoted 3 lines

1. We need extra flag in dev_info->dev_capa RTE_ETH_DEV_CAPA_RX_SHARE to advertise that the device supports Rx sharing.

dev_info->rx_queue_offload_capa could be used here, no?

It depends. But we definitely need a flag which says that below rx_domain makes sense. It could be either RTE_ETH_DEV_CAPA_RX_SHARE or an Rx offload capability.

The question is if it is really an offload. The offload is when something could be done by HW/FW and result is provided to SW. May be it is just a nit picking...

May be we don't need an offload at all. Just have RTE_ETH_DEV_CAPA_RXQ_SHARE and use non-zero group ID as a flag that an RxQ should be shared (zero - default, no sharing). ethdev layer may check consistency on its layer to ensure that the device capability is reported if non-zero group is specified on queue setup.

Quoted 37 lines
Quoted 37 lines
Quoted 7 lines

2. I think we need "rx_domain" in device info (which should be treated in boundaries of the switch_domain) if and only if RTE_ETH_DEV_CAPA_RX_SHARE is advertised. Otherwise rx_domain value does not make sense.

I see, this will give flexibility of different hw, will add it.

Quoted 26 lines

(1) and (2) will allow application to find out which devices can share Rx.

3. Primary device (representors backing device) should advertise shared RxQ offload. Enabling of the offload tells the device to provide packets to all device in the Rx domain with mbuf->port filled in appropriately. Also it allows app to identify primary device in the Rx domain. When application enables the offload, it must ensure that it does not treat used port_id as an input port_id, but always check mbuf->port for each packet.

4. A new Rx mode should be introduced for secondary devices. It should not allow to configure RSS, specify any Rx offloads etc. ethdev must ensure it. It is an open question right now if it should require to provide primary port_id. In theory representors have it. However, may be it is nice for consistency to ensure that application knows that it does. If shared Rx mode is specified for device, application does not need to setup RxQs and attempts to do it should be discarded in ethdev.
For consistency it is better to ensure that number of queues match.

Quoted 2 lines
Quoted 2 lines

RSS and Rx offloads should be supported as individual, PMD needs to check if not supported.

Thinking a bit more about it I agree that RSS settings could be individual. Offload could be individual as well, but I'm not sure about all offloads. E.g. Rx scatter which is related to Rx buffer size (which is shared since Rx mempool is shared) vs MTU. May be it is acceptable. We just must define rules what should happen if offloads contradict to each other. It should be highlighted in the description including driver callback to ensure that PMD maintainers are responsible for consistency checks.

Quoted 8 lines
Quoted 8 lines
Quoted 4 lines

It is an interesting question what should happen if primary device is reconfigured and shared Rx is disabled on reconfiguration.

I feel better no primary port/queue assumption in configuration, all members are equally treated, each queue can join or quit share group, that's important to support multiple groups.

I agree. The problem of many flexible solutions is complexity to support. We'll see how it goes.

Quoted 16 lines
Quoted 8 lines
Quoted 7 lines

5. If so, in theory implementation of the Rx burst in the secondary could simply call Rx burst on primary device.

Andrew.

Hi Andrew,

I realized that we are talking different things, this feature introduced 2 RxQ share:
1. Share mempool to save memory
2. Share polling to save latency

Quoted 4 lines

What you suggested is reuse all RxQ configuration IIUC, maybe we should break the flag into 3, so application could learn PMD capability and configure accordingly, how do you think? RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POOL

Not sure that I understand. Just specify the same mempool on Rx queue setup. Isn't it sufficient?

Quoted 1 line

RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POLL

It implies pool sharing if I'm not mistaken. Of course, we can pool many different HW queues in one poll, but it hardly makes sense to care specially about it. IMHO RxQ sharing is a sharing of the underlying HW Rx queue.

Quoted 1 line

RTE_ETH_RX_OFFLOAD_RXQ_SHARE_CFG //implies POOL and POLL

It is hardly a feature. Rather a possible limitation.

Andrew.

#107 lore raw
Quoted 213 lines · Andrew Rybchenko
Quoted 102 lines · Xueming(Steven) Li
Quoted 101 lines · Xueming Li
Quoted 32 lines · Andrew Rybchenko

Hi Xueming,

Quoted 29 lines · Xueming Li

In current DPDK framework, all RX queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared RX queue. PF and representors with same configuration in same switch domain could share RX queue set by specifying shared Rx queue offloading flag and sharing group.

All ports that Shared Rx queue actually shares One Rx queue and only pre-load mbufs to one Rx queue, memory is saved.

Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of polling two share groups:
core group queue
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3

Quoted 7 lines
Quoted 5 lines

Shared RX queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

I apologize that I jump in into the review process that late.

Appreciate the bold suggestion, never too late :)

Quoted 5 lines

Frankly speaking I doubt that it is the best design to solve the problem. Yes, I confirm that the problem exists, but I think there is better and simpler way to solve it.

Quoted 10 lines

The problem of the suggested solution is that it puts all the headache about consistency to application and PMDs without any help from ethdev layer to guarantee the consistency. As the result I believe it will be either missing/lost consistency checks or huge duplication in each PMD which supports the feature. Shared RxQs must be equally configured including number of queues, offloads (taking device level Rx offloads into account), RSS settings etc. So, applications must care about it and PMDs (or ethdev layer) must check it.

The name might be confusing, here is my understanding:
1. NIC shares the buffer supply HW Q between shared RxQs - for memory
2. PMD polls one shared RxQ - for latency and performance
3. Most per queue features like offloads and RSS not impacted. That's why this not mentioned. Some offloading might not being supported due to PMD or hw limitation, need to add check in PMD case by case.
4. Multiple group is defined for service level flexibility. For example, PF and VIP customer's load distributed via queues and dedicate cores. Low priority customers share one core with one shared queue. multiple groups enables more combination.
5. One port could assign queues to different group for polling flexibility. For example first 4 queues in group 0 and next 4 queues in group1, each group have other member ports with 4 queues, so the port with 8 queues could be polled with 8 cores w/o non-shared rxq penalty, in other words, each core only poll one shared RxQ.

Quoted 8 lines

The advantage of the solution is that any device may create group and subsequent devices join. Absence of primary device is nice. But do we really need it? Will the design work if some representors are configured to use shared RxQ, but some do not? Theoretically it is possible, but could require extra non-trivial code on fast path.

If multiple groups, any device could be hot-unplugged.

Mixed configuration is supported, the only difference is how to set mbuf->port. Since group is per queue, mixed is better to be supported, didn't see any difficulty here.

PDM could select to support only group 0, same settings for each rxq, that fits most scenario.

Quoted 8 lines

Also looking at the first two patch I don't understand how application will find out which devices may share RxQs. E.g. if we have two difference NICs which support sharing, we can try to setup only one group 0, but finally will have two devices (not one) which must be polled.

Quoted 5 lines
Quoted 5 lines
Quoted 3 lines

1. We need extra flag in dev_info->dev_capa RTE_ETH_DEV_CAPA_RX_SHARE to advertise that the device supports Rx sharing.

dev_info->rx_queue_offload_capa could be used here, no?

It depends. But we definitely need a flag which says that below rx_domain makes sense. It could be either RTE_ETH_DEV_CAPA_RX_SHARE or an Rx offload capability.

The question is if it is really an offload. The offload is when something could be done by HW/FW and result is provided to SW. May be it is just a nit picking...

May be we don't need an offload at all. Just have RTE_ETH_DEV_CAPA_RXQ_SHARE and use non-zero group ID as a flag that an RxQ should be shared (zero - default, no sharing). ethdev layer may check consistency on its layer to ensure that the device capability is reported if non-zero group is specified on queue setup.

Quoted 37 lines
Quoted 37 lines
Quoted 7 lines

2. I think we need "rx_domain" in device info (which should be treated in boundaries of the switch_domain) if and only if RTE_ETH_DEV_CAPA_RX_SHARE is advertised. Otherwise rx_domain value does not make sense.

I see, this will give flexibility of different hw, will add it.

Quoted 26 lines

(1) and (2) will allow application to find out which devices can share Rx.

3. Primary device (representors backing device) should advertise shared RxQ offload. Enabling of the offload tells the device to provide packets to all device in the Rx domain with mbuf->port filled in appropriately. Also it allows app to identify primary device in the Rx domain. When application enables the offload, it must ensure that it does not treat used port_id as an input port_id, but always check mbuf->port for each packet.

4. A new Rx mode should be introduced for secondary devices. It should not allow to configure RSS, specify any Rx offloads etc. ethdev must ensure it. It is an open question right now if it should require to provide primary port_id. In theory representors have it. However, may be it is nice for consistency to ensure that application knows that it does. If shared Rx mode is specified for device, application does not need to setup RxQs and attempts to do it should be discarded in ethdev.
For consistency it is better to ensure that number of queues match.

Quoted 2 lines
Quoted 2 lines

RSS and Rx offloads should be supported as individual, PMD needs to check if not supported.

Thinking a bit more about it I agree that RSS settings could be individual. Offload could be individual as well, but I'm not sure about all offloads. E.g. Rx scatter which is related to Rx buffer size (which is shared since Rx mempool is shared) vs MTU. May be it is acceptable. We just must define rules what should happen if offloads contradict to each other. It should be highlighted in the description including driver callback to ensure that PMD maintainers are responsible for consistency checks.

Quoted 8 lines
Quoted 8 lines
Quoted 4 lines

It is an interesting question what should happen if primary device is reconfigured and shared Rx is disabled on reconfiguration.

I feel better no primary port/queue assumption in configuration, all members are equally treated, each queue can join or quit share group, that's important to support multiple groups.

I agree. The problem of many flexible solutions is complexity to support. We'll see how it goes.

Quoted 16 lines
Quoted 8 lines
Quoted 7 lines

5. If so, in theory implementation of the Rx burst in the secondary could simply call Rx burst on primary device.

Andrew.

Hi Andrew,

I realized that we are talking different things, this feature introduced 2 RxQ share:
1. Share mempool to save memory
2. Share polling to save latency

Quoted 4 lines

What you suggested is reuse all RxQ configuration IIUC, maybe we should break the flag into 3, so application could learn PMD capability and configure accordingly, how do you think? RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POOL

Not sure that I understand. Just specify the same mempool on Rx queue setup. Isn't it sufficient?

Quoted 1 line

RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POLL

Quoted 8 lines

It implies pool sharing if I'm not mistaken. Of course, we can pool many different HW queues in one poll, but it hardly makes sense to care specially about it. IMHO RxQ sharing is a sharing of the underlying HW Rx queue.

Quoted 1 line

RTE_ETH_RX_OFFLOAD_RXQ_SHARE_CFG //implies POOL and POLL

It is hardly a feature. Rather a possible limitation.

Thanks, then I'd drop this suggestion then.

Here is the TODO list, let me know if anything missing:
1. change offload flag to RTE_ETH_DEV_CAPA_RX_SHARE
2. RxQ share group check in ethdev
3. add rx_domain into device info

Quoted 2 lines

Andrew.

#108 lore raw
Quoted 219 lines · Xueming(Steven) Li
Quoted 218 lines · Andrew Rybchenko
Quoted 102 lines · Xueming(Steven) Li
Quoted 101 lines · Xueming Li
Quoted 32 lines · Andrew Rybchenko

Hi Xueming,

Quoted 29 lines · Xueming Li

In current DPDK framework, all RX queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared RX queue. PF and representors with same configuration in same switch domain could share RX queue set by specifying shared Rx queue offloading flag and sharing group.

All ports that Shared Rx queue actually shares One Rx queue and only pre-load mbufs to one Rx queue, memory is saved.

Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of polling two share groups:
core group queue
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3

Quoted 7 lines
Quoted 5 lines

Shared RX queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

I apologize that I jump in into the review process that late.

Appreciate the bold suggestion, never too late :)

Quoted 5 lines

Frankly speaking I doubt that it is the best design to solve the problem. Yes, I confirm that the problem exists, but I think there is better and simpler way to solve it.

Quoted 10 lines

The problem of the suggested solution is that it puts all the headache about consistency to application and PMDs without any help from ethdev layer to guarantee the consistency. As the result I believe it will be either missing/lost consistency checks or huge duplication in each PMD which supports the feature. Shared RxQs must be equally configured including number of queues, offloads (taking device level Rx offloads into account), RSS settings etc. So, applications must care about it and PMDs (or ethdev layer) must check it.

The name might be confusing, here is my understanding:
1. NIC shares the buffer supply HW Q between shared RxQs - for memory
2. PMD polls one shared RxQ - for latency and performance
3. Most per queue features like offloads and RSS not impacted. That's why this not mentioned. Some offloading might not being supported due to PMD or hw limitation, need to add check in PMD case by case.
4. Multiple group is defined for service level flexibility. For example, PF and VIP customer's load distributed via queues and dedicate cores. Low priority customers share one core with one shared queue. multiple groups enables more combination.
5. One port could assign queues to different group for polling flexibility. For example first 4 queues in group 0 and next 4 queues in group1, each group have other member ports with 4 queues, so the port with 8 queues could be polled with 8 cores w/o non-shared rxq penalty, in other words, each core only poll one shared RxQ.

Quoted 8 lines

The advantage of the solution is that any device may create group and subsequent devices join. Absence of primary device is nice. But do we really need it? Will the design work if some representors are configured to use shared RxQ, but some do not? Theoretically it is possible, but could require extra non-trivial code on fast path.

If multiple groups, any device could be hot-unplugged.

Mixed configuration is supported, the only difference is how to set mbuf->port. Since group is per queue, mixed is better to be supported, didn't see any difficulty here.

PDM could select to support only group 0, same settings for each rxq, that fits most scenario.

Quoted 8 lines

Also looking at the first two patch I don't understand how application will find out which devices may share RxQs. E.g. if we have two difference NICs which support sharing, we can try to setup only one group 0, but finally will have two devices (not one) which must be polled.

Quoted 5 lines
Quoted 5 lines
Quoted 3 lines

1. We need extra flag in dev_info->dev_capa RTE_ETH_DEV_CAPA_RX_SHARE to advertise that the device supports Rx sharing.

dev_info->rx_queue_offload_capa could be used here, no?

It depends. But we definitely need a flag which says that below rx_domain makes sense. It could be either RTE_ETH_DEV_CAPA_RX_SHARE or an Rx offload capability.

The question is if it is really an offload. The offload is when something could be done by HW/FW and result is provided to SW. May be it is just a nit picking...

May be we don't need an offload at all. Just have RTE_ETH_DEV_CAPA_RXQ_SHARE and use non-zero group ID as a flag that an RxQ should be shared (zero - default, no sharing). ethdev layer may check consistency on its layer to ensure that the device capability is reported if non-zero group is specified on queue setup.

Quoted 37 lines
Quoted 37 lines
Quoted 7 lines

2. I think we need "rx_domain" in device info (which should be treated in boundaries of the switch_domain) if and only if RTE_ETH_DEV_CAPA_RX_SHARE is advertised. Otherwise rx_domain value does not make sense.

I see, this will give flexibility of different hw, will add it.

Quoted 26 lines

(1) and (2) will allow application to find out which devices can share Rx.

3. Primary device (representors backing device) should advertise shared RxQ offload. Enabling of the offload tells the device to provide packets to all device in the Rx domain with mbuf->port filled in appropriately. Also it allows app to identify primary device in the Rx domain. When application enables the offload, it must ensure that it does not treat used port_id as an input port_id, but always check mbuf->port for each packet.

4. A new Rx mode should be introduced for secondary devices. It should not allow to configure RSS, specify any Rx offloads etc. ethdev must ensure it. It is an open question right now if it should require to provide primary port_id. In theory representors have it. However, may be it is nice for consistency to ensure that application knows that it does. If shared Rx mode is specified for device, application does not need to setup RxQs and attempts to do it should be discarded in ethdev.
For consistency it is better to ensure that number of queues match.

Quoted 2 lines
Quoted 2 lines

RSS and Rx offloads should be supported as individual, PMD needs to check if not supported.

Thinking a bit more about it I agree that RSS settings could be individual. Offload could be individual as well, but I'm not sure about all offloads. E.g. Rx scatter which is related to Rx buffer size (which is shared since Rx mempool is shared) vs MTU. May be it is acceptable. We just must define rules what should happen if offloads contradict to each other. It should be highlighted in the description including driver callback to ensure that PMD maintainers are responsible for consistency checks.

Quoted 8 lines
Quoted 8 lines
Quoted 4 lines

It is an interesting question what should happen if primary device is reconfigured and shared Rx is disabled on reconfiguration.

I feel better no primary port/queue assumption in configuration, all members are equally treated, each queue can join or quit share group, that's important to support multiple groups.

I agree. The problem of many flexible solutions is complexity to support. We'll see how it goes.

Quoted 16 lines
Quoted 8 lines
Quoted 7 lines

5. If so, in theory implementation of the Rx burst in the secondary could simply call Rx burst on primary device.

Andrew.

Hi Andrew,

I realized that we are talking different things, this feature introduced 2 RxQ share:
1. Share mempool to save memory
2. Share polling to save latency

Quoted 4 lines

What you suggested is reuse all RxQ configuration IIUC, maybe we should break the flag into 3, so application could learn PMD capability and configure accordingly, how do you think? RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POOL

Not sure that I understand. Just specify the same mempool on Rx queue setup. Isn't it sufficient?

Quoted 1 line

RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POLL

It implies pool sharing if I'm not mistaken. Of course, we can pool many different HW queues in one poll, but it hardly makes sense to care specially about it. IMHO RxQ sharing is a sharing of the underlying HW Rx queue.

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

RTE_ETH_RX_OFFLOAD_RXQ_SHARE_CFG //implies POOL and POLL

It is hardly a feature. Rather a possible limitation.

Thanks, then I'd drop this suggestion then.

Here is the TODO list, let me know if anything missing:
1. change offload flag to RTE_ETH_DEV_CAPA_RX_SHARE

RTE_ETH_DEV_CAPA_RXQ_SHARE since it is not sharing of entire Rx, but just some queues.

Quoted 6 lines

2. RxQ share group check in ethdev
3. add rx_domain into device info

Quoted 2 lines

Andrew.

#109 lore raw
Quoted 224 lines · Andrew Rybchenko
Quoted 223 lines · Xueming(Steven) Li
Quoted 221 lines · Andrew Rybchenko
Quoted 102 lines · Xueming(Steven) Li
Quoted 101 lines · Xueming Li
Quoted 32 lines · Andrew Rybchenko

Hi Xueming,

Quoted 29 lines · Xueming Li

In current DPDK framework, all RX queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared RX queue. PF and representors with same configuration in same switch domain could share RX queue set by specifying shared Rx queue offloading flag and sharing group.

All ports that Shared Rx queue actually shares One Rx queue and only pre-load mbufs to one Rx queue, memory is saved.

Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of polling two share groups:
core group queue
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3

Quoted 7 lines
Quoted 5 lines

Shared RX queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

I apologize that I jump in into the review process that late.

Appreciate the bold suggestion, never too late :)

Quoted 5 lines

Frankly speaking I doubt that it is the best design to solve the problem. Yes, I confirm that the problem exists, but I think there is better and simpler way to solve it.

Quoted 10 lines

The problem of the suggested solution is that it puts all the headache about consistency to application and PMDs without any help from ethdev layer to guarantee the consistency. As the result I believe it will be either missing/lost consistency checks or huge duplication in each PMD which supports the feature. Shared RxQs must be equally configured including number of queues, offloads (taking device level Rx offloads into account), RSS settings etc. So, applications must care about it and PMDs (or ethdev layer) must check it.

The name might be confusing, here is my understanding:
1. NIC shares the buffer supply HW Q between shared RxQs - for memory
2. PMD polls one shared RxQ - for latency and performance
3. Most per queue features like offloads and RSS not impacted. That's why this not mentioned. Some offloading might not being supported due to PMD or hw limitation, need to add check in PMD case by case.
4. Multiple group is defined for service level flexibility. For example, PF and VIP customer's load distributed via queues and dedicate cores. Low priority customers share one core with one shared queue. multiple groups enables more combination.
5. One port could assign queues to different group for polling flexibility. For example first 4 queues in group 0 and next 4 queues in group1, each group have other member ports with 4 queues, so the port with 8 queues could be polled with 8 cores w/o non-shared rxq penalty, in other words, each core only poll one shared RxQ.

Quoted 8 lines

The advantage of the solution is that any device may create group and subsequent devices join. Absence of primary device is nice. But do we really need it? Will the design work if some representors are configured to use shared RxQ, but some do not? Theoretically it is possible, but could require extra non-trivial code on fast path.

If multiple groups, any device could be hot-unplugged.

Mixed configuration is supported, the only difference is how to set mbuf->port. Since group is per queue, mixed is better to be supported, didn't see any difficulty here.

PDM could select to support only group 0, same settings for each rxq, that fits most scenario.

Quoted 8 lines

Also looking at the first two patch I don't understand how application will find out which devices may share RxQs. E.g. if we have two difference NICs which support sharing, we can try to setup only one group 0, but finally will have two devices (not one) which must be polled.

Quoted 5 lines
Quoted 5 lines
Quoted 3 lines

1. We need extra flag in dev_info->dev_capa RTE_ETH_DEV_CAPA_RX_SHARE to advertise that the device supports Rx sharing.

dev_info->rx_queue_offload_capa could be used here, no?

It depends. But we definitely need a flag which says that below rx_domain makes sense. It could be either RTE_ETH_DEV_CAPA_RX_SHARE or an Rx offload capability.

The question is if it is really an offload. The offload is when something could be done by HW/FW and result is provided to SW. May be it is just a nit picking...

May be we don't need an offload at all. Just have RTE_ETH_DEV_CAPA_RXQ_SHARE and use non-zero group ID as a flag that an RxQ should be shared (zero - default, no sharing). ethdev layer may check consistency on its layer to ensure that the device capability is reported if non-zero group is specified on queue setup.

Quoted 37 lines
Quoted 37 lines
Quoted 7 lines

2. I think we need "rx_domain" in device info (which should be treated in boundaries of the switch_domain) if and only if RTE_ETH_DEV_CAPA_RX_SHARE is advertised. Otherwise rx_domain value does not make sense.

I see, this will give flexibility of different hw, will add it.

Quoted 26 lines

(1) and (2) will allow application to find out which devices can share Rx.

3. Primary device (representors backing device) should advertise shared RxQ offload. Enabling of the offload tells the device to provide packets to all device in the Rx domain with mbuf->port filled in appropriately. Also it allows app to identify primary device in the Rx domain. When application enables the offload, it must ensure that it does not treat used port_id as an input port_id, but always check mbuf->port for each packet.

4. A new Rx mode should be introduced for secondary devices. It should not allow to configure RSS, specify any Rx offloads etc. ethdev must ensure it. It is an open question right now if it should require to provide primary port_id. In theory representors have it. However, may be it is nice for consistency to ensure that application knows that it does. If shared Rx mode is specified for device, application does not need to setup RxQs and attempts to do it should be discarded in ethdev.
For consistency it is better to ensure that number of queues match.

Quoted 2 lines
Quoted 2 lines

RSS and Rx offloads should be supported as individual, PMD needs to check if not supported.

Thinking a bit more about it I agree that RSS settings could be individual. Offload could be individual as well, but I'm not sure about all offloads. E.g. Rx scatter which is related to Rx buffer size (which is shared since Rx mempool is shared) vs MTU. May be it is acceptable. We just must define rules what should happen if offloads contradict to each other. It should be highlighted in the description including driver callback to ensure that PMD maintainers are responsible for consistency checks.

Quoted 8 lines
Quoted 8 lines
Quoted 4 lines

It is an interesting question what should happen if primary device is reconfigured and shared Rx is disabled on reconfiguration.

I feel better no primary port/queue assumption in configuration, all members are equally treated, each queue can join or quit share group, that's important to support multiple groups.

I agree. The problem of many flexible solutions is complexity to support. We'll see how it goes.

Quoted 16 lines
Quoted 8 lines
Quoted 7 lines

5. If so, in theory implementation of the Rx burst in the secondary could simply call Rx burst on primary device.

Andrew.

Hi Andrew,

I realized that we are talking different things, this feature introduced 2 RxQ share:
1. Share mempool to save memory
2. Share polling to save latency

Quoted 4 lines

What you suggested is reuse all RxQ configuration IIUC, maybe we should break the flag into 3, so application could learn PMD capability and configure accordingly, how do you think? RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POOL

Not sure that I understand. Just specify the same mempool on Rx queue setup. Isn't it sufficient?

Quoted 1 line

RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POLL

It implies pool sharing if I'm not mistaken. Of course, we can pool many different HW queues in one poll, but it hardly makes sense to care specially about it. IMHO RxQ sharing is a sharing of the underlying HW Rx queue.

Quoted 1 line

RTE_ETH_RX_OFFLOAD_RXQ_SHARE_CFG //implies POOL and POLL

It is hardly a feature. Rather a possible limitation.

Quoted 7 lines
Quoted 4 lines

Thanks, then I'd drop this suggestion then.

Here is the TODO list, let me know if anything missing:
1. change offload flag to RTE_ETH_DEV_CAPA_RX_SHARE

RTE_ETH_DEV_CAPA_RXQ_SHARE since it is not sharing of entire Rx, but just some queues.

OK

Quoted 3 lines
Quoted 3 lines

2. RxQ share group check in ethdev
3. add rx_domain into device info

Seems rte_eth_switch_info is better palce for rx_domain.

Quoted 5 lines
Quoted 4 lines
Quoted 3 lines

Andrew.

#110 lore raw
In reply to Andrew Rybchenko
Quoted 224 lines · Andrew Rybchenko
Quoted 223 lines · Xueming(Steven) Li
Quoted 221 lines · Andrew Rybchenko
Quoted 102 lines · Xueming(Steven) Li
Quoted 101 lines · Xueming Li
Quoted 32 lines · Andrew Rybchenko

Hi Xueming,

Quoted 29 lines · Xueming Li

In current DPDK framework, all RX queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared RX queue. PF and representors with same configuration in same switch domain could share RX queue set by specifying shared Rx queue offloading flag and sharing group.

All ports that Shared Rx queue actually shares One Rx queue and only pre-load mbufs to one Rx queue, memory is saved.

Polling any queue using same shared RX queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of polling two share groups:
core group queue
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3

Quoted 7 lines
Quoted 5 lines

Shared RX queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

I apologize that I jump in into the review process that late.

Appreciate the bold suggestion, never too late :)

Quoted 5 lines

Frankly speaking I doubt that it is the best design to solve the problem. Yes, I confirm that the problem exists, but I think there is better and simpler way to solve it.

Quoted 10 lines

The problem of the suggested solution is that it puts all the headache about consistency to application and PMDs without any help from ethdev layer to guarantee the consistency. As the result I believe it will be either missing/lost consistency checks or huge duplication in each PMD which supports the feature. Shared RxQs must be equally configured including number of queues, offloads (taking device level Rx offloads into account), RSS settings etc. So, applications must care about it and PMDs (or ethdev layer) must check it.

The name might be confusing, here is my understanding:
1. NIC shares the buffer supply HW Q between shared RxQs - for memory
2. PMD polls one shared RxQ - for latency and performance
3. Most per queue features like offloads and RSS not impacted. That's why this not mentioned. Some offloading might not being supported due to PMD or hw limitation, need to add check in PMD case by case.
4. Multiple group is defined for service level flexibility. For example, PF and VIP customer's load distributed via queues and dedicate cores. Low priority customers share one core with one shared queue. multiple groups enables more combination.
5. One port could assign queues to different group for polling flexibility. For example first 4 queues in group 0 and next 4 queues in group1, each group have other member ports with 4 queues, so the port with 8 queues could be polled with 8 cores w/o non-shared rxq penalty, in other words, each core only poll one shared RxQ.

Quoted 8 lines

The advantage of the solution is that any device may create group and subsequent devices join. Absence of primary device is nice. But do we really need it? Will the design work if some representors are configured to use shared RxQ, but some do not? Theoretically it is possible, but could require extra non-trivial code on fast path.

If multiple groups, any device could be hot-unplugged.

Mixed configuration is supported, the only difference is how to set mbuf->port. Since group is per queue, mixed is better to be supported, didn't see any difficulty here.

PDM could select to support only group 0, same settings for each rxq, that fits most scenario.

Quoted 8 lines

Also looking at the first two patch I don't understand how application will find out which devices may share RxQs. E.g. if we have two difference NICs which support sharing, we can try to setup only one group 0, but finally will have two devices (not one) which must be polled.

Quoted 5 lines
Quoted 5 lines
Quoted 3 lines

1. We need extra flag in dev_info->dev_capa RTE_ETH_DEV_CAPA_RX_SHARE to advertise that the device supports Rx sharing.

dev_info->rx_queue_offload_capa could be used here, no?

It depends. But we definitely need a flag which says that below rx_domain makes sense. It could be either RTE_ETH_DEV_CAPA_RX_SHARE or an Rx offload capability.

The question is if it is really an offload. The offload is when something could be done by HW/FW and result is provided to SW. May be it is just a nit picking...

May be we don't need an offload at all. Just have RTE_ETH_DEV_CAPA_RXQ_SHARE and use non-zero group ID as a flag that an RxQ should be shared (zero - default, no sharing). ethdev layer may check consistency on its layer to ensure that the device capability is reported if non-zero group is specified on queue setup.

Quoted 37 lines
Quoted 37 lines
Quoted 7 lines

2. I think we need "rx_domain" in device info (which should be treated in boundaries of the switch_domain) if and only if RTE_ETH_DEV_CAPA_RX_SHARE is advertised. Otherwise rx_domain value does not make sense.

I see, this will give flexibility of different hw, will add it.

Quoted 26 lines

(1) and (2) will allow application to find out which devices can share Rx.

3. Primary device (representors backing device) should advertise shared RxQ offload. Enabling of the offload tells the device to provide packets to all device in the Rx domain with mbuf->port filled in appropriately. Also it allows app to identify primary device in the Rx domain. When application enables the offload, it must ensure that it does not treat used port_id as an input port_id, but always check mbuf->port for each packet.

4. A new Rx mode should be introduced for secondary devices. It should not allow to configure RSS, specify any Rx offloads etc. ethdev must ensure it. It is an open question right now if it should require to provide primary port_id. In theory representors have it. However, may be it is nice for consistency to ensure that application knows that it does. If shared Rx mode is specified for device, application does not need to setup RxQs and attempts to do it should be discarded in ethdev.
For consistency it is better to ensure that number of queues match.

Quoted 2 lines
Quoted 2 lines

RSS and Rx offloads should be supported as individual, PMD needs to check if not supported.

Thinking a bit more about it I agree that RSS settings could be individual. Offload could be individual as well, but I'm not sure about all offloads. E.g. Rx scatter which is related to Rx buffer size (which is shared since Rx mempool is shared) vs MTU. May be it is acceptable. We just must define rules what should happen if offloads contradict to each other. It should be highlighted in the description including driver callback to ensure that PMD maintainers are responsible for consistency checks.

Quoted 8 lines
Quoted 8 lines
Quoted 4 lines

It is an interesting question what should happen if primary device is reconfigured and shared Rx is disabled on reconfiguration.

I feel better no primary port/queue assumption in configuration, all members are equally treated, each queue can join or quit share group, that's important to support multiple groups.

I agree. The problem of many flexible solutions is complexity to support. We'll see how it goes.

Quoted 16 lines
Quoted 8 lines
Quoted 7 lines

5. If so, in theory implementation of the Rx burst in the secondary could simply call Rx burst on primary device.

Andrew.

Hi Andrew,

I realized that we are talking different things, this feature introduced 2 RxQ share:
1. Share mempool to save memory
2. Share polling to save latency

Quoted 4 lines

What you suggested is reuse all RxQ configuration IIUC, maybe we should break the flag into 3, so application could learn PMD capability and configure accordingly, how do you think? RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POOL

Not sure that I understand. Just specify the same mempool on Rx queue setup. Isn't it sufficient?

Quoted 1 line

RTE_ETH_RX_OFFLOAD_RXQ_SHARE_POLL

It implies pool sharing if I'm not mistaken. Of course, we can pool many different HW queues in one poll, but it hardly makes sense to care specially about it. IMHO RxQ sharing is a sharing of the underlying HW Rx queue.

Quoted 1 line

RTE_ETH_RX_OFFLOAD_RXQ_SHARE_CFG //implies POOL and POLL

It is hardly a feature. Rather a possible limitation.

Quoted 7 lines
Quoted 4 lines

Thanks, then I'd drop this suggestion then.

Here is the TODO list, let me know if anything missing:
1. change offload flag to RTE_ETH_DEV_CAPA_RX_SHARE

RTE_ETH_DEV_CAPA_RXQ_SHARE since it is not sharing of entire Rx, but just some queues.

V6 posted, thanks!

Quoted 8 lines
Quoted 7 lines

2. RxQ share group check in ethdev
3. add rx_domain into device info

Quoted 2 lines

Andrew.

author
#111 lore raw

v5 cover ethdev: introduce shared Rx queue

In reply to Xueming Li

In current DPDK framework, all Rx queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared Rx queue. PF and representors with same configuration in same switch domain could share Rx queue set by specifying shared Rx queue offloading flag and sharing group.

All ports that Shared Rx queue actually shares One Rx queue and only pre-load mbufs to one Rx queue, memory is saved.

Polling any queue using same shared Rx queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of two share groups:
Group0, 4 shared Rx queues per member port: PF, repr0, repr1 Group1, 2 shared Rx queues per member port: repr2, repr3, ... repr127 Poll first port for each group:
core port queue
0 0 0
1 0 1
2 0 2
3 0 3
4 2 0
5 2 1

Shared Rx queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

There was some discussion to aggregate member ports in same group into a dummy port, several ways to achieve it. Since it optional, need to collect more feedback and requirement from user, make better decision later.

v1:
- initial version
v2:
- add testpmd patches
v3:
- change common forwarding api to macro for performance, thanks Jerin.
- save global variable accessed in forwarding to flowstream to minimize cache miss
- combined patches for each forwarding engine
- support multiple groups in testpmd "--share-rxq" parameter
- new api to aggregate shared rxq group
v4:
- spelling fixes
- remove shared-rxq support for all forwarding engines
- add dedicate shared-rxq forwarding engine
v5:
- fix grammars
- remove aggregate api and leave it for later discussion
- add release notes
- add deployment example

Xueming Li (5):
ethdev: introduce shared Rx queue app/testpmd: new parameter to enable shared Rx queue app/testpmd: dump port info for shared Rx queue app/testpmd: force shared Rx queue polled on same core app/testpmd: add forwarding engine for shared Rx queue

 app/test-pmd/config.c                         | 102 +++++++++++-
 app/test-pmd/meson.build                      |   1 +
 app/test-pmd/parameters.c                     |  13 ++
 app/test-pmd/shared_rxq_fwd.c                 | 148 ++++++++++++++++++
 app/test-pmd/testpmd.c                        |  23 ++-
 app/test-pmd/testpmd.h                        |   5 +
 app/test-pmd/util.c                           |   3 +
 doc/guides/nics/features.rst                  |  11 ++
 doc/guides/nics/features/default.ini          |   1 +
 .../prog_guide/switch_representation.rst      |  10 ++
 doc/guides/rel_notes/release_21_11.rst        |   4 +
 doc/guides/testpmd_app_ug/run_app.rst         |   8 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst   |   5 +-
 lib/ethdev/rte_ethdev.c                       |   1 +
 lib/ethdev/rte_ethdev.h                       |   7 +
 15 files changed, 339 insertions(+), 3 deletions(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
Signature · 1 line
2.33.0
author
#112 lore raw

PATCH v5 1/5 ethdev: introduce shared Rx queue

In current DPDK framework, each Rx queue is pre-loaded with mbufs for incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports with same configuration in a switch domain could share Rx queue set by specifying sharing group. Polling any queue using same shared Rx queue receives packets from all member ports. Source port is identified by mbuf->port.

Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group.

Share Rx queue must be polled on single thread or core.

Multiple groups are supported by group ID.

Example grouping and polling model to reflect service priority:
Group0, 2 shared Rx queues per port: PF, rep0, rep1 Group1, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

---
Rx queue object could be used as shared Rx queue object, it's important to clear all queue control callback api that using queue object:
https://mails.dpdk.org/archives/dev/2021-July/215574.html

---
 doc/guides/nics/features.rst                    | 11 +++++++++++
 doc/guides/nics/features/default.ini            |  1 +
 doc/guides/prog_guide/switch_representation.rst | 10 ++++++++++
 doc/guides/rel_notes/release_21_11.rst          |  4 ++++
 lib/ethdev/rte_ethdev.c                         |  1 +
 lib/ethdev/rte_ethdev.h                         |  7 +++++++
 6 files changed, 34 insertions(+)
doc/guides/nics/features.rst +11 -0
index 4fce8cd1c97..69bc1d5719c 100644
@@ -626,6 +626,17 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same switch domain.
+
+* **[uses]     rte_eth_rxconf,rte_eth_rxmode**: ``offloads:RTE_ETH_RX_OFFLOAD_SHARED_RXQ``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index 754184ddd4d..ebeb4c18512 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +10 -0
index ff6aa91c806..47205f5f1cc 100644
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same switch. ``RTE_ETH_RX_OFFLOAD_SHARED_RXQ`` is
+  present in Rx offloading capability of device info. Setting the
+  offloading flag in device Rx mode or Rx queue configuration to enable
+  shared Rx queue. Polling any member port of the shared Rx queue can return
+  packets of all ports in the group, port ID is saved in ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +4 -0
index c0a7f755189..aa6b5e2e9c5 100644
@@ -134,6 +134,10 @@ New Features
   * Added tests to validate packets hard expiry.
   * Added tests to verify tunnel header verification in IPsec inbound.
 
+* **Added ethdev shared Rx queue support. **
+
+  * Added new Rx queue offloading capability flag.
+  * Added share group to Rx queue configuration.
 
 Removed Items
 -------------
lib/ethdev/rte_ethdev.c +1 -0
index fb69f6ea8d1..d78b50e1fa7 100644
@@ -127,6 +127,7 @@ static const struct {
 	RTE_RX_OFFLOAD_BIT2STR(OUTER_UDP_CKSUM),
 	RTE_RX_OFFLOAD_BIT2STR(RSS_HASH),
 	RTE_ETH_RX_OFFLOAD_BIT2STR(BUFFER_SPLIT),
+	RTE_ETH_RX_OFFLOAD_BIT2STR(SHARED_RXQ),
 };
 
 #undef RTE_RX_OFFLOAD_BIT2STR
lib/ethdev/rte_ethdev.h +7 -0
index 39d2cd612cb..b94f7ba5a3f 100644
@@ -1077,6 +1077,7 @@ struct rte_eth_rxconf {
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
 	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	uint32_t shared_group; /**< Shared port group index in switch domain. */
 	/**
 	 * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
 	 * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1403,6 +1404,12 @@ struct rte_eth_conf {
 #define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM  0x00040000
 #define DEV_RX_OFFLOAD_RSS_HASH		0x00080000
 #define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT 0x00100000
+/**
+ * Rx queue is shared among ports in same switch domain to save memory,
+ * avoid polling each port. Any port in the group can be used to receive
+ * packets. Real source port number saved in mbuf->port field.
+ */
+#define RTE_ETH_RX_OFFLOAD_SHARED_RXQ   0x00200000
 
 #define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
 				 DEV_RX_OFFLOAD_UDP_CKSUM | \
Signature · 1 line
2.33.0
author
#113 lore raw

PATCH v5 2/5 app/testpmd: new parameter to enable shared Rx queue

In reply to Xueming Li

Adds "--rxq-share" parameter to enable shared rxq for each rxq.

Default shared rxq group 0 is used, Rx queues in same switch domain shares same rxq according to queue index.

Shared Rx queue is enabled only if device support offloading flag RTE_ETH_RX_OFFLOAD_SHARED_RXQ.

---
 app/test-pmd/config.c                 |  6 +++++-
 app/test-pmd/parameters.c             | 13 +++++++++++++
 app/test-pmd/testpmd.c                | 18 ++++++++++++++++++
 app/test-pmd/testpmd.h                |  2 ++
 doc/guides/testpmd_app_ug/run_app.rst |  7 +++++++
 5 files changed, 45 insertions(+), 1 deletion(-)
app/test-pmd/config.c +5 -1
index 9c66329e96e..6c7f9dee065 100644
@@ -2709,7 +2709,11 @@ rxtx_config_display(void)
 			printf("      RX threshold registers: pthresh=%d hthresh=%d "
 				" wthresh=%d\n",
 				pthresh_tmp, hthresh_tmp, wthresh_tmp);
-			printf("      RX Offloads=0x%"PRIx64"\n", offloads_tmp);
+			printf("      RX Offloads=0x%"PRIx64, offloads_tmp);
+			if (rx_conf->offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ)
+				printf(" share group=%u",
+				       rx_conf->shared_group);
+			printf("\n");
 		}
 
 		/* per tx queue config only for first queue to be less verbose */
app/test-pmd/parameters.c +13 -0
index 3f94a82e321..30dae326310 100644
@@ -167,6 +167,7 @@ usage(char* progname)
 	printf("  --tx-ip=src,dst: IP addresses in Tx-only mode\n");
 	printf("  --tx-udp=src[,dst]: UDP ports in Tx-only mode\n");
 	printf("  --eth-link-speed: force link speed.\n");
+	printf("  --rxq-share: number of ports per shared rxq groups, defaults to MAX(1 group)\n");
 	printf("  --disable-link-check: disable check on link status when "
 	       "starting/stopping ports.\n");
 	printf("  --disable-device-start: do not automatically start port\n");
@@ -607,6 +608,7 @@ launch_args_parse(int argc, char** argv)
 		{ "rxpkts",			1, 0, 0 },
 		{ "txpkts",			1, 0, 0 },
 		{ "txonly-multi-flow",		0, 0, 0 },
+		{ "rxq-share",			2, 0, 0 },
 		{ "eth-link-speed",		1, 0, 0 },
 		{ "disable-link-check",		0, 0, 0 },
 		{ "disable-device-start",	0, 0, 0 },
@@ -1271,6 +1273,17 @@ launch_args_parse(int argc, char** argv)
 			}
 			if (!strcmp(lgopts[opt_idx].name, "txonly-multi-flow"))
 				txonly_multi_flow = 1;
+			if (!strcmp(lgopts[opt_idx].name, "rxq-share")) {
+				if (optarg == NULL) {
+					rxq_share = UINT32_MAX;
+				} else {
+					n = atoi(optarg);
+					if (n >= 0)
+						rxq_share = (uint32_t)n;
+					else
+						rte_exit(EXIT_FAILURE, "rxq-share must be >= 0\n");
+				}
+			}
 			if (!strcmp(lgopts[opt_idx].name, "no-flush-rx"))
 				no_flush_rx = 1;
 			if (!strcmp(lgopts[opt_idx].name, "eth-link-speed")) {
app/test-pmd/testpmd.c +18 -0
index 97ae52e17ec..417e92ade11 100644
@@ -498,6 +498,11 @@ uint8_t record_core_cycles;
  */
 uint8_t record_burst_stats;
 
+/*
+ * Number of ports per shared Rx queue group, 0 disable.
+ */
+uint32_t rxq_share;
+
 unsigned int num_sockets = 0;
 unsigned int socket_ids[RTE_MAX_NUMA_NODES];
 
@@ -1506,6 +1511,11 @@ init_config_port_offloads(portid_t pid, uint32_t socket_id)
 		port->dev_conf.txmode.offloads &=
 			~DEV_TX_OFFLOAD_MBUF_FAST_FREE;
 
+	if (rxq_share > 0 &&
+	    (port->dev_info.rx_offload_capa & RTE_ETH_RX_OFFLOAD_SHARED_RXQ))
+		port->dev_conf.rxmode.offloads |=
+				RTE_ETH_RX_OFFLOAD_SHARED_RXQ;
+
 	/* Apply Rx offloads configuration */
 	for (i = 0; i < port->dev_info.max_rx_queues; i++)
 		port->rx_conf[i].offloads = port->dev_conf.rxmode.offloads;
@@ -3401,6 +3411,14 @@ rxtx_port_config(struct rte_port *port)
 	for (qid = 0; qid < nb_rxq; qid++) {
 		offloads = port->rx_conf[qid].offloads;
 		port->rx_conf[qid] = port->dev_info.default_rxconf;
+
+		if (rxq_share > 0 &&
+		    (port->dev_info.rx_offload_capa &
+		     RTE_ETH_RX_OFFLOAD_SHARED_RXQ)) {
+			offloads |= RTE_ETH_RX_OFFLOAD_SHARED_RXQ;
+			port->rx_conf[qid].shared_group = nb_ports / rxq_share;
+		}
+
 		if (offloads != 0)
 			port->rx_conf[qid].offloads = offloads;
 
app/test-pmd/testpmd.h +2 -0
index 5863b2f43f3..3dfaaad94c0 100644
@@ -477,6 +477,8 @@ extern enum tx_pkt_split tx_pkt_split;
 
 extern uint8_t txonly_multi_flow;
 
+extern uint32_t rxq_share;
+
 extern uint16_t nb_pkt_per_burst;
 extern uint16_t nb_pkt_flowgen_clones;
 extern int nb_flows_flowgen;
doc/guides/testpmd_app_ug/run_app.rst +7 -0
index 640eadeff73..6cfe88951f7 100644
@@ -389,6 +389,13 @@ The command line options are:
 
     Generate multiple flows in txonly mode.
 
+*   ``--rxq-share=[X]``
+
+    Create queues in shared Rx queue mode if device supports.
+    Group number grows per X ports, default to group 0 if X not specified.
+    Only "shared-rxq" forwarding engine suppose to resolve source stream
+    correctly.
+
 *   ``--eth-link-speed``
 
     Set a forced link speed to the ethernet port::
Signature · 1 line
2.33.0
author
#114 lore raw

PATCH v5 3/5 app/testpmd: dump port info for shared Rx queue

In reply to Xueming Li

In case of shared Rx queue, polling any member port returns mbufs for all members. This patch dumps mbuf->port for each packet.

---
 app/test-pmd/util.c | 3 +++
 1 file changed, 3 insertions(+)
app/test-pmd/util.c +3 -0
index 51506e49404..e98f136d5ed 100644
@@ -100,6 +100,9 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
 		struct rte_flow_restore_info info = { 0, };
 
 		mb = pkts[i];
+		if (rxq_share > 0)
+			MKDUMPSTR(print_buf, buf_size, cur_len, "port %u, ",
+				  mb->port);
 		eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
 		eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
 		packet_type = mb->packet_type;
Signature · 1 line
2.33.0
author
#115 lore raw

PATCH v5 4/5 app/testpmd: force shared Rx queue polled on same core

In reply to Xueming Li

Shared rxqs shares one set rx queue of groups zero. Shared Rx queue must must be polled from one core.

Checks and stops forwarding if shared rxq being scheduled on multiple cores.

---
 app/test-pmd/config.c  | 96 ++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.c |  4 +-
 app/test-pmd/testpmd.h |  2 +
 3 files changed, 101 insertions(+), 1 deletion(-)
app/test-pmd/config.c +96 -0
index 6c7f9dee065..4ab500569ee 100644
@@ -2885,6 +2885,102 @@ port_rss_hash_key_update(portid_t port_id, char rss_type[], uint8_t *hash_key,
 	}
 }
 
+/*
+ * Check whether a shared rxq scheduled on other lcores.
+ */
+static bool
+fwd_stream_on_other_lcores(uint16_t domain_id, portid_t src_port,
+			   queueid_t src_rxq, lcoreid_t src_lc,
+			   uint32_t shared_group)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	struct rte_port *port;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	for (lc_id = src_lc + 1; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			port = &ports[fs->rx_port];
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((rxq_conf->offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			if (domain_id != port->dev_info.switch_info.domain_id)
+				continue;
+			if (fs->rx_queue != src_rxq)
+				continue;
+			if (rxq_conf->shared_group != shared_group)
+				continue;
+			printf("Shared Rx queue group %u can't be scheduled on different cores:\n",
+			       shared_group);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       src_lc, src_port, src_rxq);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       lc_id, fs->rx_port, fs->rx_queue);
+			printf("  please use --nb-cores=%hu to limit forwarding cores\n",
+			       nb_rxq);
+			return true;
+		}
+	}
+	return false;
+}
+
+/*
+ * Check shared rxq configuration.
+ *
+ * Shared group must not being scheduled on different core.
+ */
+bool
+pkt_fwd_shared_rxq_check(void)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	uint16_t domain_id;
+	struct rte_port *port;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	/*
+	 * Check streams on each core, make sure the same switch domain +
+	 * group + queue doesn't get scheduled on other cores.
+	 */
+	for (lc_id = 0; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			/* Update lcore info stream being scheduled. */
+			fs->lcore = fwd_lcores[lc_id];
+			port = &ports[fs->rx_port];
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((rxq_conf->offloads & RTE_ETH_RX_OFFLOAD_SHARED_RXQ)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			/* Check shared rxq not scheduled on remaining cores. */
+			domain_id = port->dev_info.switch_info.domain_id;
+			if (fwd_stream_on_other_lcores(domain_id, fs->rx_port,
+						       fs->rx_queue, lc_id,
+						       rxq_conf->shared_group))
+				return false;
+		}
+	}
+	return true;
+}
+
 /*
  * Setup forwarding configuration for each logical core.
  */
app/test-pmd/testpmd.c +3 -1
index 417e92ade11..cab4b36b046 100644
@@ -2241,10 +2241,12 @@ start_packet_forwarding(int with_tx_first)
 
 	fwd_config_setup();
 
+	pkt_fwd_config_display(&cur_fwd_config);
+	if (!pkt_fwd_shared_rxq_check())
+		return;
 	if(!no_flush_rx)
 		flush_fwd_rx_queues();
 
-	pkt_fwd_config_display(&cur_fwd_config);
 	rxtx_config_display();
 
 	fwd_stats_reset();
app/test-pmd/testpmd.h +2 -0
index 3dfaaad94c0..f121a2da90c 100644
@@ -144,6 +144,7 @@ struct fwd_stream {
 	uint64_t     core_cycles; /**< used for RX and TX processing */
 	struct pkt_burst_stats rx_burst_stats;
 	struct pkt_burst_stats tx_burst_stats;
+	struct fwd_lcore *lcore; /**< Lcore being scheduled. */
 };
 
 /**
@@ -795,6 +796,7 @@ void port_summary_header_display(void);
 void rx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void tx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void fwd_lcores_config_display(void);
+bool pkt_fwd_shared_rxq_check(void);
 void pkt_fwd_config_display(struct fwd_config *cfg);
 void rxtx_config_display(void);
 void fwd_config_setup(void);
Signature · 1 line
2.33.0
author
#116 lore raw

PATCH v5 5/5 app/testpmd: add forwarding engine for shared Rx queue

In reply to Xueming Li

To support shared Rx queue, this patch introduces dedicate forwarding engine. The engine groups received packets by mbuf->port into sub-group, updates stream statistics and simply frees packets.

---
 app/test-pmd/meson.build                    |   1 +
 app/test-pmd/shared_rxq_fwd.c               | 148 ++++++++++++++++++++
 app/test-pmd/testpmd.c                      |   1 +
 app/test-pmd/testpmd.h                      |   1 +
 doc/guides/testpmd_app_ug/run_app.rst       |   1 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |   5 +-
 6 files changed, 156 insertions(+), 1 deletion(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
app/test-pmd/meson.build +1 -0
index 98f3289bdfa..07042e45b12 100644
@@ -21,6 +21,7 @@ sources = files(
         'noisy_vnf.c',
         'parameters.c',
         'rxonly.c',
+        'shared_rxq_fwd.c',
         'testpmd.c',
         'txonly.c',
         'util.c',
app/test-pmd/shared_rxq_fwd.c new file +148 -0

148 lines not on this page · raw message

app/test-pmd/testpmd.c +1 -0
index cab4b36b046..681ea591871 100644
@@ -188,6 +188,7 @@ struct fwd_engine * fwd_engines[] = {
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
+	&shared_rxq_engine,
 	NULL,
 };
 
app/test-pmd/testpmd.h +1 -0
index f121a2da90c..f1fd607e365 100644
@@ -299,6 +299,7 @@ extern struct fwd_engine five_tuple_swap_fwd_engine;
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
+extern struct fwd_engine shared_rxq_engine;
 
 extern struct fwd_engine * fwd_engines[]; /**< NULL terminated array. */
 extern cmdline_parse_inst_t cmd_set_raw;
doc/guides/testpmd_app_ug/run_app.rst +1 -0
index 6cfe88951f7..277ef79ed9d 100644
@@ -252,6 +252,7 @@ The command line options are:
        tm
        noisy
        5tswap
+       shared-rxq
 
 *   ``--rss-ip``
 
doc/guides/testpmd_app_ug/testpmd_funcs.rst +4 -1
index bbef7063741..a30e2f4dfae 100644
@@ -314,7 +314,7 @@ set fwd
 Set the packet forwarding mode::
 
    testpmd> set fwd (io|mac|macswap|flowgen| \
-                     rxonly|txonly|csum|icmpecho|noisy|5tswap) (""|retry)
+                     rxonly|txonly|csum|icmpecho|noisy|5tswap|shared-rxq) (""|retry)
 
 ``retry`` can be specified for forwarding engines except ``rx_only``.
 
@@ -357,6 +357,9 @@ The available information categories are:
 
   L4 swaps the source port and destination port of transport layer (TCP and UDP).
 
+* ``shared-rxq``: Receive only for shared Rx queue.
+  Resolve packet source port from mbuf and update stream statistics accrodingly.
+
 Example::
 
    testpmd> set fwd rxonly
Signature · 1 line
2.33.0
author
#117 lore raw

v6 cover ethdev: introduce shared Rx queue

In reply to Xueming Li

In current DPDK framework, all Rx queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared Rx queue. PF and representors in same Rx domain and switch domain could share Rx queue set by specifying non-zero share group value in Rx queue configuration.

All ports that share Rx queue actually shares hardware descriptor queue and feed all Rx queues with one descriptor supply, memory is saved.

Polling any queue using same shared Rx queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of two share groups:
Group1, 4 shared Rx queues per member port: PF, repr0, repr1 Group2, 2 shared Rx queues per member port: repr2, repr3, ... repr127 Poll first port for each group:
core port queue
0 0 0
1 0 1
2 0 2
3 0 3
4 2 0
5 2 1

Shared Rx queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

There was some discussion to aggregate member ports in same group into a dummy port, several ways to achieve it. Since it optional, need to collect more feedback and requirement from user, make better decision later.

v1:
- initial version
v2:
- add testpmd patches
v3:
- change common forwarding api to macro for performance, thanks Jerin.
- save global variable accessed in forwarding to flowstream to minimize cache miss
- combined patches for each forwarding engine
- support multiple groups in testpmd "--share-rxq" parameter
- new api to aggregate shared rxq group
v4:
- spelling fixes
- remove shared-rxq support for all forwarding engines
- add dedicate shared-rxq forwarding engine
v5:
- fix grammars
- remove aggregate api and leave it for later discussion
- add release notes
- add deployment example
v6:
- replace RxQ offload flag with device offload capability flag
- add Rx domain
- RxQ is shared when share group > 0
- update testpmd accordingly

Xueming Li (5):
ethdev: introduce shared Rx queue app/testpmd: new parameter to enable shared Rx queue app/testpmd: dump port info for shared Rx queue app/testpmd: force shared Rx queue polled on same core app/testpmd: add forwarding engine for shared Rx queue

 app/test-pmd/config.c                         | 106 ++++++++++++-
 app/test-pmd/meson.build                      |   1 +
 app/test-pmd/parameters.c                     |  13 ++
 app/test-pmd/shared_rxq_fwd.c                 | 148 ++++++++++++++++++
 app/test-pmd/testpmd.c                        |  17 +-
 app/test-pmd/testpmd.h                        |   5 +
 app/test-pmd/util.c                           |   3 +
 doc/guides/nics/features.rst                  |  13 ++
 doc/guides/nics/features/default.ini          |   1 +
 .../prog_guide/switch_representation.rst      |  10 ++
 doc/guides/rel_notes/release_21_11.rst        |   5 +
 doc/guides/testpmd_app_ug/run_app.rst         |   8 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst   |   5 +-
 lib/ethdev/rte_ethdev.c                       |   9 ++
 lib/ethdev/rte_ethdev.h                       |  21 +++
 15 files changed, 362 insertions(+), 3 deletions(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
Signature · 1 line
2.33.0
author
#118 lore raw

PATCH v6 1/5 ethdev: introduce shared Rx queue

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, source port is identified by mbuf->port.

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

Multiple share groups are supported by non-zero share group ID. Device should support mixed configuration by allowing multiple share groups and non-shared Rx queue.

Even Rx queue shared, queue configuration like offloads and RSS should not be impacted.

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

PMD driver advertise shared Rx queue capability via RTE_ETH_DEV_CAPA_RXQ_SHARE.

PMD driver is responsible for shared Rx queue consistency checks to avoid member port's configuration contradict to each other.

---
 doc/guides/nics/features.rst                  | 13 ++++++++++++
 doc/guides/nics/features/default.ini          |  1 +
 .../prog_guide/switch_representation.rst      | 10 +++++++++
 doc/guides/rel_notes/release_21_11.rst        |  5 +++++
 lib/ethdev/rte_ethdev.c                       |  9 ++++++++
 lib/ethdev/rte_ethdev.h                       | 21 +++++++++++++++++++
 6 files changed, 59 insertions(+)
doc/guides/nics/features.rst +13 -0
index e346018e4b8..b64433b8ea5 100644
@@ -615,6 +615,19 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same Rx domain of a switch domain.
+
+* **[uses]     rte_eth_dev_info**: ``dev_capa:RTE_ETH_DEV_CAPA_RXQ_SHARE``.
+* **[uses]     rte_eth_dev_info,rte_eth_switch_info**: ``rx_domain``, ``domain_id``.
+* **[uses]     rte_eth_rxconf**: ``share_group``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index d473b94091a..93f5d1b46f4 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +10 -0
index ff6aa91c806..de41db8385d 100644
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same Rx domain. ``RTE_ETH_DEV_CAPA_RXQ_SHARE`` is
+  present in device capability of device info. Setting non-zero share group
+  in Rx queue configuration to enable share. Polling any member port can
+  receive packets of all member ports in the group, port ID is saved in
+  ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +5 -0
index 5036641842c..d72fc97f4fb 100644
@@ -141,6 +141,11 @@ New Features
   * Added tests to validate packets hard expiry.
   * Added tests to verify tunnel header verification in IPsec inbound.
 
+* **Added ethdev shared Rx queue support.**
+
+  * Added new device capability flag and rx domain field to switch info.
+  * Added share group to Rx queue configuration.
+  * Added testpmd support and dedicate forwarding engine.
 
 Removed Items
 -------------
lib/ethdev/rte_ethdev.c +9 -0
index 028907bc4b9..9b1b66370a7 100644
@@ -2159,6 +2159,15 @@ rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
 		return -EINVAL;
 	}
 
+	if (local_conf.share_group > 0 &&
+	    (dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) == 0) {
+		RTE_ETHDEV_LOG(ERR,
+			"Ethdev port_id=%d rx_queue_id=%d, enabled share_group=%u while device doesn't support Rx queue share in %s()\n",
+			port_id, rx_queue_id, local_conf.share_group,
+			__func__);
+		return -EINVAL;
+	}
+
 	/*
 	 * If LRO is enabled, check that the maximum aggregated packet
 	 * size is supported by the configured device.
lib/ethdev/rte_ethdev.h +21 -0
index 6d80514ba7a..041da6ee52f 100644
@@ -1044,6 +1044,13 @@ struct rte_eth_rxconf {
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
 	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	/**
+	 * Share group index in Rx domain and switch domain.
+	 * Non-zero value to enable Rx queue share, zero value disable share.
+	 * PMD driver is responsible for Rx queue consistency checks to avoid
+	 * member port's configuration contradict to each other.
+	 */
+	uint32_t share_group;
 	/**
 	 * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
 	 * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1445,6 +1452,14 @@ struct rte_eth_conf {
 #define RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP 0x00000001
 /** Device supports Tx queue setup after device started. */
 #define RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP 0x00000002
+/**
+ * Device supports shared Rx queue among ports within Rx domain and
+ * switch domain. Mbufs are consumed by shared Rx queue instead of
+ * every port. Multiple groups is supported by share_group of Rx
+ * queue configuration. Polling any port in the group receive packets
+ * of all member ports, source port identified by mbuf->port field.
+ */
+#define RTE_ETH_DEV_CAPA_RXQ_SHARE              0x00000004
 /**@}*/
 
 /*
@@ -1488,6 +1503,12 @@ struct rte_eth_switch_info {
 	 * but each driver should explicitly define the mapping of switch
 	 * port identifier to that physical interconnect/switch
 	 */
+	uint16_t rx_domain;
+	/**<
+	 * Shared Rx queue sub-domain boundary. Only ports in same Rx domain
+	 * and switch domain can share Rx queue. Valid only if device advertised
+	 * RTE_ETH_DEV_CAPA_RXQ_SHARE capability.
+	 */
 };
 
 /**
Signature · 1 line
2.33.0
#119 lore raw
Quoted 10 lines · Xueming Li

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Quoted 8 lines

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, source port is identified by mbuf->port.

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

Multiple share groups are supported by non-zero share group ID. Device

"by non-zero share group ID" is not required. Since it must be always non-zero to enable sharing.

Quoted 5 lines

should support mixed configuration by allowing multiple share groups and non-shared Rx queue.

Even Rx queue shared, queue configuration like offloads and RSS should not be impacted.

I don't understand above sentence.
Even when Rx queues are shared, queue configuration like offloads and RSS may differ. If a PMD has some limitation, it should care about consistency itself. These limitations should be documented in the PMD documentation.

Quoted 7 lines

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

Can I have:
PF RxQ#0, RxQ#1
Rep0 RxQ#0 shared with PF RxQ#0
Rep1 RxQ#0 shared with PF RxQ#1

I guess no, since it looks like RxQ ID must be equal. Or am I missing something? Otherwise grouping rules are not obvious to me. May be we need dedicated shared_qid in boundaries of the share_group?

Quoted 79 lines

PMD driver advertise shared Rx queue capability via RTE_ETH_DEV_CAPA_RXQ_SHARE.

PMD driver is responsible for shared Rx queue consistency checks to avoid member port's configuration contradict to each other.

---
 doc/guides/nics/features.rst                  | 13 ++++++++++++
 doc/guides/nics/features/default.ini          |  1 +
 .../prog_guide/switch_representation.rst      | 10 +++++++++
 doc/guides/rel_notes/release_21_11.rst        |  5 +++++
 lib/ethdev/rte_ethdev.c                       |  9 ++++++++
 lib/ethdev/rte_ethdev.h                       | 21 +++++++++++++++++++
 6 files changed, 59 insertions(+)
doc/guides/nics/features.rst +13 -0
index e346018e4b8..b64433b8ea5 100644
@@ -615,6 +615,19 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same Rx domain of a switch domain.
+
+* **[uses]     rte_eth_dev_info**: ``dev_capa:RTE_ETH_DEV_CAPA_RXQ_SHARE``.
+* **[uses]     rte_eth_dev_info,rte_eth_switch_info**: ``rx_domain``, ``domain_id``.
+* **[uses]     rte_eth_rxconf**: ``share_group``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index d473b94091a..93f5d1b46f4 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +10 -0
index ff6aa91c806..de41db8385d 100644
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same Rx domain. ``RTE_ETH_DEV_CAPA_RXQ_SHARE`` is
+  present in device capability of device info. Setting non-zero share group
+  in Rx queue configuration to enable share. Polling any member port can
+  receive packets of all member ports in the group, port ID is saved in
+  ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +0 -0
index 5036641842c..d72fc97f4fb 100644

doc/guides/rel_notes/release_21_11.rst New Features · line 148

Quoted 8 lines
doc/guides/rel_notes/release_21_11.rst +5 -0
@@ -141,6 +141,11 @@ New Features
   * Added tests to validate packets hard expiry.
   * Added tests to verify tunnel header verification in IPsec inbound.
 
+* **Added ethdev shared Rx queue support.**
+
+  * Added new device capability flag and rx domain field to switch info.
+  * Added share group to Rx queue configuration.
+  * Added testpmd support and dedicate forwarding engine.

Please, add one more empty line since it must be two before the next section. Also it should be put after the last ethdev item above since list of features has defined order.

Quoted 8 lines
doc/guides/rel_notes/release_21_11.rst +0 -0
 Removed Items
 -------------
lib/ethdev/rte_ethdev.c +0 -0
index 028907bc4b9..9b1b66370a7 100644

lib/ethdev/rte_ethdev.c rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id, · line 2167

Quoted 9 lines
lib/ethdev/rte_ethdev.c +6 -0
@@ -2159,6 +2159,15 @@ rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
 		return -EINVAL;
 	}
 
+	if (local_conf.share_group > 0 &&
+	    (dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) == 0) {
+		RTE_ETHDEV_LOG(ERR,
+			"Ethdev port_id=%d rx_queue_id=%d, enabled share_group=%u while device doesn't support Rx queue share in %s()\n",
+			port_id, rx_queue_id, local_conf.share_group,
+			__func__);

I'd remove function name logging here. Log is unique enough.

Quoted 11 lines
lib/ethdev/rte_ethdev.c +3 -0
+		return -EINVAL;
+	}
+
 	/*
 	 * If LRO is enabled, check that the maximum aggregated packet
 	 * size is supported by the configured device.
lib/ethdev/rte_ethdev.h +0 -0
index 6d80514ba7a..041da6ee52f 100644

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1053

Quoted 10 lines
lib/ethdev/rte_ethdev.h +7 -0
@@ -1044,6 +1044,13 @@ struct rte_eth_rxconf {
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
 	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	/**
+	 * Share group index in Rx domain and switch domain.
+	 * Non-zero value to enable Rx queue share, zero value disable share.
+	 * PMD driver is responsible for Rx queue consistency checks to avoid
+	 * member port's configuration contradict to each other.
+	 */
+	uint32_t share_group;

I think that we don't need 32-bit for shared groups. 16-bits sounds more than enough.

Quoted 5 lines
lib/ethdev/rte_ethdev.h +0 -0
 	/**
 	 * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
 	 * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1445,6 +1452,14 @@ struct rte_eth_conf {
 #define RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP 0x00000001

lib/ethdev/rte_ethdev.h struct rte_eth_conf { · line 1462

Quoted 10 lines
lib/ethdev/rte_ethdev.h +8 -0
 /** Device supports Tx queue setup after device started. */
 #define RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP 0x00000002
+/**
+ * Device supports shared Rx queue among ports within Rx domain and
+ * switch domain. Mbufs are consumed by shared Rx queue instead of
+ * every port. Multiple groups is supported by share_group of Rx
+ * queue configuration. Polling any port in the group receive packets
+ * of all member ports, source port identified by mbuf->port field.
+ */
+#define RTE_ETH_DEV_CAPA_RXQ_SHARE              0x00000004

Let's use RTE_BIT64(2)

I think above two should be fixed in a separate cleanup patch.

lib/ethdev/rte_ethdev.h struct rte_eth_switch_info { · line 1511

Quoted 13 lines
lib/ethdev/rte_ethdev.h +6 -0
 /**@}*/
 
 /*
@@ -1488,6 +1503,12 @@ struct rte_eth_switch_info {
 	 * but each driver should explicitly define the mapping of switch
 	 * port identifier to that physical interconnect/switch
 	 */
+	uint16_t rx_domain;
+	/**<
+	 * Shared Rx queue sub-domain boundary. Only ports in same Rx domain
+	 * and switch domain can share Rx queue. Valid only if device advertised
+	 * RTE_ETH_DEV_CAPA_RXQ_SHARE capability.
+	 */

Please, put the documentation before the documented field.

[snip]

#120 lore raw
Quoted 26 lines · Andrew Rybchenko
Quoted 10 lines · Xueming Li

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Quoted 8 lines

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, source port is identified by mbuf->port.

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

Multiple share groups are supported by non-zero share group ID. Device

"by non-zero share group ID" is not required. Since it must be always non-zero to enable sharing.

Quoted 3 lines

should support mixed configuration by allowing multiple share groups and non-shared Rx queue.

Quoted 9 lines
Quoted 2 lines

Even Rx queue shared, queue configuration like offloads and RSS should not be impacted.

I don't understand above sentence.
Even when Rx queues are shared, queue configuration like offloads and RSS may differ. If a PMD has some limitation, it should care about consistency itself. These limitations should be documented in the PMD documentation.

OK, I'll remove this line.

Quoted 14 lines
Quoted 7 lines

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

Can I have:
PF RxQ#0, RxQ#1
Rep0 RxQ#0 shared with PF RxQ#0
Rep1 RxQ#0 shared with PF RxQ#1

Quoted 4 lines

I guess no, since it looks like RxQ ID must be equal. Or am I missing something? Otherwise grouping rules are not obvious to me. May be we need dedicated shared_qid in boundaries of the share_group?

Yes, RxQ ID must be equal, following configuration should work:
Rep1 RxQ#1 shared with PF RxQ#1
Equal mapping should work by default instead of a new field that must be set. I'll add some description to emphasis, how do you think?

Quoted 157 lines
Quoted 80 lines

PMD driver advertise shared Rx queue capability via RTE_ETH_DEV_CAPA_RXQ_SHARE.

PMD driver is responsible for shared Rx queue consistency checks to avoid member port's configuration contradict to each other.

---
 doc/guides/nics/features.rst                  | 13 ++++++++++++
 doc/guides/nics/features/default.ini          |  1 +
 .../prog_guide/switch_representation.rst      | 10 +++++++++
 doc/guides/rel_notes/release_21_11.rst        |  5 +++++
 lib/ethdev/rte_ethdev.c                       |  9 ++++++++
 lib/ethdev/rte_ethdev.h                       | 21 +++++++++++++++++++
 6 files changed, 59 insertions(+)
doc/guides/nics/features.rst +13 -0
index e346018e4b8..b64433b8ea5 100644
@@ -615,6 +615,19 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same Rx domain of a switch domain.
+
+* **[uses]     rte_eth_dev_info**: ``dev_capa:RTE_ETH_DEV_CAPA_RXQ_SHARE``.
+* **[uses]     rte_eth_dev_info,rte_eth_switch_info**: ``rx_domain``, ``domain_id``.
+* **[uses]     rte_eth_rxconf**: ``share_group``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index d473b94091a..93f5d1b46f4 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +10 -0
index ff6aa91c806..de41db8385d 100644
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same Rx domain. ``RTE_ETH_DEV_CAPA_RXQ_SHARE`` is
+  present in device capability of device info. Setting non-zero share group
+  in Rx queue configuration to enable share. Polling any member port can
+  receive packets of all member ports in the group, port ID is saved in
+  ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +0 -0
index 5036641842c..d72fc97f4fb 100644

doc/guides/rel_notes/release_21_11.rst New Features · line 148

Quoted 8 lines
doc/guides/rel_notes/release_21_11.rst +5 -0
@@ -141,6 +141,11 @@ New Features
   * Added tests to validate packets hard expiry.
   * Added tests to verify tunnel header verification in IPsec inbound.
 
+* **Added ethdev shared Rx queue support.**
+
+  * Added new device capability flag and rx domain field to switch info.
+  * Added share group to Rx queue configuration.
+  * Added testpmd support and dedicate forwarding engine.

Please, add one more empty line since it must be two before the next section. Also it should be put after the last ethdev item above since list of features has defined order.

Quoted 8 lines
doc/guides/rel_notes/release_21_11.rst +0 -0
 Removed Items
 -------------
lib/ethdev/rte_ethdev.c +0 -0
index 028907bc4b9..9b1b66370a7 100644

lib/ethdev/rte_ethdev.c rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id, · line 2167

Quoted 9 lines
lib/ethdev/rte_ethdev.c +6 -0
@@ -2159,6 +2159,15 @@ rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
 		return -EINVAL;
 	}
 
+	if (local_conf.share_group > 0 &&
+	    (dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) == 0) {
+		RTE_ETHDEV_LOG(ERR,
+			"Ethdev port_id=%d rx_queue_id=%d, enabled share_group=%u while device doesn't support Rx queue share in %s()\n",
+			port_id, rx_queue_id, local_conf.share_group,
+			__func__);

I'd remove function name logging here. Log is unique enough.

Quoted 11 lines
lib/ethdev/rte_ethdev.c +3 -0
+		return -EINVAL;
+	}
+
 	/*
 	 * If LRO is enabled, check that the maximum aggregated packet
 	 * size is supported by the configured device.
lib/ethdev/rte_ethdev.h +0 -0
index 6d80514ba7a..041da6ee52f 100644

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1053

Quoted 10 lines
lib/ethdev/rte_ethdev.h +7 -0
@@ -1044,6 +1044,13 @@ struct rte_eth_rxconf {
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
 	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	/**
+	 * Share group index in Rx domain and switch domain.
+	 * Non-zero value to enable Rx queue share, zero value disable share.
+	 * PMD driver is responsible for Rx queue consistency checks to avoid
+	 * member port's configuration contradict to each other.
+	 */
+	uint32_t share_group;

I think that we don't need 32-bit for shared groups. 16-bits sounds more than enough.

Quoted 5 lines
lib/ethdev/rte_ethdev.h +0 -0
 	/**
 	 * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
 	 * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1445,6 +1452,14 @@ struct rte_eth_conf {
 #define RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP 0x00000001

lib/ethdev/rte_ethdev.h struct rte_eth_conf { · line 1462

Quoted 10 lines
lib/ethdev/rte_ethdev.h +8 -0
 /** Device supports Tx queue setup after device started. */
 #define RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP 0x00000002
+/**
+ * Device supports shared Rx queue among ports within Rx domain and
+ * switch domain. Mbufs are consumed by shared Rx queue instead of
+ * every port. Multiple groups is supported by share_group of Rx
+ * queue configuration. Polling any port in the group receive packets
+ * of all member ports, source port identified by mbuf->port field.
+ */
+#define RTE_ETH_DEV_CAPA_RXQ_SHARE              0x00000004

Let's use RTE_BIT64(2)

Quoted 2 lines

I think above two should be fixed in a separate cleanup patch.

Not only above two, more Rx/Tx offload bits to cleanup, let's do it later.

Quoted 19 lines
Quoted 5 lines
lib/ethdev/rte_ethdev.h +0 -0
 /**@}*/
 
 /*

lib/ethdev/rte_ethdev.h struct rte_eth_switch_info { · line 1511

Quoted 9 lines
lib/ethdev/rte_ethdev.h +6 -0
@@ -1488,6 +1503,12 @@ struct rte_eth_switch_info {
 	 * but each driver should explicitly define the mapping of switch
 	 * port identifier to that physical interconnect/switch
 	 */
+	uint16_t rx_domain;
+	/**<
+	 * Shared Rx queue sub-domain boundary. Only ports in same Rx domain
+	 * and switch domain can share Rx queue. Valid only if device advertised
+	 * RTE_ETH_DEV_CAPA_RXQ_SHARE capability.
+	 */

Please, put the documentation before the documented field.

[snip]

#121 lore raw
Quoted 53 lines · Xueming(Steven) Li
Quoted 26 lines · Andrew Rybchenko
Quoted 10 lines · Xueming Li

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Quoted 8 lines

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, source port is identified by mbuf->port.

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

Multiple share groups are supported by non-zero share group ID. Device

"by non-zero share group ID" is not required. Since it must be always non-zero to enable sharing.

Quoted 3 lines

should support mixed configuration by allowing multiple share groups and non-shared Rx queue.

Quoted 9 lines
Quoted 2 lines

Even Rx queue shared, queue configuration like offloads and RSS should not be impacted.

I don't understand above sentence.
Even when Rx queues are shared, queue configuration like offloads and RSS may differ. If a PMD has some limitation, it should care about consistency itself. These limitations should be documented in the PMD documentation.

OK, I'll remove this line.

Quoted 14 lines
Quoted 7 lines

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

Can I have:
PF RxQ#0, RxQ#1
Rep0 RxQ#0 shared with PF RxQ#0
Rep1 RxQ#0 shared with PF RxQ#1

Quoted 7 lines
Quoted 4 lines

I guess no, since it looks like RxQ ID must be equal. Or am I missing something? Otherwise grouping rules are not obvious to me. May be we need dedicated shared_qid in boundaries of the share_group?

Yes, RxQ ID must be equal, following configuration should work:
Rep1 RxQ#1 shared with PF RxQ#1

But I want just one RxQ on Rep1. I don't need two.

Quoted 2 lines

Equal mapping should work by default instead of a new field that must be set. I'll add some description to emphasis, how do you think?

Sorry for delay with reply. I think that above limitation is not nice. It is better to avoid it.

[snip]

#122 lore raw
Quoted 62 lines · Andrew Rybchenko
Quoted 53 lines · Xueming(Steven) Li
Quoted 26 lines · Andrew Rybchenko
Quoted 10 lines · Xueming Li

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Quoted 8 lines

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, source port is identified by mbuf->port.

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

Multiple share groups are supported by non-zero share group ID. Device

"by non-zero share group ID" is not required. Since it must be always non-zero to enable sharing.

Quoted 3 lines

should support mixed configuration by allowing multiple share groups and non-shared Rx queue.

Quoted 9 lines
Quoted 2 lines

Even Rx queue shared, queue configuration like offloads and RSS should not be impacted.

I don't understand above sentence.
Even when Rx queues are shared, queue configuration like offloads and RSS may differ. If a PMD has some limitation, it should care about consistency itself. These limitations should be documented in the PMD documentation.

OK, I'll remove this line.

Quoted 14 lines
Quoted 7 lines

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

Can I have:
PF RxQ#0, RxQ#1
Rep0 RxQ#0 shared with PF RxQ#0
Rep1 RxQ#0 shared with PF RxQ#1

Quoted 7 lines
Quoted 4 lines

I guess no, since it looks like RxQ ID must be equal. Or am I missing something? Otherwise grouping rules are not obvious to me. May be we need dedicated shared_qid in boundaries of the share_group?

Yes, RxQ ID must be equal, following configuration should work:
Rep1 RxQ#1 shared with PF RxQ#1

Quoted 7 lines

But I want just one RxQ on Rep1. I don't need two.

Quoted 2 lines

Equal mapping should work by default instead of a new field that must be set. I'll add some description to emphasis, how do you think?

Sorry for delay with reply. I think that above limitation is not nice. It is better to avoid it.

Okay, it will offer more flexibility. I will add in next version. User has to be aware the indirect mapping relation, the following polling in above example rx burt the same shared RxQ:
PF RxQ#1
Rep1 RxQ#0 shared with PF RxQ#1

Quoted 2 lines

[snip]

#123 lore raw
In reply to Xueming Li

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1050

Quoted 11 lines · Xueming Li

index 6d80514ba7a..041da6ee52f 100644

lib/ethdev/rte_ethdev.h +4 -0
@@ -1044,6 +1044,13 @@ struct rte_eth_rxconf {
  	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
  	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
  	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	/**
+	 * Share group index in Rx domain and switch domain.
+	 * Non-zero value to enable Rx queue share, zero value disable share.
+	 * PMD driver is responsible for Rx queue consistency checks to avoid

When you update the set, can you please update 'PMD driver' usage too?

PMD = Poll Mode Driver, so second 'driver' is duplicate, there are a few more instance of this usage in this set.

#124 lore raw
Quoted 15 lines · Ferruh Yigit

lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1050

Quoted 11 lines · Xueming Li

index 6d80514ba7a..041da6ee52f 100644

lib/ethdev/rte_ethdev.h +4 -0
@@ -1044,6 +1044,13 @@ struct rte_eth_rxconf {
  	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
  	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
  	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	/**
+	 * Share group index in Rx domain and switch domain.
+	 * Non-zero value to enable Rx queue share, zero value disable share.
+	 * PMD driver is responsible for Rx queue consistency checks to avoid

When you update the set, can you please update 'PMD driver' usage too?

Quoted 2 lines

PMD = Poll Mode Driver, so second 'driver' is duplicate, there are a few more instance of this usage in this set.

Got it, thanks!

BTW, PMD patches updated:
https://patches.dpdk.org/project/dpdk/list/?series=19709

author
#125 lore raw

PATCH v6 2/5 app/testpmd: new parameter to enable shared Rx queue

In reply to Xueming Li

Adds "--rxq-share=X" parameter to enable shared RxQ, share if device supports, otherwise fallback to standard RxQ.

Share group number grows per X ports. X defaults to MAX, implies all ports join share group 1.

Forwarding engine "shared-rxq" should be used which Rx only and update stream statistics correctly.

---
 app/test-pmd/config.c                 |  6 +++++-
 app/test-pmd/parameters.c             | 13 +++++++++++++
 app/test-pmd/testpmd.c                | 12 ++++++++++++
 app/test-pmd/testpmd.h                |  2 ++
 doc/guides/testpmd_app_ug/run_app.rst |  7 +++++++
 5 files changed, 39 insertions(+), 1 deletion(-)
app/test-pmd/config.c +5 -1
index 9c66329e96e..96fc2ab888b 100644
@@ -2709,7 +2709,11 @@ rxtx_config_display(void)
 			printf("      RX threshold registers: pthresh=%d hthresh=%d "
 				" wthresh=%d\n",
 				pthresh_tmp, hthresh_tmp, wthresh_tmp);
-			printf("      RX Offloads=0x%"PRIx64"\n", offloads_tmp);
+			printf("      RX Offloads=0x%"PRIx64, offloads_tmp);
+			if (rx_conf->share_group > 0)
+				printf(" share group=%u",
+				       rx_conf->share_group);
+			printf("\n");
 		}
 
 		/* per tx queue config only for first queue to be less verbose */
app/test-pmd/parameters.c +13 -0
index 3f94a82e321..30dae326310 100644
@@ -167,6 +167,7 @@ usage(char* progname)
 	printf("  --tx-ip=src,dst: IP addresses in Tx-only mode\n");
 	printf("  --tx-udp=src[,dst]: UDP ports in Tx-only mode\n");
 	printf("  --eth-link-speed: force link speed.\n");
+	printf("  --rxq-share: number of ports per shared rxq groups, defaults to MAX(1 group)\n");
 	printf("  --disable-link-check: disable check on link status when "
 	       "starting/stopping ports.\n");
 	printf("  --disable-device-start: do not automatically start port\n");
@@ -607,6 +608,7 @@ launch_args_parse(int argc, char** argv)
 		{ "rxpkts",			1, 0, 0 },
 		{ "txpkts",			1, 0, 0 },
 		{ "txonly-multi-flow",		0, 0, 0 },
+		{ "rxq-share",			2, 0, 0 },
 		{ "eth-link-speed",		1, 0, 0 },
 		{ "disable-link-check",		0, 0, 0 },
 		{ "disable-device-start",	0, 0, 0 },
@@ -1271,6 +1273,17 @@ launch_args_parse(int argc, char** argv)
 			}
 			if (!strcmp(lgopts[opt_idx].name, "txonly-multi-flow"))
 				txonly_multi_flow = 1;
+			if (!strcmp(lgopts[opt_idx].name, "rxq-share")) {
+				if (optarg == NULL) {
+					rxq_share = UINT32_MAX;
+				} else {
+					n = atoi(optarg);
+					if (n >= 0)
+						rxq_share = (uint32_t)n;
+					else
+						rte_exit(EXIT_FAILURE, "rxq-share must be >= 0\n");
+				}
+			}
 			if (!strcmp(lgopts[opt_idx].name, "no-flush-rx"))
 				no_flush_rx = 1;
 			if (!strcmp(lgopts[opt_idx].name, "eth-link-speed")) {
app/test-pmd/testpmd.c +12 -0
index 97ae52e17ec..9c26301d397 100644
@@ -498,6 +498,11 @@ uint8_t record_core_cycles;
  */
 uint8_t record_burst_stats;
 
+/*
+ * Number of ports per shared Rx queue group, 0 disable.
+ */
+uint32_t rxq_share;
+
 unsigned int num_sockets = 0;
 unsigned int socket_ids[RTE_MAX_NUMA_NODES];
 
@@ -3401,6 +3406,13 @@ rxtx_port_config(struct rte_port *port)
 	for (qid = 0; qid < nb_rxq; qid++) {
 		offloads = port->rx_conf[qid].offloads;
 		port->rx_conf[qid] = port->dev_info.default_rxconf;
+
+		if (rxq_share > 0 &&
+		    (port->dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE))
+			/* Non-zero share group to enable RxQ share. */
+			port->rx_conf[qid].share_group = nb_ports / rxq_share
+							 + 1;
+
 		if (offloads != 0)
 			port->rx_conf[qid].offloads = offloads;
 
app/test-pmd/testpmd.h +2 -0
index 5863b2f43f3..3dfaaad94c0 100644
@@ -477,6 +477,8 @@ extern enum tx_pkt_split tx_pkt_split;
 
 extern uint8_t txonly_multi_flow;
 
+extern uint32_t rxq_share;
+
 extern uint16_t nb_pkt_per_burst;
 extern uint16_t nb_pkt_flowgen_clones;
 extern int nb_flows_flowgen;
doc/guides/testpmd_app_ug/run_app.rst +7 -0
index 640eadeff73..ff5908dcd50 100644
@@ -389,6 +389,13 @@ The command line options are:
 
     Generate multiple flows in txonly mode.
 
+*   ``--rxq-share=[X]``
+
+    Create queues in shared Rx queue mode if device supports.
+    Group number grows per X ports. X defaults to MAX, implies all ports
+    join share group 1. Forwarding engine "shared-rxq" should be used
+    which Rx only and update stream statistics correctly.
+
 *   ``--eth-link-speed``
 
     Set a forced link speed to the ethernet port::
Signature · 1 line
2.33.0
author
#126 lore raw

PATCH v6 3/5 app/testpmd: dump port info for shared Rx queue

In reply to Xueming Li

In case of shared Rx queue, polling any member port returns mbufs for all members. This patch dumps mbuf->port for each packet.

---
 app/test-pmd/util.c | 3 +++
 1 file changed, 3 insertions(+)
app/test-pmd/util.c +3 -0
index 51506e49404..e98f136d5ed 100644
@@ -100,6 +100,9 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
 		struct rte_flow_restore_info info = { 0, };
 
 		mb = pkts[i];
+		if (rxq_share > 0)
+			MKDUMPSTR(print_buf, buf_size, cur_len, "port %u, ",
+				  mb->port);
 		eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
 		eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
 		packet_type = mb->packet_type;
Signature · 1 line
2.33.0
author
#127 lore raw

PATCH v6 4/5 app/testpmd: force shared Rx queue polled on same core

In reply to Xueming Li

Shared Rx queue must be polled on same core. This patch checks and stops forwarding if shared RxQ being scheduled on multiple
cores.

It's suggested to use same number of Rx queues and polling cores.

---
 app/test-pmd/config.c  | 100 +++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.c |   4 +-
 app/test-pmd/testpmd.h |   2 +
 3 files changed, 105 insertions(+), 1 deletion(-)
app/test-pmd/config.c +100 -0
index 96fc2ab888b..9acd2705f18 100644
@@ -2885,6 +2885,106 @@ port_rss_hash_key_update(portid_t port_id, char rss_type[], uint8_t *hash_key,
 	}
 }
 
+/*
+ * Check whether a shared rxq scheduled on other lcores.
+ */
+static bool
+fwd_stream_on_other_lcores(uint16_t domain_id, portid_t src_port,
+			   queueid_t src_rxq, lcoreid_t src_lc,
+			   uint32_t share_group)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	struct rte_port *port;
+	struct rte_eth_dev_info *dev_info;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	for (lc_id = src_lc + 1; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			port = &ports[fs->rx_port];
+			dev_info = &port->dev_info;
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			if (domain_id != port->dev_info.switch_info.domain_id)
+				continue;
+			if (fs->rx_queue != src_rxq)
+				continue;
+			if (rxq_conf->share_group != share_group)
+				continue;
+			printf("Shared Rx queue group %u can't be scheduled on different cores:\n",
+			       share_group);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       src_lc, src_port, src_rxq);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       lc_id, fs->rx_port, fs->rx_queue);
+			printf("  please use --nb-cores=%hu to limit forwarding cores\n",
+			       nb_rxq);
+			return true;
+		}
+	}
+	return false;
+}
+
+/*
+ * Check shared rxq configuration.
+ *
+ * Shared group must not being scheduled on different core.
+ */
+bool
+pkt_fwd_shared_rxq_check(void)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	uint16_t domain_id;
+	struct rte_port *port;
+	struct rte_eth_dev_info *dev_info;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	/*
+	 * Check streams on each core, make sure the same switch domain +
+	 * group + queue doesn't get scheduled on other cores.
+	 */
+	for (lc_id = 0; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			/* Update lcore info stream being scheduled. */
+			fs->lcore = fwd_lcores[lc_id];
+			port = &ports[fs->rx_port];
+			dev_info = &port->dev_info;
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			/* Check shared rxq not scheduled on remaining cores. */
+			domain_id = port->dev_info.switch_info.domain_id;
+			if (fwd_stream_on_other_lcores(domain_id, fs->rx_port,
+						       fs->rx_queue, lc_id,
+						       rxq_conf->share_group))
+				return false;
+		}
+	}
+	return true;
+}
+
 /*
  * Setup forwarding configuration for each logical core.
  */
app/test-pmd/testpmd.c +3 -1
index 9c26301d397..df301e2e683 100644
@@ -2236,10 +2236,12 @@ start_packet_forwarding(int with_tx_first)
 
 	fwd_config_setup();
 
+	pkt_fwd_config_display(&cur_fwd_config);
+	if (!pkt_fwd_shared_rxq_check())
+		return;
 	if(!no_flush_rx)
 		flush_fwd_rx_queues();
 
-	pkt_fwd_config_display(&cur_fwd_config);
 	rxtx_config_display();
 
 	fwd_stats_reset();
app/test-pmd/testpmd.h +2 -0
index 3dfaaad94c0..f121a2da90c 100644
@@ -144,6 +144,7 @@ struct fwd_stream {
 	uint64_t     core_cycles; /**< used for RX and TX processing */
 	struct pkt_burst_stats rx_burst_stats;
 	struct pkt_burst_stats tx_burst_stats;
+	struct fwd_lcore *lcore; /**< Lcore being scheduled. */
 };
 
 /**
@@ -795,6 +796,7 @@ void port_summary_header_display(void);
 void rx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void tx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void fwd_lcores_config_display(void);
+bool pkt_fwd_shared_rxq_check(void);
 void pkt_fwd_config_display(struct fwd_config *cfg);
 void rxtx_config_display(void);
 void fwd_config_setup(void);
Signature · 1 line
2.33.0
author
#128 lore raw

PATCH v6 5/5 app/testpmd: add forwarding engine for shared Rx queue

In reply to Xueming Li

To support shared Rx queue, this patch introduces dedicate forwarding engine. The engine groups received packets by mbuf->port into sub-group, updates stream statistics and simply frees packets.

---
 app/test-pmd/meson.build                    |   1 +
 app/test-pmd/shared_rxq_fwd.c               | 148 ++++++++++++++++++++
 app/test-pmd/testpmd.c                      |   1 +
 app/test-pmd/testpmd.h                      |   1 +
 doc/guides/testpmd_app_ug/run_app.rst       |   1 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |   5 +-
 6 files changed, 156 insertions(+), 1 deletion(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
app/test-pmd/meson.build +1 -0
index 98f3289bdfa..07042e45b12 100644
@@ -21,6 +21,7 @@ sources = files(
         'noisy_vnf.c',
         'parameters.c',
         'rxonly.c',
+        'shared_rxq_fwd.c',
         'testpmd.c',
         'txonly.c',
         'util.c',
app/test-pmd/shared_rxq_fwd.c new file +148 -0

148 lines not on this page · raw message

app/test-pmd/testpmd.c +1 -0
index df301e2e683..e29837b3b16 100644
@@ -188,6 +188,7 @@ struct fwd_engine * fwd_engines[] = {
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
+	&shared_rxq_engine,
 	NULL,
 };
 
app/test-pmd/testpmd.h +1 -0
index f121a2da90c..f1fd607e365 100644
@@ -299,6 +299,7 @@ extern struct fwd_engine five_tuple_swap_fwd_engine;
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
+extern struct fwd_engine shared_rxq_engine;
 
 extern struct fwd_engine * fwd_engines[]; /**< NULL terminated array. */
 extern cmdline_parse_inst_t cmd_set_raw;
doc/guides/testpmd_app_ug/run_app.rst +1 -0
index ff5908dcd50..e4b97844ced 100644
@@ -252,6 +252,7 @@ The command line options are:
        tm
        noisy
        5tswap
+       shared-rxq
 
 *   ``--rss-ip``
 
doc/guides/testpmd_app_ug/testpmd_funcs.rst +4 -1
index 8ead7a4a712..499874187f2 100644
@@ -314,7 +314,7 @@ set fwd
 Set the packet forwarding mode::
 
    testpmd> set fwd (io|mac|macswap|flowgen| \
-                     rxonly|txonly|csum|icmpecho|noisy|5tswap) (""|retry)
+                     rxonly|txonly|csum|icmpecho|noisy|5tswap|shared-rxq) (""|retry)
 
 ``retry`` can be specified for forwarding engines except ``rx_only``.
 
@@ -357,6 +357,9 @@ The available information categories are:
 
   L4 swaps the source port and destination port of transport layer (TCP and UDP).
 
+* ``shared-rxq``: Receive only for shared Rx queue.
+  Resolve packet source port from mbuf and update stream statistics accordingly.
+
 Example::
 
    testpmd> set fwd rxonly
Signature · 1 line
2.33.0
author
#129 lore raw

v7 cover ethdev: introduce shared Rx queue

In reply to Xueming Li

In current DPDK framework, all Rx queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared Rx queue. PF and representors in same Rx domain and switch domain could share Rx queue set by specifying non-zero share group value in Rx queue configuration.

All ports that share Rx queue actually shares hardware descriptor queue and feed all Rx queues with one descriptor supply, memory is saved.

Polling any queue using same shared Rx queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of two share groups:
Group1, 4 shared Rx queues per member port: PF, repr0, repr1 Group2, 2 shared Rx queues per member port: repr2, repr3, ... repr127 Poll first port for each group:
core port queue
0 0 0
1 0 1
2 0 2
3 0 3
4 2 0
5 2 1

Shared Rx queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

There was some discussion to aggregate member ports in same group into a dummy port, several ways to achieve it. Since it optional, need to collect more feedback and requirement from user, make better decision later.

v1:
- initial version
v2:
- add testpmd patches
v3:
- change common forwarding api to macro for performance, thanks Jerin.
- save global variable accessed in forwarding to flowstream to minimize cache miss
- combined patches for each forwarding engine
- support multiple groups in testpmd "--share-rxq" parameter
- new api to aggregate shared rxq group
v4:
- spelling fixes
- remove shared-rxq support for all forwarding engines
- add dedicate shared-rxq forwarding engine
v5:
- fix grammars
- remove aggregate api and leave it for later discussion
- add release notes
- add deployment example
v6:
- replace RxQ offload flag with device offload capability flag
- add Rx domain
- RxQ is shared when share group > 0
- update testpmd accordingly
v7:
- fix testpmd share group id allocation
- change rx_domain to 16bits

Xueming Li (5):
ethdev: introduce shared Rx queue app/testpmd: new parameter to enable shared Rx queue app/testpmd: dump port info for shared Rx queue app/testpmd: force shared Rx queue polled on same core app/testpmd: add forwarding engine for shared Rx queue

 app/test-pmd/config.c                         | 106 ++++++++++++-
 app/test-pmd/meson.build                      |   1 +
 app/test-pmd/parameters.c                     |  13 ++
 app/test-pmd/shared_rxq_fwd.c                 | 148 ++++++++++++++++++
 app/test-pmd/testpmd.c                        |  23 ++-
 app/test-pmd/testpmd.h                        |   5 +
 app/test-pmd/util.c                           |   3 +
 doc/guides/nics/features.rst                  |  13 ++
 doc/guides/nics/features/default.ini          |   1 +
 .../prog_guide/switch_representation.rst      |  10 ++
 doc/guides/rel_notes/release_21_11.rst        |   6 +
 doc/guides/testpmd_app_ug/run_app.rst         |   8 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst   |   5 +-
 lib/ethdev/rte_ethdev.c                       |   8 +
 lib/ethdev/rte_ethdev.h                       |  21 +++
 15 files changed, 365 insertions(+), 6 deletions(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
Signature · 1 line
2.33.0
author
#130 lore raw

PATCH v7 1/5 ethdev: introduce shared Rx queue

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Port A RxQ X can share RxQ with Port B RxQ X, but can't share with RxQ Y. All member ports in share group share a list of shared Rx queue indexed by Rx queue ID.

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, source port is identified by mbuf->port.

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

Multiple share groups are supported. Device should support mixed configuration by allowing multiple share groups and non-shared Rx queue.

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

PMD advertise shared Rx queue capability via RTE_ETH_DEV_CAPA_RXQ_SHARE.

PMD is responsible for shared Rx queue consistency checks to avoid member port's configuration contradict to each other.

---
 doc/guides/nics/features.rst                  | 13 ++++++++++++
 doc/guides/nics/features/default.ini          |  1 +
 .../prog_guide/switch_representation.rst      | 10 +++++++++
 doc/guides/rel_notes/release_21_11.rst        |  6 ++++++
 lib/ethdev/rte_ethdev.c                       |  8 +++++++
 lib/ethdev/rte_ethdev.h                       | 21 +++++++++++++++++++
 6 files changed, 59 insertions(+)
doc/guides/nics/features.rst +13 -0
index e346018e4b8..b64433b8ea5 100644
@@ -615,6 +615,19 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same Rx domain of a switch domain.
+
+* **[uses]     rte_eth_dev_info**: ``dev_capa:RTE_ETH_DEV_CAPA_RXQ_SHARE``.
+* **[uses]     rte_eth_dev_info,rte_eth_switch_info**: ``rx_domain``, ``domain_id``.
+* **[uses]     rte_eth_rxconf**: ``share_group``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index d473b94091a..93f5d1b46f4 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +10 -0
index ff6aa91c806..de41db8385d 100644
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same Rx domain. ``RTE_ETH_DEV_CAPA_RXQ_SHARE`` is
+  present in device capability of device info. Setting non-zero share group
+  in Rx queue configuration to enable share. Polling any member port can
+  receive packets of all member ports in the group, port ID is saved in
+  ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +6 -0
index 4c56cdfeaaa..1c84e896554 100644
@@ -67,6 +67,12 @@ New Features
   * Modified to allow ``--huge-dir`` option to specify a sub-directory
     within a hugetlbfs mountpoint.
 
+* **Added ethdev shared Rx queue support.**
+
+  * Added new device capability flag and rx domain field to switch info.
+  * Added share group to Rx queue configuration.
+  * Added testpmd support and dedicate forwarding engine.
+
 * **Added new RSS offload types for IPv4/L4 checksum in RSS flow.**
 
   Added macros ETH_RSS_IPV4_CHKSUM and ETH_RSS_L4_CHKSUM, now IPv4 and
lib/ethdev/rte_ethdev.c +8 -0
index 028907bc4b9..bc55f899f72 100644
@@ -2159,6 +2159,14 @@ rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
 		return -EINVAL;
 	}
 
+	if (local_conf.share_group > 0 &&
+	    (dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) == 0) {
+		RTE_ETHDEV_LOG(ERR,
+			"Ethdev port_id=%d rx_queue_id=%d, enabled share_group=%hu while device doesn't support Rx queue share\n",
+			port_id, rx_queue_id, local_conf.share_group);
+		return -EINVAL;
+	}
+
 	/*
 	 * If LRO is enabled, check that the maximum aggregated packet
 	 * size is supported by the configured device.
lib/ethdev/rte_ethdev.h +21 -0
index 6d80514ba7a..59d8904ac7c 100644
@@ -1044,6 +1044,13 @@ struct rte_eth_rxconf {
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
 	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	/**
+	 * Share group index in Rx domain and switch domain.
+	 * Non-zero value to enable Rx queue share, zero value disable share.
+	 * PMD driver is responsible for Rx queue consistency checks to avoid
+	 * member port's configuration contradict to each other.
+	 */
+	uint16_t share_group;
 	/**
 	 * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
 	 * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1445,6 +1452,14 @@ struct rte_eth_conf {
 #define RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP 0x00000001
 /** Device supports Tx queue setup after device started. */
 #define RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP 0x00000002
+/**
+ * Device supports shared Rx queue among ports within Rx domain and
+ * switch domain. Mbufs are consumed by shared Rx queue instead of
+ * every port. Multiple groups is supported by share_group of Rx
+ * queue configuration. Polling any port in the group receive packets
+ * of all member ports, source port identified by mbuf->port field.
+ */
+#define RTE_ETH_DEV_CAPA_RXQ_SHARE              RTE_BIT64(2)
 /**@}*/
 
 /*
@@ -1488,6 +1503,12 @@ struct rte_eth_switch_info {
 	 * but each driver should explicitly define the mapping of switch
 	 * port identifier to that physical interconnect/switch
 	 */
+	/**
+	 * Shared Rx queue sub-domain boundary. Only ports in same Rx domain
+	 * and switch domain can share Rx queue. Valid only if device advertised
+	 * RTE_ETH_DEV_CAPA_RXQ_SHARE capability.
+	 */
+	uint16_t rx_domain;
 };
 
 /**
Signature · 1 line
2.33.0
#131 lore raw
Quoted 11 lines · Xueming Li

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Quoted 7 lines

Port A RxQ X can share RxQ with Port B RxQ X, but can't share with RxQ Y. All member ports in share group share a list of shared Rx queue indexed by Rx queue ID.

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, source port is identified by mbuf->port.

Is this port the physical port which received the packet?
Or does this port number correlate with the port_id seen by the application?

Quoted 3 lines

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

So it is upto the application to poll the queue of any member port or all ports or a designated port to handle Rx?

Quoted 168 lines

Multiple share groups are supported. Device should support mixed configuration by allowing multiple share groups and non-shared Rx queue.

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

PMD advertise shared Rx queue capability via RTE_ETH_DEV_CAPA_RXQ_SHARE.

PMD is responsible for shared Rx queue consistency checks to avoid member port's configuration contradict to each other.

---
 doc/guides/nics/features.rst                  | 13 ++++++++++++
 doc/guides/nics/features/default.ini          |  1 +
 .../prog_guide/switch_representation.rst      | 10 +++++++++
 doc/guides/rel_notes/release_21_11.rst        |  6 ++++++
 lib/ethdev/rte_ethdev.c                       |  8 +++++++
 lib/ethdev/rte_ethdev.h                       | 21 +++++++++++++++++++
 6 files changed, 59 insertions(+)
doc/guides/nics/features.rst +13 -0
index e346018e4b8..b64433b8ea5 100644
@@ -615,6 +615,19 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same Rx domain of a switch domain.
+
+* **[uses]     rte_eth_dev_info**: ``dev_capa:RTE_ETH_DEV_CAPA_RXQ_SHARE``.
+* **[uses]     rte_eth_dev_info,rte_eth_switch_info**: ``rx_domain``, ``domain_id``.
+* **[uses]     rte_eth_rxconf**: ``share_group``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index d473b94091a..93f5d1b46f4 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +10 -0
index ff6aa91c806..de41db8385d 100644
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same Rx domain. ``RTE_ETH_DEV_CAPA_RXQ_SHARE`` is
+  present in device capability of device info. Setting non-zero share group
+  in Rx queue configuration to enable share. Polling any member port can
+  receive packets of all member ports in the group, port ID is saved in
+  ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +6 -0
index 4c56cdfeaaa..1c84e896554 100644
@@ -67,6 +67,12 @@ New Features
   * Modified to allow ``--huge-dir`` option to specify a sub-directory
     within a hugetlbfs mountpoint.
 
+* **Added ethdev shared Rx queue support.**
+
+  * Added new device capability flag and rx domain field to switch info.
+  * Added share group to Rx queue configuration.
+  * Added testpmd support and dedicate forwarding engine.
+
 * **Added new RSS offload types for IPv4/L4 checksum in RSS flow.**
 
   Added macros ETH_RSS_IPV4_CHKSUM and ETH_RSS_L4_CHKSUM, now IPv4 and
lib/ethdev/rte_ethdev.c +8 -0
index 028907bc4b9..bc55f899f72 100644
@@ -2159,6 +2159,14 @@ rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
                return -EINVAL;
        }
 
+       if (local_conf.share_group > 0 &&
+           (dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) == 0) {
+               RTE_ETHDEV_LOG(ERR,
+                       "Ethdev port_id=%d rx_queue_id=%d, enabled share_group=%hu while device doesn't support Rx queue share\n",
+                       port_id, rx_queue_id, local_conf.share_group);
+               return -EINVAL;
+       }
+
        /*
         * If LRO is enabled, check that the maximum aggregated packet
         * size is supported by the configured device.
lib/ethdev/rte_ethdev.h +21 -1
index 6d80514ba7a..59d8904ac7c 100644
@@ -1044,6 +1044,13 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+       /**
+        * Share group index in Rx domain and switch domain.
+        * Non-zero value to enable Rx queue share, zero value disable share.
+        * PMD driver is responsible for Rx queue consistency checks to avoid
+        * member port's configuration contradict to each other.
+        */
+       uint16_t share_group;
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1445,6 +1452,14 @@ struct rte_eth_conf {
 #define RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP 0x00000001
 /** Device supports Tx queue setup after device started. */
 #define RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP 0x00000002
+/**
+ * Device supports shared Rx queue among ports within Rx domain and
+ * switch domain. Mbufs are consumed by shared Rx queue instead of
+ * every port. Multiple groups is supported by share_group of Rx
+ * queue configuration. Polling any port in the group receive packets
+ * of all member ports, source port identified by mbuf->port field.
+ */
+#define RTE_ETH_DEV_CAPA_RXQ_SHARE              RTE_BIT64(2)
 /**@}*/
 
 /*
@@ -1488,6 +1503,12 @@ struct rte_eth_switch_info {
         * but each driver should explicitly define the mapping of switch
         * port identifier to that physical interconnect/switch
         */
+       /**
+        * Shared Rx queue sub-domain boundary. Only ports in same Rx domain
+        * and switch domain can share Rx queue. Valid only if device advertised
+        * RTE_ETH_DEV_CAPA_RXQ_SHARE capability.
+        */
+       uint16_t rx_domain;
 };
 
 /**
--

2.33.0

#132 lore raw
Quoted 16 lines · Ajit Khaparde
Quoted 15 lines · Xueming Li

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Port A RxQ X can share RxQ with Port B RxQ X, but can't share with RxQ Y. All member ports in share group share a list of shared Rx queue indexed by Rx queue ID.

Quoted 5 lines
Quoted 3 lines

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, source port is identified by mbuf->port.

Is this port the physical port which received the packet?
Or does this port number correlate with the port_id seen by the application?

Hi Ajit,

It's the port_id of member ports - PF or representor port. I'll update commit message to avoid confusion.

Quoted 8 lines
Quoted 6 lines

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

So it is upto the application to poll the queue of any member port or all ports or a designated port to handle Rx?

Yes, up to application. As described in cover letter, aggregator port will be considered after collecting more suggestion and user feedback.

Quoted 169 lines
Quoted 169 lines

Multiple share groups are supported. Device should support mixed configuration by allowing multiple share groups and non-shared Rx queue.

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

PMD advertise shared Rx queue capability via RTE_ETH_DEV_CAPA_RXQ_SHARE.

PMD is responsible for shared Rx queue consistency checks to avoid member port's configuration contradict to each other.

---
 doc/guides/nics/features.rst                  | 13 ++++++++++++
 doc/guides/nics/features/default.ini          |  1 +
 .../prog_guide/switch_representation.rst      | 10 +++++++++
 doc/guides/rel_notes/release_21_11.rst        |  6 ++++++
 lib/ethdev/rte_ethdev.c                       |  8 +++++++
 lib/ethdev/rte_ethdev.h                       | 21 +++++++++++++++++++
 6 files changed, 59 insertions(+)
doc/guides/nics/features.rst +13 -0
index e346018e4b8..b64433b8ea5 100644
@@ -615,6 +615,19 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same Rx domain of a switch domain.
+
+* **[uses]     rte_eth_dev_info**: ``dev_capa:RTE_ETH_DEV_CAPA_RXQ_SHARE``.
+* **[uses]     rte_eth_dev_info,rte_eth_switch_info**: ``rx_domain``, ``domain_id``.
+* **[uses]     rte_eth_rxconf**: ``share_group``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index d473b94091a..93f5d1b46f4 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +10 -0
index ff6aa91c806..de41db8385d 100644
@@ -123,6 +123,16 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same Rx domain. ``RTE_ETH_DEV_CAPA_RXQ_SHARE`` is
+  present in device capability of device info. Setting non-zero share group
+  in Rx queue configuration to enable share. Polling any member port can
+  receive packets of all member ports in the group, port ID is saved in
+  ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +6 -0
index 4c56cdfeaaa..1c84e896554 100644
@@ -67,6 +67,12 @@ New Features
   * Modified to allow ``--huge-dir`` option to specify a sub-directory
     within a hugetlbfs mountpoint.
 
+* **Added ethdev shared Rx queue support.**
+
+  * Added new device capability flag and rx domain field to switch info.
+  * Added share group to Rx queue configuration.
+  * Added testpmd support and dedicate forwarding engine.
+
 * **Added new RSS offload types for IPv4/L4 checksum in RSS flow.**
 
   Added macros ETH_RSS_IPV4_CHKSUM and ETH_RSS_L4_CHKSUM, now IPv4 and
lib/ethdev/rte_ethdev.c +8 -0
index 028907bc4b9..bc55f899f72 100644
@@ -2159,6 +2159,14 @@ rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
                return -EINVAL;
        }
 
+       if (local_conf.share_group > 0 &&
+           (dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) == 0) {
+               RTE_ETHDEV_LOG(ERR,
+                       "Ethdev port_id=%d rx_queue_id=%d, enabled share_group=%hu while device doesn't support Rx queue share\n",
+                       port_id, rx_queue_id, local_conf.share_group);
+               return -EINVAL;
+       }
+
        /*
         * If LRO is enabled, check that the maximum aggregated packet
         * size is supported by the configured device.
lib/ethdev/rte_ethdev.h +21 -1
index 6d80514ba7a..59d8904ac7c 100644
@@ -1044,6 +1044,13 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+       /**
+        * Share group index in Rx domain and switch domain.
+        * Non-zero value to enable Rx queue share, zero value disable share.
+        * PMD driver is responsible for Rx queue consistency checks to avoid
+        * member port's configuration contradict to each other.
+        */
+       uint16_t share_group;
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1445,6 +1452,14 @@ struct rte_eth_conf {
 #define RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP 0x00000001
 /** Device supports Tx queue setup after device started. */
 #define RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP 0x00000002
+/**
+ * Device supports shared Rx queue among ports within Rx domain and
+ * switch domain. Mbufs are consumed by shared Rx queue instead of
+ * every port. Multiple groups is supported by share_group of Rx
+ * queue configuration. Polling any port in the group receive packets
+ * of all member ports, source port identified by mbuf->port field.
+ */
+#define RTE_ETH_DEV_CAPA_RXQ_SHARE              RTE_BIT64(2)
 /**@}*/
 
 /*
@@ -1488,6 +1503,12 @@ struct rte_eth_switch_info {
         * but each driver should explicitly define the mapping of switch
         * port identifier to that physical interconnect/switch
         */
+       /**
+        * Shared Rx queue sub-domain boundary. Only ports in same Rx domain
+        * and switch domain can share Rx queue. Valid only if device advertised
+        * RTE_ETH_DEV_CAPA_RXQ_SHARE capability.
+        */
+       uint16_t rx_domain;
 };
 
 /**
--

2.33.0

author
#133 lore raw

PATCH v7 2/5 app/testpmd: new parameter to enable shared Rx queue

In reply to Xueming Li

Adds "--rxq-share=X" parameter to enable shared RxQ, share if device supports, otherwise fallback to standard RxQ.

Share group number grows per X ports. X defaults to MAX, implies all ports join share group 1.

Forwarding engine "shared-rxq" should be used which Rx only and update stream statistics correctly.

---
 app/test-pmd/config.c                 |  6 +++++-
 app/test-pmd/parameters.c             | 13 +++++++++++++
 app/test-pmd/testpmd.c                | 18 +++++++++++++++---
 app/test-pmd/testpmd.h                |  2 ++
 doc/guides/testpmd_app_ug/run_app.rst |  7 +++++++
 5 files changed, 42 insertions(+), 4 deletions(-)
app/test-pmd/config.c +5 -1
index 9c66329e96e..96fc2ab888b 100644
@@ -2709,7 +2709,11 @@ rxtx_config_display(void)
 			printf("      RX threshold registers: pthresh=%d hthresh=%d "
 				" wthresh=%d\n",
 				pthresh_tmp, hthresh_tmp, wthresh_tmp);
-			printf("      RX Offloads=0x%"PRIx64"\n", offloads_tmp);
+			printf("      RX Offloads=0x%"PRIx64, offloads_tmp);
+			if (rx_conf->share_group > 0)
+				printf(" share group=%u",
+				       rx_conf->share_group);
+			printf("\n");
 		}
 
 		/* per tx queue config only for first queue to be less verbose */
app/test-pmd/parameters.c +13 -0
index 3f94a82e321..30dae326310 100644
@@ -167,6 +167,7 @@ usage(char* progname)
 	printf("  --tx-ip=src,dst: IP addresses in Tx-only mode\n");
 	printf("  --tx-udp=src[,dst]: UDP ports in Tx-only mode\n");
 	printf("  --eth-link-speed: force link speed.\n");
+	printf("  --rxq-share: number of ports per shared rxq groups, defaults to MAX(1 group)\n");
 	printf("  --disable-link-check: disable check on link status when "
 	       "starting/stopping ports.\n");
 	printf("  --disable-device-start: do not automatically start port\n");
@@ -607,6 +608,7 @@ launch_args_parse(int argc, char** argv)
 		{ "rxpkts",			1, 0, 0 },
 		{ "txpkts",			1, 0, 0 },
 		{ "txonly-multi-flow",		0, 0, 0 },
+		{ "rxq-share",			2, 0, 0 },
 		{ "eth-link-speed",		1, 0, 0 },
 		{ "disable-link-check",		0, 0, 0 },
 		{ "disable-device-start",	0, 0, 0 },
@@ -1271,6 +1273,17 @@ launch_args_parse(int argc, char** argv)
 			}
 			if (!strcmp(lgopts[opt_idx].name, "txonly-multi-flow"))
 				txonly_multi_flow = 1;
+			if (!strcmp(lgopts[opt_idx].name, "rxq-share")) {
+				if (optarg == NULL) {
+					rxq_share = UINT32_MAX;
+				} else {
+					n = atoi(optarg);
+					if (n >= 0)
+						rxq_share = (uint32_t)n;
+					else
+						rte_exit(EXIT_FAILURE, "rxq-share must be >= 0\n");
+				}
+			}
 			if (!strcmp(lgopts[opt_idx].name, "no-flush-rx"))
 				no_flush_rx = 1;
 			if (!strcmp(lgopts[opt_idx].name, "eth-link-speed")) {
app/test-pmd/testpmd.c +15 -3
index 97ae52e17ec..4c501bf43f3 100644
@@ -498,6 +498,11 @@ uint8_t record_core_cycles;
  */
 uint8_t record_burst_stats;
 
+/*
+ * Number of ports per shared Rx queue group, 0 disable.
+ */
+uint32_t rxq_share;
+
 unsigned int num_sockets = 0;
 unsigned int socket_ids[RTE_MAX_NUMA_NODES];
 
@@ -3393,14 +3398,21 @@ dev_event_callback(const char *device_name, enum rte_dev_event_type type,
 }
 
 static void
-rxtx_port_config(struct rte_port *port)
+rxtx_port_config(portid_t pid)
 {
 	uint16_t qid;
 	uint64_t offloads;
+	struct rte_port *port = &ports[pid];
 
 	for (qid = 0; qid < nb_rxq; qid++) {
 		offloads = port->rx_conf[qid].offloads;
 		port->rx_conf[qid] = port->dev_info.default_rxconf;
+
+		if (rxq_share > 0 &&
+		    (port->dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE))
+			/* Non-zero share group to enable RxQ share. */
+			port->rx_conf[qid].share_group = pid / rxq_share + 1;
+
 		if (offloads != 0)
 			port->rx_conf[qid].offloads = offloads;
 
@@ -3558,7 +3570,7 @@ init_port_config(void)
 				port->dev_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
 		}
 
-		rxtx_port_config(port);
+		rxtx_port_config(pid);
 
 		ret = eth_macaddr_get_print_err(pid, &port->eth_addr);
 		if (ret != 0)
@@ -3772,7 +3784,7 @@ init_port_dcb_config(portid_t pid,
 
 	memcpy(&rte_port->dev_conf, &port_conf, sizeof(struct rte_eth_conf));
 
-	rxtx_port_config(rte_port);
+	rxtx_port_config(pid);
 	/* VLAN filter */
 	rte_port->dev_conf.rxmode.offloads |= DEV_RX_OFFLOAD_VLAN_FILTER;
 	for (i = 0; i < RTE_DIM(vlan_tags); i++)
app/test-pmd/testpmd.h +2 -0
index 5863b2f43f3..3dfaaad94c0 100644
@@ -477,6 +477,8 @@ extern enum tx_pkt_split tx_pkt_split;
 
 extern uint8_t txonly_multi_flow;
 
+extern uint32_t rxq_share;
+
 extern uint16_t nb_pkt_per_burst;
 extern uint16_t nb_pkt_flowgen_clones;
 extern int nb_flows_flowgen;
doc/guides/testpmd_app_ug/run_app.rst +7 -0
index 640eadeff73..ff5908dcd50 100644
@@ -389,6 +389,13 @@ The command line options are:
 
     Generate multiple flows in txonly mode.
 
+*   ``--rxq-share=[X]``
+
+    Create queues in shared Rx queue mode if device supports.
+    Group number grows per X ports. X defaults to MAX, implies all ports
+    join share group 1. Forwarding engine "shared-rxq" should be used
+    which Rx only and update stream statistics correctly.
+
 *   ``--eth-link-speed``
 
     Set a forced link speed to the ethernet port::
Signature · 1 line
2.33.0
author
#134 lore raw

PATCH v7 3/5 app/testpmd: dump port info for shared Rx queue

In reply to Xueming Li

In case of shared Rx queue, polling any member port returns mbufs for all members. This patch dumps mbuf->port for each packet.

---
 app/test-pmd/util.c | 3 +++
 1 file changed, 3 insertions(+)
app/test-pmd/util.c +3 -0
index 51506e49404..e98f136d5ed 100644
@@ -100,6 +100,9 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
 		struct rte_flow_restore_info info = { 0, };
 
 		mb = pkts[i];
+		if (rxq_share > 0)
+			MKDUMPSTR(print_buf, buf_size, cur_len, "port %u, ",
+				  mb->port);
 		eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
 		eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
 		packet_type = mb->packet_type;
Signature · 1 line
2.33.0
author
#135 lore raw

PATCH v7 4/5 app/testpmd: force shared Rx queue polled on same core

In reply to Xueming Li

Shared Rx queue must be polled on same core. This patch checks and stops forwarding if shared RxQ being scheduled on multiple
cores.

It's suggested to use same number of Rx queues and polling cores.

---
 app/test-pmd/config.c  | 100 +++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.c |   4 +-
 app/test-pmd/testpmd.h |   2 +
 3 files changed, 105 insertions(+), 1 deletion(-)
app/test-pmd/config.c +100 -0
index 96fc2ab888b..9acd2705f18 100644
@@ -2885,6 +2885,106 @@ port_rss_hash_key_update(portid_t port_id, char rss_type[], uint8_t *hash_key,
 	}
 }
 
+/*
+ * Check whether a shared rxq scheduled on other lcores.
+ */
+static bool
+fwd_stream_on_other_lcores(uint16_t domain_id, portid_t src_port,
+			   queueid_t src_rxq, lcoreid_t src_lc,
+			   uint32_t share_group)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	struct rte_port *port;
+	struct rte_eth_dev_info *dev_info;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	for (lc_id = src_lc + 1; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			port = &ports[fs->rx_port];
+			dev_info = &port->dev_info;
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			if (domain_id != port->dev_info.switch_info.domain_id)
+				continue;
+			if (fs->rx_queue != src_rxq)
+				continue;
+			if (rxq_conf->share_group != share_group)
+				continue;
+			printf("Shared Rx queue group %u can't be scheduled on different cores:\n",
+			       share_group);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       src_lc, src_port, src_rxq);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       lc_id, fs->rx_port, fs->rx_queue);
+			printf("  please use --nb-cores=%hu to limit forwarding cores\n",
+			       nb_rxq);
+			return true;
+		}
+	}
+	return false;
+}
+
+/*
+ * Check shared rxq configuration.
+ *
+ * Shared group must not being scheduled on different core.
+ */
+bool
+pkt_fwd_shared_rxq_check(void)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	uint16_t domain_id;
+	struct rte_port *port;
+	struct rte_eth_dev_info *dev_info;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	/*
+	 * Check streams on each core, make sure the same switch domain +
+	 * group + queue doesn't get scheduled on other cores.
+	 */
+	for (lc_id = 0; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			/* Update lcore info stream being scheduled. */
+			fs->lcore = fwd_lcores[lc_id];
+			port = &ports[fs->rx_port];
+			dev_info = &port->dev_info;
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			/* Check shared rxq not scheduled on remaining cores. */
+			domain_id = port->dev_info.switch_info.domain_id;
+			if (fwd_stream_on_other_lcores(domain_id, fs->rx_port,
+						       fs->rx_queue, lc_id,
+						       rxq_conf->share_group))
+				return false;
+		}
+	}
+	return true;
+}
+
 /*
  * Setup forwarding configuration for each logical core.
  */
app/test-pmd/testpmd.c +3 -1
index 4c501bf43f3..49c04de2501 100644
@@ -2236,10 +2236,12 @@ start_packet_forwarding(int with_tx_first)
 
 	fwd_config_setup();
 
+	pkt_fwd_config_display(&cur_fwd_config);
+	if (!pkt_fwd_shared_rxq_check())
+		return;
 	if(!no_flush_rx)
 		flush_fwd_rx_queues();
 
-	pkt_fwd_config_display(&cur_fwd_config);
 	rxtx_config_display();
 
 	fwd_stats_reset();
app/test-pmd/testpmd.h +2 -0
index 3dfaaad94c0..f121a2da90c 100644
@@ -144,6 +144,7 @@ struct fwd_stream {
 	uint64_t     core_cycles; /**< used for RX and TX processing */
 	struct pkt_burst_stats rx_burst_stats;
 	struct pkt_burst_stats tx_burst_stats;
+	struct fwd_lcore *lcore; /**< Lcore being scheduled. */
 };
 
 /**
@@ -795,6 +796,7 @@ void port_summary_header_display(void);
 void rx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void tx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void fwd_lcores_config_display(void);
+bool pkt_fwd_shared_rxq_check(void);
 void pkt_fwd_config_display(struct fwd_config *cfg);
 void rxtx_config_display(void);
 void fwd_config_setup(void);
Signature · 1 line
2.33.0
author
#136 lore raw

PATCH v7 5/5 app/testpmd: add forwarding engine for shared Rx queue

In reply to Xueming Li

To support shared Rx queue, this patch introduces dedicate forwarding engine. The engine groups received packets by mbuf->port into sub-group, updates stream statistics and simply frees packets.

---
 app/test-pmd/meson.build                    |   1 +
 app/test-pmd/shared_rxq_fwd.c               | 148 ++++++++++++++++++++
 app/test-pmd/testpmd.c                      |   1 +
 app/test-pmd/testpmd.h                      |   1 +
 doc/guides/testpmd_app_ug/run_app.rst       |   1 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |   5 +-
 6 files changed, 156 insertions(+), 1 deletion(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
app/test-pmd/meson.build +1 -0
index 98f3289bdfa..07042e45b12 100644
@@ -21,6 +21,7 @@ sources = files(
         'noisy_vnf.c',
         'parameters.c',
         'rxonly.c',
+        'shared_rxq_fwd.c',
         'testpmd.c',
         'txonly.c',
         'util.c',
app/test-pmd/shared_rxq_fwd.c new file +148 -0

148 lines not on this page · raw message

app/test-pmd/testpmd.c +1 -0
index 49c04de2501..02c8a86f321 100644
@@ -188,6 +188,7 @@ struct fwd_engine * fwd_engines[] = {
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
+	&shared_rxq_engine,
 	NULL,
 };
 
app/test-pmd/testpmd.h +1 -0
index f121a2da90c..f1fd607e365 100644
@@ -299,6 +299,7 @@ extern struct fwd_engine five_tuple_swap_fwd_engine;
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
+extern struct fwd_engine shared_rxq_engine;
 
 extern struct fwd_engine * fwd_engines[]; /**< NULL terminated array. */
 extern cmdline_parse_inst_t cmd_set_raw;
doc/guides/testpmd_app_ug/run_app.rst +1 -0
index ff5908dcd50..e4b97844ced 100644
@@ -252,6 +252,7 @@ The command line options are:
        tm
        noisy
        5tswap
+       shared-rxq
 
 *   ``--rss-ip``
 
doc/guides/testpmd_app_ug/testpmd_funcs.rst +4 -1
index 8ead7a4a712..499874187f2 100644
@@ -314,7 +314,7 @@ set fwd
 Set the packet forwarding mode::
 
    testpmd> set fwd (io|mac|macswap|flowgen| \
-                     rxonly|txonly|csum|icmpecho|noisy|5tswap) (""|retry)
+                     rxonly|txonly|csum|icmpecho|noisy|5tswap|shared-rxq) (""|retry)
 
 ``retry`` can be specified for forwarding engines except ``rx_only``.
 
@@ -357,6 +357,9 @@ The available information categories are:
 
   L4 swaps the source port and destination port of transport layer (TCP and UDP).
 
+* ``shared-rxq``: Receive only for shared Rx queue.
+  Resolve packet source port from mbuf and update stream statistics accordingly.
+
 Example::
 
    testpmd> set fwd rxonly
Signature · 1 line
2.33.0
author
#137 lore raw

v8 cover ethdev: introduce shared Rx queue

In reply to Xueming Li

In current DPDK framework, all Rx queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared Rx queue. PF and representors in same Rx domain and switch domain could share Rx queue set by specifying non-zero share group value in Rx queue configuration.

All ports that share Rx queue actually shares hardware descriptor queue and feed all Rx queues with one descriptor supply, memory is saved.

Polling any queue using same shared Rx queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of two share groups:
Group1, 4 shared Rx queues per member port: PF, repr0, repr1 Group2, 2 shared Rx queues per member port: repr2, repr3, ... repr127 Poll first port for each group:
core port queue
0 0 0
1 0 1
2 0 2
3 0 3
4 2 0
5 2 1

Shared Rx queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

There was some discussion to aggregate member ports in same group into a dummy port, several ways to achieve it. Since it optional, need to collect more feedback and requirement from user, make better decision later.

v1:
- initial version
v2:
- add testpmd patches
v3:
- change common forwarding api to macro for performance, thanks Jerin.
- save global variable accessed in forwarding to flowstream to minimize cache miss
- combined patches for each forwarding engine
- support multiple groups in testpmd "--share-rxq" parameter
- new api to aggregate shared rxq group
v4:
- spelling fixes
- remove shared-rxq support for all forwarding engines
- add dedicate shared-rxq forwarding engine
v5:
- fix grammars
- remove aggregate api and leave it for later discussion
- add release notes
- add deployment example
v6:
- replace RxQ offload flag with device offload capability flag
- add Rx domain
- RxQ is shared when share group > 0
- update testpmd accordingly
v7:
- fix testpmd share group id allocation
- change rx_domain to 16bits
v8:
- add new patch for testpmd to show device Rx domain ID and capability
- new share_qid in RxQ configuration

Xueming Li (6):
ethdev: introduce shared Rx queue app/testpmd: dump device capability and Rx domain info app/testpmd: new parameter to enable shared Rx queue app/testpmd: dump port info for shared Rx queue app/testpmd: force shared Rx queue polled on same core app/testpmd: add forwarding engine for shared Rx queue

 app/test-pmd/config.c                         | 114 +++++++++++++-
 app/test-pmd/meson.build                      |   1 +
 app/test-pmd/parameters.c                     |  13 ++
 app/test-pmd/shared_rxq_fwd.c                 | 148 ++++++++++++++++++
 app/test-pmd/testpmd.c                        |  25 ++-
 app/test-pmd/testpmd.h                        |   5 +
 app/test-pmd/util.c                           |   3 +
 doc/guides/nics/features.rst                  |  13 ++
 doc/guides/nics/features/default.ini          |   1 +
 .../prog_guide/switch_representation.rst      |  11 ++
 doc/guides/rel_notes/release_21_11.rst        |   6 +
 doc/guides/testpmd_app_ug/run_app.rst         |   8 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst   |   5 +-
 lib/ethdev/rte_ethdev.c                       |   8 +
 lib/ethdev/rte_ethdev.h                       |  24 +++
 15 files changed, 379 insertions(+), 6 deletions(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
Signature · 1 line
2.33.0
author
#138 lore raw

PATCH v8 1/6 ethdev: introduce shared Rx queue

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Shared Rx queue is identified by share_rxq field of Rx queue configuration. Port A RxQ X can share RxQ with Port B RxQ Y by using same shared Rx queue ID.

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, port_id is identified by mbuf->port. PMD is responsible to resolve shared Rx queue from device and queue data.

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

Multiple share groups are supported. Device should support mixed configuration by allowing multiple share groups and non-shared Rx queue on one port.

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

PMD advertise shared Rx queue capability via RTE_ETH_DEV_CAPA_RXQ_SHARE.

PMD is responsible for shared Rx queue consistency checks to avoid member port's configuration contradict to each other.

---
 doc/guides/nics/features.rst                  | 13 ++++++++++
 doc/guides/nics/features/default.ini          |  1 +
 .../prog_guide/switch_representation.rst      | 11 +++++++++
 doc/guides/rel_notes/release_21_11.rst        |  6 +++++
 lib/ethdev/rte_ethdev.c                       |  8 +++++++
 lib/ethdev/rte_ethdev.h                       | 24 +++++++++++++++++++
 6 files changed, 63 insertions(+)
doc/guides/nics/features.rst +13 -0
index e346018e4b8..89f9accbca1 100644
@@ -615,6 +615,19 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same Rx domain of a switch domain.
+
+* **[uses]     rte_eth_dev_info**: ``dev_capa:RTE_ETH_DEV_CAPA_RXQ_SHARE``.
+* **[uses]     rte_eth_dev_info,rte_eth_switch_info**: ``rx_domain``, ``domain_id``.
+* **[uses]     rte_eth_rxconf**: ``share_group``, ``share_qid``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index d473b94091a..93f5d1b46f4 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +11 -0
index ff6aa91c806..fe89a7f5c33 100644
@@ -123,6 +123,17 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same Rx domain. ``RTE_ETH_DEV_CAPA_RXQ_SHARE`` in
+  device info is used to indicate the capability. Setting non-zero share
+  group in Rx queue configuration to enable share, share_qid is used to
+  identifiy the shared Rx queue in group. Polling any member port can
+  receive packets of all member ports in the group, port ID is saved in
+  ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +6 -0
index d5435a64aa1..2143e38ff11 100644
@@ -75,6 +75,12 @@ New Features
     operations.
   * Added multi-process support.
 
+* **Added ethdev shared Rx queue support.**
+
+  * Added new device capability flag and rx domain field to switch info.
+  * Added share group and share queue ID to Rx queue configuration.
+  * Added testpmd support and dedicate forwarding engine.
+
 * **Added new RSS offload types for IPv4/L4 checksum in RSS flow.**
 
   Added macros ETH_RSS_IPV4_CHKSUM and ETH_RSS_L4_CHKSUM, now IPv4 and
lib/ethdev/rte_ethdev.c +8 -0
index 028907bc4b9..bc55f899f72 100644
@@ -2159,6 +2159,14 @@ rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
 		return -EINVAL;
 	}
 
+	if (local_conf.share_group > 0 &&
+	    (dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) == 0) {
+		RTE_ETHDEV_LOG(ERR,
+			"Ethdev port_id=%d rx_queue_id=%d, enabled share_group=%hu while device doesn't support Rx queue share\n",
+			port_id, rx_queue_id, local_conf.share_group);
+		return -EINVAL;
+	}
+
 	/*
 	 * If LRO is enabled, check that the maximum aggregated packet
 	 * size is supported by the configured device.
lib/ethdev/rte_ethdev.h +24 -0
index 6d80514ba7a..465293fd66d 100644
@@ -1044,6 +1044,14 @@ struct rte_eth_rxconf {
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
 	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	/**
+	 * Share group index in Rx domain and switch domain.
+	 * Non-zero value to enable Rx queue share, zero value disable share.
+	 * PMD is responsible for Rx queue consistency checks to avoid member
+	 * port's configuration contradict to each other.
+	 */
+	uint16_t share_group;
+	uint16_t share_qid; /**< Shared Rx queue ID in group. */
 	/**
 	 * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
 	 * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1445,6 +1453,16 @@ struct rte_eth_conf {
 #define RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP 0x00000001
 /** Device supports Tx queue setup after device started. */
 #define RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP 0x00000002
+/**
+ * Device supports shared Rx queue among ports within Rx domain and
+ * switch domain. Mbufs are consumed by shared Rx queue instead of
+ * each queue. Multiple groups is supported by share_group of Rx
+ * queue configuration. Shared Rx queue is identified by PMD using
+ * share_qid of Rx queue configuration. Polling any port in the group
+ * receive packets of all member ports, source port identified by
+ * mbuf->port field.
+ */
+#define RTE_ETH_DEV_CAPA_RXQ_SHARE              RTE_BIT64(2)
 /**@}*/
 
 /*
@@ -1488,6 +1506,12 @@ struct rte_eth_switch_info {
 	 * but each driver should explicitly define the mapping of switch
 	 * port identifier to that physical interconnect/switch
 	 */
+	/**
+	 * Shared Rx queue sub-domain boundary. Only ports in same Rx domain
+	 * and switch domain can share Rx queue. Valid only if device advertised
+	 * RTE_ETH_DEV_CAPA_RXQ_SHARE capability.
+	 */
+	uint16_t rx_domain;
 };
 
 /**
Signature · 1 line
2.33.0
#139 lore raw
Quoted 8 lines · Xueming Li

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and

s/introduce/introduces

Quoted 12 lines

switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Shared Rx queue is identified by share_rxq field of Rx queue configuration. Port A RxQ X can share RxQ with Port B RxQ Y by using same shared Rx queue ID.

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, port_id is identified by mbuf->port. PMD is responsible to resolve shared Rx queue from device and queue data.

Quoted 6 lines

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

Multiple share groups are supported. Device should support mixed configuration by allowing multiple share groups and non-shared Rx queue on one port.

More than a device, it should be the PMD which should support it. Right?

Quoted 8 lines

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

Quoted 4 lines

PMD advertise shared Rx queue capability via RTE_ETH_DEV_CAPA_RXQ_SHARE.

PMD is responsible for shared Rx queue consistency checks to avoid member port's configuration contradict to each other.

contradict each other.

Quoted 54 lines
---
 doc/guides/nics/features.rst                  | 13 ++++++++++
 doc/guides/nics/features/default.ini          |  1 +
 .../prog_guide/switch_representation.rst      | 11 +++++++++
 doc/guides/rel_notes/release_21_11.rst        |  6 +++++
 lib/ethdev/rte_ethdev.c                       |  8 +++++++
 lib/ethdev/rte_ethdev.h                       | 24 +++++++++++++++++++
 6 files changed, 63 insertions(+)
doc/guides/nics/features.rst +13 -0
index e346018e4b8..89f9accbca1 100644
@@ -615,6 +615,19 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same Rx domain of a switch domain.
+
+* **[uses]     rte_eth_dev_info**: ``dev_capa:RTE_ETH_DEV_CAPA_RXQ_SHARE``.
+* **[uses]     rte_eth_dev_info,rte_eth_switch_info**: ``rx_domain``, ``domain_id``.
+* **[uses]     rte_eth_rxconf**: ``share_group``, ``share_qid``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index d473b94091a..93f5d1b46f4 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +0 -0
index ff6aa91c806..fe89a7f5c33 100644
@@ -123,6 +123,17 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)

doc/guides/prog_guide/switch_representation.rst thought as a software "patch panel" front-end for applications. · line 133

Quoted 10 lines
doc/guides/prog_guide/switch_representation.rst +8 -0
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same Rx domain. ``RTE_ETH_DEV_CAPA_RXQ_SHARE`` in
+  device info is used to indicate the capability. Setting non-zero share
+  group in Rx queue configuration to enable share, share_qid is used to
+  identifiy the shared Rx queue in group. Polling any member port can

s/identifiy/identify

Quoted 62 lines
doc/guides/prog_guide/switch_representation.rst +3 -0
+  receive packets of all member ports in the group, port ID is saved in
+  ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +6 -0
index d5435a64aa1..2143e38ff11 100644
@@ -75,6 +75,12 @@ New Features
     operations.
   * Added multi-process support.
 
+* **Added ethdev shared Rx queue support.**
+
+  * Added new device capability flag and rx domain field to switch info.
+  * Added share group and share queue ID to Rx queue configuration.
+  * Added testpmd support and dedicate forwarding engine.
+
 * **Added new RSS offload types for IPv4/L4 checksum in RSS flow.**
 
   Added macros ETH_RSS_IPV4_CHKSUM and ETH_RSS_L4_CHKSUM, now IPv4 and
lib/ethdev/rte_ethdev.c +8 -0
index 028907bc4b9..bc55f899f72 100644
@@ -2159,6 +2159,14 @@ rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
                return -EINVAL;
        }
 
+       if (local_conf.share_group > 0 &&
+           (dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) == 0) {
+               RTE_ETHDEV_LOG(ERR,
+                       "Ethdev port_id=%d rx_queue_id=%d, enabled share_group=%hu while device doesn't support Rx queue share\n",
+                       port_id, rx_queue_id, local_conf.share_group);
+               return -EINVAL;
+       }
+
        /*
         * If LRO is enabled, check that the maximum aggregated packet
         * size is supported by the configured device.
lib/ethdev/rte_ethdev.h +8 -0
index 6d80514ba7a..465293fd66d 100644
@@ -1044,6 +1044,14 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+       /**
+        * Share group index in Rx domain and switch domain.
+        * Non-zero value to enable Rx queue share, zero value disable share.
+        * PMD is responsible for Rx queue consistency checks to avoid member
+        * port's configuration contradict to each other.
+        */
+       uint16_t share_group;
+       uint16_t share_qid; /**< Shared Rx queue ID in group. */
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or rx_offload_capa

lib/ethdev/rte_ethdev.h struct rte_eth_conf { · line 1459

Quoted 7 lines
lib/ethdev/rte_ethdev.h +4 -0
@@ -1445,6 +1453,16 @@ struct rte_eth_conf {
 #define RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP 0x00000001
 /** Device supports Tx queue setup after device started. */
 #define RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP 0x00000002
+/**
+ * Device supports shared Rx queue among ports within Rx domain and
+ * switch domain. Mbufs are consumed by shared Rx queue instead of
+ * each queue. Multiple groups is supported by share_group of Rx

are supported by..

Quoted 25 lines
lib/ethdev/rte_ethdev.h +12 -1
+ * queue configuration. Shared Rx queue is identified by PMD using
+ * share_qid of Rx queue configuration. Polling any port in the group
+ * receive packets of all member ports, source port identified by
+ * mbuf->port field.
+ */
+#define RTE_ETH_DEV_CAPA_RXQ_SHARE              RTE_BIT64(2)
 /**@}*/
 
 /*
@@ -1488,6 +1506,12 @@ struct rte_eth_switch_info {
         * but each driver should explicitly define the mapping of switch
         * port identifier to that physical interconnect/switch
         */
+       /**
+        * Shared Rx queue sub-domain boundary. Only ports in same Rx domain
+        * and switch domain can share Rx queue. Valid only if device advertised
+        * RTE_ETH_DEV_CAPA_RXQ_SHARE capability.
+        */
+       uint16_t rx_domain;
 };
 
 /**
--

2.33.0

#140 lore raw
Quoted 10 lines · Ajit Khaparde
Quoted 8 lines · Xueming Li

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and

s/introduce/introduces

Accepted all the comments, thanks!

Quoted 197 lines
Quoted 13 lines

switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Shared Rx queue is identified by share_rxq field of Rx queue configuration. Port A RxQ X can share RxQ with Port B RxQ Y by using same shared Rx queue ID.

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, port_id is identified by mbuf->port. PMD is responsible to resolve shared Rx queue from device and queue data.

Quoted 6 lines

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

Multiple share groups are supported. Device should support mixed configuration by allowing multiple share groups and non-shared Rx queue on one port.

More than a device, it should be the PMD which should support it. Right?

Quoted 8 lines

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

Quoted 4 lines

PMD advertise shared Rx queue capability via RTE_ETH_DEV_CAPA_RXQ_SHARE.

PMD is responsible for shared Rx queue consistency checks to avoid member port's configuration contradict to each other.

contradict each other.

Quoted 54 lines
---
 doc/guides/nics/features.rst                  | 13 ++++++++++
 doc/guides/nics/features/default.ini          |  1 +
 .../prog_guide/switch_representation.rst      | 11 +++++++++
 doc/guides/rel_notes/release_21_11.rst        |  6 +++++
 lib/ethdev/rte_ethdev.c                       |  8 +++++++
 lib/ethdev/rte_ethdev.h                       | 24 +++++++++++++++++++
 6 files changed, 63 insertions(+)
doc/guides/nics/features.rst +13 -0
index e346018e4b8..89f9accbca1 100644
@@ -615,6 +615,19 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same Rx domain of a switch domain.
+
+* **[uses]     rte_eth_dev_info**: ``dev_capa:RTE_ETH_DEV_CAPA_RXQ_SHARE``.
+* **[uses]     rte_eth_dev_info,rte_eth_switch_info**: ``rx_domain``, ``domain_id``.
+* **[uses]     rte_eth_rxconf**: ``share_group``, ``share_qid``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index d473b94091a..93f5d1b46f4 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +0 -0
index ff6aa91c806..fe89a7f5c33 100644
@@ -123,6 +123,17 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)

doc/guides/prog_guide/switch_representation.rst thought as a software "patch panel" front-end for applications. · line 133

Quoted 10 lines
doc/guides/prog_guide/switch_representation.rst +8 -0
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same Rx domain. ``RTE_ETH_DEV_CAPA_RXQ_SHARE`` in
+  device info is used to indicate the capability. Setting non-zero share
+  group in Rx queue configuration to enable share, share_qid is used to
+  identifiy the shared Rx queue in group. Polling any member port can

s/identifiy/identify

Quoted 62 lines
doc/guides/prog_guide/switch_representation.rst +3 -0
+  receive packets of all member ports in the group, port ID is saved in
+  ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +6 -0
index d5435a64aa1..2143e38ff11 100644
@@ -75,6 +75,12 @@ New Features
     operations.
   * Added multi-process support.
 
+* **Added ethdev shared Rx queue support.**
+
+  * Added new device capability flag and rx domain field to switch info.
+  * Added share group and share queue ID to Rx queue configuration.
+  * Added testpmd support and dedicate forwarding engine.
+
 * **Added new RSS offload types for IPv4/L4 checksum in RSS flow.**
 
   Added macros ETH_RSS_IPV4_CHKSUM and ETH_RSS_L4_CHKSUM, now IPv4 and
lib/ethdev/rte_ethdev.c +8 -0
index 028907bc4b9..bc55f899f72 100644
@@ -2159,6 +2159,14 @@ rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
                return -EINVAL;
        }
 
+       if (local_conf.share_group > 0 &&
+           (dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) == 0) {
+               RTE_ETHDEV_LOG(ERR,
+                       "Ethdev port_id=%d rx_queue_id=%d, enabled share_group=%hu while device doesn't support Rx queue share\n",
+                       port_id, rx_queue_id, local_conf.share_group);
+               return -EINVAL;
+       }
+
        /*
         * If LRO is enabled, check that the maximum aggregated packet
         * size is supported by the configured device.
lib/ethdev/rte_ethdev.h +8 -0
index 6d80514ba7a..465293fd66d 100644
@@ -1044,6 +1044,14 @@ struct rte_eth_rxconf {
        uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
        uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
        uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+       /**
+        * Share group index in Rx domain and switch domain.
+        * Non-zero value to enable Rx queue share, zero value disable share.
+        * PMD is responsible for Rx queue consistency checks to avoid member
+        * port's configuration contradict to each other.
+        */
+       uint16_t share_group;
+       uint16_t share_qid; /**< Shared Rx queue ID in group. */
        /**
         * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
         * Only offloads set on rx_queue_offload_capa or rx_offload_capa

lib/ethdev/rte_ethdev.h struct rte_eth_conf { · line 1459

Quoted 7 lines
lib/ethdev/rte_ethdev.h +4 -0
@@ -1445,6 +1453,16 @@ struct rte_eth_conf {
 #define RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP 0x00000001
 /** Device supports Tx queue setup after device started. */
 #define RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP 0x00000002
+/**
+ * Device supports shared Rx queue among ports within Rx domain and
+ * switch domain. Mbufs are consumed by shared Rx queue instead of
+ * each queue. Multiple groups is supported by share_group of Rx

are supported by..

Quoted 25 lines
lib/ethdev/rte_ethdev.h +12 -1
+ * queue configuration. Shared Rx queue is identified by PMD using
+ * share_qid of Rx queue configuration. Polling any port in the group
+ * receive packets of all member ports, source port identified by
+ * mbuf->port field.
+ */
+#define RTE_ETH_DEV_CAPA_RXQ_SHARE              RTE_BIT64(2)
 /**@}*/
 
 /*
@@ -1488,6 +1506,12 @@ struct rte_eth_switch_info {
         * but each driver should explicitly define the mapping of switch
         * port identifier to that physical interconnect/switch
         */
+       /**
+        * Shared Rx queue sub-domain boundary. Only ports in same Rx domain
+        * and switch domain can share Rx queue. Valid only if device advertised
+        * RTE_ETH_DEV_CAPA_RXQ_SHARE capability.
+        */
+       uint16_t rx_domain;
 };
 
 /**
--

2.33.0

Reviewed-by on v8 1/6
#141 lore raw
In reply to Xueming Li
Quoted 33 lines · Xueming Li

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduce shared Rx queue. Ports in same Rx domain and switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Shared Rx queue is identified by share_rxq field of Rx queue configuration. Port A RxQ X can share RxQ with Port B RxQ Y by using same shared Rx queue ID.

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, port_id is identified by mbuf->port. PMD is responsible to resolve shared Rx queue from device and queue data.

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

Multiple share groups are supported. Device should support mixed configuration by allowing multiple share groups and non-shared Rx queue on one port.

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

Quoted 6 lines

PMD advertise shared Rx queue capability via RTE_ETH_DEV_CAPA_RXQ_SHARE.

PMD is responsible for shared Rx queue consistency checks to avoid member port's configuration contradict to each other.

with few nits below:

[snip]

Quoted 6 lines
doc/guides/prog_guide/switch_representation.rst +0 -0
index ff6aa91c806..fe89a7f5c33 100644
@@ -123,6 +123,17 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)

doc/guides/prog_guide/switch_representation.rst thought as a software "patch panel" front-end for applications. · line 133

Quoted 10 lines
doc/guides/prog_guide/switch_representation.rst +8 -0
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same Rx domain. ``RTE_ETH_DEV_CAPA_RXQ_SHARE`` in
+  device info is used to indicate the capability. Setting non-zero share
+  group in Rx queue configuration to enable share, share_qid is used to
+  identifiy the shared Rx queue in group. Polling any member port can

identifiy -> identify

Quoted 11 lines
doc/guides/prog_guide/switch_representation.rst +3 -0
+  receive packets of all member ports in the group, port ID is saved in
+  ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +0 -0
index d5435a64aa1..2143e38ff11 100644

doc/guides/rel_notes/release_21_11.rst New Features · line 80

Quoted 6 lines
doc/guides/rel_notes/release_21_11.rst +3 -0
@@ -75,6 +75,12 @@ New Features
     operations.
   * Added multi-process support.
 
+* **Added ethdev shared Rx queue support.**
+
+  * Added new device capability flag and rx domain field to switch info.

rx -> Rx

Quoted 6 lines
doc/guides/rel_notes/release_21_11.rst +3 -0
+  * Added share group and share queue ID to Rx queue configuration.
+  * Added testpmd support and dedicate forwarding engine.
+
 * **Added new RSS offload types for IPv4/L4 checksum in RSS flow.**
 
   Added macros ETH_RSS_IPV4_CHKSUM and ETH_RSS_L4_CHKSUM, now IPv4 and

[snip]

author
#142 lore raw

PATCH v8 2/6 app/testpmd: dump device capability and Rx domain info

In reply to Xueming Li

Dump device capability and Rx domain ID if shared Rx queue is supported by device.

---
 app/test-pmd/config.c | 4 ++++
 1 file changed, 4 insertions(+)
app/test-pmd/config.c +4 -0
index 9c66329e96e..c0616dcd2fd 100644
@@ -733,6 +733,7 @@ port_infos_display(portid_t port_id)
 	printf("Max segment number per MTU/TSO: %hu\n",
 		dev_info.tx_desc_lim.nb_mtu_seg_max);
 
+	printf("Device capabilities: 0x%"PRIx64"\n", dev_info.dev_capa);
 	/* Show switch info only if valid switch domain and port id is set */
 	if (dev_info.switch_info.domain_id !=
 		RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID) {
@@ -743,6 +744,9 @@ port_infos_display(portid_t port_id)
 			dev_info.switch_info.domain_id);
 		printf("Switch Port Id: %u\n",
 			dev_info.switch_info.port_id);
+		if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) != 0)
+			printf("Switch Rx domain: %u\n",
+			       dev_info.switch_info.rx_domain);
 	}
 }
 
Signature · 1 line
2.33.0
author
#143 lore raw

PATCH v8 3/6 app/testpmd: new parameter to enable shared Rx queue

In reply to Xueming Li

Adds "--rxq-share=X" parameter to enable shared RxQ, share if device supports, otherwise fallback to standard RxQ.

Share group number grows per X ports. X defaults to MAX, implies all ports join share group 1. Queue ID is mapped equally with shared Rx queue ID.

Forwarding engine "shared-rxq" should be used which Rx only and update stream statistics correctly.

---
 app/test-pmd/config.c                 |  7 ++++++-
 app/test-pmd/parameters.c             | 13 +++++++++++++
 app/test-pmd/testpmd.c                | 20 +++++++++++++++++---
 app/test-pmd/testpmd.h                |  2 ++
 doc/guides/testpmd_app_ug/run_app.rst |  7 +++++++
 5 files changed, 45 insertions(+), 4 deletions(-)
app/test-pmd/config.c +6 -1
index c0616dcd2fd..f8fb8961cae 100644
@@ -2713,7 +2713,12 @@ rxtx_config_display(void)
 			printf("      RX threshold registers: pthresh=%d hthresh=%d "
 				" wthresh=%d\n",
 				pthresh_tmp, hthresh_tmp, wthresh_tmp);
-			printf("      RX Offloads=0x%"PRIx64"\n", offloads_tmp);
+			printf("      RX Offloads=0x%"PRIx64, offloads_tmp);
+			if (rx_conf->share_group > 0)
+				printf(" share_group=%u share_qid=%u",
+				       rx_conf->share_group,
+				       rx_conf->share_qid);
+			printf("\n");
 		}
 
 		/* per tx queue config only for first queue to be less verbose */
app/test-pmd/parameters.c +13 -0
index 3f94a82e321..30dae326310 100644
@@ -167,6 +167,7 @@ usage(char* progname)
 	printf("  --tx-ip=src,dst: IP addresses in Tx-only mode\n");
 	printf("  --tx-udp=src[,dst]: UDP ports in Tx-only mode\n");
 	printf("  --eth-link-speed: force link speed.\n");
+	printf("  --rxq-share: number of ports per shared rxq groups, defaults to MAX(1 group)\n");
 	printf("  --disable-link-check: disable check on link status when "
 	       "starting/stopping ports.\n");
 	printf("  --disable-device-start: do not automatically start port\n");
@@ -607,6 +608,7 @@ launch_args_parse(int argc, char** argv)
 		{ "rxpkts",			1, 0, 0 },
 		{ "txpkts",			1, 0, 0 },
 		{ "txonly-multi-flow",		0, 0, 0 },
+		{ "rxq-share",			2, 0, 0 },
 		{ "eth-link-speed",		1, 0, 0 },
 		{ "disable-link-check",		0, 0, 0 },
 		{ "disable-device-start",	0, 0, 0 },
@@ -1271,6 +1273,17 @@ launch_args_parse(int argc, char** argv)
 			}
 			if (!strcmp(lgopts[opt_idx].name, "txonly-multi-flow"))
 				txonly_multi_flow = 1;
+			if (!strcmp(lgopts[opt_idx].name, "rxq-share")) {
+				if (optarg == NULL) {
+					rxq_share = UINT32_MAX;
+				} else {
+					n = atoi(optarg);
+					if (n >= 0)
+						rxq_share = (uint32_t)n;
+					else
+						rte_exit(EXIT_FAILURE, "rxq-share must be >= 0\n");
+				}
+			}
 			if (!strcmp(lgopts[opt_idx].name, "no-flush-rx"))
 				no_flush_rx = 1;
 			if (!strcmp(lgopts[opt_idx].name, "eth-link-speed")) {
app/test-pmd/testpmd.c +17 -3
index 97ae52e17ec..123142ed110 100644
@@ -498,6 +498,11 @@ uint8_t record_core_cycles;
  */
 uint8_t record_burst_stats;
 
+/*
+ * Number of ports per shared Rx queue group, 0 disable.
+ */
+uint32_t rxq_share;
+
 unsigned int num_sockets = 0;
 unsigned int socket_ids[RTE_MAX_NUMA_NODES];
 
@@ -3393,14 +3398,23 @@ dev_event_callback(const char *device_name, enum rte_dev_event_type type,
 }
 
 static void
-rxtx_port_config(struct rte_port *port)
+rxtx_port_config(portid_t pid)
 {
 	uint16_t qid;
 	uint64_t offloads;
+	struct rte_port *port = &ports[pid];
 
 	for (qid = 0; qid < nb_rxq; qid++) {
 		offloads = port->rx_conf[qid].offloads;
 		port->rx_conf[qid] = port->dev_info.default_rxconf;
+
+		if (rxq_share > 0 &&
+		    (port->dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)) {
+			/* Non-zero share group to enable RxQ share. */
+			port->rx_conf[qid].share_group = pid / rxq_share + 1;
+			port->rx_conf[qid].share_qid = qid; /* Equal mapping. */
+		}
+
 		if (offloads != 0)
 			port->rx_conf[qid].offloads = offloads;
 
@@ -3558,7 +3572,7 @@ init_port_config(void)
 				port->dev_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
 		}
 
-		rxtx_port_config(port);
+		rxtx_port_config(pid);
 
 		ret = eth_macaddr_get_print_err(pid, &port->eth_addr);
 		if (ret != 0)
@@ -3772,7 +3786,7 @@ init_port_dcb_config(portid_t pid,
 
 	memcpy(&rte_port->dev_conf, &port_conf, sizeof(struct rte_eth_conf));
 
-	rxtx_port_config(rte_port);
+	rxtx_port_config(pid);
 	/* VLAN filter */
 	rte_port->dev_conf.rxmode.offloads |= DEV_RX_OFFLOAD_VLAN_FILTER;
 	for (i = 0; i < RTE_DIM(vlan_tags); i++)
app/test-pmd/testpmd.h +2 -0
index 5863b2f43f3..3dfaaad94c0 100644
@@ -477,6 +477,8 @@ extern enum tx_pkt_split tx_pkt_split;
 
 extern uint8_t txonly_multi_flow;
 
+extern uint32_t rxq_share;
+
 extern uint16_t nb_pkt_per_burst;
 extern uint16_t nb_pkt_flowgen_clones;
 extern int nb_flows_flowgen;
doc/guides/testpmd_app_ug/run_app.rst +7 -0
index 640eadeff73..ff5908dcd50 100644
@@ -389,6 +389,13 @@ The command line options are:
 
     Generate multiple flows in txonly mode.
 
+*   ``--rxq-share=[X]``
+
+    Create queues in shared Rx queue mode if device supports.
+    Group number grows per X ports. X defaults to MAX, implies all ports
+    join share group 1. Forwarding engine "shared-rxq" should be used
+    which Rx only and update stream statistics correctly.
+
 *   ``--eth-link-speed``
 
     Set a forced link speed to the ethernet port::
Signature · 1 line
2.33.0
author
#144 lore raw

PATCH v8 4/6 app/testpmd: dump port info for shared Rx queue

In reply to Xueming Li

In case of shared Rx queue, polling any member port returns mbufs for all members. This patch dumps mbuf->port for each packet.

---
 app/test-pmd/util.c | 3 +++
 1 file changed, 3 insertions(+)
app/test-pmd/util.c +3 -0
index 51506e49404..e98f136d5ed 100644
@@ -100,6 +100,9 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
 		struct rte_flow_restore_info info = { 0, };
 
 		mb = pkts[i];
+		if (rxq_share > 0)
+			MKDUMPSTR(print_buf, buf_size, cur_len, "port %u, ",
+				  mb->port);
 		eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
 		eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
 		packet_type = mb->packet_type;
Signature · 1 line
2.33.0
author
#145 lore raw

PATCH v8 5/6 app/testpmd: force shared Rx queue polled on same core

In reply to Xueming Li

Shared Rx queue must be polled on same core. This patch checks and stops forwarding if shared RxQ being scheduled on multiple
cores.

It's suggested to use same number of Rx queues and polling cores.

---
 app/test-pmd/config.c  | 103 +++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.c |   4 +-
 app/test-pmd/testpmd.h |   2 +
 3 files changed, 108 insertions(+), 1 deletion(-)
app/test-pmd/config.c +103 -0
index f8fb8961cae..c4150d77589 100644
@@ -2890,6 +2890,109 @@ port_rss_hash_key_update(portid_t port_id, char rss_type[], uint8_t *hash_key,
 	}
 }
 
+/*
+ * Check whether a shared rxq scheduled on other lcores.
+ */
+static bool
+fwd_stream_on_other_lcores(uint16_t domain_id, lcoreid_t src_lc,
+			   portid_t src_port, queueid_t src_rxq,
+			   uint32_t share_group, queueid_t share_rxq)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	struct rte_port *port;
+	struct rte_eth_dev_info *dev_info;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	/* Check remaining cores. */
+	for (lc_id = src_lc + 1; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			port = &ports[fs->rx_port];
+			dev_info = &port->dev_info;
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			if (domain_id != port->dev_info.switch_info.domain_id)
+				continue;
+			if (rxq_conf->share_group != share_group)
+				continue;
+			if (rxq_conf->share_qid != share_rxq)
+				continue;
+			printf("Shared Rx queue group %u queue %hu can't be scheduled on different cores:\n",
+			       share_group, share_rxq);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       src_lc, src_port, src_rxq);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       lc_id, fs->rx_port, fs->rx_queue);
+			printf("Please use --nb-cores=%hu to limit number of forwarding cores\n",
+			       nb_rxq);
+			return true;
+		}
+	}
+	return false;
+}
+
+/*
+ * Check shared rxq configuration.
+ *
+ * Shared group must not being scheduled on different core.
+ */
+bool
+pkt_fwd_shared_rxq_check(void)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	uint16_t domain_id;
+	struct rte_port *port;
+	struct rte_eth_dev_info *dev_info;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	/*
+	 * Check streams on each core, make sure the same switch domain +
+	 * group + queue doesn't get scheduled on other cores.
+	 */
+	for (lc_id = 0; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			/* Update lcore info stream being scheduled. */
+			fs->lcore = fwd_lcores[lc_id];
+			port = &ports[fs->rx_port];
+			dev_info = &port->dev_info;
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			/* Check shared rxq not scheduled on remaining cores. */
+			domain_id = port->dev_info.switch_info.domain_id;
+			if (fwd_stream_on_other_lcores(domain_id, lc_id,
+						       fs->rx_port,
+						       fs->rx_queue,
+						       rxq_conf->share_group,
+						       rxq_conf->share_qid))
+				return false;
+		}
+	}
+	return true;
+}
+
 /*
  * Setup forwarding configuration for each logical core.
  */
app/test-pmd/testpmd.c +3 -1
index 123142ed110..f3f81ef561f 100644
@@ -2236,10 +2236,12 @@ start_packet_forwarding(int with_tx_first)
 
 	fwd_config_setup();
 
+	pkt_fwd_config_display(&cur_fwd_config);
+	if (!pkt_fwd_shared_rxq_check())
+		return;
 	if(!no_flush_rx)
 		flush_fwd_rx_queues();
 
-	pkt_fwd_config_display(&cur_fwd_config);
 	rxtx_config_display();
 
 	fwd_stats_reset();
app/test-pmd/testpmd.h +2 -0
index 3dfaaad94c0..f121a2da90c 100644
@@ -144,6 +144,7 @@ struct fwd_stream {
 	uint64_t     core_cycles; /**< used for RX and TX processing */
 	struct pkt_burst_stats rx_burst_stats;
 	struct pkt_burst_stats tx_burst_stats;
+	struct fwd_lcore *lcore; /**< Lcore being scheduled. */
 };
 
 /**
@@ -795,6 +796,7 @@ void port_summary_header_display(void);
 void rx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void tx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void fwd_lcores_config_display(void);
+bool pkt_fwd_shared_rxq_check(void);
 void pkt_fwd_config_display(struct fwd_config *cfg);
 void rxtx_config_display(void);
 void fwd_config_setup(void);
Signature · 1 line
2.33.0
author
#146 lore raw

PATCH v8 6/6 app/testpmd: add forwarding engine for shared Rx queue

In reply to Xueming Li

To support shared Rx queue, this patch introduces dedicate forwarding engine. The engine groups received packets by mbuf->port into sub-group, updates stream statistics and simply frees packets.

---
 app/test-pmd/meson.build                    |   1 +
 app/test-pmd/shared_rxq_fwd.c               | 148 ++++++++++++++++++++
 app/test-pmd/testpmd.c                      |   1 +
 app/test-pmd/testpmd.h                      |   1 +
 doc/guides/testpmd_app_ug/run_app.rst       |   1 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |   5 +-
 6 files changed, 156 insertions(+), 1 deletion(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
app/test-pmd/meson.build +1 -0
index 98f3289bdfa..07042e45b12 100644
@@ -21,6 +21,7 @@ sources = files(
         'noisy_vnf.c',
         'parameters.c',
         'rxonly.c',
+        'shared_rxq_fwd.c',
         'testpmd.c',
         'txonly.c',
         'util.c',
app/test-pmd/shared_rxq_fwd.c new file +148 -0

148 lines not on this page · raw message

app/test-pmd/testpmd.c +1 -0
index f3f81ef561f..11a85d92d9a 100644
@@ -188,6 +188,7 @@ struct fwd_engine * fwd_engines[] = {
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
+	&shared_rxq_engine,
 	NULL,
 };
 
app/test-pmd/testpmd.h +1 -0
index f121a2da90c..f1fd607e365 100644
@@ -299,6 +299,7 @@ extern struct fwd_engine five_tuple_swap_fwd_engine;
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
+extern struct fwd_engine shared_rxq_engine;
 
 extern struct fwd_engine * fwd_engines[]; /**< NULL terminated array. */
 extern cmdline_parse_inst_t cmd_set_raw;
doc/guides/testpmd_app_ug/run_app.rst +1 -0
index ff5908dcd50..e4b97844ced 100644
@@ -252,6 +252,7 @@ The command line options are:
        tm
        noisy
        5tswap
+       shared-rxq
 
 *   ``--rss-ip``
 
doc/guides/testpmd_app_ug/testpmd_funcs.rst +4 -1
index 8ead7a4a712..499874187f2 100644
@@ -314,7 +314,7 @@ set fwd
 Set the packet forwarding mode::
 
    testpmd> set fwd (io|mac|macswap|flowgen| \
-                     rxonly|txonly|csum|icmpecho|noisy|5tswap) (""|retry)
+                     rxonly|txonly|csum|icmpecho|noisy|5tswap|shared-rxq) (""|retry)
 
 ``retry`` can be specified for forwarding engines except ``rx_only``.
 
@@ -357,6 +357,9 @@ The available information categories are:
 
   L4 swaps the source port and destination port of transport layer (TCP and UDP).
 
+* ``shared-rxq``: Receive only for shared Rx queue.
+  Resolve packet source port from mbuf and update stream statistics accordingly.
+
 Example::
 
    testpmd> set fwd rxonly
Signature · 1 line
2.33.0
author
#147 lore raw

v9 cover ethdev: introduce shared Rx queue

In reply to Xueming Li

In current DPDK framework, all Rx queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared Rx queue. PF and representors in same Rx domain and switch domain could share Rx queue set by specifying non-zero share group value in Rx queue configuration.

All ports that share Rx queue actually shares hardware descriptor queue and feed all Rx queues with one descriptor supply, memory is saved.

Polling any queue using same shared Rx queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of two share groups:
Group1, 4 shared Rx queues per member port: PF, repr0, repr1 Group2, 2 shared Rx queues per member port: repr2, repr3, ... repr127 Poll first port for each group:
core port queue
0 0 0
1 0 1
2 0 2
3 0 3
4 2 0
5 2 1

Shared Rx queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

There was some discussion to aggregate member ports in same group into a dummy port, several ways to achieve it. Since it optional, need to collect more feedback and requirement from user, make better decision later.

v1:
- initial version
v2:
- add testpmd patches
v3:
- change common forwarding api to macro for performance, thanks Jerin.
- save global variable accessed in forwarding to flowstream to minimize cache miss
- combined patches for each forwarding engine
- support multiple groups in testpmd "--share-rxq" parameter
- new api to aggregate shared rxq group
v4:
- spelling fixes
- remove shared-rxq support for all forwarding engines
- add dedicate shared-rxq forwarding engine
v5:
- fix grammars
- remove aggregate api and leave it for later discussion
- add release notes
- add deployment example
v6:
- replace RxQ offload flag with device offload capability flag
- add Rx domain
- RxQ is shared when share group > 0
- update testpmd accordingly
v7:
- fix testpmd share group id allocation
- change rx_domain to 16bits
v8:
- add new patch for testpmd to show device Rx domain ID and capability
- new share_qid in RxQ configuration
v9:
- fix some spelling

Xueming Li (6):
ethdev: introduce shared Rx queue app/testpmd: dump device capability and Rx domain info app/testpmd: new parameter to enable shared Rx queue app/testpmd: dump port info for shared Rx queue app/testpmd: force shared Rx queue polled on same core app/testpmd: add forwarding engine for shared Rx queue

 app/test-pmd/config.c                         | 114 +++++++++++++-
 app/test-pmd/meson.build                      |   1 +
 app/test-pmd/parameters.c                     |  13 ++
 app/test-pmd/shared_rxq_fwd.c                 | 148 ++++++++++++++++++
 app/test-pmd/testpmd.c                        |  25 ++-
 app/test-pmd/testpmd.h                        |   5 +
 app/test-pmd/util.c                           |   3 +
 doc/guides/nics/features.rst                  |  13 ++
 doc/guides/nics/features/default.ini          |   1 +
 .../prog_guide/switch_representation.rst      |  11 ++
 doc/guides/rel_notes/release_21_11.rst        |   6 +
 doc/guides/testpmd_app_ug/run_app.rst         |   8 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst   |   5 +-
 lib/ethdev/rte_ethdev.c                       |   8 +
 lib/ethdev/rte_ethdev.h                       |  24 +++
 15 files changed, 379 insertions(+), 6 deletions(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
Signature · 1 line
2.33.0
author
#148 lore raw

PATCH v9 1/6 ethdev: introduce shared Rx queue

In current DPDK framework, each Rx queue is pre-loaded with mbufs to save incoming packets. For some PMDs, when number of representors scale out in a switch domain, the memory consumption became significant. Polling all ports also leads to high cache miss, high latency and low throughput.

This patch introduces shared Rx queue. Ports in same Rx domain and switch domain could share Rx queue set by specifying non-zero sharing group in Rx queue configuration.

Shared Rx queue is identified by share_rxq field of Rx queue configuration. Port A RxQ X can share RxQ with Port B RxQ Y by using same shared Rx queue ID.

No special API is defined to receive packets from shared Rx queue. Polling any member port of a shared Rx queue receives packets of that queue for all member ports, port_id is identified by mbuf->port. PMD is responsible to resolve shared Rx queue from device and queue data.

Shared Rx queue must be polled in same thread or core, polling a queue ID of any member port is essentially same.

Multiple share groups are supported. PMD should support mixed configuration by allowing multiple share groups and non-shared Rx queue on one port.

Example grouping and polling model to reflect service priority:
Group1, 2 shared Rx queues per port: PF, rep0, rep1 Group2, 1 shared Rx queue per port: rep2, rep3, ... rep127
Core0: poll PF queue0
Core1: poll PF queue1
Core2: poll rep2 queue0

PMD advertise shared Rx queue capability via RTE_ETH_DEV_CAPA_RXQ_SHARE.

PMD is responsible for shared Rx queue consistency checks to avoid member port's configuration contradict each other.

---
 doc/guides/nics/features.rst                  | 13 ++++++++++
 doc/guides/nics/features/default.ini          |  1 +
 .../prog_guide/switch_representation.rst      | 11 +++++++++
 doc/guides/rel_notes/release_21_11.rst        |  6 +++++
 lib/ethdev/rte_ethdev.c                       |  8 +++++++
 lib/ethdev/rte_ethdev.h                       | 24 +++++++++++++++++++
 6 files changed, 63 insertions(+)
doc/guides/nics/features.rst +13 -0
index e346018e4b8..89f9accbca1 100644
@@ -615,6 +615,19 @@ Supports inner packet L4 checksum.
   ``tx_offload_capa,tx_queue_offload_capa:DEV_TX_OFFLOAD_OUTER_UDP_CKSUM``.
 
 
+.. _nic_features_shared_rx_queue:
+
+Shared Rx queue
+---------------
+
+Supports shared Rx queue for ports in same Rx domain of a switch domain.
+
+* **[uses]     rte_eth_dev_info**: ``dev_capa:RTE_ETH_DEV_CAPA_RXQ_SHARE``.
+* **[uses]     rte_eth_dev_info,rte_eth_switch_info**: ``rx_domain``, ``domain_id``.
+* **[uses]     rte_eth_rxconf**: ``share_group``, ``share_qid``.
+* **[provides] mbuf**: ``mbuf.port``.
+
+
 .. _nic_features_packet_type_parsing:
 
 Packet type parsing
doc/guides/nics/features/default.ini +1 -0
index d473b94091a..93f5d1b46f4 100644
@@ -19,6 +19,7 @@ Free Tx mbuf on demand =
 Queue start/stop     =
 Runtime Rx queue setup =
 Runtime Tx queue setup =
+Shared Rx queue      =
 Burst mode info      =
 Power mgmt address monitor =
 MTU update           =
doc/guides/prog_guide/switch_representation.rst +11 -0
index ff6aa91c806..4f2532a91ea 100644
@@ -123,6 +123,17 @@ thought as a software "patch panel" front-end for applications.
 .. [1] `Ethernet switch device driver model (switchdev)
        <https://www.kernel.org/doc/Documentation/networking/switchdev.txt>`_
 
+- For some PMDs, memory usage of representors is huge when number of
+  representor grows, mbufs are allocated for each descriptor of Rx queue.
+  Polling large number of ports brings more CPU load, cache miss and
+  latency. Shared Rx queue can be used to share Rx queue between PF and
+  representors among same Rx domain. ``RTE_ETH_DEV_CAPA_RXQ_SHARE`` in
+  device info is used to indicate the capability. Setting non-zero share
+  group in Rx queue configuration to enable share, share_qid is used to
+  identify the shared Rx queue in group. Polling any member port can
+  receive packets of all member ports in the group, port ID is saved in
+  ``mbuf.port``.
+
 Basic SR-IOV
 ------------
 
doc/guides/rel_notes/release_21_11.rst +6 -0
index d5435a64aa1..b34d9776a15 100644
@@ -75,6 +75,12 @@ New Features
     operations.
   * Added multi-process support.
 
+* **Added ethdev shared Rx queue support.**
+
+  * Added new device capability flag and Rx domain field to switch info.
+  * Added share group and share queue ID to Rx queue configuration.
+  * Added testpmd support and dedicate forwarding engine.
+
 * **Added new RSS offload types for IPv4/L4 checksum in RSS flow.**
 
   Added macros ETH_RSS_IPV4_CHKSUM and ETH_RSS_L4_CHKSUM, now IPv4 and
lib/ethdev/rte_ethdev.c +8 -0
index 028907bc4b9..bc55f899f72 100644
@@ -2159,6 +2159,14 @@ rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
 		return -EINVAL;
 	}
 
+	if (local_conf.share_group > 0 &&
+	    (dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) == 0) {
+		RTE_ETHDEV_LOG(ERR,
+			"Ethdev port_id=%d rx_queue_id=%d, enabled share_group=%hu while device doesn't support Rx queue share\n",
+			port_id, rx_queue_id, local_conf.share_group);
+		return -EINVAL;
+	}
+
 	/*
 	 * If LRO is enabled, check that the maximum aggregated packet
 	 * size is supported by the configured device.
lib/ethdev/rte_ethdev.h +24 -0
index 6d80514ba7a..34acc91273d 100644
@@ -1044,6 +1044,14 @@ struct rte_eth_rxconf {
 	uint8_t rx_drop_en; /**< Drop packets if no descriptors are available. */
 	uint8_t rx_deferred_start; /**< Do not start queue with rte_eth_dev_start(). */
 	uint16_t rx_nseg; /**< Number of descriptions in rx_seg array. */
+	/**
+	 * Share group index in Rx domain and switch domain.
+	 * Non-zero value to enable Rx queue share, zero value disable share.
+	 * PMD is responsible for Rx queue consistency checks to avoid member
+	 * port's configuration contradict to each other.
+	 */
+	uint16_t share_group;
+	uint16_t share_qid; /**< Shared Rx queue ID in group. */
 	/**
 	 * Per-queue Rx offloads to be set using DEV_RX_OFFLOAD_* flags.
 	 * Only offloads set on rx_queue_offload_capa or rx_offload_capa
@@ -1445,6 +1453,16 @@ struct rte_eth_conf {
 #define RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP 0x00000001
 /** Device supports Tx queue setup after device started. */
 #define RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP 0x00000002
+/**
+ * Device supports shared Rx queue among ports within Rx domain and
+ * switch domain. Mbufs are consumed by shared Rx queue instead of
+ * each queue. Multiple groups are supported by share_group of Rx
+ * queue configuration. Shared Rx queue is identified by PMD using
+ * share_qid of Rx queue configuration. Polling any port in the group
+ * receive packets of all member ports, source port identified by
+ * mbuf->port field.
+ */
+#define RTE_ETH_DEV_CAPA_RXQ_SHARE              RTE_BIT64(2)
 /**@}*/
 
 /*
@@ -1488,6 +1506,12 @@ struct rte_eth_switch_info {
 	 * but each driver should explicitly define the mapping of switch
 	 * port identifier to that physical interconnect/switch
 	 */
+	/**
+	 * Shared Rx queue sub-domain boundary. Only ports in same Rx domain
+	 * and switch domain can share Rx queue. Valid only if device advertised
+	 * RTE_ETH_DEV_CAPA_RXQ_SHARE capability.
+	 */
+	uint16_t rx_domain;
 };
 
 /**
Signature · 1 line
2.33.0
author
#149 lore raw

PATCH v9 2/6 app/testpmd: dump device capability and Rx domain info

In reply to Xueming Li

Dump device capability and Rx domain ID if shared Rx queue is supported by device.

---
 app/test-pmd/config.c | 4 ++++
 1 file changed, 4 insertions(+)
app/test-pmd/config.c +4 -0
index 9c66329e96e..c0616dcd2fd 100644
@@ -733,6 +733,7 @@ port_infos_display(portid_t port_id)
 	printf("Max segment number per MTU/TSO: %hu\n",
 		dev_info.tx_desc_lim.nb_mtu_seg_max);
 
+	printf("Device capabilities: 0x%"PRIx64"\n", dev_info.dev_capa);
 	/* Show switch info only if valid switch domain and port id is set */
 	if (dev_info.switch_info.domain_id !=
 		RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID) {
@@ -743,6 +744,9 @@ port_infos_display(portid_t port_id)
 			dev_info.switch_info.domain_id);
 		printf("Switch Port Id: %u\n",
 			dev_info.switch_info.port_id);
+		if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) != 0)
+			printf("Switch Rx domain: %u\n",
+			       dev_info.switch_info.rx_domain);
 	}
 }
 
Signature · 1 line
2.33.0
Acked-by on v9 2/6
#150 lore raw

Re: [dpdk-dev] [PATCH v9 2/6] app/testpmd: dump device capability and Rx domain info

Quoted 4 lines · Xueming Li

Dump device capability and Rx domain ID if shared Rx queue is supported by device.

LGTM except one minor note:

app/test-pmd/config.c port_infos_display(portid_t port_id) · line 736

Quoted 13 lines
---
 app/test-pmd/config.c | 4 ++++
 1 file changed, 4 insertions(+)
app/test-pmd/config.c +1 -0
index 9c66329e96e..c0616dcd2fd 100644
@@ -733,6 +733,7 @@ port_infos_display(portid_t port_id)
 	printf("Max segment number per MTU/TSO: %hu\n",
 		dev_info.tx_desc_lim.nb_mtu_seg_max);
 
+	printf("Device capabilities: 0x%"PRIx64"\n", dev_info.dev_capa);

IMHO, it should be decoded

Quoted 14 lines
app/test-pmd/config.c +3 -0
 	/* Show switch info only if valid switch domain and port id is set */
 	if (dev_info.switch_info.domain_id !=
 		RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID) {
@@ -743,6 +744,9 @@ port_infos_display(portid_t port_id)
 			dev_info.switch_info.domain_id);
 		printf("Switch Port Id: %u\n",
 			dev_info.switch_info.port_id);
+		if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) != 0)
+			printf("Switch Rx domain: %u\n",
+			       dev_info.switch_info.rx_domain);
 	}
 }
 
#151 lore raw

Re: [dpdk-dev] [PATCH v9 2/6] app/testpmd: dump device capability and Rx domain info

Quoted 22 lines · Andrew Rybchenko
Quoted 4 lines · Xueming Li

Dump device capability and Rx domain ID if shared Rx queue is supported by device.

LGTM except one minor note:

Quoted 12 lines
---
 app/test-pmd/config.c | 4 ++++
 1 file changed, 4 insertions(+)
app/test-pmd/config.c +0 -0
index 9c66329e96e..c0616dcd2fd 100644
@@ -733,6 +733,7 @@ port_infos_display(portid_t port_id)
 	printf("Max segment number per MTU/TSO: %hu\n",
 		dev_info.tx_desc_lim.nb_mtu_seg_max);
 
Quoted 3 lines

app/test-pmd/config.c port_infos_display(portid_t port_id) · line 736

Quoted 1 line
app/test-pmd/config.c +1 -0
+	printf("Device capabilities: 0x%"PRIx64"\n", dev_info.dev_capa);

IMHO, it should be decoded

Thanks for checking this, do you mean decode to readable names? Then we need a new API rte_eth_dev_capability_name(), it's simple, but is it ok to add API w/o RFC?

Quoted 16 lines
Quoted 15 lines
app/test-pmd/config.c +3 -0
 	/* Show switch info only if valid switch domain and port id is set */
 	if (dev_info.switch_info.domain_id !=
 		RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID) {
@@ -743,6 +744,9 @@ port_infos_display(portid_t port_id)
 			dev_info.switch_info.domain_id);
 		printf("Switch Port Id: %u\n",
 			dev_info.switch_info.port_id);
+		if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) != 0)
+			printf("Switch Rx domain: %u\n",
+			       dev_info.switch_info.rx_domain);
 	}
 }
 
#152 lore raw

Re: [dpdk-dev] [PATCH v9 2/6] app/testpmd: dump device capability and Rx domain info

Quoted 23 lines · Xueming(Steven) Li
Quoted 22 lines · Andrew Rybchenko
Quoted 4 lines · Xueming Li

Dump device capability and Rx domain ID if shared Rx queue is supported by device.

LGTM except one minor note:

Quoted 12 lines
---
 app/test-pmd/config.c | 4 ++++
 1 file changed, 4 insertions(+)
app/test-pmd/config.c +0 -0
index 9c66329e96e..c0616dcd2fd 100644
@@ -733,6 +733,7 @@ port_infos_display(portid_t port_id)
 	printf("Max segment number per MTU/TSO: %hu\n",
 		dev_info.tx_desc_lim.nb_mtu_seg_max);
 
Quoted 7 lines
Quoted 3 lines

app/test-pmd/config.c port_infos_display(portid_t port_id) · line 736

Quoted 1 line
app/test-pmd/config.c +1 -0
+	printf("Device capabilities: 0x%"PRIx64"\n", dev_info.dev_capa);

IMHO, it should be decoded

Thanks for checking this, do you mean decode to readable names? Then we need a new API rte_eth_dev_capability_name(), it's simple, but is it ok to add API w/o RFC?

It is trivial. So, I think it should be OK.

author
#153 lore raw

PATCH v9 3/6 app/testpmd: new parameter to enable shared Rx queue

In reply to Xueming Li

Adds "--rxq-share=X" parameter to enable shared RxQ, share if device supports, otherwise fallback to standard RxQ.

Share group number grows per X ports. X defaults to MAX, implies all ports join share group 1. Queue ID is mapped equally with shared Rx queue ID.

Forwarding engine "shared-rxq" should be used which Rx only and update stream statistics correctly.

---
 app/test-pmd/config.c                 |  7 ++++++-
 app/test-pmd/parameters.c             | 13 +++++++++++++
 app/test-pmd/testpmd.c                | 20 +++++++++++++++++---
 app/test-pmd/testpmd.h                |  2 ++
 doc/guides/testpmd_app_ug/run_app.rst |  7 +++++++
 5 files changed, 45 insertions(+), 4 deletions(-)
app/test-pmd/config.c +6 -1
index c0616dcd2fd..f8fb8961cae 100644
@@ -2713,7 +2713,12 @@ rxtx_config_display(void)
 			printf("      RX threshold registers: pthresh=%d hthresh=%d "
 				" wthresh=%d\n",
 				pthresh_tmp, hthresh_tmp, wthresh_tmp);
-			printf("      RX Offloads=0x%"PRIx64"\n", offloads_tmp);
+			printf("      RX Offloads=0x%"PRIx64, offloads_tmp);
+			if (rx_conf->share_group > 0)
+				printf(" share_group=%u share_qid=%u",
+				       rx_conf->share_group,
+				       rx_conf->share_qid);
+			printf("\n");
 		}
 
 		/* per tx queue config only for first queue to be less verbose */
app/test-pmd/parameters.c +13 -0
index 3f94a82e321..30dae326310 100644
@@ -167,6 +167,7 @@ usage(char* progname)
 	printf("  --tx-ip=src,dst: IP addresses in Tx-only mode\n");
 	printf("  --tx-udp=src[,dst]: UDP ports in Tx-only mode\n");
 	printf("  --eth-link-speed: force link speed.\n");
+	printf("  --rxq-share: number of ports per shared rxq groups, defaults to MAX(1 group)\n");
 	printf("  --disable-link-check: disable check on link status when "
 	       "starting/stopping ports.\n");
 	printf("  --disable-device-start: do not automatically start port\n");
@@ -607,6 +608,7 @@ launch_args_parse(int argc, char** argv)
 		{ "rxpkts",			1, 0, 0 },
 		{ "txpkts",			1, 0, 0 },
 		{ "txonly-multi-flow",		0, 0, 0 },
+		{ "rxq-share",			2, 0, 0 },
 		{ "eth-link-speed",		1, 0, 0 },
 		{ "disable-link-check",		0, 0, 0 },
 		{ "disable-device-start",	0, 0, 0 },
@@ -1271,6 +1273,17 @@ launch_args_parse(int argc, char** argv)
 			}
 			if (!strcmp(lgopts[opt_idx].name, "txonly-multi-flow"))
 				txonly_multi_flow = 1;
+			if (!strcmp(lgopts[opt_idx].name, "rxq-share")) {
+				if (optarg == NULL) {
+					rxq_share = UINT32_MAX;
+				} else {
+					n = atoi(optarg);
+					if (n >= 0)
+						rxq_share = (uint32_t)n;
+					else
+						rte_exit(EXIT_FAILURE, "rxq-share must be >= 0\n");
+				}
+			}
 			if (!strcmp(lgopts[opt_idx].name, "no-flush-rx"))
 				no_flush_rx = 1;
 			if (!strcmp(lgopts[opt_idx].name, "eth-link-speed")) {
app/test-pmd/testpmd.c +17 -3
index 97ae52e17ec..123142ed110 100644
@@ -498,6 +498,11 @@ uint8_t record_core_cycles;
  */
 uint8_t record_burst_stats;
 
+/*
+ * Number of ports per shared Rx queue group, 0 disable.
+ */
+uint32_t rxq_share;
+
 unsigned int num_sockets = 0;
 unsigned int socket_ids[RTE_MAX_NUMA_NODES];
 
@@ -3393,14 +3398,23 @@ dev_event_callback(const char *device_name, enum rte_dev_event_type type,
 }
 
 static void
-rxtx_port_config(struct rte_port *port)
+rxtx_port_config(portid_t pid)
 {
 	uint16_t qid;
 	uint64_t offloads;
+	struct rte_port *port = &ports[pid];
 
 	for (qid = 0; qid < nb_rxq; qid++) {
 		offloads = port->rx_conf[qid].offloads;
 		port->rx_conf[qid] = port->dev_info.default_rxconf;
+
+		if (rxq_share > 0 &&
+		    (port->dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)) {
+			/* Non-zero share group to enable RxQ share. */
+			port->rx_conf[qid].share_group = pid / rxq_share + 1;
+			port->rx_conf[qid].share_qid = qid; /* Equal mapping. */
+		}
+
 		if (offloads != 0)
 			port->rx_conf[qid].offloads = offloads;
 
@@ -3558,7 +3572,7 @@ init_port_config(void)
 				port->dev_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
 		}
 
-		rxtx_port_config(port);
+		rxtx_port_config(pid);
 
 		ret = eth_macaddr_get_print_err(pid, &port->eth_addr);
 		if (ret != 0)
@@ -3772,7 +3786,7 @@ init_port_dcb_config(portid_t pid,
 
 	memcpy(&rte_port->dev_conf, &port_conf, sizeof(struct rte_eth_conf));
 
-	rxtx_port_config(rte_port);
+	rxtx_port_config(pid);
 	/* VLAN filter */
 	rte_port->dev_conf.rxmode.offloads |= DEV_RX_OFFLOAD_VLAN_FILTER;
 	for (i = 0; i < RTE_DIM(vlan_tags); i++)
app/test-pmd/testpmd.h +2 -0
index 5863b2f43f3..3dfaaad94c0 100644
@@ -477,6 +477,8 @@ extern enum tx_pkt_split tx_pkt_split;
 
 extern uint8_t txonly_multi_flow;
 
+extern uint32_t rxq_share;
+
 extern uint16_t nb_pkt_per_burst;
 extern uint16_t nb_pkt_flowgen_clones;
 extern int nb_flows_flowgen;
doc/guides/testpmd_app_ug/run_app.rst +7 -0
index 640eadeff73..ff5908dcd50 100644
@@ -389,6 +389,13 @@ The command line options are:
 
     Generate multiple flows in txonly mode.
 
+*   ``--rxq-share=[X]``
+
+    Create queues in shared Rx queue mode if device supports.
+    Group number grows per X ports. X defaults to MAX, implies all ports
+    join share group 1. Forwarding engine "shared-rxq" should be used
+    which Rx only and update stream statistics correctly.
+
 *   ``--eth-link-speed``
 
     Set a forced link speed to the ethernet port::
Signature · 1 line
2.33.0
author
#154 lore raw

PATCH v9 4/6 app/testpmd: dump port info for shared Rx queue

In reply to Xueming Li

In case of shared Rx queue, polling any member port returns mbufs for all members. This patch dumps mbuf->port for each packet.

---
 app/test-pmd/util.c | 3 +++
 1 file changed, 3 insertions(+)
app/test-pmd/util.c +3 -0
index 51506e49404..e98f136d5ed 100644
@@ -100,6 +100,9 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
 		struct rte_flow_restore_info info = { 0, };
 
 		mb = pkts[i];
+		if (rxq_share > 0)
+			MKDUMPSTR(print_buf, buf_size, cur_len, "port %u, ",
+				  mb->port);
 		eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
 		eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
 		packet_type = mb->packet_type;
Signature · 1 line
2.33.0
author
#155 lore raw

PATCH v9 5/6 app/testpmd: force shared Rx queue polled on same core

In reply to Xueming Li

Shared Rx queue must be polled on same core. This patch checks and stops forwarding if shared RxQ being scheduled on multiple
cores.

It's suggested to use same number of Rx queues and polling cores.

---
 app/test-pmd/config.c  | 103 +++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.c |   4 +-
 app/test-pmd/testpmd.h |   2 +
 3 files changed, 108 insertions(+), 1 deletion(-)
app/test-pmd/config.c +103 -0
index f8fb8961cae..c4150d77589 100644
@@ -2890,6 +2890,109 @@ port_rss_hash_key_update(portid_t port_id, char rss_type[], uint8_t *hash_key,
 	}
 }
 
+/*
+ * Check whether a shared rxq scheduled on other lcores.
+ */
+static bool
+fwd_stream_on_other_lcores(uint16_t domain_id, lcoreid_t src_lc,
+			   portid_t src_port, queueid_t src_rxq,
+			   uint32_t share_group, queueid_t share_rxq)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	struct rte_port *port;
+	struct rte_eth_dev_info *dev_info;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	/* Check remaining cores. */
+	for (lc_id = src_lc + 1; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			port = &ports[fs->rx_port];
+			dev_info = &port->dev_info;
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			if (domain_id != port->dev_info.switch_info.domain_id)
+				continue;
+			if (rxq_conf->share_group != share_group)
+				continue;
+			if (rxq_conf->share_qid != share_rxq)
+				continue;
+			printf("Shared Rx queue group %u queue %hu can't be scheduled on different cores:\n",
+			       share_group, share_rxq);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       src_lc, src_port, src_rxq);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       lc_id, fs->rx_port, fs->rx_queue);
+			printf("Please use --nb-cores=%hu to limit number of forwarding cores\n",
+			       nb_rxq);
+			return true;
+		}
+	}
+	return false;
+}
+
+/*
+ * Check shared rxq configuration.
+ *
+ * Shared group must not being scheduled on different core.
+ */
+bool
+pkt_fwd_shared_rxq_check(void)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	uint16_t domain_id;
+	struct rte_port *port;
+	struct rte_eth_dev_info *dev_info;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	/*
+	 * Check streams on each core, make sure the same switch domain +
+	 * group + queue doesn't get scheduled on other cores.
+	 */
+	for (lc_id = 0; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			/* Update lcore info stream being scheduled. */
+			fs->lcore = fwd_lcores[lc_id];
+			port = &ports[fs->rx_port];
+			dev_info = &port->dev_info;
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			/* Check shared rxq not scheduled on remaining cores. */
+			domain_id = port->dev_info.switch_info.domain_id;
+			if (fwd_stream_on_other_lcores(domain_id, lc_id,
+						       fs->rx_port,
+						       fs->rx_queue,
+						       rxq_conf->share_group,
+						       rxq_conf->share_qid))
+				return false;
+		}
+	}
+	return true;
+}
+
 /*
  * Setup forwarding configuration for each logical core.
  */
app/test-pmd/testpmd.c +3 -1
index 123142ed110..f3f81ef561f 100644
@@ -2236,10 +2236,12 @@ start_packet_forwarding(int with_tx_first)
 
 	fwd_config_setup();
 
+	pkt_fwd_config_display(&cur_fwd_config);
+	if (!pkt_fwd_shared_rxq_check())
+		return;
 	if(!no_flush_rx)
 		flush_fwd_rx_queues();
 
-	pkt_fwd_config_display(&cur_fwd_config);
 	rxtx_config_display();
 
 	fwd_stats_reset();
app/test-pmd/testpmd.h +2 -0
index 3dfaaad94c0..f121a2da90c 100644
@@ -144,6 +144,7 @@ struct fwd_stream {
 	uint64_t     core_cycles; /**< used for RX and TX processing */
 	struct pkt_burst_stats rx_burst_stats;
 	struct pkt_burst_stats tx_burst_stats;
+	struct fwd_lcore *lcore; /**< Lcore being scheduled. */
 };
 
 /**
@@ -795,6 +796,7 @@ void port_summary_header_display(void);
 void rx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void tx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void fwd_lcores_config_display(void);
+bool pkt_fwd_shared_rxq_check(void);
 void pkt_fwd_config_display(struct fwd_config *cfg);
 void rxtx_config_display(void);
 void fwd_config_setup(void);
Signature · 1 line
2.33.0
author
#156 lore raw

PATCH v9 6/6 app/testpmd: add forwarding engine for shared Rx queue

In reply to Xueming Li

To support shared Rx queue, this patch introduces dedicate forwarding engine. The engine groups received packets by mbuf->port into sub-group, updates stream statistics and simply frees packets.

---
 app/test-pmd/meson.build                    |   1 +
 app/test-pmd/shared_rxq_fwd.c               | 148 ++++++++++++++++++++
 app/test-pmd/testpmd.c                      |   1 +
 app/test-pmd/testpmd.h                      |   1 +
 doc/guides/testpmd_app_ug/run_app.rst       |   1 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |   5 +-
 6 files changed, 156 insertions(+), 1 deletion(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
app/test-pmd/meson.build +1 -0
index 98f3289bdfa..07042e45b12 100644
@@ -21,6 +21,7 @@ sources = files(
         'noisy_vnf.c',
         'parameters.c',
         'rxonly.c',
+        'shared_rxq_fwd.c',
         'testpmd.c',
         'txonly.c',
         'util.c',
app/test-pmd/shared_rxq_fwd.c new file +148 -0

148 lines not on this page · raw message

app/test-pmd/testpmd.c +1 -0
index f3f81ef561f..11a85d92d9a 100644
@@ -188,6 +188,7 @@ struct fwd_engine * fwd_engines[] = {
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
+	&shared_rxq_engine,
 	NULL,
 };
 
app/test-pmd/testpmd.h +1 -0
index f121a2da90c..f1fd607e365 100644
@@ -299,6 +299,7 @@ extern struct fwd_engine five_tuple_swap_fwd_engine;
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
+extern struct fwd_engine shared_rxq_engine;
 
 extern struct fwd_engine * fwd_engines[]; /**< NULL terminated array. */
 extern cmdline_parse_inst_t cmd_set_raw;
doc/guides/testpmd_app_ug/run_app.rst +1 -0
index ff5908dcd50..e4b97844ced 100644
@@ -252,6 +252,7 @@ The command line options are:
        tm
        noisy
        5tswap
+       shared-rxq
 
 *   ``--rss-ip``
 
doc/guides/testpmd_app_ug/testpmd_funcs.rst +4 -1
index 8ead7a4a712..499874187f2 100644
@@ -314,7 +314,7 @@ set fwd
 Set the packet forwarding mode::
 
    testpmd> set fwd (io|mac|macswap|flowgen| \
-                     rxonly|txonly|csum|icmpecho|noisy|5tswap) (""|retry)
+                     rxonly|txonly|csum|icmpecho|noisy|5tswap|shared-rxq) (""|retry)
 
 ``retry`` can be specified for forwarding engines except ``rx_only``.
 
@@ -357,6 +357,9 @@ The available information categories are:
 
   L4 swaps the source port and destination port of transport layer (TCP and UDP).
 
+* ``shared-rxq``: Receive only for shared Rx queue.
+  Resolve packet source port from mbuf and update stream statistics accordingly.
+
 Example::
 
    testpmd> set fwd rxonly
Signature · 1 line
2.33.0
author
#157 lore raw

v10 cover ethdev: introduce shared Rx queue

In reply to Xueming Li

In current DPDK framework, all Rx queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared Rx queue. PF and representors in same Rx domain and switch domain could share Rx queue set by specifying non-zero share group value in Rx queue configuration.

All ports that share Rx queue actually shares hardware descriptor queue and feed all Rx queues with one descriptor supply, memory is saved.

Polling any queue using same shared Rx queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of two share groups:
Group1, 4 shared Rx queues per member port: PF, repr0, repr1 Group2, 2 shared Rx queues per member port: repr2, repr3, ... repr127 Poll first port for each group:
core port queue
0 0 0
1 0 1
2 0 2
3 0 3
4 2 0
5 2 1

Shared Rx queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

There was some discussion to aggregate member ports in same group into a dummy port, several ways to achieve it. Since it optional, need to collect more feedback and requirement from user, make better decision later.

v1:
- initial version
v2:
- add testpmd patches
v3:
- change common forwarding api to macro for performance, thanks Jerin.
- save global variable accessed in forwarding to flowstream to minimize cache miss
- combined patches for each forwarding engine
- support multiple groups in testpmd "--share-rxq" parameter
- new api to aggregate shared rxq group
v4:
- spelling fixes
- remove shared-rxq support for all forwarding engines
- add dedicate shared-rxq forwarding engine
v5:
- fix grammars
- remove aggregate api and leave it for later discussion
- add release notes
- add deployment example
v6:
- replace RxQ offload flag with device offload capability flag
- add Rx domain
- RxQ is shared when share group > 0
- update testpmd accordingly
v7:
- fix testpmd share group id allocation
- change rx_domain to 16bits
v8:
- add new patch for testpmd to show device Rx domain ID and capability
- new share_qid in RxQ configuration
v9:
- fix some spelling
v10:
- add device capability name api

Xueming Li (6):
ethdev: new API to resolve device capability name app/testpmd: dump device capability and Rx domain info app/testpmd: new parameter to enable shared Rx queue app/testpmd: dump port info for shared Rx queue app/testpmd: force shared Rx queue polled on same core app/testpmd: add forwarding engine for shared Rx queue

 app/test-pmd/config.c                       | 139 +++++++++++++++++-
 app/test-pmd/meson.build                    |   1 +
 app/test-pmd/parameters.c                   |  13 ++
 app/test-pmd/shared_rxq_fwd.c               | 148 ++++++++++++++++++++
 app/test-pmd/testpmd.c                      |  25 +++-
 app/test-pmd/testpmd.h                      |   5 +
 app/test-pmd/util.c                         |   3 +
 doc/guides/testpmd_app_ug/run_app.rst       |   8 ++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |   5 +-
 lib/ethdev/rte_ethdev.c                     |  30 ++++
 lib/ethdev/rte_ethdev.h                     |  14 ++
 lib/ethdev/version.map                      |   3 +
 12 files changed, 388 insertions(+), 6 deletions(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
Signature · 1 line
2.33.0
author
#158 lore raw

PATCH v10 1/6 ethdev: new API to resolve device capability name

This patch adds API to return name of device capability.

---
 lib/ethdev/rte_ethdev.c | 30 ++++++++++++++++++++++++++++++
 lib/ethdev/rte_ethdev.h | 14 ++++++++++++++
 lib/ethdev/version.map  |  3 +++
 3 files changed, 47 insertions(+)
lib/ethdev/rte_ethdev.c +30 -0
index bc55f899f72..97217529449 100644
@@ -165,6 +165,20 @@ static const struct {
 
 #undef RTE_TX_OFFLOAD_BIT2STR
 
+#define RTE_ETH_DEV_CAPA_BIT2STR(_name)	\
+	{ RTE_ETH_DEV_CAPA_##_name, #_name }
+
+static const struct {
+	uint64_t offload;
+	const char *name;
+} rte_eth_dev_capa_names[] = {
+	RTE_ETH_DEV_CAPA_BIT2STR(RUNTIME_RX_QUEUE_SETUP),
+	RTE_ETH_DEV_CAPA_BIT2STR(RUNTIME_TX_QUEUE_SETUP),
+	RTE_ETH_DEV_CAPA_BIT2STR(RXQ_SHARE),
+};
+
+#undef RTE_ETH_DEV_CAPA_BIT2STR
+
 /**
  * The user application callback description.
  *
@@ -1260,6 +1274,22 @@ rte_eth_dev_tx_offload_name(uint64_t offload)
 	return name;
 }
 
+const char *
+rte_eth_dev_capability_name(uint64_t capability)
+{
+	const char *name = "UNKNOWN";
+	unsigned int i;
+
+	for (i = 0; i < RTE_DIM(rte_eth_dev_capa_names); ++i) {
+		if (capability == rte_eth_dev_capa_names[i].offload) {
+			name = rte_eth_dev_capa_names[i].name;
+			break;
+		}
+	}
+
+	return name;
+}
+
 static inline int
 eth_dev_check_lro_pkt_size(uint16_t port_id, uint32_t config_size,
 		   uint32_t max_rx_pkt_len, uint32_t dev_info_size)
lib/ethdev/rte_ethdev.h +14 -0
index 34acc91273d..df8ef9382a9 100644
@@ -2109,6 +2109,20 @@ const char *rte_eth_dev_rx_offload_name(uint64_t offload);
  */
 const char *rte_eth_dev_tx_offload_name(uint64_t offload);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Get RTE_ETH_DEV_CAPA_* flag name.
+ *
+ * @param capability
+ *   Capability flag.
+ * @return
+ *   Capability name or 'UNKNOWN' if the flag cannot be recognized.
+ */
+__rte_experimental
+const char *rte_eth_dev_capability_name(uint64_t capability);
+
 /**
  * Configure an Ethernet device.
  * This function must be invoked first before any other function in the
lib/ethdev/version.map +3 -0
index efd729c0f2d..e1d403dd357 100644
@@ -245,6 +245,9 @@ EXPERIMENTAL {
 	rte_mtr_meter_policy_delete;
 	rte_mtr_meter_policy_update;
 	rte_mtr_meter_policy_validate;
+
+	# added in 21.11
+	rte_eth_dev_capability_name;
 };
 
 INTERNAL {
Signature · 1 line
2.33.0
author
#159 lore raw

PATCH v10 2/6 app/testpmd: dump device capability and Rx domain info

In reply to Xueming Li

Dump device capability and Rx domain ID if shared Rx queue is supported by device.

---
 app/test-pmd/config.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)
app/test-pmd/config.c +29 -0
index 9c66329e96e..2c1b06c544d 100644
@@ -582,6 +582,29 @@ device_infos_display(const char *identifier)
 	rte_devargs_reset(&da);
 }
 
+static void
+print_dev_capabilities(uint64_t capabilities)
+{
+	uint64_t single_capa;
+	int begin;
+	int end;
+	int bit;
+
+	if (capabilities == 0)
+		return;
+
+	begin = __builtin_ctzll(capabilities);
+	end = sizeof(capabilities) * CHAR_BIT - __builtin_clzll(capabilities);
+
+	single_capa = 1ULL << begin;
+	for (bit = begin; bit < end; bit++) {
+		if (capabilities & single_capa)
+			printf(" %s",
+			       rte_eth_dev_capability_name(single_capa));
+		single_capa <<= 1;
+	}
+}
+
 void
 port_infos_display(portid_t port_id)
 {
@@ -733,6 +756,9 @@ port_infos_display(portid_t port_id)
 	printf("Max segment number per MTU/TSO: %hu\n",
 		dev_info.tx_desc_lim.nb_mtu_seg_max);
 
+	printf("Device capabilities: 0x%"PRIx64"(", dev_info.dev_capa);
+	print_dev_capabilities(dev_info.dev_capa);
+	printf(" )\n");
 	/* Show switch info only if valid switch domain and port id is set */
 	if (dev_info.switch_info.domain_id !=
 		RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID) {
@@ -743,6 +769,9 @@ port_infos_display(portid_t port_id)
 			dev_info.switch_info.domain_id);
 		printf("Switch Port Id: %u\n",
 			dev_info.switch_info.port_id);
+		if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) != 0)
+			printf("Switch Rx domain: %u\n",
+			       dev_info.switch_info.rx_domain);
 	}
 }
 
Signature · 1 line
2.33.0
author
#160 lore raw

PATCH v10 3/6 app/testpmd: new parameter to enable shared Rx queue

In reply to Xueming Li

Adds "--rxq-share=X" parameter to enable shared RxQ, share if device supports, otherwise fallback to standard RxQ.

Share group number grows per X ports. X defaults to MAX, implies all ports join share group 1. Queue ID is mapped equally with shared Rx queue ID.

Forwarding engine "shared-rxq" should be used which Rx only and update stream statistics correctly.

---
 app/test-pmd/config.c                 |  7 ++++++-
 app/test-pmd/parameters.c             | 13 +++++++++++++
 app/test-pmd/testpmd.c                | 20 +++++++++++++++++---
 app/test-pmd/testpmd.h                |  2 ++
 doc/guides/testpmd_app_ug/run_app.rst |  7 +++++++
 5 files changed, 45 insertions(+), 4 deletions(-)
app/test-pmd/config.c +6 -1
index 2c1b06c544d..fa951a86704 100644
@@ -2738,7 +2738,12 @@ rxtx_config_display(void)
 			printf("      RX threshold registers: pthresh=%d hthresh=%d "
 				" wthresh=%d\n",
 				pthresh_tmp, hthresh_tmp, wthresh_tmp);
-			printf("      RX Offloads=0x%"PRIx64"\n", offloads_tmp);
+			printf("      RX Offloads=0x%"PRIx64, offloads_tmp);
+			if (rx_conf->share_group > 0)
+				printf(" share_group=%u share_qid=%u",
+				       rx_conf->share_group,
+				       rx_conf->share_qid);
+			printf("\n");
 		}
 
 		/* per tx queue config only for first queue to be less verbose */
app/test-pmd/parameters.c +13 -0
index 3f94a82e321..30dae326310 100644
@@ -167,6 +167,7 @@ usage(char* progname)
 	printf("  --tx-ip=src,dst: IP addresses in Tx-only mode\n");
 	printf("  --tx-udp=src[,dst]: UDP ports in Tx-only mode\n");
 	printf("  --eth-link-speed: force link speed.\n");
+	printf("  --rxq-share: number of ports per shared rxq groups, defaults to MAX(1 group)\n");
 	printf("  --disable-link-check: disable check on link status when "
 	       "starting/stopping ports.\n");
 	printf("  --disable-device-start: do not automatically start port\n");
@@ -607,6 +608,7 @@ launch_args_parse(int argc, char** argv)
 		{ "rxpkts",			1, 0, 0 },
 		{ "txpkts",			1, 0, 0 },
 		{ "txonly-multi-flow",		0, 0, 0 },
+		{ "rxq-share",			2, 0, 0 },
 		{ "eth-link-speed",		1, 0, 0 },
 		{ "disable-link-check",		0, 0, 0 },
 		{ "disable-device-start",	0, 0, 0 },
@@ -1271,6 +1273,17 @@ launch_args_parse(int argc, char** argv)
 			}
 			if (!strcmp(lgopts[opt_idx].name, "txonly-multi-flow"))
 				txonly_multi_flow = 1;
+			if (!strcmp(lgopts[opt_idx].name, "rxq-share")) {
+				if (optarg == NULL) {
+					rxq_share = UINT32_MAX;
+				} else {
+					n = atoi(optarg);
+					if (n >= 0)
+						rxq_share = (uint32_t)n;
+					else
+						rte_exit(EXIT_FAILURE, "rxq-share must be >= 0\n");
+				}
+			}
 			if (!strcmp(lgopts[opt_idx].name, "no-flush-rx"))
 				no_flush_rx = 1;
 			if (!strcmp(lgopts[opt_idx].name, "eth-link-speed")) {
app/test-pmd/testpmd.c +17 -3
index 97ae52e17ec..123142ed110 100644
@@ -498,6 +498,11 @@ uint8_t record_core_cycles;
  */
 uint8_t record_burst_stats;
 
+/*
+ * Number of ports per shared Rx queue group, 0 disable.
+ */
+uint32_t rxq_share;
+
 unsigned int num_sockets = 0;
 unsigned int socket_ids[RTE_MAX_NUMA_NODES];
 
@@ -3393,14 +3398,23 @@ dev_event_callback(const char *device_name, enum rte_dev_event_type type,
 }
 
 static void
-rxtx_port_config(struct rte_port *port)
+rxtx_port_config(portid_t pid)
 {
 	uint16_t qid;
 	uint64_t offloads;
+	struct rte_port *port = &ports[pid];
 
 	for (qid = 0; qid < nb_rxq; qid++) {
 		offloads = port->rx_conf[qid].offloads;
 		port->rx_conf[qid] = port->dev_info.default_rxconf;
+
+		if (rxq_share > 0 &&
+		    (port->dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)) {
+			/* Non-zero share group to enable RxQ share. */
+			port->rx_conf[qid].share_group = pid / rxq_share + 1;
+			port->rx_conf[qid].share_qid = qid; /* Equal mapping. */
+		}
+
 		if (offloads != 0)
 			port->rx_conf[qid].offloads = offloads;
 
@@ -3558,7 +3572,7 @@ init_port_config(void)
 				port->dev_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
 		}
 
-		rxtx_port_config(port);
+		rxtx_port_config(pid);
 
 		ret = eth_macaddr_get_print_err(pid, &port->eth_addr);
 		if (ret != 0)
@@ -3772,7 +3786,7 @@ init_port_dcb_config(portid_t pid,
 
 	memcpy(&rte_port->dev_conf, &port_conf, sizeof(struct rte_eth_conf));
 
-	rxtx_port_config(rte_port);
+	rxtx_port_config(pid);
 	/* VLAN filter */
 	rte_port->dev_conf.rxmode.offloads |= DEV_RX_OFFLOAD_VLAN_FILTER;
 	for (i = 0; i < RTE_DIM(vlan_tags); i++)
app/test-pmd/testpmd.h +2 -0
index 5863b2f43f3..3dfaaad94c0 100644
@@ -477,6 +477,8 @@ extern enum tx_pkt_split tx_pkt_split;
 
 extern uint8_t txonly_multi_flow;
 
+extern uint32_t rxq_share;
+
 extern uint16_t nb_pkt_per_burst;
 extern uint16_t nb_pkt_flowgen_clones;
 extern int nb_flows_flowgen;
doc/guides/testpmd_app_ug/run_app.rst +7 -0
index 640eadeff73..ff5908dcd50 100644
@@ -389,6 +389,13 @@ The command line options are:
 
     Generate multiple flows in txonly mode.
 
+*   ``--rxq-share=[X]``
+
+    Create queues in shared Rx queue mode if device supports.
+    Group number grows per X ports. X defaults to MAX, implies all ports
+    join share group 1. Forwarding engine "shared-rxq" should be used
+    which Rx only and update stream statistics correctly.
+
 *   ``--eth-link-speed``
 
     Set a forced link speed to the ethernet port::
Signature · 1 line
2.33.0
author
#161 lore raw

PATCH v10 4/6 app/testpmd: dump port info for shared Rx queue

In reply to Xueming Li

In case of shared Rx queue, polling any member port returns mbufs for all members. This patch dumps mbuf->port for each packet.

---
 app/test-pmd/util.c | 3 +++
 1 file changed, 3 insertions(+)
app/test-pmd/util.c +3 -0
index 51506e49404..e98f136d5ed 100644
@@ -100,6 +100,9 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
 		struct rte_flow_restore_info info = { 0, };
 
 		mb = pkts[i];
+		if (rxq_share > 0)
+			MKDUMPSTR(print_buf, buf_size, cur_len, "port %u, ",
+				  mb->port);
 		eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
 		eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
 		packet_type = mb->packet_type;
Signature · 1 line
2.33.0
author
#162 lore raw

PATCH v10 5/6 app/testpmd: force shared Rx queue polled on same core

In reply to Xueming Li

Shared Rx queue must be polled on same core. This patch checks and stops forwarding if shared RxQ being scheduled on multiple
cores.

It's suggested to use same number of Rx queues and polling cores.

---
 app/test-pmd/config.c  | 103 +++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.c |   4 +-
 app/test-pmd/testpmd.h |   2 +
 3 files changed, 108 insertions(+), 1 deletion(-)
app/test-pmd/config.c +103 -0
index fa951a86704..1f1307178be 100644
@@ -2915,6 +2915,109 @@ port_rss_hash_key_update(portid_t port_id, char rss_type[], uint8_t *hash_key,
 	}
 }
 
+/*
+ * Check whether a shared rxq scheduled on other lcores.
+ */
+static bool
+fwd_stream_on_other_lcores(uint16_t domain_id, lcoreid_t src_lc,
+			   portid_t src_port, queueid_t src_rxq,
+			   uint32_t share_group, queueid_t share_rxq)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	struct rte_port *port;
+	struct rte_eth_dev_info *dev_info;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	/* Check remaining cores. */
+	for (lc_id = src_lc + 1; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			port = &ports[fs->rx_port];
+			dev_info = &port->dev_info;
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			if (domain_id != port->dev_info.switch_info.domain_id)
+				continue;
+			if (rxq_conf->share_group != share_group)
+				continue;
+			if (rxq_conf->share_qid != share_rxq)
+				continue;
+			printf("Shared Rx queue group %u queue %hu can't be scheduled on different cores:\n",
+			       share_group, share_rxq);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       src_lc, src_port, src_rxq);
+			printf("  lcore %hhu Port %hu queue %hu\n",
+			       lc_id, fs->rx_port, fs->rx_queue);
+			printf("Please use --nb-cores=%hu to limit number of forwarding cores\n",
+			       nb_rxq);
+			return true;
+		}
+	}
+	return false;
+}
+
+/*
+ * Check shared rxq configuration.
+ *
+ * Shared group must not being scheduled on different core.
+ */
+bool
+pkt_fwd_shared_rxq_check(void)
+{
+	streamid_t sm_id;
+	streamid_t nb_fs_per_lcore;
+	lcoreid_t  nb_fc;
+	lcoreid_t  lc_id;
+	struct fwd_stream *fs;
+	uint16_t domain_id;
+	struct rte_port *port;
+	struct rte_eth_dev_info *dev_info;
+	struct rte_eth_rxconf *rxq_conf;
+
+	nb_fc = cur_fwd_config.nb_fwd_lcores;
+	/*
+	 * Check streams on each core, make sure the same switch domain +
+	 * group + queue doesn't get scheduled on other cores.
+	 */
+	for (lc_id = 0; lc_id < nb_fc; lc_id++) {
+		sm_id = fwd_lcores[lc_id]->stream_idx;
+		nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb;
+		for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore;
+		     sm_id++) {
+			fs = fwd_streams[sm_id];
+			/* Update lcore info stream being scheduled. */
+			fs->lcore = fwd_lcores[lc_id];
+			port = &ports[fs->rx_port];
+			dev_info = &port->dev_info;
+			rxq_conf = &port->rx_conf[fs->rx_queue];
+			if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE)
+			    == 0)
+				/* Not shared rxq. */
+				continue;
+			/* Check shared rxq not scheduled on remaining cores. */
+			domain_id = port->dev_info.switch_info.domain_id;
+			if (fwd_stream_on_other_lcores(domain_id, lc_id,
+						       fs->rx_port,
+						       fs->rx_queue,
+						       rxq_conf->share_group,
+						       rxq_conf->share_qid))
+				return false;
+		}
+	}
+	return true;
+}
+
 /*
  * Setup forwarding configuration for each logical core.
  */
app/test-pmd/testpmd.c +3 -1
index 123142ed110..f3f81ef561f 100644
@@ -2236,10 +2236,12 @@ start_packet_forwarding(int with_tx_first)
 
 	fwd_config_setup();
 
+	pkt_fwd_config_display(&cur_fwd_config);
+	if (!pkt_fwd_shared_rxq_check())
+		return;
 	if(!no_flush_rx)
 		flush_fwd_rx_queues();
 
-	pkt_fwd_config_display(&cur_fwd_config);
 	rxtx_config_display();
 
 	fwd_stats_reset();
app/test-pmd/testpmd.h +2 -0
index 3dfaaad94c0..f121a2da90c 100644
@@ -144,6 +144,7 @@ struct fwd_stream {
 	uint64_t     core_cycles; /**< used for RX and TX processing */
 	struct pkt_burst_stats rx_burst_stats;
 	struct pkt_burst_stats tx_burst_stats;
+	struct fwd_lcore *lcore; /**< Lcore being scheduled. */
 };
 
 /**
@@ -795,6 +796,7 @@ void port_summary_header_display(void);
 void rx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void tx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
 void fwd_lcores_config_display(void);
+bool pkt_fwd_shared_rxq_check(void);
 void pkt_fwd_config_display(struct fwd_config *cfg);
 void rxtx_config_display(void);
 void fwd_config_setup(void);
Signature · 1 line
2.33.0
author
#163 lore raw

PATCH v10 6/6 app/testpmd: add forwarding engine for shared Rx queue

In reply to Xueming Li

To support shared Rx queue, this patch introduces dedicate forwarding engine. The engine groups received packets by mbuf->port into sub-group, updates stream statistics and simply frees packets.

---
 app/test-pmd/meson.build                    |   1 +
 app/test-pmd/shared_rxq_fwd.c               | 148 ++++++++++++++++++++
 app/test-pmd/testpmd.c                      |   1 +
 app/test-pmd/testpmd.h                      |   1 +
 doc/guides/testpmd_app_ug/run_app.rst       |   1 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |   5 +-
 6 files changed, 156 insertions(+), 1 deletion(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
app/test-pmd/meson.build +1 -0
index 98f3289bdfa..07042e45b12 100644
@@ -21,6 +21,7 @@ sources = files(
         'noisy_vnf.c',
         'parameters.c',
         'rxonly.c',
+        'shared_rxq_fwd.c',
         'testpmd.c',
         'txonly.c',
         'util.c',
app/test-pmd/shared_rxq_fwd.c new file +148 -0

148 lines not on this page · raw message

app/test-pmd/testpmd.c +1 -0
index f3f81ef561f..11a85d92d9a 100644
@@ -188,6 +188,7 @@ struct fwd_engine * fwd_engines[] = {
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
+	&shared_rxq_engine,
 	NULL,
 };
 
app/test-pmd/testpmd.h +1 -0
index f121a2da90c..f1fd607e365 100644
@@ -299,6 +299,7 @@ extern struct fwd_engine five_tuple_swap_fwd_engine;
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
+extern struct fwd_engine shared_rxq_engine;
 
 extern struct fwd_engine * fwd_engines[]; /**< NULL terminated array. */
 extern cmdline_parse_inst_t cmd_set_raw;
doc/guides/testpmd_app_ug/run_app.rst +1 -0
index ff5908dcd50..e4b97844ced 100644
@@ -252,6 +252,7 @@ The command line options are:
        tm
        noisy
        5tswap
+       shared-rxq
 
 *   ``--rss-ip``
 
doc/guides/testpmd_app_ug/testpmd_funcs.rst +4 -1
index 8ead7a4a712..499874187f2 100644
@@ -314,7 +314,7 @@ set fwd
 Set the packet forwarding mode::
 
    testpmd> set fwd (io|mac|macswap|flowgen| \
-                     rxonly|txonly|csum|icmpecho|noisy|5tswap) (""|retry)
+                     rxonly|txonly|csum|icmpecho|noisy|5tswap|shared-rxq) (""|retry)
 
 ``retry`` can be specified for forwarding engines except ``rx_only``.
 
@@ -357,6 +357,9 @@ The available information categories are:
 
   L4 swaps the source port and destination port of transport layer (TCP and UDP).
 
+* ``shared-rxq``: Receive only for shared Rx queue.
+  Resolve packet source port from mbuf and update stream statistics accordingly.
+
 Example::
 
    testpmd> set fwd rxonly
Signature · 1 line
2.33.0
author
#164 lore raw

v10 cover ethdev: introduce shared Rx queue

In reply to Xueming Li

In current DPDK framework, all Rx queues is pre-loaded with mbufs for incoming packets. When number of representors scale out in a switch domain, the memory consumption became significant. Further more, polling all ports leads to high cache miss, high latency and low throughputs.

This patch introduces shared Rx queue. PF and representors in same Rx domain and switch domain could share Rx queue set by specifying non-zero share group value in Rx queue configuration.

All ports that share Rx queue actually shares hardware descriptor queue and feed all Rx queues with one descriptor supply, memory is saved.

Polling any queue using same shared Rx queue receives packets from all member ports. Source port is identified by mbuf->port.

Multiple groups is supported by group ID. Port queue number in a shared group should be identical. Queue index is 1:1 mapped in shared group. An example of two share groups:
Group1, 4 shared Rx queues per member port: PF, repr0, repr1 Group2, 2 shared Rx queues per member port: repr2, repr3, ... repr127 Poll first port for each group:
core port queue
0 0 0
1 0 1
2 0 2
3 0 3
4 2 0
5 2 1

Shared Rx queue must be polled on single thread or core. If both PF0 and representor0 joined same share group, can't poll pf0rxq0 on core1 and rep0rxq0 on core2. Actually, polling one port within share group is sufficient since polling any port in group will return packets for any port in group.

There was some discussion to aggregate member ports in same group into a dummy port, several ways to achieve it. Since it optional, need to collect more feedback and requirement from user, make better decision later.

v1:
- initial version
v2:
- add testpmd patches
v3:
- change common forwarding api to macro for performance, thanks Jerin.
- save global variable accessed in forwarding to flowstream to minimize cache miss
- combined patches for each forwarding engine
- support multiple groups in testpmd "--share-rxq" parameter
- new api to aggregate shared rxq group
v4:
- spelling fixes
- remove shared-rxq support for all forwarding engines
- add dedicate shared-rxq forwarding engine
v5:
- fix grammars
- remove aggregate api and leave it for later discussion
- add release notes
- add deployment example
v6:
- replace RxQ offload flag with device offload capability flag
- add Rx domain
- RxQ is shared when share group > 0
- update testpmd accordingly
v7:
- fix testpmd share group id allocation
- change rx_domain to 16bits
v8:
- add new patch for testpmd to show device Rx domain ID and capability
- new share_qid in RxQ configuration
v9:
- fix some spelling
v10:
- add device capability name api

Xueming Li (7):
ethdev: introduce shared Rx queue
ethdev: new API to resolve device capability name app/testpmd: dump device capability and Rx domain info app/testpmd: new parameter to enable shared Rx queue app/testpmd: dump port info for shared Rx queue app/testpmd: force shared Rx queue polled on same core app/testpmd: add forwarding engine for shared Rx queue

 app/test-pmd/config.c                         | 139 +++++++++++++++-
 app/test-pmd/meson.build                      |   1 +
 app/test-pmd/parameters.c                     |  13 ++
 app/test-pmd/shared_rxq_fwd.c                 | 148 ++++++++++++++++++
 app/test-pmd/testpmd.c                        |  25 ++-
 app/test-pmd/testpmd.h                        |   5 +
 app/test-pmd/util.c                           |   3 +
 doc/guides/nics/features.rst                  |  13 ++
 doc/guides/nics/features/default.ini          |   1 +
 .../prog_guide/switch_representation.rst      |  11 ++
 doc/guides/rel_notes/release_21_11.rst        |   6 +
 doc/guides/testpmd_app_ug/run_app.rst         |   8 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst   |   5 +-
 lib/ethdev/rte_ethdev.c                       |  38 +++++
 lib/ethdev/rte_ethdev.h                       |  38 +++++
 lib/ethdev/version.map                        |   3 +
 16 files changed, 451 insertions(+), 6 deletions(-)
 create mode 100644 app/test-pmd/shared_rxq_fwd.c
Signature · 1 line
2.33.0