Skip to content

Commit

Permalink
net/mlx5: add support for modify GENEVE option header
Browse files Browse the repository at this point in the history
Add support for GENEVE option fields modification.
Only fields configured in parser creation can be modified.

Signed-off-by: Michael Baum <michaelba@nvidia.com>
Acked-by: Suanming Mou <suanmingm@nvidia.com>
  • Loading branch information
michaelbaum1 authored and raslandarawsheh committed Jan 28, 2024
1 parent 1cdb671 commit 081a1f7
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 26 deletions.
4 changes: 4 additions & 0 deletions doc/guides/nics/mlx5.rst
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,10 @@ Limitations
- Modification of GENEVE Network ID's is not supported when configured
``FLEX_PARSER_PROFILE_ENABLE`` supports Geneve TLV options.
See :ref:`mlx5_firmware_config` for more flex parser information.
- Modification of GENEVE TLV option fields is supported only for HW steering.
Only DWs configured in :ref:`parser creation <geneve_parser_api>` can be modified,
'type' and 'class' fields can be modified when ``match_on_class_mode=2``.
- Modification of GENEVE TLV option data supports one DW per action.
- Encapsulation levels are not supported, can modify outermost header fields only.
- Offsets cannot skip past the boundary of a field.
- If the field type is ``RTE_FLOW_FIELD_MAC_TYPE``
Expand Down
3 changes: 3 additions & 0 deletions doc/guides/rel_notes/release_24_03.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ New Features

* Added HW steering support for ``RTE_FLOW_ITEM_TYPE_GENEVE_OPT`` flow item.
* Added HW steering support for modify field ``RTE_FLOW_FIELD_GENEVE_VNI`` flow action.
* Added HW steering support for modify field ``RTE_FLOW_FIELD_GENEVE_OPT_TYPE`` flow action.
* Added HW steering support for modify field ``RTE_FLOW_FIELD_GENEVE_OPT_CLASS`` flow action.
* Added HW steering support for modify field ``RTE_FLOW_FIELD_GENEVE_OPT_DATA`` flow action.


Removed Items
Expand Down
21 changes: 21 additions & 0 deletions drivers/net/mlx5/mlx5_flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -1811,6 +1811,25 @@ mlx5_get_geneve_hl_data(const void *dr_ctx, uint8_t type, uint16_t class,
struct mlx5_hl_data ** const hl_dws,
bool *ok_bit_on_class);

/**
* Get modify field ID for single DW inside configured GENEVE TLV option.
*
* @param[in] dr_ctx
* Pointer to HW steering DR context.
* @param[in] type
* GENEVE TLV option type.
* @param[in] class
* GENEVE TLV option class.
* @param[in] dw_offset
* Offset of DW inside the option.
*
* @return
* Modify field ID on success, negative errno otherwise and rte_errno is set.
*/
int
mlx5_get_geneve_option_modify_field_id(const void *dr_ctx, uint8_t type,
uint16_t class, uint8_t dw_offset);

void *
mlx5_geneve_tlv_parser_create(uint16_t port_id,
const struct rte_pmd_mlx5_geneve_tlv tlv_list[],
Expand All @@ -1819,6 +1838,8 @@ int mlx5_geneve_tlv_parser_destroy(void *handle);
int mlx5_flow_geneve_tlv_option_validate(struct mlx5_priv *priv,
const struct rte_flow_item *geneve_opt,
struct rte_flow_error *error);
int mlx5_geneve_opt_modi_field_get(struct mlx5_priv *priv,
const struct rte_flow_action_modify_data *data);

struct mlx5_geneve_tlv_options_mng;
int mlx5_geneve_tlv_option_register(struct mlx5_priv *priv,
Expand Down
78 changes: 76 additions & 2 deletions drivers/net/mlx5/mlx5_flow_dv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1465,6 +1465,21 @@ mlx5_mpls_modi_field_get(const struct rte_flow_action_modify_data *data)
return MLX5_MODI_IN_MPLS_LABEL_0 + data->tag_index;
}

static __rte_always_inline int
flow_geneve_opt_modi_field_get(struct mlx5_priv *priv,
const struct rte_flow_action_modify_data *data)
{
#ifdef HAVE_MLX5_HWS_SUPPORT
return mlx5_geneve_opt_modi_field_get(priv, data);
#else
(void)priv;
(void)data;
DRV_LOG(ERR, "GENEVE option modification is not supported.");
rte_errno = ENOTSUP;
return -rte_errno;
#endif
}

static void
mlx5_modify_flex_item(const struct rte_eth_dev *dev,
const struct mlx5_flex_item *flex,
Expand Down Expand Up @@ -1604,9 +1619,11 @@ mlx5_flow_field_id_to_modify_info
const struct rte_flow_attr *attr, struct rte_flow_error *error)
{
struct mlx5_priv *priv = dev->data->dev_private;
enum mlx5_modification_field modi_id;
uint32_t idx = 0;
uint32_t off_be = 0;
uint32_t length = 0;

switch ((int)data->field) {
case RTE_FLOW_FIELD_START:
/* not supported yet */
Expand Down Expand Up @@ -1968,6 +1985,48 @@ mlx5_flow_field_id_to_modify_info
else
info[idx].offset = off_be;
break;
case RTE_FLOW_FIELD_GENEVE_OPT_TYPE:
MLX5_ASSERT(data->offset + width <= 8);
modi_id = flow_geneve_opt_modi_field_get(priv, data);
if (modi_id < 0)
return;
/* Type is on bits 16-8 of GENEVE option header (DW0). */
off_be = 32 - (16 + data->offset + width);
info[idx] = (struct field_modify_info){4, 0, modi_id};
if (mask)
mask[idx] = flow_modify_info_mask_32(width, off_be);
else
info[idx].offset = off_be;
break;
case RTE_FLOW_FIELD_GENEVE_OPT_CLASS:
MLX5_ASSERT(data->offset + width <= 16);
modi_id = flow_geneve_opt_modi_field_get(priv, data);
if (modi_id < 0)
return;
/* Class is on bits 31-16 of GENEVE option header (DW0). */
off_be = 32 - (data->offset + width);
info[idx] = (struct field_modify_info){4, 0, modi_id};
if (mask)
mask[idx] = flow_modify_info_mask_32(width, off_be);
else
info[idx].offset = off_be;
break;
case RTE_FLOW_FIELD_GENEVE_OPT_DATA:
if ((data->offset % 32) + width > 32) {
DRV_LOG(ERR, "Geneve TLV option data is per DW.");
return;
}
modi_id = flow_geneve_opt_modi_field_get(priv, data);
if (modi_id < 0)
return;
/* Use offset inside DW. */
off_be = 32 - ((data->offset % 32) + width);
info[idx] = (struct field_modify_info){4, 0, modi_id};
if (mask)
mask[idx] = flow_modify_info_mask_32(width, off_be);
else
info[idx].offset = off_be;
break;
case RTE_FLOW_FIELD_GTP_TEID:
MLX5_ASSERT(data->offset + width <= 32);
off_be = 32 - (data->offset + width);
Expand All @@ -1981,8 +2040,8 @@ mlx5_flow_field_id_to_modify_info
case RTE_FLOW_FIELD_MPLS:
MLX5_ASSERT(data->offset + width <= 32);
off_be = 32 - (data->offset + width);
info[idx] = (struct field_modify_info){4, 0,
mlx5_mpls_modi_field_get(data)};
modi_id = mlx5_mpls_modi_field_get(data);
info[idx] = (struct field_modify_info){4, 0, modi_id};
if (mask)
mask[idx] = flow_modify_info_mask_32(width, off_be);
else
Expand Down Expand Up @@ -5488,6 +5547,21 @@ flow_dv_validate_action_modify_field(struct rte_eth_dev *dev,
RTE_FLOW_ERROR_TYPE_ACTION, action,
"modifications of the GENEVE Network"
" Identifier is not supported");
if (dst_data->field == RTE_FLOW_FIELD_GENEVE_OPT_TYPE ||
src_data->field == RTE_FLOW_FIELD_GENEVE_OPT_TYPE)
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ACTION, action,
"modifications of the GENEVE option type is not supported");
if (dst_data->field == RTE_FLOW_FIELD_GENEVE_OPT_CLASS ||
src_data->field == RTE_FLOW_FIELD_GENEVE_OPT_CLASS)
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ACTION, action,
"modifications of the GENEVE option class is not supported");
if (dst_data->field == RTE_FLOW_FIELD_GENEVE_OPT_DATA ||
src_data->field == RTE_FLOW_FIELD_GENEVE_OPT_DATA)
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ACTION, action,
"modifications of the GENEVE option data is not supported");
if (dst_data->field == RTE_FLOW_FIELD_MPLS ||
src_data->field == RTE_FLOW_FIELD_MPLS)
return rte_flow_error_set(error, ENOTSUP,
Expand Down
117 changes: 117 additions & 0 deletions drivers/net/mlx5/mlx5_flow_geneve.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,123 @@ mlx5_geneve_tlv_options_unregister(struct mlx5_priv *priv,
mng->nb_options = 0;
}

/**
* Get single DW resource from given option.
*
* @param option
* Pointer to single GENEVE TLV option.
* @param offset
* Offset of DW related to option start.
*
* @return
* DW resource on success, NULL otherwise and rte_errno is set.
*/
static struct mlx5_geneve_tlv_resource *
mlx5_geneve_tlv_option_get_resource_by_offset(struct mlx5_geneve_tlv_option *option,
uint8_t offset)
{
uint8_t i;

for (i = 0; option->resources[i].obj != NULL; ++i) {
if (option->resources[i].offset < offset)
continue;
if (option->resources[i].offset == offset)
return &option->resources[i];
break;
}
DRV_LOG(ERR, "The DW in offset %u wasn't configured.", offset);
rte_errno = EINVAL;
return NULL;
}

int
mlx5_get_geneve_option_modify_field_id(const void *dr_ctx, uint8_t type,
uint16_t class, uint8_t dw_offset)
{
uint16_t port_id;

MLX5_ETH_FOREACH_DEV(port_id, NULL) {
struct mlx5_priv *priv;
struct mlx5_geneve_tlv_option *option;
struct mlx5_geneve_tlv_resource *resource;

priv = rte_eth_devices[port_id].data->dev_private;
if (priv->dr_ctx != dr_ctx)
continue;
/* Find specific option inside list. */
option = mlx5_geneve_tlv_option_get(priv, type, class);
if (option == NULL)
return -rte_errno;
/* Find specific FW object inside option resources. */
resource = mlx5_geneve_tlv_option_get_resource_by_offset(option,
dw_offset);
if (resource == NULL)
return -rte_errno;
return resource->modify_field;
}
DRV_LOG(ERR, "DR CTX %p doesn't belong to any DPDK port.", dr_ctx);
rte_errno = EINVAL;
return -rte_errno;
}

/**
* Get modify field ID for single DW inside configured GENEVE TLV option.
*
* @param[in] priv
* Pointer to port's private data.
* @param[in] data
* Pointer to modify field data structure.
*
* @return
* Modify field ID on success, negative errno otherwise and rte_errno is set.
*/
int
mlx5_geneve_opt_modi_field_get(struct mlx5_priv *priv,
const struct rte_flow_action_modify_data *data)
{
uint16_t class = data->class_id;
uint8_t type = data->type;
struct mlx5_geneve_tlv_option *option;
struct mlx5_geneve_tlv_resource *resource;
uint8_t offset;

option = mlx5_geneve_tlv_option_get(priv, type, class);
if (option == NULL)
return -rte_errno;
switch (data->field) {
case RTE_FLOW_FIELD_GENEVE_OPT_TYPE:
case RTE_FLOW_FIELD_GENEVE_OPT_CLASS:
if (!option->match_data[0].dw_mask) {
DRV_LOG(ERR, "DW0 isn't configured");
rte_errno = EINVAL;
return -rte_errno;
}
resource = &option->resources[0];
MLX5_ASSERT(resource->offset == 0);
break;
case RTE_FLOW_FIELD_GENEVE_OPT_DATA:
/*
* Convert offset twice:
* - First conversion from bit offset to DW offset.
* - Second conversion is to be related to data start instead
* of option start.
*/
offset = (data->offset >> 5) + 1;
resource = mlx5_geneve_tlv_option_get_resource_by_offset(option,
offset);
break;
default:
DRV_LOG(ERR,
"Field ID %u doesn't describe GENEVE option header.",
data->field);
rte_errno = EINVAL;
return -rte_errno;
}
if (resource == NULL)
return -rte_errno;
return resource->modify_field;
}

/**
* Create single GENEVE TLV option sample.
*
Expand Down
Loading

0 comments on commit 081a1f7

Please sign in to comment.