summaryrefslogtreecommitdiff
path: root/drivers/net/mlx5
diff options
context:
space:
mode:
authorViacheslav Ovsiienko <viacheslavo@mellanox.com>2019-11-07 17:09:47 +0000
committerFerruh Yigit <ferruh.yigit@intel.com>2019-11-11 14:23:01 +0100
commit9597330c684408fd7ec588b252b84cff36f2b1ec (patch)
treeea92975229d10b4ebe7fa7fb0a3ef4bbaa347d62 /drivers/net/mlx5
parentcff811c7240e10369845bc263aca34f2011bb8fd (diff)
downloaddpdk-9597330c684408fd7ec588b252b84cff36f2b1ec.zip
dpdk-9597330c684408fd7ec588b252b84cff36f2b1ec.tar.gz
dpdk-9597330c684408fd7ec588b252b84cff36f2b1ec.tar.xz
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 <yskoh@mellanox.com> Signed-off-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com> Acked-by: Matan Azrad <matan@mellanox.com>
Diffstat (limited to 'drivers/net/mlx5')
-rw-r--r--drivers/net/mlx5/mlx5_flow_dv.c150
-rw-r--r--drivers/net/mlx5/mlx5_prm.h18
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 f507358..7409bae 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -240,12 +240,62 @@ 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 = &eth;
item.mask = &eth_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 96b9166..b9e53f5 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;
+ };
};
};