Skip to content

Commit e469b1f

Browse files
orospgregkh
authored andcommitted
iavf: wait for PF confirmation before removing VLAN filters
[ Upstream commit bbcbe4e ] The VLAN filter DELETE path was asymmetric with the ADD path: ADD waits for PF confirmation (ADD -> ADDING -> ACTIVE), but DELETE immediately frees the filter struct after sending the DEL message without waiting for the PF response. This is problematic because: - If the PF rejects the DEL, the filter remains in HW but the driver has already freed the tracking structure, losing sync. - Race conditions between DEL pending and other operations (add, reset) cannot be properly resolved if the filter struct is already gone. Add IAVF_VLAN_REMOVING state to make the DELETE path symmetric: REMOVE -> REMOVING (send DEL) -> PF confirms -> kfree -> PF rejects -> ACTIVE In iavf_del_vlans(), transition filters from REMOVE to REMOVING instead of immediately freeing them. The new DEL completion handler in iavf_virtchnl_completion() frees filters on success or reverts them to ACTIVE on error. Update iavf_add_vlan() to handle the REMOVING state: if a DEL is pending and the user re-adds the same VLAN, queue it for ADD so it gets re-programmed after the PF processes the DEL. The !VLAN_FILTERING_ALLOWED early-exit path still frees filters directly since no PF message is sent in that case. Also update iavf_del_vlan() to skip filters already in REMOVING state: DEL has been sent to PF and the completion handler will free the filter when PF confirms. Without this guard, the sequence DEL(pending) -> user-del -> second DEL could cause the PF to return an error for the second DEL (filter already gone), causing the completion handler to incorrectly revert a deleted filter back to ACTIVE. Fixes: 968996c ("iavf: Fix VLAN_V2 addition/rejection") Signed-off-by: Petr Oros <poros@redhat.com> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Tested-by: Rafal Romanowski <rafal.romanowski@intel.com> Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-3-cdcb48303fd8@intel.com Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent b0173c3 commit e469b1f

3 files changed

Lines changed: 34 additions & 17 deletions

File tree

drivers/net/ethernet/intel/iavf/iavf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ enum iavf_vlan_state_t {
161161
IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */
162162
IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */
163163
IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */
164+
IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */
164165
};
165166

166167
struct iavf_vlan_filter {

drivers/net/ethernet/intel/iavf/iavf_main.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -757,10 +757,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
757757
adapter->num_vlan_filters++;
758758
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
759759
} else if (f->state == IAVF_VLAN_REMOVE) {
760-
/* Re-add the filter since we cannot tell whether the
761-
* pending delete has already been processed by the PF.
762-
* A duplicate add is harmless.
763-
*/
760+
/* DEL not yet sent to PF, cancel it */
761+
f->state = IAVF_VLAN_ACTIVE;
762+
} else if (f->state == IAVF_VLAN_REMOVING) {
763+
/* DEL already sent to PF, re-add after completion */
764764
f->state = IAVF_VLAN_ADD;
765765
iavf_schedule_aq_request(adapter,
766766
IAVF_FLAG_AQ_ADD_VLAN_FILTER);
@@ -791,11 +791,14 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)
791791
list_del(&f->list);
792792
kfree(f);
793793
adapter->num_vlan_filters--;
794-
} else {
794+
} else if (f->state != IAVF_VLAN_REMOVING) {
795795
f->state = IAVF_VLAN_REMOVE;
796796
iavf_schedule_aq_request(adapter,
797797
IAVF_FLAG_AQ_DEL_VLAN_FILTER);
798798
}
799+
/* If REMOVING, DEL is already sent to PF; completion
800+
* handler will free the filter when PF confirms.
801+
*/
799802
}
800803

801804
spin_unlock_bh(&adapter->mac_vlan_list_lock);

drivers/net/ethernet/intel/iavf/iavf_virtchnl.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -945,12 +945,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
945945

946946
vvfl->vsi_id = adapter->vsi_res->vsi_id;
947947
vvfl->num_elements = count;
948-
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
948+
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
949949
if (f->state == IAVF_VLAN_REMOVE) {
950950
vvfl->vlan_id[i] = f->vlan.vid;
951-
list_del(&f->list);
952-
kfree(f);
953-
adapter->num_vlan_filters--;
951+
f->state = IAVF_VLAN_REMOVING;
954952
i++;
955953
if (i == count)
956954
break;
@@ -986,7 +984,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
986984

987985
vvfl_v2->vport_id = adapter->vsi_res->vsi_id;
988986
vvfl_v2->num_elements = count;
989-
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
987+
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
990988
if (f->state == IAVF_VLAN_REMOVE) {
991989
struct virtchnl_vlan_supported_caps *filtering_support =
992990
&adapter->vlan_v2_caps.filtering.filtering_support;
@@ -1001,9 +999,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
1001999
vlan->tci = f->vlan.vid;
10021000
vlan->tpid = f->vlan.tpid;
10031001

1004-
list_del(&f->list);
1005-
kfree(f);
1006-
adapter->num_vlan_filters--;
1002+
f->state = IAVF_VLAN_REMOVING;
10071003
i++;
10081004
if (i == count)
10091005
break;
@@ -2366,10 +2362,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
23662362
ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
23672363
wake_up(&adapter->vc_waitqueue);
23682364
break;
2369-
case VIRTCHNL_OP_DEL_VLAN:
2370-
dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n",
2371-
iavf_stat_str(&adapter->hw, v_retval));
2372-
break;
23732365
case VIRTCHNL_OP_DEL_ETH_ADDR:
23742366
dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
23752367
iavf_stat_str(&adapter->hw, v_retval));
@@ -2891,6 +2883,27 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
28912883
spin_unlock_bh(&adapter->mac_vlan_list_lock);
28922884
}
28932885
break;
2886+
case VIRTCHNL_OP_DEL_VLAN:
2887+
case VIRTCHNL_OP_DEL_VLAN_V2: {
2888+
struct iavf_vlan_filter *f, *ftmp;
2889+
2890+
spin_lock_bh(&adapter->mac_vlan_list_lock);
2891+
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list,
2892+
list) {
2893+
if (f->state == IAVF_VLAN_REMOVING) {
2894+
if (v_retval) {
2895+
/* PF rejected DEL, keep filter */
2896+
f->state = IAVF_VLAN_ACTIVE;
2897+
} else {
2898+
list_del(&f->list);
2899+
kfree(f);
2900+
adapter->num_vlan_filters--;
2901+
}
2902+
}
2903+
}
2904+
spin_unlock_bh(&adapter->mac_vlan_list_lock);
2905+
}
2906+
break;
28942907
case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
28952908
/* PF enabled vlan strip on this VF.
28962909
* Update netdev->features if needed to be in sync with ethtool.

0 commit comments

Comments
 (0)