+static int
+ice_hash_parse_raw_pattern(struct ice_adapter *ad,
+ const struct rte_flow_item *item,
+ struct ice_rss_meta *meta)
+{
+ const struct rte_flow_item_raw *raw_spec, *raw_mask;
+ struct ice_parser_profile prof;
+ struct ice_parser_result rslt;
+ uint8_t *pkt_buf, *msk_buf;
+ uint8_t spec_len, pkt_len;
+ uint8_t tmp_val = 0;
+ uint8_t tmp_c = 0;
+ int i, j;
+
+ if (ad->psr == NULL)
+ return -rte_errno;
+
+ raw_spec = item->spec;
+ raw_mask = item->mask;
+
+ spec_len = strlen((char *)(uintptr_t)raw_spec->pattern);
+ if (strlen((char *)(uintptr_t)raw_mask->pattern) !=
+ spec_len)
+ return -rte_errno;
+
+ pkt_len = spec_len / 2;
+
+ pkt_buf = rte_zmalloc(NULL, pkt_len, 0);
+ if (!pkt_buf)
+ return -ENOMEM;
+
+ msk_buf = rte_zmalloc(NULL, pkt_len, 0);
+ if (!msk_buf)
+ return -ENOMEM;
+
+ /* convert string to int array */
+ for (i = 0, j = 0; i < spec_len; i += 2, j++) {
+ tmp_c = raw_spec->pattern[i];
+ if (tmp_c >= 'a' && tmp_c <= 'f')
+ tmp_val = tmp_c - 'a' + 10;
+ if (tmp_c >= 'A' && tmp_c <= 'F')
+ tmp_val = tmp_c - 'A' + 10;
+ if (tmp_c >= '0' && tmp_c <= '9')
+ tmp_val = tmp_c - '0';
+
+ tmp_c = raw_spec->pattern[i + 1];
+ if (tmp_c >= 'a' && tmp_c <= 'f')
+ pkt_buf[j] = tmp_val * 16 + tmp_c - 'a' + 10;
+ if (tmp_c >= 'A' && tmp_c <= 'F')
+ pkt_buf[j] = tmp_val * 16 + tmp_c - 'A' + 10;
+ if (tmp_c >= '0' && tmp_c <= '9')
+ pkt_buf[j] = tmp_val * 16 + tmp_c - '0';
+
+ tmp_c = raw_mask->pattern[i];
+ if (tmp_c >= 'a' && tmp_c <= 'f')
+ tmp_val = tmp_c - 0x57;
+ if (tmp_c >= 'A' && tmp_c <= 'F')
+ tmp_val = tmp_c - 0x37;
+ if (tmp_c >= '0' && tmp_c <= '9')
+ tmp_val = tmp_c - '0';
+
+ tmp_c = raw_mask->pattern[i + 1];
+ if (tmp_c >= 'a' && tmp_c <= 'f')
+ msk_buf[j] = tmp_val * 16 + tmp_c - 'a' + 10;
+ if (tmp_c >= 'A' && tmp_c <= 'F')
+ msk_buf[j] = tmp_val * 16 + tmp_c - 'A' + 10;
+ if (tmp_c >= '0' && tmp_c <= '9')
+ msk_buf[j] = tmp_val * 16 + tmp_c - '0';
+ }
+
+ if (ice_parser_run(ad->psr, pkt_buf, pkt_len, &rslt))
+ return -rte_errno;
+
+ if (ice_parser_profile_init(&rslt, pkt_buf, msk_buf,
+ pkt_len, ICE_BLK_RSS, true, &prof))
+ return -rte_errno;
+
+ rte_memcpy(&meta->raw.prof, &prof, sizeof(prof));
+
+ rte_free(pkt_buf);
+ rte_free(msk_buf);
+ return 0;
+}
+
+static void
+ice_refine_hash_cfg_l234(struct ice_rss_hash_cfg *hash_cfg,
+ uint64_t rss_type)
+{
+ uint32_t *addl_hdrs = &hash_cfg->addl_hdrs;
+ uint64_t *hash_flds = &hash_cfg->hash_flds;
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_ETH) {
+ if (!(rss_type & RTE_ETH_RSS_ETH))
+ *hash_flds &= ~ICE_FLOW_HASH_ETH;
+ if (rss_type & RTE_ETH_RSS_L2_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_DA));
+ else if (rss_type & RTE_ETH_RSS_L2_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_SA));
+ *addl_hdrs &= ~ICE_FLOW_SEG_HDR_ETH;
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_ETH_NON_IP) {
+ if (rss_type & RTE_ETH_RSS_ETH)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_TYPE);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_VLAN) {
+ if (rss_type & RTE_ETH_RSS_C_VLAN)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_C_VLAN);
+ else if (rss_type & RTE_ETH_RSS_S_VLAN)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_S_VLAN);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_PPPOE) {
+ if (!(rss_type & RTE_ETH_RSS_PPPOE))
+ *hash_flds &= ~ICE_FLOW_HASH_PPPOE_SESS_ID;
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_IPV4) {
+ if (rss_type &
+ (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4 |
+ RTE_ETH_RSS_NONFRAG_IPV4_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV4_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV4_SCTP)) {
+ if (rss_type & RTE_ETH_RSS_FRAG_IPV4) {
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_IPV_FRAG;
+ *addl_hdrs &= ~(ICE_FLOW_SEG_HDR_IPV_OTHER);
+ *hash_flds |=
+ BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_ID);
+ }
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA));
+ else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA));
+ else if (rss_type &
+ (RTE_ETH_RSS_L4_SRC_ONLY |
+ RTE_ETH_RSS_L4_DST_ONLY))
+ *hash_flds &= ~ICE_FLOW_HASH_IPV4;
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_IPV4;
+ }
+
+ if (rss_type & RTE_ETH_RSS_IPV4_CHKSUM)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_IPV6) {
+ if (rss_type &
+ (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 |
+ RTE_ETH_RSS_NONFRAG_IPV6_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV6_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV6_SCTP)) {
+ if (rss_type & RTE_ETH_RSS_FRAG_IPV6)
+ *hash_flds |=
+ BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_ID);
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA));
+ else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA));
+ else if (rss_type &
+ (RTE_ETH_RSS_L4_SRC_ONLY |
+ RTE_ETH_RSS_L4_DST_ONLY))
+ *hash_flds &= ~ICE_FLOW_HASH_IPV6;
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_IPV6;
+ }
+
+ if (rss_type & RTE_ETH_RSS_L3_PRE32) {
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE32_SA));
+ } else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE32_DA));
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_IPV6;
+ *hash_flds |= ICE_FLOW_HASH_IPV6_PRE32;
+ }
+ }
+ if (rss_type & RTE_ETH_RSS_L3_PRE48) {
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE48_SA));
+ } else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE48_DA));
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_IPV6;
+ *hash_flds |= ICE_FLOW_HASH_IPV6_PRE48;
+ }
+ }
+ if (rss_type & RTE_ETH_RSS_L3_PRE64) {
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_SA));
+ } else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_DA));
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_IPV6;
+ *hash_flds |= ICE_FLOW_HASH_IPV6_PRE64;
+ }
+ }
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_UDP) {
+ if (rss_type &
+ (RTE_ETH_RSS_NONFRAG_IPV4_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV6_UDP)) {
+ if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT));
+ else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT));
+ else if (rss_type &
+ (RTE_ETH_RSS_L3_SRC_ONLY |
+ RTE_ETH_RSS_L3_DST_ONLY))
+ *hash_flds &= ~ICE_FLOW_HASH_UDP_PORT;
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_UDP_PORT;
+ }
+
+ if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_CHKSUM);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_TCP) {
+ if (rss_type &
+ (RTE_ETH_RSS_NONFRAG_IPV4_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV6_TCP)) {
+ if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT));
+ else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT));
+ else if (rss_type &
+ (RTE_ETH_RSS_L3_SRC_ONLY |
+ RTE_ETH_RSS_L3_DST_ONLY))
+ *hash_flds &= ~ICE_FLOW_HASH_TCP_PORT;
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_TCP_PORT;
+ }
+
+ if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_CHKSUM);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_SCTP) {
+ if (rss_type &
+ (RTE_ETH_RSS_NONFRAG_IPV4_SCTP |
+ RTE_ETH_RSS_NONFRAG_IPV6_SCTP)) {
+ if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT));
+ else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT));
+ else if (rss_type &
+ (RTE_ETH_RSS_L3_SRC_ONLY |
+ RTE_ETH_RSS_L3_DST_ONLY))
+ *hash_flds &= ~ICE_FLOW_HASH_SCTP_PORT;
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_SCTP_PORT;
+ }
+
+ if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_CHKSUM);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_L2TPV3) {
+ if (!(rss_type & RTE_ETH_RSS_L2TPV3))
+ *hash_flds &= ~ICE_FLOW_HASH_L2TPV3_SESS_ID;
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_ESP) {
+ if (!(rss_type & RTE_ETH_RSS_ESP))
+ *hash_flds &= ~ICE_FLOW_HASH_ESP_SPI;
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_AH) {
+ if (!(rss_type & RTE_ETH_RSS_AH))
+ *hash_flds &= ~ICE_FLOW_HASH_AH_SPI;
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_PFCP_SESSION) {
+ if (!(rss_type & RTE_ETH_RSS_PFCP))
+ *hash_flds &= ~ICE_FLOW_HASH_PFCP_SEID;
+ }
+}
+
+static void
+ice_refine_proto_hdrs_by_pattern(struct ice_rss_hash_cfg *hash_cfg,
+ uint64_t phint)
+{
+ uint32_t *addl_hdrs = &hash_cfg->addl_hdrs;
+ if (phint & ICE_PHINT_VLAN)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_VLAN;
+
+ if (phint & ICE_PHINT_PPPOE)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_PPPOE;
+
+ if (phint & ICE_PHINT_GTPU_EH_DWN)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_GTPU_DWN;
+ else if (phint & ICE_PHINT_GTPU_EH_UP)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_GTPU_UP;
+ else if (phint & ICE_PHINT_GTPU_EH)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_GTPU_EH;
+ else if (phint & ICE_PHINT_GTPU)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_GTPU_IP;
+}
+
+static void
+ice_refine_hash_cfg_gtpu(struct ice_rss_hash_cfg *hash_cfg,
+ uint64_t rss_type)
+{
+ uint32_t *addl_hdrs = &hash_cfg->addl_hdrs;
+ uint64_t *hash_flds = &hash_cfg->hash_flds;
+
+ /* update hash field for gtpu eh/gtpu dwn/gtpu up. */
+ if (!(rss_type & RTE_ETH_RSS_GTPU))
+ return;
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_GTPU_DWN)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_DWN_TEID);
+ else if (*addl_hdrs & ICE_FLOW_SEG_HDR_GTPU_UP)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_UP_TEID);
+ else if (*addl_hdrs & ICE_FLOW_SEG_HDR_GTPU_EH)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_EH_TEID);
+ else if (*addl_hdrs & ICE_FLOW_SEG_HDR_GTPU_IP)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_IP_TEID);
+}
+
+static void ice_refine_hash_cfg(struct ice_rss_hash_cfg *hash_cfg,
+ uint64_t rss_type, uint64_t phint)
+{
+ ice_refine_proto_hdrs_by_pattern(hash_cfg, phint);
+ ice_refine_hash_cfg_l234(hash_cfg, rss_type);
+ ice_refine_hash_cfg_gtpu(hash_cfg, rss_type);
+}
+
+static uint64_t invalid_rss_comb[] = {
+ RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_UDP,
+ RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_TCP,
+ RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_UDP,
+ RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_TCP,
+ RTE_ETH_RSS_L3_PRE40 |
+ RTE_ETH_RSS_L3_PRE56 |
+ RTE_ETH_RSS_L3_PRE96
+};
+
+struct rss_attr_type {
+ uint64_t attr;
+ uint64_t type;
+};
+
+static struct rss_attr_type rss_attr_to_valid_type[] = {
+ {RTE_ETH_RSS_L2_SRC_ONLY | RTE_ETH_RSS_L2_DST_ONLY, RTE_ETH_RSS_ETH},
+ {RTE_ETH_RSS_L3_SRC_ONLY | RTE_ETH_RSS_L3_DST_ONLY, VALID_RSS_L3},
+ {RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY, VALID_RSS_L4},
+ /* current ipv6 prefix only supports prefix 64 bits*/
+ {RTE_ETH_RSS_L3_PRE32, VALID_RSS_IPV6},
+ {RTE_ETH_RSS_L3_PRE48, VALID_RSS_IPV6},
+ {RTE_ETH_RSS_L3_PRE64, VALID_RSS_IPV6},
+ {INVALID_RSS_ATTR, 0}
+};
+
+static bool
+ice_any_invalid_rss_type(enum rte_eth_hash_function rss_func,
+ uint64_t rss_type, uint64_t allow_rss_type)
+{
+ uint32_t i;
+
+ /**
+ * Check if l3/l4 SRC/DST_ONLY is set for SYMMETRIC_TOEPLITZ
+ * hash function.
+ */
+ if (rss_func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
+ if (rss_type & (RTE_ETH_RSS_L3_SRC_ONLY | RTE_ETH_RSS_L3_DST_ONLY |
+ RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY))
+ return true;
+
+ if (!(rss_type &
+ (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_IPV6 |
+ RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_FRAG_IPV6 |
+ RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV6_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV6_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV4_SCTP | RTE_ETH_RSS_NONFRAG_IPV6_SCTP)))
+ return true;
+ }
+
+ /* check invalid combination */
+ for (i = 0; i < RTE_DIM(invalid_rss_comb); i++) {
+ if (__builtin_popcountll(rss_type & invalid_rss_comb[i]) > 1)
+ return true;
+ }
+
+ /* check invalid RSS attribute */
+ for (i = 0; i < RTE_DIM(rss_attr_to_valid_type); i++) {
+ struct rss_attr_type *rat = &rss_attr_to_valid_type[i];
+
+ if (rat->attr & rss_type && !(rat->type & rss_type))
+ return true;
+ }
+
+ /* check not allowed RSS type */
+ rss_type &= ~VALID_RSS_ATTR;
+
+ return ((rss_type & allow_rss_type) != rss_type);
+}
+