+/**
+ * Add GRE optional items to matcher and to the value.
+ *
+ * @param[in, out] matcher
+ * Flow matcher.
+ * @param[in, out] key
+ * Flow matcher value.
+ * @param[in] item
+ * Flow pattern to translate.
+ * @param[in] gre_item
+ * Pointer to gre_item.
+ * @param[in] pattern_flags
+ * Accumulated pattern flags.
+ */
+static void
+flow_dv_translate_item_gre_option(void *matcher, void *key,
+ const struct rte_flow_item *item,
+ const struct rte_flow_item *gre_item,
+ uint64_t pattern_flags)
+{
+ const struct rte_flow_item_gre_opt *option_m = item->mask;
+ const struct rte_flow_item_gre_opt *option_v = item->spec;
+ const struct rte_flow_item_gre *gre_m = gre_item->mask;
+ const struct rte_flow_item_gre *gre_v = gre_item->spec;
+ static const struct rte_flow_item_gre empty_gre = {0};
+ struct rte_flow_item gre_key_item;
+ uint16_t c_rsvd0_ver_m, c_rsvd0_ver_v;
+ uint16_t protocol_m, protocol_v;
+ void *misc5_m;
+ void *misc5_v;
+
+ /*
+ * If only match key field, keep using misc for matching.
+ * If need to match checksum or sequence, using misc5 and do
+ * not need using misc.
+ */
+ if (!(option_m->sequence.sequence ||
+ option_m->checksum_rsvd.checksum)) {
+ flow_dv_translate_item_gre(matcher, key, gre_item,
+ pattern_flags);
+ gre_key_item.spec = &option_v->key.key;
+ gre_key_item.mask = &option_m->key.key;
+ flow_dv_translate_item_gre_key(matcher, key, &gre_key_item);
+ return;
+ }
+ if (!gre_v) {
+ gre_v = &empty_gre;
+ gre_m = &empty_gre;
+ } else {
+ if (!gre_m)
+ gre_m = &rte_flow_item_gre_mask;
+ }
+ protocol_v = gre_v->protocol;
+ protocol_m = gre_m->protocol;
+ if (!protocol_m) {
+ /* Force next protocol to prevent matchers duplication */
+ uint16_t ether_type =
+ mlx5_translate_tunnel_etypes(pattern_flags);
+ if (ether_type) {
+ protocol_v = rte_be_to_cpu_16(ether_type);
+ protocol_m = UINT16_MAX;
+ }
+ }
+ c_rsvd0_ver_v = gre_v->c_rsvd0_ver;
+ c_rsvd0_ver_m = gre_m->c_rsvd0_ver;
+ if (option_m->sequence.sequence) {
+ c_rsvd0_ver_v |= RTE_BE16(0x1000);
+ c_rsvd0_ver_m |= RTE_BE16(0x1000);
+ }
+ if (option_m->key.key) {
+ c_rsvd0_ver_v |= RTE_BE16(0x2000);
+ c_rsvd0_ver_m |= RTE_BE16(0x2000);
+ }
+ if (option_m->checksum_rsvd.checksum) {
+ c_rsvd0_ver_v |= RTE_BE16(0x8000);
+ c_rsvd0_ver_m |= RTE_BE16(0x8000);
+ }
+ /*
+ * Hardware parses GRE optional field into the fixed location,
+ * do not need to adjust the tunnel dword indices.
+ */
+ misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5);
+ misc5_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_5);
+ MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_0,
+ rte_be_to_cpu_32((c_rsvd0_ver_v | protocol_v << 16) &
+ (c_rsvd0_ver_m | protocol_m << 16)));
+ MLX5_SET(fte_match_set_misc5, misc5_m, tunnel_header_0,
+ rte_be_to_cpu_32(c_rsvd0_ver_m | protocol_m << 16));
+ MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_1,
+ rte_be_to_cpu_32(option_v->checksum_rsvd.checksum &
+ option_m->checksum_rsvd.checksum));
+ MLX5_SET(fte_match_set_misc5, misc5_m, tunnel_header_1,
+ rte_be_to_cpu_32(option_m->checksum_rsvd.checksum));
+ MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_2,
+ rte_be_to_cpu_32(option_v->key.key & option_m->key.key));
+ MLX5_SET(fte_match_set_misc5, misc5_m, tunnel_header_2,
+ rte_be_to_cpu_32(option_m->key.key));
+ MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_3,
+ rte_be_to_cpu_32(option_v->sequence.sequence &
+ option_m->sequence.sequence));
+ MLX5_SET(fte_match_set_misc5, misc5_m, tunnel_header_3,
+ rte_be_to_cpu_32(option_m->sequence.sequence));
+}
+