+static void
+mlx5_flow_field_id_to_modify_info
+ (const struct rte_flow_action_modify_data *data,
+ struct field_modify_info *info,
+ uint32_t *mask, uint32_t *value, uint32_t width,
+ struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ struct rte_flow_error *error)
+{
+ uint32_t idx = 0;
+ switch (data->field) {
+ case RTE_FLOW_FIELD_START:
+ /* not supported yet */
+ MLX5_ASSERT(false);
+ break;
+ case RTE_FLOW_FIELD_MAC_DST:
+ if (mask) {
+ if (data->offset < 32) {
+ info[idx] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_DMAC_47_16};
+ mask[idx] = 0xffffffff;
+ if (width < 32) {
+ mask[idx] = mask[idx] << (32 - width);
+ width = 0;
+ } else {
+ width -= 32;
+ }
+ if (!width)
+ break;
+ ++idx;
+ }
+ info[idx] = (struct field_modify_info){2, 4 * idx,
+ MLX5_MODI_OUT_DMAC_15_0};
+ mask[idx] = (width) ? 0x0000ffff : 0x0;
+ if (width < 16)
+ mask[idx] = (mask[idx] << (16 - width)) &
+ 0x0000ffff;
+ } else {
+ if (data->offset < 32)
+ info[idx++] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_DMAC_47_16};
+ info[idx] = (struct field_modify_info){2, 0,
+ MLX5_MODI_OUT_DMAC_15_0};
+ }
+ break;
+ case RTE_FLOW_FIELD_MAC_SRC:
+ if (mask) {
+ if (data->offset < 32) {
+ info[idx] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_SMAC_47_16};
+ mask[idx] = 0xffffffff;
+ if (width < 32) {
+ mask[idx] = mask[idx] << (32 - width);
+ width = 0;
+ } else {
+ width -= 32;
+ }
+ if (!width)
+ break;
+ ++idx;
+ }
+ info[idx] = (struct field_modify_info){2, 4 * idx,
+ MLX5_MODI_OUT_SMAC_15_0};
+ mask[idx] = (width) ? 0x0000ffff : 0x0;
+ if (width < 16)
+ mask[idx] = (mask[idx] << (16 - width)) &
+ 0x0000ffff;
+ } else {
+ if (data->offset < 32)
+ info[idx++] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_SMAC_47_16};
+ info[idx] = (struct field_modify_info){2, 0,
+ MLX5_MODI_OUT_SMAC_15_0};
+ }
+ break;
+ case RTE_FLOW_FIELD_VLAN_TYPE:
+ /* not supported yet */
+ break;
+ case RTE_FLOW_FIELD_VLAN_ID:
+ info[idx] = (struct field_modify_info){2, 0,
+ MLX5_MODI_OUT_FIRST_VID};
+ if (mask) {
+ mask[idx] = 0x00000fff;
+ if (width < 12)
+ mask[idx] = (mask[idx] << (12 - width)) &
+ 0x00000fff;
+ }
+ break;
+ case RTE_FLOW_FIELD_MAC_TYPE:
+ info[idx] = (struct field_modify_info){2, 0,
+ MLX5_MODI_OUT_ETHERTYPE};
+ if (mask) {
+ mask[idx] = 0x0000ffff;
+ if (width < 16)
+ mask[idx] = (mask[idx] << (16 - width)) &
+ 0x0000ffff;
+ }
+ break;
+ case RTE_FLOW_FIELD_IPV4_DSCP:
+ info[idx] = (struct field_modify_info){1, 0,
+ MLX5_MODI_OUT_IP_DSCP};
+ if (mask) {
+ mask[idx] = 0x0000003f;
+ if (width < 6)
+ mask[idx] = (mask[idx] << (6 - width)) &
+ 0x0000003f;
+ }
+ break;
+ case RTE_FLOW_FIELD_IPV4_TTL:
+ info[idx] = (struct field_modify_info){1, 0,
+ MLX5_MODI_OUT_IPV4_TTL};
+ if (mask) {
+ mask[idx] = 0x000000ff;
+ if (width < 8)
+ mask[idx] = (mask[idx] << (8 - width)) &
+ 0x000000ff;
+ }
+ break;
+ case RTE_FLOW_FIELD_IPV4_SRC:
+ info[idx] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_SIPV4};
+ if (mask) {
+ mask[idx] = 0xffffffff;
+ if (width < 32)
+ mask[idx] = mask[idx] << (32 - width);
+ }
+ break;
+ case RTE_FLOW_FIELD_IPV4_DST:
+ info[idx] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_DIPV4};
+ if (mask) {
+ mask[idx] = 0xffffffff;
+ if (width < 32)
+ mask[idx] = mask[idx] << (32 - width);
+ }
+ break;
+ case RTE_FLOW_FIELD_IPV6_DSCP:
+ info[idx] = (struct field_modify_info){1, 0,
+ MLX5_MODI_OUT_IP_DSCP};
+ if (mask) {
+ mask[idx] = 0x0000003f;
+ if (width < 6)
+ mask[idx] = (mask[idx] << (6 - width)) &
+ 0x0000003f;
+ }
+ break;
+ case RTE_FLOW_FIELD_IPV6_HOPLIMIT:
+ info[idx] = (struct field_modify_info){1, 0,
+ MLX5_MODI_OUT_IPV6_HOPLIMIT};
+ if (mask) {
+ mask[idx] = 0x000000ff;
+ if (width < 8)
+ mask[idx] = (mask[idx] << (8 - width)) &
+ 0x000000ff;
+ }
+ break;
+ case RTE_FLOW_FIELD_IPV6_SRC:
+ if (mask) {
+ if (data->offset < 32) {
+ info[idx] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_SIPV6_127_96};
+ mask[idx] = 0xffffffff;
+ if (width < 32) {
+ mask[idx] = mask[idx] << (32 - width);
+ width = 0;
+ } else {
+ width -= 32;
+ }
+ if (!width)
+ break;
+ ++idx;
+ }
+ if (data->offset < 64) {
+ info[idx] = (struct field_modify_info){4,
+ 4 * idx,
+ MLX5_MODI_OUT_SIPV6_95_64};
+ mask[idx] = 0xffffffff;
+ if (width < 32) {
+ mask[idx] = mask[idx] << (32 - width);
+ width = 0;
+ } else {
+ width -= 32;
+ }
+ if (!width)
+ break;
+ ++idx;
+ }
+ if (data->offset < 96) {
+ info[idx] = (struct field_modify_info){4,
+ 8 * idx,
+ MLX5_MODI_OUT_SIPV6_63_32};
+ mask[idx] = 0xffffffff;
+ if (width < 32) {
+ mask[idx] = mask[idx] << (32 - width);
+ width = 0;
+ } else {
+ width -= 32;
+ }
+ if (!width)
+ break;
+ ++idx;
+ }
+ info[idx] = (struct field_modify_info){4, 12 * idx,
+ MLX5_MODI_OUT_SIPV6_31_0};
+ mask[idx] = 0xffffffff;
+ if (width < 32)
+ mask[idx] = mask[idx] << (32 - width);
+ } else {
+ if (data->offset < 32)
+ info[idx++] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_SIPV6_127_96};
+ if (data->offset < 64)
+ info[idx++] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_SIPV6_95_64};
+ if (data->offset < 96)
+ info[idx++] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_SIPV6_63_32};
+ if (data->offset < 128)
+ info[idx++] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_SIPV6_31_0};
+ }
+ break;
+ case RTE_FLOW_FIELD_IPV6_DST:
+ if (mask) {
+ if (data->offset < 32) {
+ info[idx] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_DIPV6_127_96};
+ mask[idx] = 0xffffffff;
+ if (width < 32) {
+ mask[idx] = mask[idx] << (32 - width);
+ width = 0;
+ } else {
+ width -= 32;
+ }
+ if (!width)
+ break;
+ ++idx;
+ }
+ if (data->offset < 64) {
+ info[idx] = (struct field_modify_info){4,
+ 4 * idx,
+ MLX5_MODI_OUT_DIPV6_95_64};
+ mask[idx] = 0xffffffff;
+ if (width < 32) {
+ mask[idx] = mask[idx] << (32 - width);
+ width = 0;
+ } else {
+ width -= 32;
+ }
+ if (!width)
+ break;
+ ++idx;
+ }
+ if (data->offset < 96) {
+ info[idx] = (struct field_modify_info){4,
+ 8 * idx,
+ MLX5_MODI_OUT_DIPV6_63_32};
+ mask[idx] = 0xffffffff;
+ if (width < 32) {
+ mask[idx] = mask[idx] << (32 - width);
+ width = 0;
+ } else {
+ width -= 32;
+ }
+ if (!width)
+ break;
+ ++idx;
+ }
+ info[idx] = (struct field_modify_info){4, 12 * idx,
+ MLX5_MODI_OUT_DIPV6_31_0};
+ mask[idx] = 0xffffffff;
+ if (width < 32)
+ mask[idx] = mask[idx] << (32 - width);
+ } else {
+ if (data->offset < 32)
+ info[idx++] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_DIPV6_127_96};
+ if (data->offset < 64)
+ info[idx++] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_DIPV6_95_64};
+ if (data->offset < 96)
+ info[idx++] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_DIPV6_63_32};
+ if (data->offset < 128)
+ info[idx++] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_DIPV6_31_0};
+ }
+ break;
+ case RTE_FLOW_FIELD_TCP_PORT_SRC:
+ info[idx] = (struct field_modify_info){2, 0,
+ MLX5_MODI_OUT_TCP_SPORT};
+ if (mask) {
+ mask[idx] = 0x0000ffff;
+ if (width < 16)
+ mask[idx] = (mask[idx] << (16 - width)) &
+ 0x0000ffff;
+ }
+ break;
+ case RTE_FLOW_FIELD_TCP_PORT_DST:
+ info[idx] = (struct field_modify_info){2, 0,
+ MLX5_MODI_OUT_TCP_DPORT};
+ if (mask) {
+ mask[idx] = 0x0000ffff;
+ if (width < 16)
+ mask[idx] = (mask[idx] << (16 - width)) &
+ 0x0000ffff;
+ }
+ break;
+ case RTE_FLOW_FIELD_TCP_SEQ_NUM:
+ info[idx] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_TCP_SEQ_NUM};
+ if (mask) {
+ mask[idx] = 0xffffffff;
+ if (width < 32)
+ mask[idx] = (mask[idx] << (32 - width));
+ }
+ break;
+ case RTE_FLOW_FIELD_TCP_ACK_NUM:
+ info[idx] = (struct field_modify_info){4, 0,
+ MLX5_MODI_OUT_TCP_ACK_NUM};
+ if (mask) {
+ mask[idx] = 0xffffffff;
+ if (width < 32)
+ mask[idx] = (mask[idx] << (32 - width));
+ }
+ break;
+ case RTE_FLOW_FIELD_TCP_FLAGS:
+ info[idx] = (struct field_modify_info){1, 0,
+ MLX5_MODI_OUT_TCP_FLAGS};
+ if (mask) {
+ mask[idx] = 0x0000003f;
+ if (width < 6)
+ mask[idx] = (mask[idx] << (6 - width)) &
+ 0x0000003f;
+ }
+ break;
+ case RTE_FLOW_FIELD_UDP_PORT_SRC:
+ info[idx] = (struct field_modify_info){2, 0,
+ MLX5_MODI_OUT_UDP_SPORT};
+ if (mask) {
+ mask[idx] = 0x0000ffff;
+ if (width < 16)
+ mask[idx] = (mask[idx] << (16 - width)) &
+ 0x0000ffff;
+ }
+ break;
+ case RTE_FLOW_FIELD_UDP_PORT_DST:
+ info[idx] = (struct field_modify_info){2, 0,
+ MLX5_MODI_OUT_UDP_DPORT};
+ if (mask) {
+ mask[idx] = 0x0000ffff;
+ if (width < 16)
+ mask[idx] = (mask[idx] << (16 - width)) &
+ 0x0000ffff;
+ }
+ break;
+ case RTE_FLOW_FIELD_VXLAN_VNI:
+ /* not supported yet */
+ break;
+ case RTE_FLOW_FIELD_GENEVE_VNI:
+ /* not supported yet*/
+ break;
+ case RTE_FLOW_FIELD_GTP_TEID:
+ info[idx] = (struct field_modify_info){4, 0,
+ MLX5_MODI_GTP_TEID};
+ if (mask) {
+ mask[idx] = 0xffffffff;
+ if (width < 32)
+ mask[idx] = mask[idx] << (32 - width);
+ }
+ break;
+ case RTE_FLOW_FIELD_TAG:
+ {
+ int reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG,
+ data->level, error);
+ if (reg < 0)
+ return;
+ MLX5_ASSERT(reg != REG_NON);
+ MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
+ info[idx] = (struct field_modify_info){4, 0,
+ reg_to_field[reg]};
+ if (mask) {
+ mask[idx] = 0xffffffff;
+ if (width < 32)
+ mask[idx] = mask[idx] << (32 - width);
+ }
+ }
+ break;
+ case RTE_FLOW_FIELD_MARK:
+ {
+ int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK,
+ 0, error);
+ if (reg < 0)
+ return;
+ MLX5_ASSERT(reg != REG_NON);
+ MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
+ info[idx] = (struct field_modify_info){4, 0,
+ reg_to_field[reg]};
+ if (mask) {
+ mask[idx] = 0xffffffff;
+ if (width < 32)
+ mask[idx] = mask[idx] << (32 - width);
+ }
+ }
+ break;
+ case RTE_FLOW_FIELD_META:
+ {
+ int reg = flow_dv_get_metadata_reg(dev, attr, error);
+ if (reg < 0)
+ return;
+ MLX5_ASSERT(reg != REG_NON);
+ MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
+ info[idx] = (struct field_modify_info){4, 0,
+ reg_to_field[reg]};
+ if (mask) {
+ mask[idx] = 0xffffffff;
+ if (width < 32)
+ mask[idx] = mask[idx] << (32 - width);
+ }
+ }
+ break;
+ case RTE_FLOW_FIELD_POINTER:
+ for (idx = 0; idx < MLX5_ACT_MAX_MOD_FIELDS; idx++) {
+ if (mask[idx]) {
+ memcpy(&value[idx],
+ (void *)(uintptr_t)data->value, 32);
+ value[idx] = RTE_BE32(value[idx]);
+ break;
+ }
+ }
+ break;
+ case RTE_FLOW_FIELD_VALUE:
+ for (idx = 0; idx < MLX5_ACT_MAX_MOD_FIELDS; idx++) {
+ if (mask[idx]) {
+ value[idx] = RTE_BE32((uint32_t)data->value);
+ break;
+ }
+ }
+ break;
+ default:
+ MLX5_ASSERT(false);
+ break;
+ }
+}
+
+/**
+ * Convert modify_field action to DV specification.
+ *
+ * @param[in] dev
+ * Pointer to the rte_eth_dev structure.
+ * @param[in,out] resource
+ * Pointer to the modify-header resource.
+ * @param[in] action
+ * Pointer to action specification.
+ * @param[in] attr
+ * Attributes of flow that includes this item.
+ * @param[out] error
+ * Pointer to the error structure.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_convert_action_modify_field
+ (struct rte_eth_dev *dev,
+ struct mlx5_flow_dv_modify_hdr_resource *resource,
+ const struct rte_flow_action *action,
+ const struct rte_flow_attr *attr,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_action_modify_field *conf =
+ (const struct rte_flow_action_modify_field *)(action->conf);
+ struct rte_flow_item item;
+ struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = {
+ {0, 0, 0} };
+ struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = {
+ {0, 0, 0} };
+ uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0};
+ uint32_t value[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0};
+ uint32_t type;
+
+ if (conf->src.field == RTE_FLOW_FIELD_POINTER ||
+ conf->src.field == RTE_FLOW_FIELD_VALUE) {
+ type = MLX5_MODIFICATION_TYPE_SET;
+ /** For SET fill the destination field (field) first. */
+ mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask,
+ value, conf->width, dev, attr, error);
+ /** Then copy immediate value from source as per mask. */
+ mlx5_flow_field_id_to_modify_info(&conf->src, dcopy, mask,
+ value, conf->width, dev, attr, error);
+ item.spec = &value;
+ } else {
+ type = MLX5_MODIFICATION_TYPE_COPY;
+ /** For COPY fill the destination field (dcopy) without mask. */
+ mlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL,
+ value, conf->width, dev, attr, error);
+ /** Then construct the source field (field) with mask. */
+ mlx5_flow_field_id_to_modify_info(&conf->src, field, mask,
+ value, conf->width, dev, attr, error);
+ }
+ item.mask = &mask;
+ return flow_dv_convert_modify_action(&item,
+ field, dcopy, resource, type, error);
+}
+