Skip to contentSkip to conversation

net/txgbe: fix FDIR Rx packet buffer handling

PATCH Superseded Zhang Tengfei 4 participants 16 messages Oct 13 – Oct 22 Network drivers

lore
Share & tools
lore
#0 lore raw

cover net/txgbe: fix FDIR Rx packet buffer handling

Enabling Flow Director reduces the Rx packet buffer 0 to reserve memory for the filter table, but the size was computed from the current register value and never restored when FDIR was no longer used. Since the FDIR mode is reset when the last rule is removed, on flush, or when enabling FDIR fails, the next rule enabled FDIR again and shrank the buffer once more, until it underflowed. Validating a rule also enabled FDIR.

Patch 1 computes the buffer size from the default packet buffer size, which alone stops the repeated reduction.
Patch 2 stops enabling FDIR from flow validate and rolls back the mode when the first rule fails.
Patch 3 disables FDIR and restores the buffer when no rule is left.

The same issue was fixed in ixgbe:
<https://patches.dpdk.org/project/dpdk/patch/[email protected]>

Compile tested only.

Zhang Tengfei (3):
net/txgbe: fix Rx packet buffer size with flow director net/txgbe: do not enable flow director on flow validate net/txgbe: disable flow director when no rule is left

 drivers/net/txgbe/txgbe_ethdev.h |  1 +
 drivers/net/txgbe/txgbe_fdir.c   | 36 +++++++++++++++----
 drivers/net/txgbe/txgbe_flow.c   | 60 +++++++++++++++++---------------
 3 files changed, 62 insertions(+), 35 deletions(-)
Signature · 1 line
2.53.0
#1 lore raw

PATCH 1/3 net/txgbe: fix Rx packet buffer size with flow director

Enabling Flow Director reduces PBRXSIZE(0) to reserve packet buffer memory for the filter table. The new size was computed from the current register value, but the FDIR mode is reset to none when the last rule is destroyed, on flush, or when enabling FDIR fails, without restoring the buffer. The next FDIR rule created or validated then enabled FDIR again and reduced the buffer a second time, until the size underflowed.

Compute PBRXSIZE(0) from the default packet buffer size instead.

Fixes ea230dda16ad ("net/txgbe: configure flow director filter")
---
 drivers/net/txgbe/txgbe_fdir.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/net/txgbe/txgbe_fdir.c +2 -3
index 67f586ffc7..cee38a42b8 100644
@@ -390,11 +390,10 @@ txgbe_fdir_configure(struct rte_eth_dev *dev)
 
 	/*
 	 * Before enabling Flow Director, the Rx Packet Buffer size
-	 * must be reduced.  The new value is the current size minus
+	 * must be reduced.  The new value is the default size minus
 	 * flow director memory usage size.
 	 */
-	pbsize = rd32(hw, TXGBE_PBRXSIZE(0));
-	pbsize -= TXGBD_FDIRCTL_BUF_BYTE(fdirctrl);
+	pbsize = (hw->mac.rx_pb_size << 10) - TXGBD_FDIRCTL_BUF_BYTE(fdirctrl);
 	wr32(hw, TXGBE_PBRXSIZE(0), pbsize);
 
 	/*
Signature · 1 line
2.53.0
#2 lore raw

PATCH 2/3 net/txgbe: do not enable flow director on flow validate

In reply to Zhang Tengfei

Flow Director was enabled and its mode recorded while parsing a rule, so validating a rule configured the hardware, and the mode stayed locked when the rule was rejected afterwards, e.g. for an invalid queue or when the rule could not be programmed.

Enable Flow Director only when creating the rule, and reset the mode if the first rule fails.

Fixes 5007ac13189d ("ethdev: remove deprecated Flow Director configuration")
---
 drivers/net/txgbe/txgbe_flow.c | 55 +++++++++++++++++-----------------
 1 file changed, 27 insertions(+), 28 deletions(-)
drivers/net/txgbe/txgbe_flow.c +27 -28
index f8d8c6850d..f2fc589a10 100644
@@ -2966,16 +2966,9 @@ txgbe_parse_fdir_filter(struct rte_eth_dev *dev,
 	if (!txgbe_is_pf(TXGBE_DEV_HW(dev)))
 		return ret;
 
-	if (fdir_conf->mode == RTE_FDIR_MODE_NONE) {
-		fdir_conf->mode = rule->mode;
-		ret = txgbe_fdir_configure(dev);
-		if (ret) {
-			fdir_conf->mode = RTE_FDIR_MODE_NONE;
-			return ret;
-		}
-	} else if (fdir_conf->mode != rule->mode) {
+	if (fdir_conf->mode != RTE_FDIR_MODE_NONE &&
+	    fdir_conf->mode != rule->mode)
 		return -ENOTSUP;
-	}
 
 	if (rule->queue >= dev->data->nb_rx_queues)
 		return -ENOTSUP;
@@ -3208,17 +3201,19 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 	struct txgbe_fdir_rule fdir_rule;
 	struct txgbe_l2_tunnel_conf l2_tn_filter;
 	struct txgbe_hw_fdir_info *fdir_info = TXGBE_DEV_FDIR(dev);
+	struct rte_eth_fdir_conf *fdir_conf = TXGBE_DEV_FDIR_CONF(dev);
 	struct txgbe_rte_flow_rss_conf rss_conf;
 	struct rte_flow *flow = NULL;
 	struct txgbe_ntuple_filter_ele *ntuple_filter_ptr;
 	struct txgbe_ethertype_filter_ele *ethertype_filter_ptr;
 	struct txgbe_eth_syn_filter_ele *syn_filter_ptr;
 	struct txgbe_eth_l2_tunnel_conf_ele *l2_tn_filter_ptr;
-	struct txgbe_fdir_rule_ele *fdir_rule_ptr;
+	struct txgbe_fdir_rule_ele *fdir_rule_ptr = NULL;
 	struct txgbe_rss_conf_ele *rss_filter_ptr;
 	struct txgbe_flow_mem *txgbe_flow_mem_ptr;
 	struct txgbe_filter_info *filter_info = TXGBE_DEV_FILTER(dev);
 	uint8_t first_mask = FALSE;
+	bool fdir_configured = false;
 
 	flow = rte_zmalloc("txgbe_rte_flow", sizeof(struct rte_flow), 0);
 	if (!flow) {
@@ -3360,6 +3355,16 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 			goto out;
 		}
 
+		if (fdir_conf->mode == RTE_FDIR_MODE_NONE) {
+			fdir_conf->mode = fdir_rule.mode;
+			ret = txgbe_fdir_configure(dev);
+			if (ret) {
+				fdir_conf->mode = RTE_FDIR_MODE_NONE;
+				goto fdir_out;
+			}
+			fdir_configured = true;
+		}
+
 		/* A mask cannot be deleted. */
 		if (fdir_rule.b_mask) {
 			if (!fdir_info->mask_added) {
@@ -3381,10 +3386,8 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 				fdir_info->mask.pkt_type_mask =
 					fdir_rule.mask.pkt_type_mask;
 				ret = txgbe_fdir_set_input_mask(dev);
-				if (ret) {
-					rte_free(fdir_rule_ptr);
-					goto out;
-				}
+				if (ret)
+					goto fdir_out;
 
 				fdir_info->mask_added = TRUE;
 				first_mask = TRUE;
@@ -3397,9 +3400,8 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 					&fdir_rule.mask,
 					sizeof(struct txgbe_hw_fdir_mask)) != 0) {
 					PMD_DRV_LOG(ERR, "only support one global mask");
-					rte_free(fdir_rule_ptr);
 					ret = -EINVAL;
-					goto out;
+					goto fdir_out;
 				}
 
 				if (fdir_info->flex_bytes_offset !=
@@ -3408,25 +3410,16 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 				    fdir_rule.flex_relative) {
 					PMD_DRV_LOG(ERR,
 						"flex bytes offset mismatch");
-					rte_free(fdir_rule_ptr);
 					ret = -EINVAL;
-					goto out;
+					goto fdir_out;
 				}
 			}
 		}
 
 		ret = txgbe_fdir_filter_program(dev, &fdir_rule,
 				FALSE, FALSE);
-		if (ret) {
-			rte_free(fdir_rule_ptr);
-			/**
-			 * clean the mask_added flag if fail to
-			 * program
-			 **/
-			if (first_mask)
-				fdir_info->mask_added = FALSE;
-			goto out;
-		}
+		if (ret)
+			goto fdir_out;
 
 		fdir_rule_ptr->filter_info = fdir_rule;
 		TAILQ_INSERT_TAIL(&filter_fdir_list,
@@ -3486,6 +3479,12 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 		return flow;
 	}
 
+fdir_out:
+	rte_free(fdir_rule_ptr);
+	if (first_mask)
+		fdir_info->mask_added = FALSE;
+	if (fdir_configured)
+		fdir_conf->mode = RTE_FDIR_MODE_NONE;
 out:
 	TAILQ_REMOVE(&txgbe_flow_list,
 		txgbe_flow_mem_ptr, entries);
Signature · 1 line
2.53.0
#3 lore raw

PATCH 3/3 net/txgbe: disable flow director when no rule is left

In reply to Zhang Tengfei

When the last FDIR rule is destroyed, on flush, or when enabling FDIR fails, the FDIR mode is reset to none, but Flow Director is left enabled and the Rx packet buffer stays reduced.

Disable Flow Director and restore the Rx packet buffer size in these cases, and when the first rule fails after FDIR was enabled.

Fixes ea230dda16ad ("net/txgbe: configure flow director filter")
Fixes 26048c25942f ("net/txgbe: fix FDIR mode clearing")
---
 drivers/net/txgbe/txgbe_ethdev.h |  1 +
 drivers/net/txgbe/txgbe_fdir.c   | 31 +++++++++++++++++++++++++++----
 drivers/net/txgbe/txgbe_flow.c   |  7 ++++++-
 3 files changed, 34 insertions(+), 5 deletions(-)
drivers/net/txgbe/txgbe_ethdev.h +1 -0
index a617b70e3c..05c20fd58c 100644
@@ -552,6 +552,7 @@ void txgbe_set_ivar_map(struct txgbe_hw *hw, int8_t direction,
  * Flow director function prototypes
  */
 int txgbe_fdir_configure(struct rte_eth_dev *dev);
+void txgbe_fdir_disable(struct txgbe_hw *hw);
 int txgbe_fdir_set_input_mask(struct rte_eth_dev *dev);
 uint16_t txgbe_fdir_get_flex_base(struct txgbe_fdir_rule *rule);
 int txgbe_fdir_set_flexbytes_offset(struct rte_eth_dev *dev,
drivers/net/txgbe/txgbe_fdir.c +27 -4
index cee38a42b8..8e397c995c 100644
@@ -368,6 +368,18 @@ txgbe_set_fdir_flex_conf(struct rte_eth_dev *dev, uint32_t flex)
 	return 0;
 }
 
+void
+txgbe_fdir_disable(struct txgbe_hw *hw)
+{
+	int i;
+
+	wr32(hw, TXGBE_FDIRCTL, 0);
+	wr32(hw, TXGBE_PBRXSIZE(0), hw->mac.rx_pb_size << 10);
+	for (i = 1; i < 8; i++)
+		wr32(hw, TXGBE_PBRXSIZE(i), 0);
+	txgbe_flush(hw);
+}
+
 int
 txgbe_fdir_configure(struct rte_eth_dev *dev)
 {
@@ -408,27 +420,31 @@ txgbe_fdir_configure(struct rte_eth_dev *dev)
 	err = txgbe_fdir_store_input_mask(dev);
 	if (err < 0) {
 		PMD_INIT_LOG(ERR, " Error on setting FD mask");
-		return err;
+		goto error;
 	}
 
 	err = txgbe_fdir_set_input_mask(dev);
 	if (err < 0) {
 		PMD_INIT_LOG(ERR, " Error on setting FD mask");
-		return err;
+		goto error;
 	}
 
 	err = txgbe_set_fdir_flex_conf(dev, flex);
 	if (err < 0) {
 		PMD_INIT_LOG(ERR, " Error on setting FD flexible arguments.");
-		return err;
+		goto error;
 	}
 
 	err = txgbe_fdir_enable(hw, fdirctrl);
 	if (err < 0) {
 		PMD_INIT_LOG(ERR, " Error on enabling FD.");
-		return err;
+		goto error;
 	}
 	return 0;
+
+error:
+	txgbe_fdir_disable(hw);
+	return err;
 }
 
 /*
@@ -1138,12 +1154,16 @@ txgbe_fdir_filter_restore(struct rte_eth_dev *dev)
 int
 txgbe_clear_all_fdir_filter(struct rte_eth_dev *dev)
 {
+	struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
 	struct rte_eth_fdir_conf *fdir_conf = TXGBE_DEV_FDIR_CONF(dev);
 	struct txgbe_hw_fdir_info *fdir_info = TXGBE_DEV_FDIR(dev);
 	struct txgbe_fdir_filter *fdir_filter;
 	struct txgbe_fdir_filter *filter_flag;
+	bool fdir_enabled;
 	int ret = 0;
 
+	fdir_enabled = fdir_conf->mode != RTE_FDIR_MODE_NONE;
+
 	/* flush flow director */
 	rte_hash_reset(fdir_info->hash_handle);
 	memset(fdir_info->hash_map, 0,
@@ -1161,5 +1181,8 @@ txgbe_clear_all_fdir_filter(struct rte_eth_dev *dev)
 	if (filter_flag != NULL)
 		ret = txgbe_fdir_flush(dev);
 
+	if (fdir_enabled && txgbe_is_pf(hw))
+		txgbe_fdir_disable(hw);
+
 	return ret;
 }
drivers/net/txgbe/txgbe_flow.c +6 -1
index f2fc589a10..9fa79fc064 100644
@@ -3483,8 +3483,10 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 	rte_free(fdir_rule_ptr);
 	if (first_mask)
 		fdir_info->mask_added = FALSE;
-	if (fdir_configured)
+	if (fdir_configured) {
+		txgbe_fdir_disable(TXGBE_DEV_HW(dev));
 		fdir_conf->mode = RTE_FDIR_MODE_NONE;
+	}
 out:
 	TAILQ_REMOVE(&txgbe_flow_list,
 		txgbe_flow_mem_ptr, entries);
@@ -3637,6 +3639,9 @@ txgbe_flow_destroy(struct rte_eth_dev *dev,
 				fdir_info->mask_added = false;
 				fdir_info->flex_relative = false;
 				fdir_info->flex_bytes_offset = 0;
+				if (fdir_conf->mode != RTE_FDIR_MODE_NONE &&
+				    txgbe_is_pf(TXGBE_DEV_HW(dev)))
+					txgbe_fdir_disable(TXGBE_DEV_HW(dev));
 				fdir_conf->mode = RTE_FDIR_MODE_NONE;
 			}
 		}
Signature · 1 line
2.53.0
#4 lore raw
In reply to Zhang Tengfei
Quoted 24 lines · On Tue, 13 Oct 2026 22:00:16 +0800 Zhang Tengfei <[email protected]> wrote:

Enabling Flow Director reduces the Rx packet buffer 0 to reserve memory for the filter table, but the size was computed from the current register value and never restored when FDIR was no longer used. Since the FDIR mode is reset when the last rule is removed, on flush, or when enabling FDIR fails, the next rule enabled FDIR again and shrank the buffer once more, until it underflowed. Validating a rule also enabled FDIR.

Patch 1 computes the buffer size from the default packet buffer size, which alone stops the repeated reduction.
Patch 2 stops enabling FDIR from flow validate and rolls back the mode when the first rule fails.
Patch 3 disables FDIR and restores the buffer when no rule is left.

The same issue was fixed in ixgbe:
<https://patches.dpdk.org/project/dpdk/patch/[email protected]>

Compile tested only.

Zhang Tengfei (3):
net/txgbe: fix Rx packet buffer size with flow director net/txgbe: do not enable flow director on flow validate net/txgbe: disable flow director when no rule is left

Quoted 5 lines
 drivers/net/txgbe/txgbe_ethdev.h |  1 +
 drivers/net/txgbe/txgbe_fdir.c   | 36 +++++++++++++++----
 drivers/net/txgbe/txgbe_flow.c   | 60 +++++++++++++++++---------------
 3 files changed, 62 insertions(+), 35 deletions(-)

AI review saw a warning that would be easy to fix.

Subject: Re: [PATCH 0/3] net/txgbe: flow director state fixes

Applied to main, each commit builds with -Dwerror=true. Fixes: tags check out.

Series looks right overall; one validate regression in 2/3.

[PATCH 2/3] net/txgbe: do not enable flow director on flow validate

Warning: validate now accepts rules that create will always reject.

txgbe_parse_fdir_filter_normal() can set
rule->mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN. Before this patch, with mode NONE, parse called txgbe_fdir_configure() which returns -ENOSYS for anything other than SIGNATURE or PERFECT, so validate failed. Now parse only checks for a mode mismatch, validate succeeds, and create fails later in txgbe_fdir_configure().

Keep the cheap mode check in parse so validate and create agree:

	if (rule->mode != RTE_FDIR_MODE_SIGNATURE &&
	    rule->mode != RTE_FDIR_MODE_PERFECT)
		return -ENOTSUP;

	if (fdir_conf->mode != RTE_FDIR_MODE_NONE &&
	    fdir_conf->mode != rule->mode)
		return -ENOTSUP;

[PATCH 3/3] net/txgbe: disable flow director when no rule is left

Info: txgbe_fdir_disable() restores a single packet buffer layout (PB0 = rx_pb_size, PB1-7 = 0), not what txgbe_configure_dcb() set at dev_start. That matches what txgbe_fdir_configure() already does, so FDIR with DCB is already broken and this is not a new problem. If you respin, consider saving the PBRXSIZE values before enabling FDIR and restoring them on disable, or reject FDIR when DCB Rx is configured.

#8 lore raw
In reply to Zhang Tengfei
Quoted 24 lines

-----Original Message-----
From: Zhang Tengfei <[email protected]>
Sent: Tuesday, October 13, 2026 10:00 PM
To: [email protected]; [email protected]
Cc: [email protected]; Zhang Tengfei <[email protected]>; [email protected]; [email protected]; [email protected]; Zhang Tengfei <[email protected]>; [email protected]; [email protected]
Subject: [PATCH 0/3] net/txgbe: fix FDIR Rx packet buffer handling

Enabling Flow Director reduces the Rx packet buffer 0 to reserve memory for the filter table, but the size was computed from the current register value and never restored when FDIR was no longer used. Since the FDIR mode is reset when the last rule is removed, on flush, or when enabling FDIR fails, the next rule enabled FDIR again and shrank the buffer once more, until it underflowed. Validating a rule also enabled FDIR.

Patch 1 computes the buffer size from the default packet buffer size, which alone stops the repeated reduction.
Patch 2 stops enabling FDIR from flow validate and rolls back the mode when the first rule fails.
Patch 3 disables FDIR and restores the buffer when no rule is left.

Quoted 4 lines

The same issue was fixed in ixgbe:
<https://patches.dpdk.org/project/dpdk/patch/[email protected]>

Compile tested only.

It should to be tested with the actual NICs.

Quoted 15 lines

Zhang Tengfei (3):
net/txgbe: fix Rx packet buffer size with flow director net/txgbe: do not enable flow director on flow validate net/txgbe: disable flow director when no rule is left

 drivers/net/txgbe/txgbe_ethdev.h |  1 +
 drivers/net/txgbe/txgbe_fdir.c   | 36 +++++++++++++++----
 drivers/net/txgbe/txgbe_flow.c   | 60 +++++++++++++++++---------------
 3 files changed, 62 insertions(+), 35 deletions(-)

--
2.53.0

#11 lore raw

v2 cover net/txgbe: fix FDIR Rx packet buffer handling

In reply to Zhang Tengfei

Enabling Flow Director reduces the Rx packet buffer 0 to reserve memory for the filter table, but the size was computed from the current register value and never restored when FDIR was no longer used. Since the FDIR mode is reset when the last rule is removed, on flush, or when enabling FDIR fails, the next rule enabled FDIR again and shrank the buffer once more, until it underflowed. Validating a rule also enabled FDIR.

Patch 1 computes the buffer size from the default packet buffer size, which alone stops the repeated reduction.
Patch 2 stops enabling FDIR from flow validate and rolls back the mode when the first rule fails. It also rejects a mode other than signature or perfect while parsing, which configuration does not implement, so validate and create fail the same way.
Patch 3 disables FDIR and restores the buffer when no rule is left.

The same issue was fixed in ixgbe:
<https://patches.dpdk.org/project/dpdk/patch/[email protected]>

Compile tested only.

v2:
* 2/3: reject modes other than signature and perfect while parsing, so validate no longer accepts a MAC VLAN rule that create rejects.
* 1/3 and 3/3 are unchanged. Restoring a single packet buffer on disable matches what enabling FDIR already does, including with DCB. Rejecting FDIR when DCB Rx is configured can be a separate patch.

Zhang Tengfei (3):
net/txgbe: fix Rx packet buffer size with flow director net/txgbe: do not enable flow director on flow validate net/txgbe: disable flow director when no rule is left

 drivers/net/txgbe/txgbe_ethdev.h |  1 +
 drivers/net/txgbe/txgbe_fdir.c   | 36 ++++++++++++++----
 drivers/net/txgbe/txgbe_flow.c   | 64 ++++++++++++++++++--------------
 3 files changed, 66 insertions(+), 35 deletions(-)
Signature · 1 line
2.53.0
#12 lore raw

PATCH v2 1/3 net/txgbe: fix Rx packet buffer size with flow director

Enabling Flow Director reduces PBRXSIZE(0) to reserve packet buffer memory for the filter table. The new size was computed from the current register value, but the FDIR mode is reset to none when the last rule is destroyed, on flush, or when enabling FDIR fails, without restoring the buffer. The next FDIR rule created or validated then enabled FDIR again and reduced the buffer a second time, until the size underflowed.

Compute PBRXSIZE(0) from the default packet buffer size instead.

Fixes ea230dda16ad ("net/txgbe: configure flow director filter")
---
 drivers/net/txgbe/txgbe_fdir.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/net/txgbe/txgbe_fdir.c +2 -3
index 67f586ffc7..cee38a42b8 100644
@@ -390,11 +390,10 @@ txgbe_fdir_configure(struct rte_eth_dev *dev)
 
 	/*
 	 * Before enabling Flow Director, the Rx Packet Buffer size
-	 * must be reduced.  The new value is the current size minus
+	 * must be reduced.  The new value is the default size minus
 	 * flow director memory usage size.
 	 */
-	pbsize = rd32(hw, TXGBE_PBRXSIZE(0));
-	pbsize -= TXGBD_FDIRCTL_BUF_BYTE(fdirctrl);
+	pbsize = (hw->mac.rx_pb_size << 10) - TXGBD_FDIRCTL_BUF_BYTE(fdirctrl);
 	wr32(hw, TXGBE_PBRXSIZE(0), pbsize);
 
 	/*
Signature · 1 line
2.53.0
#13 lore raw

PATCH v2 2/3 net/txgbe: do not enable flow director on flow validate

In reply to Zhang Tengfei

Flow Director was enabled and its mode recorded while parsing a rule, so validating a rule configured the hardware, and the mode stayed locked when the rule was rejected afterwards, e.g. for an invalid queue or when the rule could not be programmed.

Enable Flow Director only when creating the rule, and reset the mode if the first rule fails. Reject a mode other than signature or perfect while parsing. Configuration does not implement it, so validate and create fail the same way.

Fixes 5007ac13189d ("ethdev: remove deprecated Flow Director configuration")
---
 drivers/net/txgbe/txgbe_flow.c | 59 ++++++++++++++++++----------------
 1 file changed, 31 insertions(+), 28 deletions(-)
drivers/net/txgbe/txgbe_flow.c +31 -28
index f8d8c6850d..0b7ce3aa2d 100644
@@ -2966,16 +2966,13 @@ txgbe_parse_fdir_filter(struct rte_eth_dev *dev,
 	if (!txgbe_is_pf(TXGBE_DEV_HW(dev)))
 		return ret;
 
-	if (fdir_conf->mode == RTE_FDIR_MODE_NONE) {
-		fdir_conf->mode = rule->mode;
-		ret = txgbe_fdir_configure(dev);
-		if (ret) {
-			fdir_conf->mode = RTE_FDIR_MODE_NONE;
-			return ret;
-		}
-	} else if (fdir_conf->mode != rule->mode) {
+	if (rule->mode != RTE_FDIR_MODE_SIGNATURE &&
+	    rule->mode != RTE_FDIR_MODE_PERFECT)
+		return -ENOTSUP;
+
+	if (fdir_conf->mode != RTE_FDIR_MODE_NONE &&
+	    fdir_conf->mode != rule->mode)
 		return -ENOTSUP;
-	}
 
 	if (rule->queue >= dev->data->nb_rx_queues)
 		return -ENOTSUP;
@@ -3208,17 +3205,19 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 	struct txgbe_fdir_rule fdir_rule;
 	struct txgbe_l2_tunnel_conf l2_tn_filter;
 	struct txgbe_hw_fdir_info *fdir_info = TXGBE_DEV_FDIR(dev);
+	struct rte_eth_fdir_conf *fdir_conf = TXGBE_DEV_FDIR_CONF(dev);
 	struct txgbe_rte_flow_rss_conf rss_conf;
 	struct rte_flow *flow = NULL;
 	struct txgbe_ntuple_filter_ele *ntuple_filter_ptr;
 	struct txgbe_ethertype_filter_ele *ethertype_filter_ptr;
 	struct txgbe_eth_syn_filter_ele *syn_filter_ptr;
 	struct txgbe_eth_l2_tunnel_conf_ele *l2_tn_filter_ptr;
-	struct txgbe_fdir_rule_ele *fdir_rule_ptr;
+	struct txgbe_fdir_rule_ele *fdir_rule_ptr = NULL;
 	struct txgbe_rss_conf_ele *rss_filter_ptr;
 	struct txgbe_flow_mem *txgbe_flow_mem_ptr;
 	struct txgbe_filter_info *filter_info = TXGBE_DEV_FILTER(dev);
 	uint8_t first_mask = FALSE;
+	bool fdir_configured = false;
 
 	flow = rte_zmalloc("txgbe_rte_flow", sizeof(struct rte_flow), 0);
 	if (!flow) {
@@ -3360,6 +3359,16 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 			goto out;
 		}
 
+		if (fdir_conf->mode == RTE_FDIR_MODE_NONE) {
+			fdir_conf->mode = fdir_rule.mode;
+			ret = txgbe_fdir_configure(dev);
+			if (ret) {
+				fdir_conf->mode = RTE_FDIR_MODE_NONE;
+				goto fdir_out;
+			}
+			fdir_configured = true;
+		}
+
 		/* A mask cannot be deleted. */
 		if (fdir_rule.b_mask) {
 			if (!fdir_info->mask_added) {
@@ -3381,10 +3390,8 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 				fdir_info->mask.pkt_type_mask =
 					fdir_rule.mask.pkt_type_mask;
 				ret = txgbe_fdir_set_input_mask(dev);
-				if (ret) {
-					rte_free(fdir_rule_ptr);
-					goto out;
-				}
+				if (ret)
+					goto fdir_out;
 
 				fdir_info->mask_added = TRUE;
 				first_mask = TRUE;
@@ -3397,9 +3404,8 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 					&fdir_rule.mask,
 					sizeof(struct txgbe_hw_fdir_mask)) != 0) {
 					PMD_DRV_LOG(ERR, "only support one global mask");
-					rte_free(fdir_rule_ptr);
 					ret = -EINVAL;
-					goto out;
+					goto fdir_out;
 				}
 
 				if (fdir_info->flex_bytes_offset !=
@@ -3408,25 +3414,16 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 				    fdir_rule.flex_relative) {
 					PMD_DRV_LOG(ERR,
 						"flex bytes offset mismatch");
-					rte_free(fdir_rule_ptr);
 					ret = -EINVAL;
-					goto out;
+					goto fdir_out;
 				}
 			}
 		}
 
 		ret = txgbe_fdir_filter_program(dev, &fdir_rule,
 				FALSE, FALSE);
-		if (ret) {
-			rte_free(fdir_rule_ptr);
-			/**
-			 * clean the mask_added flag if fail to
-			 * program
-			 **/
-			if (first_mask)
-				fdir_info->mask_added = FALSE;
-			goto out;
-		}
+		if (ret)
+			goto fdir_out;
 
 		fdir_rule_ptr->filter_info = fdir_rule;
 		TAILQ_INSERT_TAIL(&filter_fdir_list,
@@ -3486,6 +3483,12 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 		return flow;
 	}
 
+fdir_out:
+	rte_free(fdir_rule_ptr);
+	if (first_mask)
+		fdir_info->mask_added = FALSE;
+	if (fdir_configured)
+		fdir_conf->mode = RTE_FDIR_MODE_NONE;
 out:
 	TAILQ_REMOVE(&txgbe_flow_list,
 		txgbe_flow_mem_ptr, entries);
Signature · 1 line
2.53.0
#14 lore raw

PATCH v2 3/3 net/txgbe: disable flow director when no rule is left

In reply to Zhang Tengfei

When the last FDIR rule is destroyed, on flush, or when enabling FDIR fails, the FDIR mode is reset to none, but Flow Director is left enabled and the Rx packet buffer stays reduced.

Disable Flow Director and restore the Rx packet buffer size in these cases, and when the first rule fails after FDIR was enabled.

Fixes ea230dda16ad ("net/txgbe: configure flow director filter")
Fixes 26048c25942f ("net/txgbe: fix FDIR mode clearing")
---
 drivers/net/txgbe/txgbe_ethdev.h |  1 +
 drivers/net/txgbe/txgbe_fdir.c   | 31 +++++++++++++++++++++++++++----
 drivers/net/txgbe/txgbe_flow.c   |  7 ++++++-
 3 files changed, 34 insertions(+), 5 deletions(-)
drivers/net/txgbe/txgbe_ethdev.h +1 -0
index a617b70e3c..05c20fd58c 100644
@@ -552,6 +552,7 @@ void txgbe_set_ivar_map(struct txgbe_hw *hw, int8_t direction,
  * Flow director function prototypes
  */
 int txgbe_fdir_configure(struct rte_eth_dev *dev);
+void txgbe_fdir_disable(struct txgbe_hw *hw);
 int txgbe_fdir_set_input_mask(struct rte_eth_dev *dev);
 uint16_t txgbe_fdir_get_flex_base(struct txgbe_fdir_rule *rule);
 int txgbe_fdir_set_flexbytes_offset(struct rte_eth_dev *dev,
drivers/net/txgbe/txgbe_fdir.c +27 -4
index cee38a42b8..8e397c995c 100644
@@ -368,6 +368,18 @@ txgbe_set_fdir_flex_conf(struct rte_eth_dev *dev, uint32_t flex)
 	return 0;
 }
 
+void
+txgbe_fdir_disable(struct txgbe_hw *hw)
+{
+	int i;
+
+	wr32(hw, TXGBE_FDIRCTL, 0);
+	wr32(hw, TXGBE_PBRXSIZE(0), hw->mac.rx_pb_size << 10);
+	for (i = 1; i < 8; i++)
+		wr32(hw, TXGBE_PBRXSIZE(i), 0);
+	txgbe_flush(hw);
+}
+
 int
 txgbe_fdir_configure(struct rte_eth_dev *dev)
 {
@@ -408,27 +420,31 @@ txgbe_fdir_configure(struct rte_eth_dev *dev)
 	err = txgbe_fdir_store_input_mask(dev);
 	if (err < 0) {
 		PMD_INIT_LOG(ERR, " Error on setting FD mask");
-		return err;
+		goto error;
 	}
 
 	err = txgbe_fdir_set_input_mask(dev);
 	if (err < 0) {
 		PMD_INIT_LOG(ERR, " Error on setting FD mask");
-		return err;
+		goto error;
 	}
 
 	err = txgbe_set_fdir_flex_conf(dev, flex);
 	if (err < 0) {
 		PMD_INIT_LOG(ERR, " Error on setting FD flexible arguments.");
-		return err;
+		goto error;
 	}
 
 	err = txgbe_fdir_enable(hw, fdirctrl);
 	if (err < 0) {
 		PMD_INIT_LOG(ERR, " Error on enabling FD.");
-		return err;
+		goto error;
 	}
 	return 0;
+
+error:
+	txgbe_fdir_disable(hw);
+	return err;
 }
 
 /*
@@ -1138,12 +1154,16 @@ txgbe_fdir_filter_restore(struct rte_eth_dev *dev)
 int
 txgbe_clear_all_fdir_filter(struct rte_eth_dev *dev)
 {
+	struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
 	struct rte_eth_fdir_conf *fdir_conf = TXGBE_DEV_FDIR_CONF(dev);
 	struct txgbe_hw_fdir_info *fdir_info = TXGBE_DEV_FDIR(dev);
 	struct txgbe_fdir_filter *fdir_filter;
 	struct txgbe_fdir_filter *filter_flag;
+	bool fdir_enabled;
 	int ret = 0;
 
+	fdir_enabled = fdir_conf->mode != RTE_FDIR_MODE_NONE;
+
 	/* flush flow director */
 	rte_hash_reset(fdir_info->hash_handle);
 	memset(fdir_info->hash_map, 0,
@@ -1161,5 +1181,8 @@ txgbe_clear_all_fdir_filter(struct rte_eth_dev *dev)
 	if (filter_flag != NULL)
 		ret = txgbe_fdir_flush(dev);
 
+	if (fdir_enabled && txgbe_is_pf(hw))
+		txgbe_fdir_disable(hw);
+
 	return ret;
 }
drivers/net/txgbe/txgbe_flow.c +6 -1
index 0b7ce3aa2d..7016fb29d2 100644
@@ -3487,8 +3487,10 @@ txgbe_flow_create(struct rte_eth_dev *dev,
 	rte_free(fdir_rule_ptr);
 	if (first_mask)
 		fdir_info->mask_added = FALSE;
-	if (fdir_configured)
+	if (fdir_configured) {
+		txgbe_fdir_disable(TXGBE_DEV_HW(dev));
 		fdir_conf->mode = RTE_FDIR_MODE_NONE;
+	}
 out:
 	TAILQ_REMOVE(&txgbe_flow_list,
 		txgbe_flow_mem_ptr, entries);
@@ -3641,6 +3643,9 @@ txgbe_flow_destroy(struct rte_eth_dev *dev,
 				fdir_info->mask_added = false;
 				fdir_info->flex_relative = false;
 				fdir_info->flex_bytes_offset = 0;
+				if (fdir_conf->mode != RTE_FDIR_MODE_NONE &&
+				    txgbe_is_pf(TXGBE_DEV_HW(dev)))
+					txgbe_fdir_disable(TXGBE_DEV_HW(dev));
 				fdir_conf->mode = RTE_FDIR_MODE_NONE;
 			}
 		}
Signature · 1 line
2.53.0
#5 lore raw
In reply to Stephen Hemminger
Quoted 25 lines · Stephen Hemminger

On Tue, 13 Oct 2026 22:00:16 +0800
Zhang Tengfei <[email protected]> wrote:
[PATCH 2/3] net/txgbe: do not enable flow director on flow validate

Warning: validate now accepts rules that create will always reject.

txgbe_parse_fdir_filter_normal() can set
rule->mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN. Before this patch, with mode NONE, parse called txgbe_fdir_configure() which returns -ENOSYS for anything other than SIGNATURE or PERFECT, so validate failed. Now parse only checks for a mode mismatch, validate succeeds, and create fails later in txgbe_fdir_configure().

Keep the cheap mode check in parse so validate and create agree:

	if (rule->mode != RTE_FDIR_MODE_SIGNATURE &&
	    rule->mode != RTE_FDIR_MODE_PERFECT)
		return -ENOTSUP;

	if (fdir_conf->mode != RTE_FDIR_MODE_NONE &&
	    fdir_conf->mode != rule->mode)
		return -ENOTSUP;

[PATCH 3/3] net/txgbe: disable flow director when no rule is left

Quoted 7 lines

Info: txgbe_fdir_disable() restores a single packet buffer layout (PB0 = rx_pb_size, PB1-7 = 0), not what txgbe_configure_dcb() set at dev_start. That matches what txgbe_fdir_configure() already does, so FDIR with DCB is already broken and this is not a new problem. If you respin, consider saving the PBRXSIZE values before enabling FDIR and restoring them on disable, or reject FDIR when DCB Rx is configured.

Thanks for review.

Addressed in v2.

2/3 now rejects modes other than signature and perfect while parsing, so validate and create both fail for a MAC VLAN rule.

On 3/3 I left the DCB packet buffer as it is. Enabling FDIR already clears PBRXSIZE(1..7). Rejecting FDIR when DCB Rx is configured can be a separate patch.

#9 lore raw
In reply to Jiawen Wu
Quoted 12 lines · Jiawen Wu
Quoted 12 lines

-----Original Message-----
From: Zhang Tengfei <[email protected]>
Sent: Tuesday, October 13, 2026 10:00 PM
To: [email protected]; [email protected]
Cc: [email protected]; Zhang Tengfei <[email protected]>; [email protected]; [email protected]; [email protected]; Zhang Tengfei <[email protected]>; [email protected]; [email protected]
Subject: [PATCH 0/3] net/txgbe: fix FDIR Rx packet buffer handling
The same issue was fixed in ixgbe:
<https://patches.dpdk.org/project/dpdk/patch/[email protected]>

Quoted 4 lines
Quoted 1 line

Compile tested only.

It should to be tested with the actual NICs.

v2 is out. I do not have a txgbe NIC, so it is compile-tested only.
Would you be able to test it on a txgbe NIC?

With the port started: create and delete one FDIR rule ten times, then check that PBRXSIZE(0) (0x19020) does not keep shrinking and that FDIRCTL (0x19500) is 0 after delete. flow validate must not change either register. A rule with an out-of-range queue must fail and leave them unchanged. flow flush must restore PBRXSIZE(0). SP and AML if you have both.

Acked-by
#10 lore raw
Quoted 8 lines

v2 is out. I do not have a txgbe NIC, so it is compile-tested only. Would you be able to test it on a txgbe NIC?

With the port started: create and delete one FDIR rule ten times, then check that PBRXSIZE(0) (0x19020) does not keep shrinking and that FDIRCTL (0x19500) is 0 after delete.
flow validate must not change either register. A rule with an out-of-range queue must fail and leave them unchanged. flow flush must restore PBRXSIZE(0). SP and AML if you have both.

Hi Tengfei,

Thanks for the series, and for taking the time to fix these in the txgbe driver.

I have tested the v2 series on both SP and AML hardware, and it behaves as you described

No further comments from my side. Thanks again.

#6 lore raw
In reply to Zhang Tengfei
Quoted 36 lines · On Thu, 15 Oct 2026 00:45:00 +0800 Zhang Tengfei <[email protected]> wrote:
Quoted 25 lines · Stephen Hemminger

On Tue, 13 Oct 2026 22:00:16 +0800
Zhang Tengfei <[email protected]> wrote:
[PATCH 2/3] net/txgbe: do not enable flow director on flow validate

Warning: validate now accepts rules that create will always reject.

txgbe_parse_fdir_filter_normal() can set
rule->mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN. Before this patch, with mode NONE, parse called txgbe_fdir_configure() which returns -ENOSYS for anything other than SIGNATURE or PERFECT, so validate failed. Now parse only checks for a mode mismatch, validate succeeds, and create fails later in txgbe_fdir_configure().

Keep the cheap mode check in parse so validate and create agree:

	if (rule->mode != RTE_FDIR_MODE_SIGNATURE &&
	    rule->mode != RTE_FDIR_MODE_PERFECT)
		return -ENOTSUP;

	if (fdir_conf->mode != RTE_FDIR_MODE_NONE &&
	    fdir_conf->mode != rule->mode)
		return -ENOTSUP;

[PATCH 3/3] net/txgbe: disable flow director when no rule is left

Quoted 7 lines

Info: txgbe_fdir_disable() restores a single packet buffer layout (PB0 = rx_pb_size, PB1-7 = 0), not what txgbe_configure_dcb() set at dev_start. That matches what txgbe_fdir_configure() already does, so FDIR with DCB is already broken and this is not a new problem. If you respin, consider saving the PBRXSIZE values before enabling FDIR and restoring them on disable, or reject FDIR when DCB Rx is configured.

Thanks for review.

Quoted 8 lines

Addressed in v2.

2/3 now rejects modes other than signature and perfect while parsing, so validate and create both fail for a MAC VLAN rule.

On 3/3 I left the DCB packet buffer as it is. Enabling FDIR already clears PBRXSIZE(1..7). Rejecting FDIR when DCB Rx is configured can be a separate patch.

Still waiting for ACK from a maintainer of that driver.

author Acked-by Zaiyu Wang
#7 lore raw
Quoted 4 lines · Stephen Hemminger

On Thu, 15 Oct 2026 00:45:00 +0800

Quoted 2 lines

Addressed in v2.

Quoted 8 lines
Quoted 6 lines

2/3 now rejects modes other than signature and perfect while parsing, so validate and create both fail for a MAC VLAN rule.

On 3/3 I left the DCB packet buffer as it is. Enabling FDIR already clears PBRXSIZE(1..7). Rejecting FDIR when DCB Rx is configured can be a separate patch.

Still waiting for ACK from a maintainer of that driver.

Hi Stephen,

Zaiyu tested v2 on hardware and provided an Acked-by on October 19.

https://inbox.dpdk.org/dev/[email protected]/

The reply is under the v1 thread,but explicitly confirms testing of the v2 series.

Thanks,
Tengfei

#15 lore raw
In reply to Zhang Tengfei
Quoted 16 lines · On Thu, 15 Oct 2026 00:39:21 +0800 Zhang Tengfei <[email protected]> wrote:

Enabling Flow Director reduces the Rx packet buffer 0 to reserve memory for the filter table, but the size was computed from the current register value and never restored when FDIR was no longer used. Since the FDIR mode is reset when the last rule is removed, on flush, or when enabling FDIR fails, the next rule enabled FDIR again and shrank the buffer once more, until it underflowed. Validating a rule also enabled FDIR.

Patch 1 computes the buffer size from the default packet buffer size, which alone stops the repeated reduction.
Patch 2 stops enabling FDIR from flow validate and rolls back the mode when the first rule fails. It also rejects a mode other than signature or perfect while parsing, which configuration does not implement, so validate and create fail the same way.
Patch 3 disables FDIR and restores the buffer when no rule is left.

Quoted 4 lines

The same issue was fixed in ixgbe:
<https://patches.dpdk.org/project/dpdk/patch/[email protected]>

Compile tested only.

Applied to next-net