OSDN Git Service

ice: Enable flex-bytes support
authorHenry Tieman <henry.w.tieman@intel.com>
Tue, 12 May 2020 01:01:44 +0000 (18:01 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Sat, 23 May 2020 04:44:48 +0000 (21:44 -0700)
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>
drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
drivers/net/ethernet/intel/ice/ice_fdir.c
drivers/net/ethernet/intel/ice/ice_fdir.h
drivers/net/ethernet/intel/ice/ice_flow.c
drivers/net/ethernet/intel/ice/ice_flow.h
drivers/net/ethernet/intel/ice/ice_protocol_type.h

index aa85d5a..f240c06 100644 (file)
@@ -93,6 +93,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
  * @cmd: ethtool command data structure to receive the filter data
@@ -336,6 +349,53 @@ void ice_fdir_release_flows(struct ice_hw *hw)
 }
 
 /**
+ * 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
  * @vsi: software VSI 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);
 
index d50cc6e..6834df1 100644 (file)
@@ -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;
 }
 
index 977dcbc..1c58776 100644 (file)
@@ -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;
index f4b6c39..d74e529 100644 (file)
@@ -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
@@ -348,6 +382,81 @@ ice_flow_xtract_fld(struct ice_hw *hw, struct ice_flow_prof_params *params,
 }
 
 /**
+ * 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
  * @params: information about the flow to be processed
@@ -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)
 
index 3c784c3..3913da2 100644 (file)
@@ -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
index babe4a4..7f4c1ec 100644 (file)
@@ -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,