Skip to content

Commit 01d7e58

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 d9dc444 commit 01d7e58

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
@@ -774,10 +774,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
774774
adapter->num_vlan_filters++;
775775
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
776776
} else if (f->state == IAVF_VLAN_REMOVE) {
777-
/* Re-add the filter since we cannot tell whether the
778-
* pending delete has already been processed by the PF.
779-
* A duplicate add is harmless.
780-
*/
777+
/* DEL not yet sent to PF, cancel it */
778+
f->state = IAVF_VLAN_ACTIVE;
779+
} else if (f->state == IAVF_VLAN_REMOVING) {
780+
/* DEL already sent to PF, re-add after completion */
781781
f->state = IAVF_VLAN_ADD;
782782
iavf_schedule_aq_request(adapter,
783783
IAVF_FLAG_AQ_ADD_VLAN_FILTER);
@@ -808,11 +808,14 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)
808808
list_del(&f->list);
809809
kfree(f);
810810
adapter->num_vlan_filters--;
811-
} else {
811+
} else if (f->state != IAVF_VLAN_REMOVING) {
812812
f->state = IAVF_VLAN_REMOVE;
813813
iavf_schedule_aq_request(adapter,
814814
IAVF_FLAG_AQ_DEL_VLAN_FILTER);
815815
}
816+
/* If REMOVING, DEL is already sent to PF; completion
817+
* handler will free the filter when PF confirms.
818+
*/
816819
}
817820

818821
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
@@ -835,12 +835,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
835835

836836
vvfl->vsi_id = adapter->vsi_res->vsi_id;
837837
vvfl->num_elements = count;
838-
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
838+
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
839839
if (f->state == IAVF_VLAN_REMOVE) {
840840
vvfl->vlan_id[i] = f->vlan.vid;
841-
list_del(&f->list);
842-
kfree(f);
843-
adapter->num_vlan_filters--;
841+
f->state = IAVF_VLAN_REMOVING;
844842
i++;
845843
if (i == count)
846844
break;
@@ -876,7 +874,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
876874

877875
vvfl_v2->vport_id = adapter->vsi_res->vsi_id;
878876
vvfl_v2->num_elements = count;
879-
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
877+
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
880878
if (f->state == IAVF_VLAN_REMOVE) {
881879
struct virtchnl_vlan_supported_caps *filtering_support =
882880
&adapter->vlan_v2_caps.filtering.filtering_support;
@@ -891,9 +889,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
891889
vlan->tci = f->vlan.vid;
892890
vlan->tpid = f->vlan.tpid;
893891

894-
list_del(&f->list);
895-
kfree(f);
896-
adapter->num_vlan_filters--;
892+
f->state = IAVF_VLAN_REMOVING;
897893
i++;
898894
if (i == count)
899895
break;
@@ -2040,10 +2036,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
20402036
ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
20412037
wake_up(&adapter->vc_waitqueue);
20422038
break;
2043-
case VIRTCHNL_OP_DEL_VLAN:
2044-
dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n",
2045-
iavf_stat_str(&adapter->hw, v_retval));
2046-
break;
20472039
case VIRTCHNL_OP_DEL_ETH_ADDR:
20482040
dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
20492041
iavf_stat_str(&adapter->hw, v_retval));
@@ -2534,6 +2526,27 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
25342526
spin_unlock_bh(&adapter->mac_vlan_list_lock);
25352527
}
25362528
break;
2529+
case VIRTCHNL_OP_DEL_VLAN:
2530+
case VIRTCHNL_OP_DEL_VLAN_V2: {
2531+
struct iavf_vlan_filter *f, *ftmp;
2532+
2533+
spin_lock_bh(&adapter->mac_vlan_list_lock);
2534+
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list,
2535+
list) {
2536+
if (f->state == IAVF_VLAN_REMOVING) {
2537+
if (v_retval) {
2538+
/* PF rejected DEL, keep filter */
2539+
f->state = IAVF_VLAN_ACTIVE;
2540+
} else {
2541+
list_del(&f->list);
2542+
kfree(f);
2543+
adapter->num_vlan_filters--;
2544+
}
2545+
}
2546+
}
2547+
spin_unlock_bh(&adapter->mac_vlan_list_lock);
2548+
}
2549+
break;
25372550
case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
25382551
/* PF enabled vlan strip on this VF.
25392552
* Update netdev->features if needed to be in sync with ethtool.

0 commit comments

Comments
 (0)