[PATCH] net/ixgbe: fix repeated Rx packet buffer shrink for FDIR

Burakov, Anatoly anatoly.burakov at intel.com
Fri Sep 25 12:05:22 CEST 2026


On 9/25/2026 11:47 AM, Burakov, Anatoly wrote:
> A general comment: instead of reducing/bringing things back and storing 
> a flag noting whether we did, I would rather do the following:
> 
> 0) store default rx pb size at init
> 1) on enabling FDIR, recalculate using that value minus FDIR table size
> 2) on disabling FDIR[*], restore the default
> 3) similarly, on enable/disable VMDq, recalculate and/or reset
> 
> [*] there is no "disable FDIR" call, only fdir flush which just flushes 
> the FDIR tables but does not actually disable FDIR. arguably, we should 
> convert it to "disable FDIR" by flushing FDIR *and* writing 0 to 
> FDIRCTRL *and* restoring rx pb size to defaults. naturally, after 
> running fdir disable function, FDIR will need to be reconfigured for 
> next FDIR flow and get rx pb size recalculated again.
> 
> So, a bit of a refactor, but I think that would make way more sense.

I asked an AI to implement a fix based on this, and here's what it came 
up with, it is roughly what I would like to see instead (obviously, 
please review/rework as appropriate e.g. to properly support VMDq as well):

diff --git a/drivers/net/intel/ixgbe/ixgbe_fdir.c 
b/drivers/net/intel/ixgbe/ixgbe_fdir.c
index b32dc542874..9f48a27cb3a 100644
--- a/drivers/net/intel/ixgbe/ixgbe_fdir.c
+++ b/drivers/net/intel/ixgbe/ixgbe_fdir.c
@@ -101,7 +101,6 @@ static int fdir_write_perfect_filter_82599(struct 
ixgbe_hw *hw,
  static int fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
                 union ixgbe_atr_input *input, u8 queue, uint32_t fdircmd,
                 uint32_t fdirhash);
-static int ixgbe_fdir_flush(struct rte_eth_dev *dev);

  /**
   * This function is based on ixgbe_fdir_enable_82599() in 
base/ixgbe_82599.c.
@@ -554,6 +553,20 @@ ixgbe_set_fdir_flex_conf(struct ixgbe_adapter *adapter,
         return 0;
  }

+static void
+ixgbe_fdir_disable(struct ixgbe_hw *hw)
+{
+       uint32_t rx_pb_size;
+       int i;
+
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, 0);
+       rx_pb_size = (uint32_t)hw->mac.rx_pb_size << IXGBE_RXPBSIZE_SHIFT;
+       IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), rx_pb_size);
+       for (i = 1; i < 8; i++)
+               IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0);
+       IXGBE_WRITE_FLUSH(hw);
+}
+
  int
  ixgbe_fdir_configure(struct ixgbe_adapter *adapter,
                 const struct rte_eth_fdir_conf *fdir_conf,
@@ -561,7 +574,7 @@ ixgbe_fdir_configure(struct ixgbe_adapter *adapter,
  {
         struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(adapter);
         int err;
-       uint32_t fdirctrl, pbsize;
+       uint32_t fdirctrl, pbsize, rx_pb_size;
         int i;
         enum rte_fdir_mode mode = fdir_conf->mode;

@@ -589,13 +602,14 @@ ixgbe_fdir_configure(struct ixgbe_adapter *adapter,
                 return err;

         /*
-        * Before enabling Flow Director, the Rx Packet Buffer size
-        * must be reduced.  The new value is the current size minus
-        * flow director memory usage size.
+        * Before enabling Flow Director, the Rx Packet Buffer size must be
+        * reduced. The new value is the default size minus flow director
+        * memory usage size.
          */
-       pbsize = (1 << (PBALLOC_SIZE_SHIFT + (fdirctrl & 
FDIRCTRL_PBALLOC_MASK)));
-       IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0),
-           (IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) - pbsize));
+       pbsize = 1 << (PBALLOC_SIZE_SHIFT +
+                       (fdirctrl & FDIRCTRL_PBALLOC_MASK));
+       rx_pb_size = (uint32_t)hw->mac.rx_pb_size << IXGBE_RXPBSIZE_SHIFT;
+       IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), rx_pb_size - pbsize);

         /*
          * The defaults in the HW for RX PB 1-7 are not zero and so 
should be
@@ -609,21 +623,25 @@ ixgbe_fdir_configure(struct ixgbe_adapter *adapter,
         err = ixgbe_fdir_set_input_mask(adapter, fdir_mask, mode);
         if (err < 0) {
                 PMD_INIT_LOG(ERR, " Error on setting FD mask");
-               return err;
+               goto error;
         }
         err = ixgbe_set_fdir_flex_conf(adapter, &fdir_conf->flex_conf,
                                        &fdirctrl);
         if (err < 0) {
                 PMD_INIT_LOG(ERR, " Error on setting FD flexible 
arguments.");
-               return err;
+               goto error;
         }

         err = fdir_enable_82599(hw, fdirctrl);
         if (err < 0) {
                 PMD_INIT_LOG(ERR, " Error on enabling FD.");
-               return err;
+               goto error;
         }
         return 0;
+
+error:
+       ixgbe_fdir_disable(hw);
+       return err;
  }

  /*
@@ -1180,28 +1198,6 @@ ixgbe_fdir_filter_program(struct ixgbe_adapter 
*adapter,
         return err;
  }

-static int
-ixgbe_fdir_flush(struct rte_eth_dev *dev)
-{
-       struct ixgbe_hw *hw = 
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       struct ixgbe_hw_fdir_info *info =
- 
IXGBE_DEV_PRIVATE_TO_FDIR_INFO(dev->data->dev_private);
-       int ret;
-
-       ret = ixgbe_reinit_fdir_tables_82599(hw);
-       if (ret < 0) {
-               PMD_INIT_LOG(ERR, "Failed to re-initialize FD table.");
-               return ret;
-       }
-
-       info->f_add = 0;
-       info->f_remove = 0;
-       info->add = 0;
-       info->remove = 0;
-
-       return ret;
-}
-
  #define FDIRENTRIES_NUM_SHIFT 10
  void
  ixgbe_fdir_info_get(struct rte_eth_dev *dev, struct rte_eth_fdir_info 
*fdir_info)
@@ -1360,13 +1356,26 @@ int
  ixgbe_clear_all_fdir_filter(struct rte_eth_dev *dev)
  {
         struct rte_eth_fdir_conf *fdir_conf = IXGBE_DEV_FDIR_CONF(dev);
+       struct ixgbe_hw *hw = 
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
         struct ixgbe_hw_fdir_info *fdir_info =
                 IXGBE_DEV_PRIVATE_TO_FDIR_INFO(dev->data->dev_private);
         struct ixgbe_fdir_filter *fdir_filter;
-       bool had_flows;
-       int ret = 0;
+       int ret;

-       had_flows = (fdir_info->n_flows != 0);
+       if (fdir_conf->mode != RTE_FDIR_MODE_NONE) {
+               ret = ixgbe_reinit_fdir_tables_82599(hw);
+               if (ret < 0) {
+                       PMD_INIT_LOG(ERR, "Failed to re-initialize FD 
table.");
+                       return ret;
+               }
+
+               fdir_info->f_add = 0;
+               fdir_info->f_remove = 0;
+               fdir_info->add = 0;
+               fdir_info->remove = 0;
+
+               ixgbe_fdir_disable(hw);
+       }

         /* flush flow director */
         rte_hash_reset(fdir_info->hash_handle);
@@ -1386,8 +1395,5 @@ ixgbe_clear_all_fdir_filter(struct rte_eth_dev *dev)
         fdir_info->mask_added = FALSE;
         fdir_conf->mode = RTE_FDIR_MODE_NONE;

-       if (had_flows)
-               ret = ixgbe_fdir_flush(dev);
-
-       return ret;
+       return 0;
  }
diff --git a/drivers/net/intel/ixgbe/ixgbe_flow.c 
b/drivers/net/intel/ixgbe/ixgbe_flow.c
index 6868893d46a..da05e61e8b4 100644
--- a/drivers/net/intel/ixgbe/ixgbe_flow.c
+++ b/drivers/net/intel/ixgbe/ixgbe_flow.c
@@ -3157,15 +3157,15 @@ ixgbe_flow_destroy(struct rte_eth_dev *dev,
                 memcpy(&fdir_rule,
                         &fdir_rule_ptr->filter_info,
                         sizeof(struct ixgbe_fdir_rule));
-               ret = ixgbe_fdir_filter_program(adapter, fdir_conf, 
&fdir_rule, TRUE, FALSE);
+               if (fdir_info->n_flows == 1)
+                       ret = ixgbe_clear_all_fdir_filter(dev);
+               else
+                       ret = ixgbe_fdir_filter_program(adapter, fdir_conf,
+                                       &fdir_rule, TRUE, FALSE);
                 if (!ret) {
                         rte_free(fdir_rule_ptr);
-                       if (fdir_info->n_flows > 0 && 
--(fdir_info->n_flows) == 0) {
-                               fdir_info->mask_added = false;
-                               fdir_info->mask = (struct 
ixgbe_hw_fdir_mask){0};
-                               fdir_info->flex_bytes_offset = 0;
-                               fdir_conf->mode = RTE_FDIR_MODE_NONE;
-                       }
+                       if (fdir_info->n_flows > 1)
+                               fdir_info->n_flows--;
                 }
                 break;
         case RTE_ETH_FILTER_L2_TUNNEL:

-- 
Thanks,
Anatoly


More information about the stable mailing list