Skip to content

Commit 2c57ffc

Browse files
Henry TiemanJeff Kirsher
authored andcommitted
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 <[email protected]> Signed-off-by: Tony Nguyen <[email protected]> Tested-by: Andrew Bowers <[email protected]> Signed-off-by: Jeff Kirsher <[email protected]>
1 parent 165d80d commit 2c57ffc

File tree

6 files changed

+265
-2
lines changed

6 files changed

+265
-2
lines changed

drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,19 @@ static enum ice_fltr_ptype ice_ethtool_flow_to_fltr(int eth)
9292
}
9393
}
9494

95+
/**
96+
* ice_is_mask_valid - check mask field set
97+
* @mask: full mask to check
98+
* @field: field for which mask should be valid
99+
*
100+
* If the mask is fully set return true. If it is not valid for field return
101+
* false.
102+
*/
103+
static bool ice_is_mask_valid(u64 mask, u64 field)
104+
{
105+
return (mask & field) == field;
106+
}
107+
95108
/**
96109
* ice_get_ethtool_fdir_entry - fill ethtool structure with fdir filter data
97110
* @hw: hardware structure that contains filter list
@@ -335,6 +348,53 @@ void ice_fdir_release_flows(struct ice_hw *hw)
335348
ice_fdir_erase_flow_from_hw(hw, ICE_BLK_FD, flow);
336349
}
337350

351+
/**
352+
* ice_parse_rx_flow_user_data - deconstruct user-defined data
353+
* @fsp: pointer to ethtool Rx flow specification
354+
* @data: pointer to userdef data structure for storage
355+
*
356+
* Returns 0 on success, negative error value on failure
357+
*/
358+
static int
359+
ice_parse_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp,
360+
struct ice_rx_flow_userdef *data)
361+
{
362+
u64 value, mask;
363+
364+
memset(data, 0, sizeof(*data));
365+
if (!(fsp->flow_type & FLOW_EXT))
366+
return 0;
367+
368+
value = be64_to_cpu(*((__force __be64 *)fsp->h_ext.data));
369+
mask = be64_to_cpu(*((__force __be64 *)fsp->m_ext.data));
370+
if (!mask)
371+
return 0;
372+
373+
#define ICE_USERDEF_FLEX_WORD_M GENMASK_ULL(15, 0)
374+
#define ICE_USERDEF_FLEX_OFFS_S 16
375+
#define ICE_USERDEF_FLEX_OFFS_M GENMASK_ULL(31, ICE_USERDEF_FLEX_OFFS_S)
376+
#define ICE_USERDEF_FLEX_FLTR_M GENMASK_ULL(31, 0)
377+
378+
/* 0x1fe is the maximum value for offsets stored in the internal
379+
* filtering tables.
380+
*/
381+
#define ICE_USERDEF_FLEX_MAX_OFFS_VAL 0x1fe
382+
383+
if (!ice_is_mask_valid(mask, ICE_USERDEF_FLEX_FLTR_M) ||
384+
value > ICE_USERDEF_FLEX_FLTR_M)
385+
return -EINVAL;
386+
387+
data->flex_word = value & ICE_USERDEF_FLEX_WORD_M;
388+
data->flex_offset = (value & ICE_USERDEF_FLEX_OFFS_M) >>
389+
ICE_USERDEF_FLEX_OFFS_S;
390+
if (data->flex_offset > ICE_USERDEF_FLEX_MAX_OFFS_VAL)
391+
return -EINVAL;
392+
393+
data->flex_fltr = true;
394+
395+
return 0;
396+
}
397+
338398
/**
339399
* ice_fdir_num_avail_fltr - return the number of unused flow director filters
340400
* @hw: pointer to hardware structure
@@ -936,11 +996,13 @@ ice_set_fdir_ip6_usr_seg(struct ice_flow_seg_info *seg,
936996
* ice_cfg_fdir_xtrct_seq - Configure extraction sequence for the given filter
937997
* @pf: PF structure
938998
* @fsp: pointer to ethtool Rx flow specification
999+
* @user: user defined data from flow specification
9391000
*
9401001
* Returns 0 on success.
9411002
*/
9421003
static int
943-
ice_cfg_fdir_xtrct_seq(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp)
1004+
ice_cfg_fdir_xtrct_seq(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp,
1005+
struct ice_rx_flow_userdef *user)
9441006
{
9451007
struct ice_flow_seg_info *seg, *tun_seg;
9461008
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)
10081070
/* tunnel segments are shifted up one. */
10091071
memcpy(&tun_seg[1], seg, sizeof(*seg));
10101072

1073+
if (user && user->flex_fltr) {
1074+
perfect_filter = false;
1075+
ice_flow_add_fld_raw(seg, user->flex_offset,
1076+
ICE_FLTR_PRGM_FLEX_WORD_SIZE,
1077+
ICE_FLOW_FLD_OFF_INVAL,
1078+
ICE_FLOW_FLD_OFF_INVAL);
1079+
ice_flow_add_fld_raw(&tun_seg[1], user->flex_offset,
1080+
ICE_FLTR_PRGM_FLEX_WORD_SIZE,
1081+
ICE_FLOW_FLD_OFF_INVAL,
1082+
ICE_FLOW_FLD_OFF_INVAL);
1083+
}
1084+
10111085
/* add filter for outer headers */
10121086
fltr_idx = ice_ethtool_flow_to_fltr(fsp->flow_type & ~FLOW_EXT);
10131087
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,
14331507
*/
14341508
int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
14351509
{
1510+
struct ice_rx_flow_userdef userdata;
14361511
struct ethtool_rx_flow_spec *fsp;
14371512
struct ice_fdir_fltr *input;
14381513
struct device *dev;
@@ -1460,10 +1535,13 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
14601535

14611536
fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
14621537

1538+
if (ice_parse_rx_flow_user_data(fsp, &userdata))
1539+
return -EINVAL;
1540+
14631541
if (fsp->flow_type & FLOW_MAC_EXT)
14641542
return -EINVAL;
14651543

1466-
ret = ice_cfg_fdir_xtrct_seq(pf, fsp);
1544+
ret = ice_cfg_fdir_xtrct_seq(pf, fsp, &userdata);
14671545
if (ret)
14681546
return ret;
14691547

@@ -1495,6 +1573,12 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
14951573
goto release_lock;
14961574
}
14971575

1576+
if (userdata.flex_fltr) {
1577+
input->flex_fltr = true;
1578+
input->flex_word = cpu_to_be16(userdata.flex_word);
1579+
input->flex_offset = userdata.flex_offset;
1580+
}
1581+
14981582
/* input struct is added to the HW filter list */
14991583
ice_fdir_update_list_entry(pf, input, fsp->location);
15001584

drivers/net/ethernet/intel/ice/ice_fdir.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,9 @@ ice_fdir_get_gen_prgm_pkt(struct ice_hw *hw, struct ice_fdir_fltr *input,
650650
return ICE_ERR_PARAM;
651651
}
652652

653+
if (input->flex_fltr)
654+
ice_pkt_insert_u16(loc, input->flex_offset, input->flex_word);
655+
653656
return 0;
654657
}
655658

drivers/net/ethernet/intel/ice/ice_fdir.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ struct ice_fd_fltr_desc_ctx {
6868
u8 fdid_mdid;
6969
};
7070

71+
#define ICE_FLTR_PRGM_FLEX_WORD_SIZE sizeof(__be16)
72+
73+
struct ice_rx_flow_userdef {
74+
u16 flex_word;
75+
u16 flex_offset;
76+
u16 flex_fltr;
77+
};
78+
7179
struct ice_fdir_v4 {
7280
__be32 dst_ip;
7381
__be32 src_ip;
@@ -112,6 +120,11 @@ struct ice_fdir_fltr {
112120
struct ice_fdir_extra ext_data;
113121
struct ice_fdir_extra ext_mask;
114122

123+
/* flex byte filter data */
124+
__be16 flex_word;
125+
u16 flex_offset;
126+
u16 flex_fltr;
127+
115128
/* filter control */
116129
u16 q_index;
117130
u16 dest_vsi;

drivers/net/ethernet/intel/ice/ice_flow.c

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,40 @@ ice_flow_val_hdrs(struct ice_flow_seg_info *segs, u8 segs_cnt)
193193
return 0;
194194
}
195195

196+
/* Sizes of fixed known protocol headers without header options */
197+
#define ICE_FLOW_PROT_HDR_SZ_MAC 14
198+
#define ICE_FLOW_PROT_HDR_SZ_IPV4 20
199+
#define ICE_FLOW_PROT_HDR_SZ_IPV6 40
200+
#define ICE_FLOW_PROT_HDR_SZ_TCP 20
201+
#define ICE_FLOW_PROT_HDR_SZ_UDP 8
202+
#define ICE_FLOW_PROT_HDR_SZ_SCTP 12
203+
204+
/**
205+
* ice_flow_calc_seg_sz - calculates size of a packet segment based on headers
206+
* @params: information about the flow to be processed
207+
* @seg: index of packet segment whose header size is to be determined
208+
*/
209+
static u16 ice_flow_calc_seg_sz(struct ice_flow_prof_params *params, u8 seg)
210+
{
211+
u16 sz = ICE_FLOW_PROT_HDR_SZ_MAC;
212+
213+
/* L3 headers */
214+
if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV4)
215+
sz += ICE_FLOW_PROT_HDR_SZ_IPV4;
216+
else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV6)
217+
sz += ICE_FLOW_PROT_HDR_SZ_IPV6;
218+
219+
/* L4 headers */
220+
if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_TCP)
221+
sz += ICE_FLOW_PROT_HDR_SZ_TCP;
222+
else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_UDP)
223+
sz += ICE_FLOW_PROT_HDR_SZ_UDP;
224+
else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_SCTP)
225+
sz += ICE_FLOW_PROT_HDR_SZ_SCTP;
226+
227+
return sz;
228+
}
229+
196230
/**
197231
* ice_flow_proc_seg_hdrs - process protocol headers present in pkt segments
198232
* @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,
347381
return 0;
348382
}
349383

384+
/**
385+
* ice_flow_xtract_raws - Create extract sequence entries for raw bytes
386+
* @hw: pointer to the HW struct
387+
* @params: information about the flow to be processed
388+
* @seg: index of packet segment whose raw fields are to be be extracted
389+
*/
390+
static enum ice_status
391+
ice_flow_xtract_raws(struct ice_hw *hw, struct ice_flow_prof_params *params,
392+
u8 seg)
393+
{
394+
u16 fv_words;
395+
u16 hdrs_sz;
396+
u8 i;
397+
398+
if (!params->prof->segs[seg].raws_cnt)
399+
return 0;
400+
401+
if (params->prof->segs[seg].raws_cnt >
402+
ARRAY_SIZE(params->prof->segs[seg].raws))
403+
return ICE_ERR_MAX_LIMIT;
404+
405+
/* Offsets within the segment headers are not supported */
406+
hdrs_sz = ice_flow_calc_seg_sz(params, seg);
407+
if (!hdrs_sz)
408+
return ICE_ERR_PARAM;
409+
410+
fv_words = hw->blk[params->blk].es.fvw;
411+
412+
for (i = 0; i < params->prof->segs[seg].raws_cnt; i++) {
413+
struct ice_flow_seg_fld_raw *raw;
414+
u16 off, cnt, j;
415+
416+
raw = &params->prof->segs[seg].raws[i];
417+
418+
/* Storing extraction information */
419+
raw->info.xtrct.prot_id = ICE_PROT_MAC_OF_OR_S;
420+
raw->info.xtrct.off = (raw->off / ICE_FLOW_FV_EXTRACT_SZ) *
421+
ICE_FLOW_FV_EXTRACT_SZ;
422+
raw->info.xtrct.disp = (raw->off % ICE_FLOW_FV_EXTRACT_SZ) *
423+
BITS_PER_BYTE;
424+
raw->info.xtrct.idx = params->es_cnt;
425+
426+
/* Determine the number of field vector entries this raw field
427+
* consumes.
428+
*/
429+
cnt = DIV_ROUND_UP(raw->info.xtrct.disp +
430+
(raw->info.src.last * BITS_PER_BYTE),
431+
(ICE_FLOW_FV_EXTRACT_SZ * BITS_PER_BYTE));
432+
off = raw->info.xtrct.off;
433+
for (j = 0; j < cnt; j++) {
434+
u16 idx;
435+
436+
/* Make sure the number of extraction sequence required
437+
* does not exceed the block's capability
438+
*/
439+
if (params->es_cnt >= hw->blk[params->blk].es.count ||
440+
params->es_cnt >= ICE_MAX_FV_WORDS)
441+
return ICE_ERR_MAX_LIMIT;
442+
443+
/* some blocks require a reversed field vector layout */
444+
if (hw->blk[params->blk].es.reverse)
445+
idx = fv_words - params->es_cnt - 1;
446+
else
447+
idx = params->es_cnt;
448+
449+
params->es[idx].prot_id = raw->info.xtrct.prot_id;
450+
params->es[idx].off = off;
451+
params->es_cnt++;
452+
off += ICE_FLOW_FV_EXTRACT_SZ;
453+
}
454+
}
455+
456+
return 0;
457+
}
458+
350459
/**
351460
* ice_flow_create_xtrct_seq - Create an extraction sequence for given segments
352461
* @hw: pointer to the HW struct
@@ -373,6 +482,11 @@ ice_flow_create_xtrct_seq(struct ice_hw *hw,
373482
if (status)
374483
return status;
375484
}
485+
486+
/* Process raw matching bytes */
487+
status = ice_flow_xtract_raws(hw, params, i);
488+
if (status)
489+
return status;
376490
}
377491

378492
return status;
@@ -943,6 +1057,42 @@ ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
9431057
ice_flow_set_fld_ext(seg, fld, t, val_loc, mask_loc, last_loc);
9441058
}
9451059

1060+
/**
1061+
* ice_flow_add_fld_raw - sets locations of a raw field from entry's input buf
1062+
* @seg: packet segment the field being set belongs to
1063+
* @off: offset of the raw field from the beginning of the segment in bytes
1064+
* @len: length of the raw pattern to be matched
1065+
* @val_loc: location of the value to match from entry's input buffer
1066+
* @mask_loc: location of mask value from entry's input buffer
1067+
*
1068+
* This function specifies the offset of the raw field to be match from the
1069+
* beginning of the specified packet segment, and the locations, in the form of
1070+
* byte offsets from the start of the input buffer for a flow entry, from where
1071+
* the value to match and the mask value to be extracted. These locations are
1072+
* then stored in the flow profile. When adding flow entries to the associated
1073+
* flow profile, these locations can be used to quickly extract the values to
1074+
* create the content of a match entry. This function should only be used for
1075+
* fixed-size data structures.
1076+
*/
1077+
void
1078+
ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
1079+
u16 val_loc, u16 mask_loc)
1080+
{
1081+
if (seg->raws_cnt < ICE_FLOW_SEG_RAW_FLD_MAX) {
1082+
seg->raws[seg->raws_cnt].off = off;
1083+
seg->raws[seg->raws_cnt].info.type = ICE_FLOW_FLD_TYPE_SIZE;
1084+
seg->raws[seg->raws_cnt].info.src.val = val_loc;
1085+
seg->raws[seg->raws_cnt].info.src.mask = mask_loc;
1086+
/* The "last" field is used to store the length of the field */
1087+
seg->raws[seg->raws_cnt].info.src.last = len;
1088+
}
1089+
1090+
/* Overflows of "raws" will be handled as an error condition later in
1091+
* the flow when this information is processed.
1092+
*/
1093+
seg->raws_cnt++;
1094+
}
1095+
9461096
#define ICE_FLOW_RSS_SEG_HDR_L3_MASKS \
9471097
(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
9481098

drivers/net/ethernet/intel/ice/ice_flow.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ enum ice_flow_priority {
128128
};
129129

130130
#define ICE_FLOW_SEG_MAX 2
131+
#define ICE_FLOW_SEG_RAW_FLD_MAX 2
131132
#define ICE_FLOW_FV_EXTRACT_SZ 2
132133

133134
#define ICE_FLOW_SET_HDRS(seg, val) ((seg)->hdrs |= (u32)(val))
@@ -164,12 +165,20 @@ struct ice_flow_fld_info {
164165
struct ice_flow_seg_xtrct xtrct;
165166
};
166167

168+
struct ice_flow_seg_fld_raw {
169+
struct ice_flow_fld_info info;
170+
u16 off; /* Offset from the start of the segment */
171+
};
172+
167173
struct ice_flow_seg_info {
168174
u32 hdrs; /* Bitmask indicating protocol headers present */
169175
u64 match; /* Bitmask indicating header fields to be matched */
170176
u64 range; /* Bitmask indicating header fields matched as ranges */
171177

172178
struct ice_flow_fld_info fields[ICE_FLOW_FIELD_IDX_MAX];
179+
180+
u8 raws_cnt; /* Number of raw fields to be matched */
181+
struct ice_flow_seg_fld_raw raws[ICE_FLOW_SEG_RAW_FLD_MAX];
173182
};
174183

175184
/* 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);
228237
void
229238
ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
230239
u16 val_loc, u16 mask_loc, u16 last_loc, bool range);
240+
void
241+
ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
242+
u16 val_loc, u16 mask_loc);
231243
void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle);
232244
enum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle);
233245
enum ice_status

0 commit comments

Comments
 (0)