From 9597330c684408fd7ec588b252b84cff36f2b1ec Mon Sep 17 00:00:00 2001 From: Viacheslav Ovsiienko Date: Thu, 7 Nov 2019 17:09:47 +0000 Subject: [PATCH] net/mlx5: update modify header action translator When composing device command for modify header action, provided mask should be taken more accurate into account thus length and offset in action should be set accordingly at precise bit-wise boundaries. For the future use, metadata register copy action is also added. Signed-off-by: Yongseok Koh Signed-off-by: Viacheslav Ovsiienko Acked-by: Matan Azrad --- drivers/net/mlx5/mlx5_flow_dv.c | 150 ++++++++++++++++++++++++-------- drivers/net/mlx5/mlx5_prm.h | 18 ++-- 2 files changed, 128 insertions(+), 40 deletions(-) diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index f507358e48..7409bae130 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -239,13 +239,63 @@ mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action, } } +/** + * Fetch 1, 2, 3 or 4 byte field from the byte array + * and return as unsigned integer in host-endian format. + * + * @param[in] data + * Pointer to data array. + * @param[in] size + * Size of field to extract. + * + * @return + * converted field in host endian format. + */ +static inline uint32_t +flow_dv_fetch_field(const uint8_t *data, uint32_t size) +{ + uint32_t ret; + + switch (size) { + case 1: + ret = *data; + break; + case 2: + ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); + break; + case 3: + ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); + ret = (ret << 8) | *(data + sizeof(uint16_t)); + break; + case 4: + ret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data); + break; + default: + assert(false); + ret = 0; + break; + } + return ret; +} + /** * Convert modify-header action to DV specification. * + * Data length of each action is determined by provided field description + * and the item mask. Data bit offset and width of each action is determined + * by provided item mask. + * * @param[in] item * Pointer to item specification. * @param[in] field * Pointer to field modification information. + * For MLX5_MODIFICATION_TYPE_SET specifies destination field. + * For MLX5_MODIFICATION_TYPE_ADD specifies destination field. + * For MLX5_MODIFICATION_TYPE_COPY specifies source field. + * @param[in] dcopy + * Destination field info for MLX5_MODIFICATION_TYPE_COPY in @type. + * Negative offset value sets the same offset as source offset. + * size field is ignored, value is taken from source field. * @param[in,out] resource * Pointer to the modify-header resource. * @param[in] type @@ -259,38 +309,68 @@ mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action, static int flow_dv_convert_modify_action(struct rte_flow_item *item, struct field_modify_info *field, + struct field_modify_info *dcopy, struct mlx5_flow_dv_modify_hdr_resource *resource, - uint32_t type, - struct rte_flow_error *error) + uint32_t type, struct rte_flow_error *error) { uint32_t i = resource->actions_num; struct mlx5_modification_cmd *actions = resource->actions; - const uint8_t *spec = item->spec; - const uint8_t *mask = item->mask; - uint32_t set; - - while (field->size) { - set = 0; - /* Generate modify command for each mask segment. */ - memcpy(&set, &mask[field->offset], field->size); - if (set) { - if (i >= MLX5_MODIFY_NUM) - return rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ACTION, NULL, - "too many items to modify"); - actions[i].action_type = type; - actions[i].field = field->id; - actions[i].length = field->size == - 4 ? 0 : field->size * 8; - rte_memcpy(&actions[i].data[4 - field->size], - &spec[field->offset], field->size); - actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); - ++i; + + /* + * The item and mask are provided in big-endian format. + * The fields should be presented as in big-endian format either. + * Mask must be always present, it defines the actual field width. + */ + assert(item->mask); + assert(field->size); + do { + unsigned int size_b; + unsigned int off_b; + uint32_t mask; + uint32_t data; + + if (i >= MLX5_MODIFY_NUM) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "too many items to modify"); + /* Fetch variable byte size mask from the array. */ + mask = flow_dv_fetch_field((const uint8_t *)item->mask + + field->offset, field->size); + if (!mask) { + ++field; + continue; } - if (resource->actions_num != i) - resource->actions_num = i; - field++; - } + /* Deduce actual data width in bits from mask value. */ + off_b = rte_bsf32(mask); + size_b = sizeof(uint32_t) * CHAR_BIT - + off_b - __builtin_clz(mask); + assert(size_b); + size_b = size_b == sizeof(uint32_t) * CHAR_BIT ? 0 : size_b; + actions[i].action_type = type; + actions[i].field = field->id; + actions[i].offset = off_b; + actions[i].length = size_b; + /* Convert entire record to expected big-endian format. */ + actions[i].data0 = rte_cpu_to_be_32(actions[i].data0); + if (type == MLX5_MODIFICATION_TYPE_COPY) { + assert(dcopy); + actions[i].dst_field = dcopy->id; + actions[i].dst_offset = + (int)dcopy->offset < 0 ? off_b : dcopy->offset; + /* Convert entire record to big-endian format. */ + actions[i].data1 = rte_cpu_to_be_32(actions[i].data1); + } else { + assert(item->spec); + data = flow_dv_fetch_field((const uint8_t *)item->spec + + field->offset, field->size); + /* Shift out the trailing masked bits from data. */ + data = (data & mask) >> off_b; + actions[i].data1 = rte_cpu_to_be_32(data); + } + ++i; + ++field; + } while (field->size); + resource->actions_num = i; if (!resource->actions_num) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, NULL, @@ -334,7 +414,7 @@ flow_dv_convert_action_modify_ipv4 } item.spec = &ipv4; item.mask = &ipv4_mask; - return flow_dv_convert_modify_action(&item, modify_ipv4, resource, + return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource, MLX5_MODIFICATION_TYPE_SET, error); } @@ -380,7 +460,7 @@ flow_dv_convert_action_modify_ipv6 } item.spec = &ipv6; item.mask = &ipv6_mask; - return flow_dv_convert_modify_action(&item, modify_ipv6, resource, + return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource, MLX5_MODIFICATION_TYPE_SET, error); } @@ -426,7 +506,7 @@ flow_dv_convert_action_modify_mac } item.spec = ð item.mask = ð_mask; - return flow_dv_convert_modify_action(&item, modify_eth, resource, + return flow_dv_convert_modify_action(&item, modify_eth, NULL, resource, MLX5_MODIFICATION_TYPE_SET, error); } @@ -540,7 +620,7 @@ flow_dv_convert_action_modify_tp item.mask = &tcp_mask; field = modify_tcp; } - return flow_dv_convert_modify_action(&item, field, resource, + return flow_dv_convert_modify_action(&item, field, NULL, resource, MLX5_MODIFICATION_TYPE_SET, error); } @@ -600,7 +680,7 @@ flow_dv_convert_action_modify_ttl item.mask = &ipv6_mask; field = modify_ipv6; } - return flow_dv_convert_modify_action(&item, field, resource, + return flow_dv_convert_modify_action(&item, field, NULL, resource, MLX5_MODIFICATION_TYPE_SET, error); } @@ -657,7 +737,7 @@ flow_dv_convert_action_modify_dec_ttl item.mask = &ipv6_mask; field = modify_ipv6; } - return flow_dv_convert_modify_action(&item, field, resource, + return flow_dv_convert_modify_action(&item, field, NULL, resource, MLX5_MODIFICATION_TYPE_ADD, error); } @@ -702,7 +782,7 @@ flow_dv_convert_action_modify_tcp_seq item.type = RTE_FLOW_ITEM_TYPE_TCP; item.spec = &tcp; item.mask = &tcp_mask; - return flow_dv_convert_modify_action(&item, modify_tcp, resource, + return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource, MLX5_MODIFICATION_TYPE_ADD, error); } @@ -747,7 +827,7 @@ flow_dv_convert_action_modify_tcp_ack item.type = RTE_FLOW_ITEM_TYPE_TCP; item.spec = &tcp; item.mask = &tcp_mask; - return flow_dv_convert_modify_action(&item, modify_tcp, resource, + return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource, MLX5_MODIFICATION_TYPE_ADD, error); } diff --git a/drivers/net/mlx5/mlx5_prm.h b/drivers/net/mlx5/mlx5_prm.h index 96b916684f..b9e53f5ae1 100644 --- a/drivers/net/mlx5/mlx5_prm.h +++ b/drivers/net/mlx5/mlx5_prm.h @@ -383,11 +383,12 @@ struct mlx5_cqe { /* CQE format value. */ #define MLX5_COMPRESSED 0x3 -/* Write a specific data value to a field. */ -#define MLX5_MODIFICATION_TYPE_SET 1 - -/* Add a specific data value to a field. */ -#define MLX5_MODIFICATION_TYPE_ADD 2 +/* Action type of header modification. */ +enum { + MLX5_MODIFICATION_TYPE_SET = 0x1, + MLX5_MODIFICATION_TYPE_ADD = 0x2, + MLX5_MODIFICATION_TYPE_COPY = 0x3, +}; /* The field of packet to be modified. */ enum mlx5_modification_field { @@ -470,6 +471,13 @@ struct mlx5_modification_cmd { union { uint32_t data1; uint8_t data[4]; + struct { + unsigned int rsvd2:8; + unsigned int dst_offset:5; + unsigned int rsvd3:3; + unsigned int dst_field:12; + unsigned int rsvd4:4; + }; }; }; -- 2.20.1