Commit f2ce65b9 authored by Petr Oros's avatar Petr Oros Committed by Paolo Abeni
Browse files

iavf: stop removing VLAN filters from PF on interface down



When a VF goes down, the driver currently sends DEL_VLAN to the PF for
every VLAN filter (ACTIVE -> DISABLE -> send DEL -> INACTIVE), then
re-adds them all on UP (INACTIVE -> ADD -> send ADD -> ADDING ->
ACTIVE). This round-trip is unnecessary because:

 1. The PF disables the VF's queues via VIRTCHNL_OP_DISABLE_QUEUES,
    which already prevents all RX/TX traffic regardless of VLAN filter
    state.

 2. The VLAN filters remaining in PF HW while the VF is down is
    harmless - packets matching those filters have nowhere to go with
    queues disabled.

 3. The DEL+ADD cycle during down/up creates race windows where the
    VLAN filter list is incomplete. With spoofcheck enabled, the PF
    enables TX VLAN filtering on the first non-zero VLAN add, blocking
    traffic for any VLANs not yet re-added.

Remove the entire DISABLE/INACTIVE state machinery:
 - Remove IAVF_VLAN_DISABLE and IAVF_VLAN_INACTIVE enum values
 - Remove iavf_restore_filters() and its call from iavf_open()
 - Remove VLAN filter handling from iavf_clear_mac_vlan_filters(),
   rename it to iavf_clear_mac_filters()
 - Remove DEL_VLAN_FILTER scheduling from iavf_down()
 - Remove all DISABLE/INACTIVE handling from iavf_del_vlans()

VLAN filters now stay ACTIVE across down/up cycles. Only explicit
user removal (ndo_vlan_rx_kill_vid) or PF/VF reset triggers VLAN
filter deletion/re-addition.

Fixes: ed1f5b58 ("i40evf: remove VLAN filters on close")
Signed-off-by: default avatarPetr Oros <poros@redhat.com>
Reviewed-by: default avatarAleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: default avatarRafal Romanowski <rafal.romanowski@intel.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Reviewed-by: default avatarPrzemek Kitszel <przemyslaw.kitszel@intel.com>
Signed-off-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-2-cdcb48303fd8@intel.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 70d62b66
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -159,10 +159,8 @@ enum iavf_vlan_state_t {
	IAVF_VLAN_INVALID,
	IAVF_VLAN_ADD,		/* filter needs to be added */
	IAVF_VLAN_ADDING,	/* ADD sent to PF, waiting for response */
	IAVF_VLAN_ACTIVE,	/* filter is accepted by PF */
	IAVF_VLAN_DISABLE,	/* filter needs to be deleted by PF, then marked INACTIVE */
	IAVF_VLAN_INACTIVE,	/* filter is inactive, we are in IFF_DOWN */
	IAVF_VLAN_REMOVE,	/* filter needs to be removed from list */
	IAVF_VLAN_ACTIVE,	/* PF confirmed, filter is in HW */
	IAVF_VLAN_REMOVE,	/* filter queued for DEL from PF */
};

struct iavf_vlan_filter {
+4 −35
Original line number Diff line number Diff line
@@ -801,27 +801,6 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)
	spin_unlock_bh(&adapter->mac_vlan_list_lock);
}

/**
 * iavf_restore_filters
 * @adapter: board private structure
 *
 * Restore existing non MAC filters when VF netdev comes back up
 **/
static void iavf_restore_filters(struct iavf_adapter *adapter)
{
	struct iavf_vlan_filter *f;

	/* re-add all VLAN filters */
	spin_lock_bh(&adapter->mac_vlan_list_lock);

	list_for_each_entry(f, &adapter->vlan_filter_list, list) {
		if (f->state == IAVF_VLAN_INACTIVE)
			f->state = IAVF_VLAN_ADD;
	}

	spin_unlock_bh(&adapter->mac_vlan_list_lock);
	adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
}

/**
 * iavf_get_num_vlans_added - get number of VLANs added
@@ -1246,13 +1225,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter)
}

/**
 * iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF
 * yet and mark other to be removed.
 * iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark
 * others to be removed.
 * @adapter: board private structure
 **/
static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter)
static void iavf_clear_mac_filters(struct iavf_adapter *adapter)
{
	struct iavf_vlan_filter *vlf, *vlftmp;
	struct iavf_mac_filter *f, *ftmp;

	spin_lock_bh(&adapter->mac_vlan_list_lock);
@@ -1271,11 +1249,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter)
		}
	}

	/* disable all VLAN filters */
	list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list,
				 list)
		vlf->state = IAVF_VLAN_DISABLE;

	spin_unlock_bh(&adapter->mac_vlan_list_lock);
}

@@ -1371,7 +1344,7 @@ void iavf_down(struct iavf_adapter *adapter)
	iavf_napi_disable_all(adapter);
	iavf_irq_disable(adapter);

	iavf_clear_mac_vlan_filters(adapter);
	iavf_clear_mac_filters(adapter);
	iavf_clear_cloud_filters(adapter);
	iavf_clear_fdir_filters(adapter);
	iavf_clear_adv_rss_conf(adapter);
@@ -1388,8 +1361,6 @@ void iavf_down(struct iavf_adapter *adapter)
		 */
		if (!list_empty(&adapter->mac_filter_list))
			adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER;
		if (!list_empty(&adapter->vlan_filter_list))
			adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER;
		if (!list_empty(&adapter->cloud_filter_list))
			adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER;
		if (!list_empty(&adapter->fdir_list_head))
@@ -4494,8 +4465,6 @@ static int iavf_open(struct net_device *netdev)
	iavf_add_filter(adapter, adapter->hw.mac.addr);
	spin_unlock_bh(&adapter->mac_vlan_list_lock);

	/* Restore filters that were removed with IFF_DOWN */
	iavf_restore_filters(adapter);
	iavf_restore_fdir_filters(adapter);

	iavf_configure(adapter);
+6 −27
Original line number Diff line number Diff line
@@ -911,22 +911,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
	spin_lock_bh(&adapter->mac_vlan_list_lock);

	list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
		/* since VLAN capabilities are not allowed, we dont want to send
		 * a VLAN delete request because it will most likely fail and
		 * create unnecessary errors/noise, so just free the VLAN
		 * filters marked for removal to enable bailing out before
		 * sending a virtchnl message
		 */
		if (f->state == IAVF_VLAN_REMOVE &&
		    !VLAN_FILTERING_ALLOWED(adapter)) {
			list_del(&f->list);
			kfree(f);
			adapter->num_vlan_filters--;
		} else if (f->state == IAVF_VLAN_DISABLE &&
		    !VLAN_FILTERING_ALLOWED(adapter)) {
			f->state = IAVF_VLAN_INACTIVE;
		} else if (f->state == IAVF_VLAN_REMOVE ||
			   f->state == IAVF_VLAN_DISABLE) {
		} else if (f->state == IAVF_VLAN_REMOVE) {
			count++;
		}
	}
@@ -959,13 +949,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
		vvfl->vsi_id = adapter->vsi_res->vsi_id;
		vvfl->num_elements = count;
		list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
			if (f->state == IAVF_VLAN_DISABLE) {
				vvfl->vlan_id[i] = f->vlan.vid;
				f->state = IAVF_VLAN_INACTIVE;
				i++;
				if (i == count)
					break;
			} else if (f->state == IAVF_VLAN_REMOVE) {
			if (f->state == IAVF_VLAN_REMOVE) {
				vvfl->vlan_id[i] = f->vlan.vid;
				list_del(&f->list);
				kfree(f);
@@ -1007,8 +991,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
		vvfl_v2->vport_id = adapter->vsi_res->vsi_id;
		vvfl_v2->num_elements = count;
		list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
			if (f->state == IAVF_VLAN_DISABLE ||
			    f->state == IAVF_VLAN_REMOVE) {
			if (f->state == IAVF_VLAN_REMOVE) {
				struct virtchnl_vlan_supported_caps *filtering_support =
					&adapter->vlan_v2_caps.filtering.filtering_support;
				struct virtchnl_vlan *vlan;
@@ -1022,13 +1005,9 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
				vlan->tci = f->vlan.vid;
				vlan->tpid = f->vlan.tpid;

				if (f->state == IAVF_VLAN_DISABLE) {
					f->state = IAVF_VLAN_INACTIVE;
				} else {
				list_del(&f->list);
				kfree(f);
				adapter->num_vlan_filters--;
				}
				i++;
				if (i == count)
					break;