Commit e793095e authored by Jacob Keller's avatar Jacob Keller Committed by Jeff Kirsher

i40e: add parsing of flexible filter fields from userdef

Add code to parse the user-def field into a data structure format. This
code is intended to allow future extensions of the user-def field by
keeping all code that actually reads and writes the field into a single
location. This ensures that we do not litter the driver with references
to the user-def field and minimizes the amount of bitwise operations we
need to do on the data.

Add code which parses the lower 32bits into a flexible word and its
offset. This will be used in a future patch to enable flexible filters
which can match on some arbitrary data in the packet payload. For now,
we just return -EOPNOTSUPP when this is used.

Add code to fill in the user-def field when reporting the filter back,
even though we don't actually implement any user-def fields yet.

Additionally, ensure that we mask the extended FLOW_EXT bit from the
flow_type now that we will be accepting filters which have the FLOW_EXT
bit set (and thus make use of the user-def field).

Change-Id: I238845035c179380a347baa8db8223304f5f6dd7
Signed-off-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 43b15697
...@@ -202,6 +202,15 @@ enum i40e_fd_stat_idx { ...@@ -202,6 +202,15 @@ enum i40e_fd_stat_idx {
#define I40E_FD_ATR_TUNNEL_STAT_IDX(pf_id) \ #define I40E_FD_ATR_TUNNEL_STAT_IDX(pf_id) \
(I40E_FD_STAT_PF_IDX(pf_id) + I40E_FD_STAT_ATR_TUNNEL) (I40E_FD_STAT_PF_IDX(pf_id) + I40E_FD_STAT_ATR_TUNNEL)
/* The following structure contains the data parsed from the user-defined
* field of the ethtool_rx_flow_spec structure.
*/
struct i40e_rx_flow_userdef {
bool flex_filter;
u16 flex_word;
u16 flex_offset;
};
struct i40e_fdir_filter { struct i40e_fdir_filter {
struct hlist_node fdir_node; struct hlist_node fdir_node;
/* filter ipnut set */ /* filter ipnut set */
......
...@@ -2331,6 +2331,102 @@ static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd) ...@@ -2331,6 +2331,102 @@ static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd)
return 0; return 0;
} }
/**
* i40e_check_mask - Check whether a mask field is set
* @mask: the full mask value
* @field; mask of the field to check
*
* If the given mask is fully set, return positive value. If the mask for the
* field is fully unset, return zero. Otherwise return a negative error code.
**/
static int i40e_check_mask(u64 mask, u64 field)
{
u64 value = mask & field;
if (value == field)
return 1;
else if (!value)
return 0;
else
return -1;
}
/**
* i40e_parse_rx_flow_user_data - Deconstruct user-defined data
* @fsp: pointer to rx flow specification
* @data: pointer to userdef data structure for storage
*
* Read the user-defined data and deconstruct the value into a structure. No
* other code should read the user-defined data, so as to ensure that every
* place consistently reads the value correctly.
*
* The user-defined field is a 64bit Big Endian format value, which we
* deconstruct by reading bits or bit fields from it. Single bit flags shall
* be defined starting from the highest bits, while small bit field values
* shall be defined starting from the lowest bits.
*
* Returns 0 if the data is valid, and non-zero if the userdef data is invalid
* and the filter should be rejected. The data structure will always be
* modified even if FLOW_EXT is not set.
*
**/
static int i40e_parse_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp,
struct i40e_rx_flow_userdef *data)
{
u64 value, mask;
int valid;
/* Zero memory first so it's always consistent. */
memset(data, 0, sizeof(*data));
if (!(fsp->flow_type & FLOW_EXT))
return 0;
value = be64_to_cpu(*((__be64 *)fsp->h_ext.data));
mask = be64_to_cpu(*((__be64 *)fsp->m_ext.data));
#define I40E_USERDEF_FLEX_WORD GENMASK_ULL(15, 0)
#define I40E_USERDEF_FLEX_OFFSET GENMASK_ULL(31, 16)
#define I40E_USERDEF_FLEX_FILTER GENMASK_ULL(31, 0)
valid = i40e_check_mask(mask, I40E_USERDEF_FLEX_FILTER);
if (valid < 0) {
return -EINVAL;
} else if (valid) {
data->flex_word = value & I40E_USERDEF_FLEX_WORD;
data->flex_offset =
(value & I40E_USERDEF_FLEX_OFFSET) >> 16;
data->flex_filter = true;
}
return 0;
}
/**
* i40e_fill_rx_flow_user_data - Fill in user-defined data field
* @fsp: pointer to rx_flow specification
*
* Reads the userdef data structure and properly fills in the user defined
* fields of the rx_flow_spec.
**/
static void i40e_fill_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp,
struct i40e_rx_flow_userdef *data)
{
u64 value = 0, mask = 0;
if (data->flex_filter) {
value |= data->flex_word;
value |= (u64)data->flex_offset << 16;
mask |= I40E_USERDEF_FLEX_FILTER;
}
if (value || mask)
fsp->flow_type |= FLOW_EXT;
*((__be64 *)fsp->h_ext.data) = cpu_to_be64(value);
*((__be64 *)fsp->m_ext.data) = cpu_to_be64(mask);
}
/** /**
* i40e_get_ethtool_fdir_all - Populates the rule count of a command * i40e_get_ethtool_fdir_all - Populates the rule count of a command
* @pf: Pointer to the physical function struct * @pf: Pointer to the physical function struct
...@@ -2382,6 +2478,7 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf, ...@@ -2382,6 +2478,7 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,
{ {
struct ethtool_rx_flow_spec *fsp = struct ethtool_rx_flow_spec *fsp =
(struct ethtool_rx_flow_spec *)&cmd->fs; (struct ethtool_rx_flow_spec *)&cmd->fs;
struct i40e_rx_flow_userdef userdef = {0};
struct i40e_fdir_filter *rule = NULL; struct i40e_fdir_filter *rule = NULL;
struct hlist_node *node2; struct hlist_node *node2;
u64 input_set; u64 input_set;
...@@ -2468,6 +2565,8 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf, ...@@ -2468,6 +2565,8 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,
} }
} }
i40e_fill_rx_flow_user_data(fsp, &userdef);
return 0; return 0;
} }
...@@ -3041,6 +3140,7 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi, ...@@ -3041,6 +3140,7 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,
static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi, static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
struct ethtool_rxnfc *cmd) struct ethtool_rxnfc *cmd)
{ {
struct i40e_rx_flow_userdef userdef;
struct ethtool_rx_flow_spec *fsp; struct ethtool_rx_flow_spec *fsp;
struct i40e_fdir_filter *input; struct i40e_fdir_filter *input;
u16 dest_vsi = 0, q_index = 0; u16 dest_vsi = 0, q_index = 0;
...@@ -3067,6 +3167,14 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi, ...@@ -3067,6 +3167,14 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
/* Parse the user-defined field */
if (i40e_parse_rx_flow_user_data(fsp, &userdef))
return -EINVAL;
/* Flexible filters not yet supported */
if (userdef.flex_filter)
return -EOPNOTSUPP;
/* Extended MAC field is not supported */ /* Extended MAC field is not supported */
if (fsp->flow_type & FLOW_MAC_EXT) if (fsp->flow_type & FLOW_MAC_EXT)
return -EINVAL; return -EINVAL;
...@@ -3120,7 +3228,7 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi, ...@@ -3120,7 +3228,7 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
input->cnt_index = I40E_FD_SB_STAT_IDX(pf->hw.pf_id); input->cnt_index = I40E_FD_SB_STAT_IDX(pf->hw.pf_id);
input->dst_ip = fsp->h_u.tcp_ip4_spec.ip4src; input->dst_ip = fsp->h_u.tcp_ip4_spec.ip4src;
input->src_ip = fsp->h_u.tcp_ip4_spec.ip4dst; input->src_ip = fsp->h_u.tcp_ip4_spec.ip4dst;
input->flow_type = fsp->flow_type; input->flow_type = fsp->flow_type & ~FLOW_EXT;
input->ip4_proto = fsp->h_u.usr_ip4_spec.proto; input->ip4_proto = fsp->h_u.usr_ip4_spec.proto;
/* Reverse the src and dest notion, since the HW expects them to be from /* Reverse the src and dest notion, since the HW expects them to be from
......
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