[PATCH v4-S3 27/65] net/dpaa2: support DCB Rx mode via rte_flow

Prashant Gupta prashant.gupta_3 at nxp.com
Fri Oct 23 15:43:07 CEST 2026


From: Jun Yang <jun.yang at nxp.com>

Add DCB (Data Center Bridging) support to the DPAA2 PMD so that
applications requesting RTE_ETH_MQ_RX_DCB map VLAN PCP priorities
to receive TCs, and expose the per-port mapping through the
standard rte_eth_dev_get_dcb_info() API.

Reject QoS entries whose index collides with an already-installed
DCB flow slot with -ENODATA, so user-added QoS rules cannot silently
overwrite the DCB-generated ones.

Signed-off-by: Jun Yang <jun.yang at nxp.com>
---
 drivers/net/dpaa2/dpaa2_ethdev.c | 107 ++++++++++++++++++++++++++++---
 drivers/net/dpaa2/dpaa2_ethdev.h |   3 +
 drivers/net/dpaa2/dpaa2_flow.c   |   5 ++
 3 files changed, 105 insertions(+), 10 deletions(-)

diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index 9f92789d4e..cca7aa0891 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -507,7 +507,7 @@ dpaa2_setup_table_miss_action(struct rte_eth_dev *eth_dev,
 }
 
 static int
-dpaa2_setup_flow_dist(struct rte_eth_dev *eth_dev,
+dpaa2_setup_flow_rss_dist(struct rte_eth_dev *eth_dev,
 	uint64_t req_dist_set, int tc_index)
 {
 	struct dpaa2_dev_priv *priv = eth_dev->data->dev_private;
@@ -555,6 +555,49 @@ dpaa2_setup_flow_dist(struct rte_eth_dev *eth_dev,
 	return 0;
 }
 
+static int
+dpaa2_setup_flow_dcb_dist(struct rte_eth_dev *eth_dev,
+	uint8_t prio, uint8_t tc)
+{
+	struct dpaa2_dev_priv *priv = eth_dev->data->dev_private;
+	struct rte_flow_attr attr;
+	struct rte_flow_action actions[2];
+	struct rte_flow_item_vlan vlan_item;
+	struct rte_flow_item_vlan vlan_mask;
+	struct rte_flow_item items[2];
+	struct rte_flow_action_jump action_jump;
+	struct rte_flow *qos_flow;
+
+	memset(&attr, 0, sizeof(struct rte_flow_attr));
+	attr.ingress = 1;
+
+	attr.group = priv->num_rx_tc;
+	attr.priority = prio;
+	memset(&vlan_item, 0, sizeof(struct rte_flow_item_vlan));
+	memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
+	vlan_item.hdr.vlan_tci = rte_cpu_to_be_16(RTE_VLAN_TCI_MAKE(0, prio, 0));
+	vlan_mask.hdr.vlan_tci = rte_cpu_to_be_16(RTE_VLAN_PRI_MASK);
+	items[0].spec = &vlan_item;
+	items[0].mask = &vlan_mask;
+	items[0].type = RTE_FLOW_ITEM_TYPE_VLAN;
+	items[1].type = RTE_FLOW_ITEM_TYPE_END;
+
+	actions[0].type = RTE_FLOW_ACTION_TYPE_JUMP;
+	action_jump.group = tc;
+	actions[0].conf = &action_jump;
+	actions[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	qos_flow = rte_flow_create(eth_dev->data->port_id,
+		&attr, items, actions, NULL);
+	if (!qos_flow) {
+		DPAA2_PMD_WARN("Failed to direct vlan with prio(%d) to tc%d", prio, tc);
+		return -EIO;
+	}
+	priv->dcb_flow[prio] = qos_flow;
+
+	return 0;
+}
+
 static int
 dpaa2_remove_flow_rss_dist(struct rte_eth_dev *eth_dev,
 	uint8_t tc_index)
@@ -1175,6 +1218,28 @@ dpaa2_free_rx_tx_queues(struct rte_eth_dev *dev)
 	}
 }
 
+static int
+dpaa2_dev_dcb_info(struct rte_eth_dev *dev,
+	struct rte_eth_dcb_info *dcb_info)
+{
+	struct dpaa2_dev_priv *priv = dev->data->dev_private;
+	int i;
+
+	if (!priv->nb_dcb_tcs)
+		return -ENOTSUP;
+
+	memset(dcb_info, 0, sizeof(struct rte_eth_dcb_info));
+	dcb_info->nb_tcs = priv->nb_dcb_tcs;
+	rte_memcpy(dcb_info->prio_tc, priv->prio_dcb_tc,
+		sizeof(uint8_t) * RTE_ETH_DCB_NUM_USER_PRIORITIES);
+	for (i = 0; i < dcb_info->nb_tcs; i++) {
+		dcb_info->tc_queue.tc_rxq[0][i].base = priv->dist_queues * i;
+		dcb_info->tc_queue.tc_rxq[0][i].nb_queue = priv->dist_queues;
+	}
+
+	return 0;
+}
+
 static int
 dpaa2_eth_dev_configure(struct rte_eth_dev *dev)
 {
@@ -1187,7 +1252,7 @@ dpaa2_eth_dev_configure(struct rte_eth_dev *dev)
 	int rx_l4_csum_offload = false;
 	int tx_l3_csum_offload = false;
 	int tx_l4_csum_offload = false;
-	int ret, tc_index;
+	int ret, tc_index, nb_tcs;
 	uint32_t max_rx_pktlen;
 
 	PMD_INIT_FUNC_TRACE();
@@ -1245,15 +1310,26 @@ dpaa2_eth_dev_configure(struct rte_eth_dev *dev)
 			ret, dev->data->name);
 	}
 
-	if (eth_conf->rxmode.mq_mode == RTE_ETH_MQ_RX_RSS) {
+	if (eth_conf->rxmode.mq_mode & RTE_ETH_MQ_RX_RSS) {
 		for (tc_index = 0; tc_index < priv->num_rx_tc; tc_index++) {
-			ret = dpaa2_setup_flow_dist(dev,
-					eth_conf->rx_adv_conf.rss_conf.rss_hf,
-					tc_index);
+			ret = dpaa2_setup_flow_rss_dist(dev,
+				eth_conf->rx_adv_conf.rss_conf.rss_hf, tc_index);
 			if (ret) {
-				DPAA2_PMD_ERR(
-					"Unable to set flow distribution on tc%d."
-					"Check queue config", tc_index);
+				DPAA2_PMD_ERR("RSS dist on tc%d err(%d)", tc_index, ret);
+				return ret;
+			}
+		}
+	}
+
+	if ((eth_conf->rxmode.mq_mode & RTE_ETH_MQ_RX_DCB) && priv->qos_entries) {
+		nb_tcs = eth_conf->rx_adv_conf.dcb_rx_conf.nb_tcs;
+		for (tc_index = 0; tc_index < nb_tcs; tc_index++) {
+			if (tc_index >= priv->num_rx_tc)
+				break;
+			ret = dpaa2_setup_flow_dcb_dist(dev,
+				eth_conf->rx_adv_conf.dcb_rx_conf.dcb_tc[tc_index], tc_index);
+			if (ret) {
+				DPAA2_PMD_ERR("DCB direct to tc%d err(%d)", tc_index, ret);
 				return ret;
 			}
 		}
@@ -1320,7 +1396,7 @@ dpaa2_eth_dev_configure(struct rte_eth_dev *dev)
 	 */
 	if (dpaa2_svr_family == SVR_LX2160A) {
 		ret = dpni_set_offload(dpni, CMD_PRI_LOW, priv->token,
-				       DPNI_FLCTYPE_HASH, true);
+				DPNI_FLCTYPE_HASH, true);
 		if (ret) {
 			DPAA2_PMD_ERR("Error setting FLCTYPE: Err = %d", ret);
 			return ret;
@@ -2282,6 +2358,8 @@ dpaa2_dev_close(struct rte_eth_dev *dev)
 
 	dpaa2_tm_deinit(dev);
 	dpaa2_flow_clean(dev, MAX_TCS, DPAA2_FLOW_ALL_TYPE);
+	/** No matter dcb flows are created or not, they are destroyed in flow clean.*/
+	memset(priv->dcb_flow, 0, sizeof(void *) * RTE_ETH_DCB_NUM_USER_PRIORITIES);
 	/* Clean the device first */
 	ret = dpni_reset(dpni, CMD_PRI_LOW, priv->token);
 	if (ret) {
@@ -3725,6 +3803,7 @@ static struct eth_dev_ops dpaa2_ethdev_ops = {
 	.txq_info_get	      = dpaa2_txq_info_get,
 	.tm_ops_get	      = dpaa2_tm_ops_get,
 	.mtr_ops_get = dpaa2_mtr_ops_get,
+	.get_dcb_info = dpaa2_dev_dcb_info,
 	.timesync_enable      = dpaa2_timesync_enable,
 	.timesync_disable     = dpaa2_timesync_disable,
 	.timesync_read_time   = dpaa2_timesync_read_time,
@@ -4054,6 +4133,14 @@ dpaa2_dev_init(struct rte_eth_dev *eth_dev)
 		tbl_profile->entry_map_size = entry_num / 8 + 1;
 	}
 
+	for (i = 0; i < priv->num_rx_tc; i++) {
+		if (i >= RTE_ETH_DCB_NUM_USER_PRIORITIES)
+			break;
+		if (i >= priv->qos_entries)
+			break;
+		priv->prio_dcb_tc[i] = i;
+	}
+	priv->nb_dcb_tcs = i;
 	ret = dpni_set_max_frame_length(dpni_dev, CMD_PRI_LOW, priv->token,
 		RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN + VLAN_TAG_SIZE);
 	if (ret) {
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.h b/drivers/net/dpaa2/dpaa2_ethdev.h
index 0ad237a5cc..9ef6ee0e8c 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.h
+++ b/drivers/net/dpaa2/dpaa2_ethdev.h
@@ -436,6 +436,9 @@ struct dpaa2_dev_priv {
 	char ep_name[RTE_DEV_NAME_MAX_LEN];
 
 	struct dpaa2_flow_profile flow_profile;
+	uint8_t nb_dcb_tcs;
+	uint8_t prio_dcb_tc[RTE_ETH_DCB_NUM_USER_PRIORITIES];
+	void *dcb_flow[RTE_ETH_DCB_NUM_USER_PRIORITIES];
 
 	uint16_t ss_offset;
 	uint64_t ss_iova;
diff --git a/drivers/net/dpaa2/dpaa2_flow.c b/drivers/net/dpaa2/dpaa2_flow.c
index 920e9edc51..d9f7391faf 100644
--- a/drivers/net/dpaa2/dpaa2_flow.c
+++ b/drivers/net/dpaa2/dpaa2_flow.c
@@ -3228,6 +3228,11 @@ dpaa2_flow_get_flow_index(struct dpaa2_dev_priv *priv,
 			DPAA2_PMD_ERR("QoS flow index(%d) >= max(%d)", idx, priv->qos_entries);
 			return -ENOSPC;
 		}
+
+		if (idx < RTE_ETH_DCB_NUM_USER_PRIORITIES && priv->dcb_flow[idx]) {
+			DPAA2_PMD_ERR("QoS flow[%d] added conflicts with dcb flow", idx);
+			return -ENODATA;
+		}
 	} else {
 		if (attr->priority >= priv->fs_entries) {
 			DPAA2_PMD_ERR("FS[%d].entry(%d) >= max(%d)",
-- 
2.43.0



More information about the dev mailing list