Commit 3a0b5a29 authored by Piotr Gardocki's avatar Piotr Gardocki Committed by Tony Nguyen

iavf: Introduce new state machines for flow director

New states introduced:

 IAVF_FDIR_FLTR_DIS_REQUEST
 IAVF_FDIR_FLTR_DIS_PENDING
 IAVF_FDIR_FLTR_INACTIVE

Current FDIR state machines (SM) are not adequate to handle a few
scenarios in the link DOWN/UP event, reset event and ntuple-feature.

For example, when VF link goes DOWN and comes back UP administratively,
the expectation is that previously installed filters should also be
restored. But with current SM, filters are not restored.
So with new SM, during link DOWN filters are marked as INACTIVE in
the iavf list but removed from PF. After link UP, SM will transition
from INACTIVE to ADD_REQUEST to restore the filter.

Similarly, with VF reset, filters will be removed from the PF, but
marked as INACTIVE in the iavf list. Filters will be restored after
reset completion.

Steps to reproduce:
-------------------

1. Create a VF. Here VF is enp8s0.

2. Assign IP addresses to VF and link partner and ping continuously
from remote. Here remote IP is 1.1.1.1.

3. Check default RX Queue of traffic.

ethtool -S enp8s0 | grep -E "rx-[[:digit:]]+\.packets"

4. Add filter - change default RX Queue (to 15 here)

ethtool -U ens8s0 flow-type ip4 src-ip 1.1.1.1 action 15 loc 5

5. Ensure filter gets added and traffic is received on RX queue 15 now.

Link event testing:
-------------------
6. Bring VF link down and up. If traffic flows to configured queue 15,
test is success, otherwise it is a failure.

Reset event testing:
--------------------
7. Reset the VF. If traffic flows to configured queue 15, test is success,
otherwise it is a failure.

Fixes: 0dbfbabb ("iavf: Add framework to enable ethtool ntuple filters")
Signed-off-by: default avatarPiotr Gardocki <piotrx.gardocki@intel.com>
Reviewed-by: default avatarLarysa Zaremba <larysa.zaremba@intel.com>
Signed-off-by: default avatarRanganatha Rao <ranganatha.rao@intel.com>
Tested-by: default avatarRafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 810c38a3
...@@ -292,6 +292,7 @@ struct iavf_adapter { ...@@ -292,6 +292,7 @@ struct iavf_adapter {
#define IAVF_FLAG_QUEUES_DISABLED BIT(17) #define IAVF_FLAG_QUEUES_DISABLED BIT(17)
#define IAVF_FLAG_SETUP_NETDEV_FEATURES BIT(18) #define IAVF_FLAG_SETUP_NETDEV_FEATURES BIT(18)
#define IAVF_FLAG_REINIT_MSIX_NEEDED BIT(20) #define IAVF_FLAG_REINIT_MSIX_NEEDED BIT(20)
#define IAVF_FLAG_FDIR_ENABLED BIT(21)
/* duplicates for common code */ /* duplicates for common code */
#define IAVF_FLAG_DCB_ENABLED 0 #define IAVF_FLAG_DCB_ENABLED 0
/* flags for admin queue service task */ /* flags for admin queue service task */
......
...@@ -1061,7 +1061,7 @@ iavf_get_ethtool_fdir_entry(struct iavf_adapter *adapter, ...@@ -1061,7 +1061,7 @@ iavf_get_ethtool_fdir_entry(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *rule = NULL; struct iavf_fdir_fltr *rule = NULL;
int ret = 0; int ret = 0;
if (!FDIR_FLTR_SUPPORT(adapter)) if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
return -EOPNOTSUPP; return -EOPNOTSUPP;
spin_lock_bh(&adapter->fdir_fltr_lock); spin_lock_bh(&adapter->fdir_fltr_lock);
...@@ -1203,7 +1203,7 @@ iavf_get_fdir_fltr_ids(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd, ...@@ -1203,7 +1203,7 @@ iavf_get_fdir_fltr_ids(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd,
unsigned int cnt = 0; unsigned int cnt = 0;
int val = 0; int val = 0;
if (!FDIR_FLTR_SUPPORT(adapter)) if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
return -EOPNOTSUPP; return -EOPNOTSUPP;
cmd->data = IAVF_MAX_FDIR_FILTERS; cmd->data = IAVF_MAX_FDIR_FILTERS;
...@@ -1395,7 +1395,7 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx ...@@ -1395,7 +1395,7 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
int count = 50; int count = 50;
int err; int err;
if (!FDIR_FLTR_SUPPORT(adapter)) if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (fsp->flow_type & FLOW_MAC_EXT) if (fsp->flow_type & FLOW_MAC_EXT)
...@@ -1436,12 +1436,16 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx ...@@ -1436,12 +1436,16 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
spin_lock_bh(&adapter->fdir_fltr_lock); spin_lock_bh(&adapter->fdir_fltr_lock);
iavf_fdir_list_add_fltr(adapter, fltr); iavf_fdir_list_add_fltr(adapter, fltr);
adapter->fdir_active_fltr++; adapter->fdir_active_fltr++;
fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST; if (adapter->link_up) {
adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER; fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;
adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER;
} else {
fltr->state = IAVF_FDIR_FLTR_INACTIVE;
}
spin_unlock_bh(&adapter->fdir_fltr_lock); spin_unlock_bh(&adapter->fdir_fltr_lock);
mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); if (adapter->link_up)
mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
ret: ret:
if (err && fltr) if (err && fltr)
kfree(fltr); kfree(fltr);
...@@ -1463,7 +1467,7 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx ...@@ -1463,7 +1467,7 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
struct iavf_fdir_fltr *fltr = NULL; struct iavf_fdir_fltr *fltr = NULL;
int err = 0; int err = 0;
if (!FDIR_FLTR_SUPPORT(adapter)) if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
return -EOPNOTSUPP; return -EOPNOTSUPP;
spin_lock_bh(&adapter->fdir_fltr_lock); spin_lock_bh(&adapter->fdir_fltr_lock);
...@@ -1472,6 +1476,11 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx ...@@ -1472,6 +1476,11 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) { if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) {
fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST; fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST;
adapter->aq_required |= IAVF_FLAG_AQ_DEL_FDIR_FILTER; adapter->aq_required |= IAVF_FLAG_AQ_DEL_FDIR_FILTER;
} else if (fltr->state == IAVF_FDIR_FLTR_INACTIVE) {
list_del(&fltr->list);
kfree(fltr);
adapter->fdir_active_fltr--;
fltr = NULL;
} else { } else {
err = -EBUSY; err = -EBUSY;
} }
...@@ -1780,7 +1789,7 @@ static int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, ...@@ -1780,7 +1789,7 @@ static int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
ret = 0; ret = 0;
break; break;
case ETHTOOL_GRXCLSRLCNT: case ETHTOOL_GRXCLSRLCNT:
if (!FDIR_FLTR_SUPPORT(adapter)) if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
break; break;
spin_lock_bh(&adapter->fdir_fltr_lock); spin_lock_bh(&adapter->fdir_fltr_lock);
cmd->rule_cnt = adapter->fdir_active_fltr; cmd->rule_cnt = adapter->fdir_active_fltr;
......
...@@ -6,12 +6,25 @@ ...@@ -6,12 +6,25 @@
struct iavf_adapter; struct iavf_adapter;
/* State of Flow Director filter */ /* State of Flow Director filter
*
* *_REQUEST states are used to mark filter to be sent to PF driver to perform
* an action (either add or delete filter). *_PENDING states are an indication
* that request was sent to PF and the driver is waiting for response.
*
* Both DELETE and DISABLE states are being used to delete a filter in PF.
* The difference is that after a successful response filter in DEL_PENDING
* state is being deleted from VF driver as well and filter in DIS_PENDING state
* is being changed to INACTIVE state.
*/
enum iavf_fdir_fltr_state_t { enum iavf_fdir_fltr_state_t {
IAVF_FDIR_FLTR_ADD_REQUEST, /* User requests to add filter */ IAVF_FDIR_FLTR_ADD_REQUEST, /* User requests to add filter */
IAVF_FDIR_FLTR_ADD_PENDING, /* Filter pending add by the PF */ IAVF_FDIR_FLTR_ADD_PENDING, /* Filter pending add by the PF */
IAVF_FDIR_FLTR_DEL_REQUEST, /* User requests to delete filter */ IAVF_FDIR_FLTR_DEL_REQUEST, /* User requests to delete filter */
IAVF_FDIR_FLTR_DEL_PENDING, /* Filter pending delete by the PF */ IAVF_FDIR_FLTR_DEL_PENDING, /* Filter pending delete by the PF */
IAVF_FDIR_FLTR_DIS_REQUEST, /* Filter scheduled to be disabled */
IAVF_FDIR_FLTR_DIS_PENDING, /* Filter pending disable by the PF */
IAVF_FDIR_FLTR_INACTIVE, /* Filter inactive on link down */
IAVF_FDIR_FLTR_ACTIVE, /* Filter is active */ IAVF_FDIR_FLTR_ACTIVE, /* Filter is active */
}; };
......
...@@ -1353,18 +1353,20 @@ static void iavf_clear_cloud_filters(struct iavf_adapter *adapter) ...@@ -1353,18 +1353,20 @@ static void iavf_clear_cloud_filters(struct iavf_adapter *adapter)
**/ **/
static void iavf_clear_fdir_filters(struct iavf_adapter *adapter) static void iavf_clear_fdir_filters(struct iavf_adapter *adapter)
{ {
struct iavf_fdir_fltr *fdir, *fdirtmp; struct iavf_fdir_fltr *fdir;
/* remove all Flow Director filters */ /* remove all Flow Director filters */
spin_lock_bh(&adapter->fdir_fltr_lock); spin_lock_bh(&adapter->fdir_fltr_lock);
list_for_each_entry_safe(fdir, fdirtmp, &adapter->fdir_list_head, list_for_each_entry(fdir, &adapter->fdir_list_head, list) {
list) {
if (fdir->state == IAVF_FDIR_FLTR_ADD_REQUEST) { if (fdir->state == IAVF_FDIR_FLTR_ADD_REQUEST) {
list_del(&fdir->list); /* Cancel a request, keep filter as inactive */
kfree(fdir); fdir->state = IAVF_FDIR_FLTR_INACTIVE;
adapter->fdir_active_fltr--; } else if (fdir->state == IAVF_FDIR_FLTR_ADD_PENDING ||
} else { fdir->state == IAVF_FDIR_FLTR_ACTIVE) {
fdir->state = IAVF_FDIR_FLTR_DEL_REQUEST; /* Disable filters which are active or have a pending
* request to PF to be added
*/
fdir->state = IAVF_FDIR_FLTR_DIS_REQUEST;
} }
} }
spin_unlock_bh(&adapter->fdir_fltr_lock); spin_unlock_bh(&adapter->fdir_fltr_lock);
...@@ -4112,6 +4114,33 @@ static int iavf_setup_tc(struct net_device *netdev, enum tc_setup_type type, ...@@ -4112,6 +4114,33 @@ static int iavf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
} }
} }
/**
* iavf_restore_fdir_filters
* @adapter: board private structure
*
* Restore existing FDIR filters when VF netdev comes back up.
**/
static void iavf_restore_fdir_filters(struct iavf_adapter *adapter)
{
struct iavf_fdir_fltr *f;
spin_lock_bh(&adapter->fdir_fltr_lock);
list_for_each_entry(f, &adapter->fdir_list_head, list) {
if (f->state == IAVF_FDIR_FLTR_DIS_REQUEST) {
/* Cancel a request, keep filter as active */
f->state = IAVF_FDIR_FLTR_ACTIVE;
} else if (f->state == IAVF_FDIR_FLTR_DIS_PENDING ||
f->state == IAVF_FDIR_FLTR_INACTIVE) {
/* Add filters which are inactive or have a pending
* request to PF to be deleted
*/
f->state = IAVF_FDIR_FLTR_ADD_REQUEST;
adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER;
}
}
spin_unlock_bh(&adapter->fdir_fltr_lock);
}
/** /**
* iavf_open - Called when a network interface is made active * iavf_open - Called when a network interface is made active
* @netdev: network interface device structure * @netdev: network interface device structure
...@@ -4179,8 +4208,9 @@ static int iavf_open(struct net_device *netdev) ...@@ -4179,8 +4208,9 @@ static int iavf_open(struct net_device *netdev)
spin_unlock_bh(&adapter->mac_vlan_list_lock); spin_unlock_bh(&adapter->mac_vlan_list_lock);
/* Restore VLAN filters that were removed with IFF_DOWN */ /* Restore filters that were removed with IFF_DOWN */
iavf_restore_filters(adapter); iavf_restore_filters(adapter);
iavf_restore_fdir_filters(adapter);
iavf_configure(adapter); iavf_configure(adapter);
......
...@@ -1735,8 +1735,8 @@ void iavf_add_fdir_filter(struct iavf_adapter *adapter) ...@@ -1735,8 +1735,8 @@ void iavf_add_fdir_filter(struct iavf_adapter *adapter)
**/ **/
void iavf_del_fdir_filter(struct iavf_adapter *adapter) void iavf_del_fdir_filter(struct iavf_adapter *adapter)
{ {
struct virtchnl_fdir_del f = {};
struct iavf_fdir_fltr *fdir; struct iavf_fdir_fltr *fdir;
struct virtchnl_fdir_del f;
bool process_fltr = false; bool process_fltr = false;
int len; int len;
...@@ -1753,11 +1753,16 @@ void iavf_del_fdir_filter(struct iavf_adapter *adapter) ...@@ -1753,11 +1753,16 @@ void iavf_del_fdir_filter(struct iavf_adapter *adapter)
list_for_each_entry(fdir, &adapter->fdir_list_head, list) { list_for_each_entry(fdir, &adapter->fdir_list_head, list) {
if (fdir->state == IAVF_FDIR_FLTR_DEL_REQUEST) { if (fdir->state == IAVF_FDIR_FLTR_DEL_REQUEST) {
process_fltr = true; process_fltr = true;
memset(&f, 0, len);
f.vsi_id = fdir->vc_add_msg.vsi_id; f.vsi_id = fdir->vc_add_msg.vsi_id;
f.flow_id = fdir->flow_id; f.flow_id = fdir->flow_id;
fdir->state = IAVF_FDIR_FLTR_DEL_PENDING; fdir->state = IAVF_FDIR_FLTR_DEL_PENDING;
break; break;
} else if (fdir->state == IAVF_FDIR_FLTR_DIS_REQUEST) {
process_fltr = true;
f.vsi_id = fdir->vc_add_msg.vsi_id;
f.flow_id = fdir->flow_id;
fdir->state = IAVF_FDIR_FLTR_DIS_PENDING;
break;
} }
} }
spin_unlock_bh(&adapter->fdir_fltr_lock); spin_unlock_bh(&adapter->fdir_fltr_lock);
...@@ -1901,6 +1906,48 @@ static void iavf_netdev_features_vlan_strip_set(struct net_device *netdev, ...@@ -1901,6 +1906,48 @@ static void iavf_netdev_features_vlan_strip_set(struct net_device *netdev,
netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
} }
/**
* iavf_activate_fdir_filters - Reactivate all FDIR filters after a reset
* @adapter: private adapter structure
*
* Called after a reset to re-add all FDIR filters and delete some of them
* if they were pending to be deleted.
*/
static void iavf_activate_fdir_filters(struct iavf_adapter *adapter)
{
struct iavf_fdir_fltr *f, *ftmp;
bool add_filters = false;
spin_lock_bh(&adapter->fdir_fltr_lock);
list_for_each_entry_safe(f, ftmp, &adapter->fdir_list_head, list) {
if (f->state == IAVF_FDIR_FLTR_ADD_REQUEST ||
f->state == IAVF_FDIR_FLTR_ADD_PENDING ||
f->state == IAVF_FDIR_FLTR_ACTIVE) {
/* All filters and requests have been removed in PF,
* restore them
*/
f->state = IAVF_FDIR_FLTR_ADD_REQUEST;
add_filters = true;
} else if (f->state == IAVF_FDIR_FLTR_DIS_REQUEST ||
f->state == IAVF_FDIR_FLTR_DIS_PENDING) {
/* Link down state, leave filters as inactive */
f->state = IAVF_FDIR_FLTR_INACTIVE;
} else if (f->state == IAVF_FDIR_FLTR_DEL_REQUEST ||
f->state == IAVF_FDIR_FLTR_DEL_PENDING) {
/* Delete filters that were pending to be deleted, the
* list on PF is already cleared after a reset
*/
list_del(&f->list);
kfree(f);
adapter->fdir_active_fltr--;
}
}
spin_unlock_bh(&adapter->fdir_fltr_lock);
if (add_filters)
adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER;
}
/** /**
* iavf_virtchnl_completion * iavf_virtchnl_completion
* @adapter: adapter structure * @adapter: adapter structure
...@@ -2078,7 +2125,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, ...@@ -2078,7 +2125,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
spin_lock_bh(&adapter->fdir_fltr_lock); spin_lock_bh(&adapter->fdir_fltr_lock);
list_for_each_entry(fdir, &adapter->fdir_list_head, list_for_each_entry(fdir, &adapter->fdir_list_head,
list) { list) {
if (fdir->state == IAVF_FDIR_FLTR_DEL_PENDING) { if (fdir->state == IAVF_FDIR_FLTR_DEL_PENDING ||
fdir->state == IAVF_FDIR_FLTR_DIS_PENDING) {
fdir->state = IAVF_FDIR_FLTR_ACTIVE; fdir->state = IAVF_FDIR_FLTR_ACTIVE;
dev_info(&adapter->pdev->dev, "Failed to del Flow Director filter, error %s\n", dev_info(&adapter->pdev->dev, "Failed to del Flow Director filter, error %s\n",
iavf_stat_str(&adapter->hw, iavf_stat_str(&adapter->hw,
...@@ -2214,6 +2262,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, ...@@ -2214,6 +2262,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
spin_unlock_bh(&adapter->mac_vlan_list_lock); spin_unlock_bh(&adapter->mac_vlan_list_lock);
iavf_activate_fdir_filters(adapter);
iavf_parse_vf_resource_msg(adapter); iavf_parse_vf_resource_msg(adapter);
/* negotiated VIRTCHNL_VF_OFFLOAD_VLAN_V2, so wait for the /* negotiated VIRTCHNL_VF_OFFLOAD_VLAN_V2, so wait for the
...@@ -2390,7 +2440,9 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, ...@@ -2390,7 +2440,9 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
list_for_each_entry_safe(fdir, fdir_tmp, &adapter->fdir_list_head, list_for_each_entry_safe(fdir, fdir_tmp, &adapter->fdir_list_head,
list) { list) {
if (fdir->state == IAVF_FDIR_FLTR_DEL_PENDING) { if (fdir->state == IAVF_FDIR_FLTR_DEL_PENDING) {
if (del_fltr->status == VIRTCHNL_FDIR_SUCCESS) { if (del_fltr->status == VIRTCHNL_FDIR_SUCCESS ||
del_fltr->status ==
VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST) {
dev_info(&adapter->pdev->dev, "Flow Director filter with location %u is deleted\n", dev_info(&adapter->pdev->dev, "Flow Director filter with location %u is deleted\n",
fdir->loc); fdir->loc);
list_del(&fdir->list); list_del(&fdir->list);
...@@ -2402,6 +2454,17 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, ...@@ -2402,6 +2454,17 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
del_fltr->status); del_fltr->status);
iavf_print_fdir_fltr(adapter, fdir); iavf_print_fdir_fltr(adapter, fdir);
} }
} else if (fdir->state == IAVF_FDIR_FLTR_DIS_PENDING) {
if (del_fltr->status == VIRTCHNL_FDIR_SUCCESS ||
del_fltr->status ==
VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST) {
fdir->state = IAVF_FDIR_FLTR_INACTIVE;
} else {
fdir->state = IAVF_FDIR_FLTR_ACTIVE;
dev_info(&adapter->pdev->dev, "Failed to disable Flow Director filter with status: %d\n",
del_fltr->status);
iavf_print_fdir_fltr(adapter, fdir);
}
} }
} }
spin_unlock_bh(&adapter->fdir_fltr_lock); spin_unlock_bh(&adapter->fdir_fltr_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment