summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
diff options
context:
space:
mode:
authorHenry Tieman <henry.w.tieman@intel.com>2020-05-11 18:01:44 -0700
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2020-05-22 21:44:48 -0700
commit2c57ffcb199004825184f96081fbf036d3b2426a (patch)
tree5d8d5bf9837f2d3c88f3dd1c254206c879a3e0a1 /drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
parent165d80d6adab51b6a2f9c40ad0c8d3dec18d7bef (diff)
ice: Enable flex-bytes support
Flex-bytes allows for packet matching based on an offset and value. This is supported via the ethtool user-def option. It is specified by providing an offset followed by a 2 byte match value. Offset is measured from the start of the MAC address. The following restrictions apply to flex-bytes. The specified offset must be an even number and be smaller than 0x1fe. Example usage: ethtool -N eth0 flow-type tcp4 src-ip 192.168.0.55 dst-ip 172.16.0.55 \ src-port 12 dst-port 13 user-def 0x10ffff action 32 Signed-off-by: Henry Tieman <henry.w.tieman@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c')
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c88
1 files changed, 86 insertions, 2 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
index aa85d5ad2477..f240c062860b 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
@@ -93,6 +93,19 @@ static enum ice_fltr_ptype ice_ethtool_flow_to_fltr(int eth)
}
/**
+ * ice_is_mask_valid - check mask field set
+ * @mask: full mask to check
+ * @field: field for which mask should be valid
+ *
+ * If the mask is fully set return true. If it is not valid for field return
+ * false.
+ */
+static bool ice_is_mask_valid(u64 mask, u64 field)
+{
+ return (mask & field) == field;
+}
+
+/**
* ice_get_ethtool_fdir_entry - fill ethtool structure with fdir filter data
* @hw: hardware structure that contains filter list
* @cmd: ethtool command data structure to receive the filter data
@@ -336,6 +349,53 @@ void ice_fdir_release_flows(struct ice_hw *hw)
}
/**
+ * ice_parse_rx_flow_user_data - deconstruct user-defined data
+ * @fsp: pointer to ethtool Rx flow specification
+ * @data: pointer to userdef data structure for storage
+ *
+ * Returns 0 on success, negative error value on failure
+ */
+static int
+ice_parse_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp,
+ struct ice_rx_flow_userdef *data)
+{
+ u64 value, mask;
+
+ memset(data, 0, sizeof(*data));
+ if (!(fsp->flow_type & FLOW_EXT))
+ return 0;
+
+ value = be64_to_cpu(*((__force __be64 *)fsp->h_ext.data));
+ mask = be64_to_cpu(*((__force __be64 *)fsp->m_ext.data));
+ if (!mask)
+ return 0;
+
+#define ICE_USERDEF_FLEX_WORD_M GENMASK_ULL(15, 0)
+#define ICE_USERDEF_FLEX_OFFS_S 16
+#define ICE_USERDEF_FLEX_OFFS_M GENMASK_ULL(31, ICE_USERDEF_FLEX_OFFS_S)
+#define ICE_USERDEF_FLEX_FLTR_M GENMASK_ULL(31, 0)
+
+ /* 0x1fe is the maximum value for offsets stored in the internal
+ * filtering tables.
+ */
+#define ICE_USERDEF_FLEX_MAX_OFFS_VAL 0x1fe
+
+ if (!ice_is_mask_valid(mask, ICE_USERDEF_FLEX_FLTR_M) ||
+ value > ICE_USERDEF_FLEX_FLTR_M)
+ return -EINVAL;
+
+ data->flex_word = value & ICE_USERDEF_FLEX_WORD_M;
+ data->flex_offset = (value & ICE_USERDEF_FLEX_OFFS_M) >>
+ ICE_USERDEF_FLEX_OFFS_S;
+ if (data->flex_offset > ICE_USERDEF_FLEX_MAX_OFFS_VAL)
+ return -EINVAL;
+
+ data->flex_fltr = true;
+
+ return 0;
+}
+
+/**
* ice_fdir_num_avail_fltr - return the number of unused flow director filters
* @hw: pointer to hardware structure
* @vsi: software VSI structure
@@ -936,11 +996,13 @@ ice_set_fdir_ip6_usr_seg(struct ice_flow_seg_info *seg,
* ice_cfg_fdir_xtrct_seq - Configure extraction sequence for the given filter
* @pf: PF structure
* @fsp: pointer to ethtool Rx flow specification
+ * @user: user defined data from flow specification
*
* Returns 0 on success.
*/
static int
-ice_cfg_fdir_xtrct_seq(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp)
+ice_cfg_fdir_xtrct_seq(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp,
+ struct ice_rx_flow_userdef *user)
{
struct ice_flow_seg_info *seg, *tun_seg;
struct device *dev = ice_pf_to_dev(pf);
@@ -1008,6 +1070,18 @@ ice_cfg_fdir_xtrct_seq(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp)
/* tunnel segments are shifted up one. */
memcpy(&tun_seg[1], seg, sizeof(*seg));
+ if (user && user->flex_fltr) {
+ perfect_filter = false;
+ ice_flow_add_fld_raw(seg, user->flex_offset,
+ ICE_FLTR_PRGM_FLEX_WORD_SIZE,
+ ICE_FLOW_FLD_OFF_INVAL,
+ ICE_FLOW_FLD_OFF_INVAL);
+ ice_flow_add_fld_raw(&tun_seg[1], user->flex_offset,
+ ICE_FLTR_PRGM_FLEX_WORD_SIZE,
+ ICE_FLOW_FLD_OFF_INVAL,
+ ICE_FLOW_FLD_OFF_INVAL);
+ }
+
/* add filter for outer headers */
fltr_idx = ice_ethtool_flow_to_fltr(fsp->flow_type & ~FLOW_EXT);
ret = ice_fdir_set_hw_fltr_rule(pf, seg, fltr_idx,
@@ -1433,6 +1507,7 @@ ice_set_fdir_input_set(struct ice_vsi *vsi, struct ethtool_rx_flow_spec *fsp,
*/
int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
{
+ struct ice_rx_flow_userdef userdata;
struct ethtool_rx_flow_spec *fsp;
struct ice_fdir_fltr *input;
struct device *dev;
@@ -1460,10 +1535,13 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
+ if (ice_parse_rx_flow_user_data(fsp, &userdata))
+ return -EINVAL;
+
if (fsp->flow_type & FLOW_MAC_EXT)
return -EINVAL;
- ret = ice_cfg_fdir_xtrct_seq(pf, fsp);
+ ret = ice_cfg_fdir_xtrct_seq(pf, fsp, &userdata);
if (ret)
return ret;
@@ -1495,6 +1573,12 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
goto release_lock;
}
+ if (userdata.flex_fltr) {
+ input->flex_fltr = true;
+ input->flex_word = cpu_to_be16(userdata.flex_word);
+ input->flex_offset = userdata.flex_offset;
+ }
+
/* input struct is added to the HW filter list */
ice_fdir_update_list_entry(pf, input, fsp->location);