Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -202,6 +202,15 @@ enum i40e_fd_stat_idx {
#define I40E_FD_ATR_TUNNEL_STAT_IDX(pf_id) \
			(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 hlist_node fdir_node;
	/* filter ipnut set */
+109 −1
Original line number Diff line number Diff line
@@ -2331,6 +2331,102 @@ static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd)
	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
 * @pf: Pointer to the physical function struct
@@ -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 *)&cmd->fs;
	struct i40e_rx_flow_userdef userdef = {0};
	struct i40e_fdir_filter *rule = NULL;
	struct hlist_node *node2;
	u64 input_set;
@@ -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;
}

@@ -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,
				 struct ethtool_rxnfc *cmd)
{
	struct i40e_rx_flow_userdef userdef;
	struct ethtool_rx_flow_spec *fsp;
	struct i40e_fdir_filter *input;
	u16 dest_vsi = 0, q_index = 0;
@@ -3067,6 +3167,14 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,

	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 */
	if (fsp->flow_type & FLOW_MAC_EXT)
		return -EINVAL;
@@ -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->dst_ip = fsp->h_u.tcp_ip4_spec.ip4src;
	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;

	/* Reverse the src and dest notion, since the HW expects them to be from