[v1,18/23] net/mlx5/hws: support GENEVE options header

Message ID 20231203112543.844014-19-michaelba@nvidia.com (mailing list archive)
State Superseded, archived
Delegated to: Raslan Darawsheh
Headers
Series net/mlx5: support Geneve and options for HWS |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Michael Baum Dec. 3, 2023, 11:25 a.m. UTC
  From: Alex Vesker <valex@nvidia.com>

Add support for matching multiple GENEVE options. Options
header introduces new complexities since there can be more
than one GENEVE option. This requires us to track the total
DWs used for matching. Current code supports 8DWs for data
including type, class, length. There is also an optimization
to use a special OK bit to reduce the use of limited data DWs.

Signed-off-by: Alex Vesker <valex@nvidia.com>
---
 drivers/net/mlx5/hws/mlx5dr_definer.c | 147 ++++++++++++++++++++++++--
 drivers/net/mlx5/hws/mlx5dr_definer.h |  24 +++++
 2 files changed, 165 insertions(+), 6 deletions(-)
  

Patch

diff --git a/drivers/net/mlx5/hws/mlx5dr_definer.c b/drivers/net/mlx5/hws/mlx5dr_definer.c
index 141941c309..126e522235 100644
--- a/drivers/net/mlx5/hws/mlx5dr_definer.c
+++ b/drivers/net/mlx5/hws/mlx5dr_definer.c
@@ -117,6 +117,8 @@  struct mlx5dr_definer_conv_data {
 	uint8_t relaxed;
 	uint8_t tunnel;
 	uint8_t mpls_idx;
+	uint8_t geneve_opt_ok_idx;
+	uint8_t geneve_opt_data_idx;
 	enum rte_flow_item_type last_item;
 };
 
@@ -696,6 +698,29 @@  mlx5dr_definer_geneve_vni_set(struct mlx5dr_definer_fc *fc,
 	memcpy(tag + fc->byte_off, v->vni, sizeof(v->vni));
 }
 
+static void
+mlx5dr_definer_geneve_opt_ctrl_set(struct mlx5dr_definer_fc *fc,
+				   const void *item_spec,
+				   uint8_t *tag)
+{
+	const struct rte_flow_item_geneve_opt *v = item_spec;
+	uint32_t dw0 = 0;
+
+	dw0 |= v->option_type << __mlx5_dw_bit_off(header_geneve_opt, type);
+	dw0 |= rte_cpu_to_be_16(v->option_class) << __mlx5_dw_bit_off(header_geneve_opt, class);
+	DR_SET(tag, dw0, fc->byte_off, fc->bit_off, fc->bit_mask);
+}
+
+static void
+mlx5dr_definer_geneve_opt_data_set(struct mlx5dr_definer_fc *fc,
+				   const void *item_spec,
+				   uint8_t *tag)
+{
+	const struct rte_flow_item_geneve_opt *v = item_spec;
+
+	DR_SET_BE32(tag, v->data[fc->extra_data], fc->byte_off, fc->bit_off, fc->bit_mask);
+}
+
 static void
 mlx5dr_definer_ib_l4_qp_set(struct mlx5dr_definer_fc *fc,
 			    const void *item_spec,
@@ -1328,7 +1353,6 @@  mlx5dr_definer_conv_item_port(struct mlx5dr_definer_conv_data *cd,
 	struct mlx5dr_cmd_query_caps *caps = cd->ctx->caps;
 	const struct rte_flow_item_ethdev *m = item->mask;
 	struct mlx5dr_definer_fc *fc;
-	uint8_t bit_offset = 0;
 
 	if (m->port_id) {
 		if (!caps->wire_regc_mask) {
@@ -1337,16 +1361,13 @@  mlx5dr_definer_conv_item_port(struct mlx5dr_definer_conv_data *cd,
 			return rte_errno;
 		}
 
-		while (!(caps->wire_regc_mask & (1 << bit_offset)))
-			bit_offset++;
-
 		fc = &cd->fc[MLX5DR_DEFINER_FNAME_VPORT_REG_C_0];
 		fc->item_idx = item_idx;
 		fc->tag_set = &mlx5dr_definer_vport_set;
 		fc->tag_mask_set = &mlx5dr_definer_ones_set;
 		DR_CALC_SET_HDR(fc, registers, register_c_0);
-		fc->bit_off = bit_offset;
-		fc->bit_mask = caps->wire_regc_mask >> bit_offset;
+		fc->bit_off = __builtin_ctz(caps->wire_regc_mask);
+		fc->bit_mask = caps->wire_regc_mask >> fc->bit_off;
 	} else {
 		DR_LOG(ERR, "Pord ID item mask must specify ID mask");
 		rte_errno = EINVAL;
@@ -2259,6 +2280,116 @@  mlx5dr_definer_conv_item_geneve(struct mlx5dr_definer_conv_data *cd,
 	return 0;
 }
 
+static int
+mlx5dr_definer_conv_item_geneve_opt(struct mlx5dr_definer_conv_data *cd,
+				    struct rte_flow_item *item,
+				    int item_idx)
+{
+	const struct rte_flow_item_geneve_opt *m = item->mask;
+	const struct rte_flow_item_geneve_opt *v = item->spec;
+	struct mlx5_hl_data *hl_ok_bit, *hl_dws;
+	struct mlx5dr_definer_fc *fc;
+	uint8_t num_of_dws, i;
+	bool ok_bit_on_class;
+	int ret;
+
+	if (!m || !(m->option_class || m->option_type || m->data))
+		return 0;
+
+	if (!v || m->option_type != 0xff) {
+		DR_LOG(ERR, "Cannot match geneve opt without valid opt type");
+		goto out_not_supp;
+	}
+
+	if (m->option_class && m->option_class != RTE_BE16(UINT16_MAX)) {
+		DR_LOG(ERR, "Geneve option class has invalid mask");
+		goto out_not_supp;
+	}
+
+	ret = mlx5_get_geneve_hl_data(cd->ctx,
+				      v->option_type,
+				      v->option_class,
+				      &hl_ok_bit,
+				      &num_of_dws,
+				      &hl_dws,
+				      &ok_bit_on_class);
+	if (ret) {
+		DR_LOG(ERR, "Geneve opt type and class %d not supported", v->option_type);
+		goto out_not_supp;
+	}
+
+	if (!ok_bit_on_class && m->option_class) {
+		/* DW0 is used, we will match type, class */
+		if (!num_of_dws || hl_dws[0].dw_mask != UINT32_MAX) {
+			DR_LOG(ERR, "Geneve opt type %d DW0 not supported", v->option_type);
+			goto out_not_supp;
+		}
+
+		if (MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_0 + cd->geneve_opt_data_idx >
+		    MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_7) {
+			DR_LOG(ERR, "Max match geneve opt DWs reached");
+			goto out_not_supp;
+		}
+
+		fc = &cd->fc[MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_0 + cd->geneve_opt_data_idx++];
+		fc->item_idx = item_idx;
+		fc->tag_set = &mlx5dr_definer_geneve_opt_ctrl_set;
+		fc->byte_off = hl_dws[0].dw_offset * DW_SIZE;
+		fc->bit_mask = UINT32_MAX;
+	} else {
+		/* DW0 is not used, we must verify geneve opt type exists in packet */
+		if (!hl_ok_bit->dw_mask) {
+			DR_LOG(ERR, "Geneve opt OK bits not supported");
+			goto out_not_supp;
+		}
+
+		if (MLX5DR_DEFINER_FNAME_GENEVE_OPT_OK_0 + cd->geneve_opt_ok_idx >
+		    MLX5DR_DEFINER_FNAME_GENEVE_OPT_OK_7) {
+			DR_LOG(ERR, "Max match geneve opt reached");
+			goto out_not_supp;
+		}
+
+		fc = &cd->fc[MLX5DR_DEFINER_FNAME_GENEVE_OPT_OK_0 + cd->geneve_opt_ok_idx++];
+		fc->item_idx = item_idx;
+		fc->tag_set = &mlx5dr_definer_ones_set;
+		fc->byte_off = hl_ok_bit->dw_offset * DW_SIZE +
+				__builtin_clz(hl_ok_bit->dw_mask) / 8;
+		fc->bit_off = __builtin_ctz(hl_ok_bit->dw_mask);
+		fc->bit_mask = 0x1;
+	}
+
+	for (i = 1; i < num_of_dws; i++) {
+		/* Process each valid geneve option data DW1..N */
+		if (!m->data[i - 1])
+			continue;
+
+		if (hl_dws[i].dw_mask != UINT32_MAX) {
+			DR_LOG(ERR, "Matching Geneve opt data[%d] not supported", i - 1);
+			goto out_not_supp;
+		}
+
+		if (MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_0 + cd->geneve_opt_data_idx >
+		    MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_7) {
+			DR_LOG(ERR, "Max match geneve options DWs reached");
+			goto out_not_supp;
+		}
+
+		fc = &cd->fc[MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_0 + cd->geneve_opt_data_idx++];
+		fc->item_idx = item_idx;
+		fc->tag_set = &mlx5dr_definer_geneve_opt_data_set;
+		fc->byte_off = hl_dws[i].dw_offset * DW_SIZE;
+		fc->bit_mask = m->data[i - 1];
+		/* Use extra_data for data[] set offset */
+		fc->extra_data = i - 1;
+	}
+
+	return 0;
+
+out_not_supp:
+	rte_errno = ENOTSUP;
+	return rte_errno;
+}
+
 static int
 mlx5dr_definer_mt_set_fc(struct mlx5dr_match_template *mt,
 			 struct mlx5dr_definer_fc *fc,
@@ -2619,6 +2750,10 @@  mlx5dr_definer_conv_items_to_hl(struct mlx5dr_context *ctx,
 			ret = mlx5dr_definer_conv_item_geneve(&cd, items, i);
 			item_flags |= MLX5_FLOW_LAYER_GENEVE;
 			break;
+		case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
+			ret = mlx5dr_definer_conv_item_geneve_opt(&cd, items, i);
+			item_flags |= RTE_FLOW_ITEM_TYPE_GENEVE_OPT;
+			break;
 		case RTE_FLOW_ITEM_TYPE_IB_BTH:
 			ret = mlx5dr_definer_conv_item_ib_l4(&cd, items, i);
 			item_flags |= MLX5_FLOW_ITEM_IB_BTH;
diff --git a/drivers/net/mlx5/hws/mlx5dr_definer.h b/drivers/net/mlx5/hws/mlx5dr_definer.h
index c09c0be62e..0aaafe46de 100644
--- a/drivers/net/mlx5/hws/mlx5dr_definer.h
+++ b/drivers/net/mlx5/hws/mlx5dr_definer.h
@@ -141,6 +141,22 @@  enum mlx5dr_definer_fname {
 	MLX5DR_DEFINER_FNAME_OKS2_MPLS2_I,
 	MLX5DR_DEFINER_FNAME_OKS2_MPLS3_I,
 	MLX5DR_DEFINER_FNAME_OKS2_MPLS4_I,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_OK_0,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_OK_1,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_OK_2,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_OK_3,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_OK_4,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_OK_5,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_OK_6,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_OK_7,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_0,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_1,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_2,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_3,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_4,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_5,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_6,
+	MLX5DR_DEFINER_FNAME_GENEVE_OPT_DW_7,
 	MLX5DR_DEFINER_FNAME_IB_L4_OPCODE,
 	MLX5DR_DEFINER_FNAME_IB_L4_QPN,
 	MLX5DR_DEFINER_FNAME_IB_L4_A,
@@ -165,6 +181,7 @@  enum mlx5dr_definer_type {
 struct mlx5dr_definer_fc {
 	uint8_t item_idx;
 	uint8_t is_range;
+	uint16_t extra_data;
 	uint32_t byte_off;
 	int bit_off;
 	uint32_t bit_mask;
@@ -627,6 +644,13 @@  struct mlx5_ifc_header_geneve_bits {
 	u8 reserved_at_38[0x8];
 };
 
+struct mlx5_ifc_header_geneve_opt_bits {
+	u8 class[0x10];
+	u8 type[0x8];
+	u8 reserved[0x3];
+	u8 len[0x5];
+};
+
 struct mlx5_ifc_header_icmp_bits {
 	union {
 		u8 icmp_dw1[0x20];