diff options
author | Henry Tieman <henry.w.tieman@intel.com> | 2020-05-11 18:01:44 -0700 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2020-05-22 21:44:48 -0700 |
commit | 2c57ffcb199004825184f96081fbf036d3b2426a (patch) | |
tree | 5d8d5bf9837f2d3c88f3dd1c254206c879a3e0a1 /drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c | |
parent | 165d80d6adab51b6a2f9c40ad0c8d3dec18d7bef (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.c | 88 |
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); |