Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iavf: wait for PF confirmation before removing VLAN filters

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: 968996c070ef ("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>

authored by

Petr Oros and committed by
Paolo Abeni
bbcbe4ed f2ce65b9

+34 -17
+1
drivers/net/ethernet/intel/iavf/iavf.h
··· 161 161 IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ 162 162 IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ 163 163 IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ 164 + IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ 164 165 }; 165 166 166 167 struct iavf_vlan_filter {
+8 -5
drivers/net/ethernet/intel/iavf/iavf_main.c
··· 757 757 adapter->num_vlan_filters++; 758 758 iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); 759 759 } 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 */ 764 764 f->state = IAVF_VLAN_ADD; 765 765 iavf_schedule_aq_request(adapter, 766 766 IAVF_FLAG_AQ_ADD_VLAN_FILTER); ··· 791 791 list_del(&f->list); 792 792 kfree(f); 793 793 adapter->num_vlan_filters--; 794 - } else { 794 + } else if (f->state != IAVF_VLAN_REMOVING) { 795 795 f->state = IAVF_VLAN_REMOVE; 796 796 iavf_schedule_aq_request(adapter, 797 797 IAVF_FLAG_AQ_DEL_VLAN_FILTER); 798 798 } 799 + /* If REMOVING, DEL is already sent to PF; completion 800 + * handler will free the filter when PF confirms. 801 + */ 799 802 } 800 803 801 804 spin_unlock_bh(&adapter->mac_vlan_list_lock);
+25 -12
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
··· 948 948 949 949 vvfl->vsi_id = adapter->vsi_res->vsi_id; 950 950 vvfl->num_elements = count; 951 - list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { 951 + list_for_each_entry(f, &adapter->vlan_filter_list, list) { 952 952 if (f->state == IAVF_VLAN_REMOVE) { 953 953 vvfl->vlan_id[i] = f->vlan.vid; 954 - list_del(&f->list); 955 - kfree(f); 956 - adapter->num_vlan_filters--; 954 + f->state = IAVF_VLAN_REMOVING; 957 955 i++; 958 956 if (i == count) 959 957 break; ··· 988 990 989 991 vvfl_v2->vport_id = adapter->vsi_res->vsi_id; 990 992 vvfl_v2->num_elements = count; 991 - list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { 993 + list_for_each_entry(f, &adapter->vlan_filter_list, list) { 992 994 if (f->state == IAVF_VLAN_REMOVE) { 993 995 struct virtchnl_vlan_supported_caps *filtering_support = 994 996 &adapter->vlan_v2_caps.filtering.filtering_support; ··· 1003 1005 vlan->tci = f->vlan.vid; 1004 1006 vlan->tpid = f->vlan.tpid; 1005 1007 1006 - list_del(&f->list); 1007 - kfree(f); 1008 - adapter->num_vlan_filters--; 1008 + f->state = IAVF_VLAN_REMOVING; 1009 1009 i++; 1010 1010 if (i == count) 1011 1011 break; ··· 2366 2370 ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); 2367 2371 wake_up(&adapter->vc_waitqueue); 2368 2372 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; 2373 2373 case VIRTCHNL_OP_DEL_ETH_ADDR: 2374 2374 dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", 2375 2375 iavf_stat_str(&adapter->hw, v_retval)); ··· 2883 2891 list_for_each_entry(f, &adapter->vlan_filter_list, list) { 2884 2892 if (f->state == IAVF_VLAN_ADDING) 2885 2893 f->state = IAVF_VLAN_ACTIVE; 2894 + } 2895 + spin_unlock_bh(&adapter->mac_vlan_list_lock); 2896 + } 2897 + break; 2898 + case VIRTCHNL_OP_DEL_VLAN: 2899 + case VIRTCHNL_OP_DEL_VLAN_V2: { 2900 + struct iavf_vlan_filter *f, *ftmp; 2901 + 2902 + spin_lock_bh(&adapter->mac_vlan_list_lock); 2903 + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, 2904 + list) { 2905 + if (f->state == IAVF_VLAN_REMOVING) { 2906 + if (v_retval) { 2907 + /* PF rejected DEL, keep filter */ 2908 + f->state = IAVF_VLAN_ACTIVE; 2909 + } else { 2910 + list_del(&f->list); 2911 + kfree(f); 2912 + adapter->num_vlan_filters--; 2913 + } 2914 + } 2886 2915 } 2887 2916 spin_unlock_bh(&adapter->mac_vlan_list_lock); 2888 2917 }