Commit 2c57ffcb authored by Henry Tieman's avatar Henry Tieman Committed by Jeff Kirsher

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: default avatarHenry Tieman <henry.w.tieman@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 165d80d6
......@@ -92,6 +92,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
......@@ -335,6 +348,53 @@ void ice_fdir_release_flows(struct ice_hw *hw)
ice_fdir_erase_flow_from_hw(hw, ICE_BLK_FD, flow);
}
/**
* 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
......@@ -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);
......
......@@ -650,6 +650,9 @@ ice_fdir_get_gen_prgm_pkt(struct ice_hw *hw, struct ice_fdir_fltr *input,
return ICE_ERR_PARAM;
}
if (input->flex_fltr)
ice_pkt_insert_u16(loc, input->flex_offset, input->flex_word);
return 0;
}
......
......@@ -68,6 +68,14 @@ struct ice_fd_fltr_desc_ctx {
u8 fdid_mdid;
};
#define ICE_FLTR_PRGM_FLEX_WORD_SIZE sizeof(__be16)
struct ice_rx_flow_userdef {
u16 flex_word;
u16 flex_offset;
u16 flex_fltr;
};
struct ice_fdir_v4 {
__be32 dst_ip;
__be32 src_ip;
......@@ -112,6 +120,11 @@ struct ice_fdir_fltr {
struct ice_fdir_extra ext_data;
struct ice_fdir_extra ext_mask;
/* flex byte filter data */
__be16 flex_word;
u16 flex_offset;
u16 flex_fltr;
/* filter control */
u16 q_index;
u16 dest_vsi;
......
......@@ -193,6 +193,40 @@ ice_flow_val_hdrs(struct ice_flow_seg_info *segs, u8 segs_cnt)
return 0;
}
/* Sizes of fixed known protocol headers without header options */
#define ICE_FLOW_PROT_HDR_SZ_MAC 14
#define ICE_FLOW_PROT_HDR_SZ_IPV4 20
#define ICE_FLOW_PROT_HDR_SZ_IPV6 40
#define ICE_FLOW_PROT_HDR_SZ_TCP 20
#define ICE_FLOW_PROT_HDR_SZ_UDP 8
#define ICE_FLOW_PROT_HDR_SZ_SCTP 12
/**
* ice_flow_calc_seg_sz - calculates size of a packet segment based on headers
* @params: information about the flow to be processed
* @seg: index of packet segment whose header size is to be determined
*/
static u16 ice_flow_calc_seg_sz(struct ice_flow_prof_params *params, u8 seg)
{
u16 sz = ICE_FLOW_PROT_HDR_SZ_MAC;
/* L3 headers */
if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV4)
sz += ICE_FLOW_PROT_HDR_SZ_IPV4;
else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV6)
sz += ICE_FLOW_PROT_HDR_SZ_IPV6;
/* L4 headers */
if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_TCP)
sz += ICE_FLOW_PROT_HDR_SZ_TCP;
else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_UDP)
sz += ICE_FLOW_PROT_HDR_SZ_UDP;
else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_SCTP)
sz += ICE_FLOW_PROT_HDR_SZ_SCTP;
return sz;
}
/**
* ice_flow_proc_seg_hdrs - process protocol headers present in pkt segments
* @params: information about the flow to be processed
......@@ -347,6 +381,81 @@ ice_flow_xtract_fld(struct ice_hw *hw, struct ice_flow_prof_params *params,
return 0;
}
/**
* ice_flow_xtract_raws - Create extract sequence entries for raw bytes
* @hw: pointer to the HW struct
* @params: information about the flow to be processed
* @seg: index of packet segment whose raw fields are to be be extracted
*/
static enum ice_status
ice_flow_xtract_raws(struct ice_hw *hw, struct ice_flow_prof_params *params,
u8 seg)
{
u16 fv_words;
u16 hdrs_sz;
u8 i;
if (!params->prof->segs[seg].raws_cnt)
return 0;
if (params->prof->segs[seg].raws_cnt >
ARRAY_SIZE(params->prof->segs[seg].raws))
return ICE_ERR_MAX_LIMIT;
/* Offsets within the segment headers are not supported */
hdrs_sz = ice_flow_calc_seg_sz(params, seg);
if (!hdrs_sz)
return ICE_ERR_PARAM;
fv_words = hw->blk[params->blk].es.fvw;
for (i = 0; i < params->prof->segs[seg].raws_cnt; i++) {
struct ice_flow_seg_fld_raw *raw;
u16 off, cnt, j;
raw = &params->prof->segs[seg].raws[i];
/* Storing extraction information */
raw->info.xtrct.prot_id = ICE_PROT_MAC_OF_OR_S;
raw->info.xtrct.off = (raw->off / ICE_FLOW_FV_EXTRACT_SZ) *
ICE_FLOW_FV_EXTRACT_SZ;
raw->info.xtrct.disp = (raw->off % ICE_FLOW_FV_EXTRACT_SZ) *
BITS_PER_BYTE;
raw->info.xtrct.idx = params->es_cnt;
/* Determine the number of field vector entries this raw field
* consumes.
*/
cnt = DIV_ROUND_UP(raw->info.xtrct.disp +
(raw->info.src.last * BITS_PER_BYTE),
(ICE_FLOW_FV_EXTRACT_SZ * BITS_PER_BYTE));
off = raw->info.xtrct.off;
for (j = 0; j < cnt; j++) {
u16 idx;
/* Make sure the number of extraction sequence required
* does not exceed the block's capability
*/
if (params->es_cnt >= hw->blk[params->blk].es.count ||
params->es_cnt >= ICE_MAX_FV_WORDS)
return ICE_ERR_MAX_LIMIT;
/* some blocks require a reversed field vector layout */
if (hw->blk[params->blk].es.reverse)
idx = fv_words - params->es_cnt - 1;
else
idx = params->es_cnt;
params->es[idx].prot_id = raw->info.xtrct.prot_id;
params->es[idx].off = off;
params->es_cnt++;
off += ICE_FLOW_FV_EXTRACT_SZ;
}
}
return 0;
}
/**
* ice_flow_create_xtrct_seq - Create an extraction sequence for given segments
* @hw: pointer to the HW struct
......@@ -373,6 +482,11 @@ ice_flow_create_xtrct_seq(struct ice_hw *hw,
if (status)
return status;
}
/* Process raw matching bytes */
status = ice_flow_xtract_raws(hw, params, i);
if (status)
return status;
}
return status;
......@@ -943,6 +1057,42 @@ ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
ice_flow_set_fld_ext(seg, fld, t, val_loc, mask_loc, last_loc);
}
/**
* ice_flow_add_fld_raw - sets locations of a raw field from entry's input buf
* @seg: packet segment the field being set belongs to
* @off: offset of the raw field from the beginning of the segment in bytes
* @len: length of the raw pattern to be matched
* @val_loc: location of the value to match from entry's input buffer
* @mask_loc: location of mask value from entry's input buffer
*
* This function specifies the offset of the raw field to be match from the
* beginning of the specified packet segment, and the locations, in the form of
* byte offsets from the start of the input buffer for a flow entry, from where
* the value to match and the mask value to be extracted. These locations are
* then stored in the flow profile. When adding flow entries to the associated
* flow profile, these locations can be used to quickly extract the values to
* create the content of a match entry. This function should only be used for
* fixed-size data structures.
*/
void
ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
u16 val_loc, u16 mask_loc)
{
if (seg->raws_cnt < ICE_FLOW_SEG_RAW_FLD_MAX) {
seg->raws[seg->raws_cnt].off = off;
seg->raws[seg->raws_cnt].info.type = ICE_FLOW_FLD_TYPE_SIZE;
seg->raws[seg->raws_cnt].info.src.val = val_loc;
seg->raws[seg->raws_cnt].info.src.mask = mask_loc;
/* The "last" field is used to store the length of the field */
seg->raws[seg->raws_cnt].info.src.last = len;
}
/* Overflows of "raws" will be handled as an error condition later in
* the flow when this information is processed.
*/
seg->raws_cnt++;
}
#define ICE_FLOW_RSS_SEG_HDR_L3_MASKS \
(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
......
......@@ -128,6 +128,7 @@ enum ice_flow_priority {
};
#define ICE_FLOW_SEG_MAX 2
#define ICE_FLOW_SEG_RAW_FLD_MAX 2
#define ICE_FLOW_FV_EXTRACT_SZ 2
#define ICE_FLOW_SET_HDRS(seg, val) ((seg)->hdrs |= (u32)(val))
......@@ -164,12 +165,20 @@ struct ice_flow_fld_info {
struct ice_flow_seg_xtrct xtrct;
};
struct ice_flow_seg_fld_raw {
struct ice_flow_fld_info info;
u16 off; /* Offset from the start of the segment */
};
struct ice_flow_seg_info {
u32 hdrs; /* Bitmask indicating protocol headers present */
u64 match; /* Bitmask indicating header fields to be matched */
u64 range; /* Bitmask indicating header fields matched as ranges */
struct ice_flow_fld_info fields[ICE_FLOW_FIELD_IDX_MAX];
u8 raws_cnt; /* Number of raw fields to be matched */
struct ice_flow_seg_fld_raw raws[ICE_FLOW_SEG_RAW_FLD_MAX];
};
/* This structure describes a flow entry, and is tracked only in this file */
......@@ -228,6 +237,9 @@ ice_flow_rem_entry(struct ice_hw *hw, enum ice_block blk, u64 entry_h);
void
ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
u16 val_loc, u16 mask_loc, u16 last_loc, bool range);
void
ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
u16 val_loc, u16 mask_loc);
void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle);
enum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle);
enum ice_status
......
......@@ -12,6 +12,7 @@
*/
enum ice_prot_id {
ICE_PROT_ID_INVAL = 0,
ICE_PROT_MAC_OF_OR_S = 1,
ICE_PROT_IPV4_OF_OR_S = 32,
ICE_PROT_IPV4_IL = 33,
ICE_PROT_IPV6_OF_OR_S = 40,
......
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