From: Piotr Skajewski <[email protected]>

When the same flow specification is added twice (same 5-tuple with
different sw_idx values), ixgbe_add_ethtool_fdir_entry() silently
programs the duplicate into hardware using a second FDIR table slot.
This wastes a scarce FDIR entry and can cause confusing behaviour
when deleting rules.

Add a helper ixgbe_match_ethtool_fdir_entry() that walks the in-kernel
filter list before programming hardware.  If an entry with an
identical filter (excluding the sw_idx) already exists, the new add
request is rejected with -EEXIST.

Signed-off-by: Piotr Skajewski <[email protected]>
Signed-off-by: Aleksandr Loktionov <[email protected]>
---
 .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c  | 25 +++++++++++++++++++
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index ba049b3..a2009df 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -2938,6 +2938,21 @@ static int ixgbe_flowspec_to_flow_type(struct 
ethtool_rx_flow_spec *fsp,
        return 1;
 }
 
+static bool ixgbe_match_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
+                                          struct ixgbe_fdir_filter *input)
+{
+       struct ixgbe_fdir_filter *rule = NULL;
+
+       hlist_for_each_entry(rule, &adapter->fdir_filter_list, fdir_node) {
+               if (rule->sw_idx == input->sw_idx)
+                       continue;
+               if (!memcmp(&rule->filter, &input->filter,
+                           sizeof(rule->filter)))
+                       return true;
+       }
+       return false;
+}
+
 static int ixgbe_add_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
                                        struct ethtool_rxnfc *cmd)
 {
@@ -2947,7 +2964,7 @@ static int ixgbe_add_ethtool_fdir_entry(struct 
ixgbe_adapter *adapter,
        struct ixgbe_fdir_filter *input;
        union ixgbe_atr_input mask;
-       u8 queue;
-       int err;
+       int err = -EINVAL;
+       u8 queue;
 
        if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
                return -EOPNOTSUPP;
@@ -3050,6 +3067,12 @@ static int ixgbe_add_ethtool_fdir_entry(struct 
ixgbe_adapter *adapter,
        /* apply mask and compute/store hash */
        ixgbe_atr_compute_perfect_hash_82599(&input->filter, &mask);
 
+       /* check for a duplicate filter */
+       if (ixgbe_match_ethtool_fdir_entry(adapter, input)) {
+               err = -EEXIST;
+               goto err_out_w_lock;
+       }
+
        /* program filters to filter memory */
        err = ixgbe_fdir_write_perfect_filter_82599(hw,
                                &input->filter, input->sw_idx, queue);
@@ -3065,7 +3088,7 @@ static int ixgbe_add_ethtool_fdir_entry(struct 
ixgbe_adapter *adapter,
        spin_unlock(&adapter->fdir_perfect_lock);
 err_out:
        kfree(input);
-       return -EINVAL;
+       return err;
 }
 
 static int ixgbe_del_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
-- 
2.52.0

Reply via email to