]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
i40e: improve VF MAC filters accounting
authorLukasz Czapnik <lukasz.czapnik@intel.com>
Wed, 13 Aug 2025 10:45:18 +0000 (12:45 +0200)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Thu, 18 Sep 2025 22:46:30 +0000 (15:46 -0700)
When adding new VM MAC, driver checks only *active* filters in
vsi->mac_filter_hash. Each MAC, even in non-active state is using resources.

To determine number of MACs VM uses, count VSI filters in *any* state.

Add i40e_count_all_filters() to simply count all filters, and rename
i40e_count_filters() to i40e_count_active_filters() to avoid ambiguity.

Fixes: cfb1d572c986 ("i40e: Add ensurance of MacVlan resources for every trusted VF")
Cc: stable@vger.kernel.org
Signed-off-by: Lukasz Czapnik <lukasz.czapnik@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c

index 49aa4497efce7d493491cdbde5d4920a83c967c6..801a57a925dadc288f53d26256fb1317e01eabbf 100644 (file)
@@ -1278,7 +1278,8 @@ struct i40e_mac_filter *i40e_add_mac_filter(struct i40e_vsi *vsi,
                                            const u8 *macaddr);
 int i40e_del_mac_filter(struct i40e_vsi *vsi, const u8 *macaddr);
 bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi);
-int i40e_count_filters(struct i40e_vsi *vsi);
+int i40e_count_all_filters(struct i40e_vsi *vsi);
+int i40e_count_active_filters(struct i40e_vsi *vsi);
 struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr);
 void i40e_vlan_stripping_enable(struct i40e_vsi *vsi);
 static inline bool i40e_is_sw_dcb(struct i40e_pf *pf)
index b14019d44b58118fa69ce191b7d3c0fb2b6b2598..529d5501baacadf1e62872e7adcf152b5dd02612 100644 (file)
@@ -1243,12 +1243,30 @@ void i40e_update_stats(struct i40e_vsi *vsi)
 }
 
 /**
- * i40e_count_filters - counts VSI mac filters
+ * i40e_count_all_filters - counts VSI MAC filters
  * @vsi: the VSI to be searched
  *
- * Returns count of mac filters
- **/
-int i40e_count_filters(struct i40e_vsi *vsi)
+ * Return: count of MAC filters in any state.
+ */
+int i40e_count_all_filters(struct i40e_vsi *vsi)
+{
+       struct i40e_mac_filter *f;
+       struct hlist_node *h;
+       int bkt, cnt = 0;
+
+       hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist)
+               cnt++;
+
+       return cnt;
+}
+
+/**
+ * i40e_count_active_filters - counts VSI MAC filters
+ * @vsi: the VSI to be searched
+ *
+ * Return: count of active MAC filters.
+ */
+int i40e_count_active_filters(struct i40e_vsi *vsi)
 {
        struct i40e_mac_filter *f;
        struct hlist_node *h;
index f9b2197f09425ffa962dc8fedd0a786b1cf0b7f7..081a4526a2f0003d51bb54e0d34fd1fa621b7ae3 100644 (file)
@@ -2862,24 +2862,6 @@ error_param:
                                      (u8 *)&stats, sizeof(stats));
 }
 
-/**
- * i40e_can_vf_change_mac
- * @vf: pointer to the VF info
- *
- * Return true if the VF is allowed to change its MAC filters, false otherwise
- */
-static bool i40e_can_vf_change_mac(struct i40e_vf *vf)
-{
-       /* If the VF MAC address has been set administratively (via the
-        * ndo_set_vf_mac command), then deny permission to the VF to
-        * add/delete unicast MAC addresses, unless the VF is trusted
-        */
-       if (vf->pf_set_mac && !vf->trusted)
-               return false;
-
-       return true;
-}
-
 #define I40E_MAX_MACVLAN_PER_HW 3072
 #define I40E_MAX_MACVLAN_PER_PF(num_ports) (I40E_MAX_MACVLAN_PER_HW /  \
        (num_ports))
@@ -2918,8 +2900,10 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
        struct i40e_pf *pf = vf->pf;
        struct i40e_vsi *vsi = pf->vsi[vf->lan_vsi_idx];
        struct i40e_hw *hw = &pf->hw;
-       int mac2add_cnt = 0;
-       int i;
+       int i, mac_add_max, mac_add_cnt = 0;
+       bool vf_trusted;
+
+       vf_trusted = test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
 
        for (i = 0; i < al->num_elements; i++) {
                struct i40e_mac_filter *f;
@@ -2939,9 +2923,8 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
                 * The VF may request to set the MAC address filter already
                 * assigned to it so do not return an error in that case.
                 */
-               if (!i40e_can_vf_change_mac(vf) &&
-                   !is_multicast_ether_addr(addr) &&
-                   !ether_addr_equal(addr, vf->default_lan_addr.addr)) {
+               if (!vf_trusted && !is_multicast_ether_addr(addr) &&
+                   vf->pf_set_mac && !ether_addr_equal(addr, vf->default_lan_addr.addr)) {
                        dev_err(&pf->pdev->dev,
                                "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n");
                        return -EPERM;
@@ -2950,29 +2933,33 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
                /*count filters that really will be added*/
                f = i40e_find_mac(vsi, addr);
                if (!f)
-                       ++mac2add_cnt;
+                       ++mac_add_cnt;
        }
 
        /* If this VF is not privileged, then we can't add more than a limited
-        * number of addresses. Check to make sure that the additions do not
-        * push us over the limit.
-        */
-       if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
-               if ((i40e_count_filters(vsi) + mac2add_cnt) >
-                   I40E_VC_MAX_MAC_ADDR_PER_VF) {
-                       dev_err(&pf->pdev->dev,
-                               "Cannot add more MAC addresses, VF is not trusted, switch the VF to trusted to add more functionality\n");
-                       return -EPERM;
-               }
-       /* If this VF is trusted, it can use more resources than untrusted.
+        * number of addresses.
+        *
+        * If this VF is trusted, it can use more resources than untrusted.
         * However to ensure that every trusted VF has appropriate number of
         * resources, divide whole pool of resources per port and then across
         * all VFs.
         */
-       } else {
-               if ((i40e_count_filters(vsi) + mac2add_cnt) >
-                   I40E_VC_MAX_MACVLAN_PER_TRUSTED_VF(pf->num_alloc_vfs,
-                                                      hw->num_ports)) {
+       if (!vf_trusted)
+               mac_add_max = I40E_VC_MAX_MAC_ADDR_PER_VF;
+       else
+               mac_add_max = I40E_VC_MAX_MACVLAN_PER_TRUSTED_VF(pf->num_alloc_vfs, hw->num_ports);
+
+       /* VF can replace all its filters in one step, in this case mac_add_max
+        * will be added as active and another mac_add_max will be in
+        * a to-be-removed state. Account for that.
+        */
+       if ((i40e_count_active_filters(vsi) + mac_add_cnt) > mac_add_max ||
+           (i40e_count_all_filters(vsi) + mac_add_cnt) > 2 * mac_add_max) {
+               if (!vf_trusted) {
+                       dev_err(&pf->pdev->dev,
+                               "Cannot add more MAC addresses, VF is not trusted, switch the VF to trusted to add more functionality\n");
+                       return -EPERM;
+               } else {
                        dev_err(&pf->pdev->dev,
                                "Cannot add more MAC addresses, trusted VF exhausted it's resources\n");
                        return -EPERM;