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>
This commit is contained in:
parent
165d80d6ad
commit
2c57ffcb19
|
@ -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 = ¶ms->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,
|
||||
|
|
Loading…
Reference in New Issue