> -----Original Message----- > From: dev <dev-boun...@dpdk.org> On Behalf Of Dekel Peled > Sent: Sunday, September 16, 2018 9:42 PM > To: dev@dpdk.org; Shahaf Shuler <shah...@mellanox.com>; Yongseok Koh > <ys...@mellanox.com> > Cc: Ori Kam <or...@mellanox.com> > Subject: [dpdk-dev] [PATCH] net/mlx5: support metadata as flow rule criteria > > As described in series starting at [1], it adds option to set metadata value > as match pattern when > creating a new flow rule. > > This patch adds metadata support in mlx5 driver, in several parts: > - Add the setting of metadata value in matcher when creating a new flow rule. > - Add the passing of metadata value from mbuf to wqe when indicated by > ol_flag, in different burst > functions. > - Allow flow rule with attribute egress in specific cases. > > This patch must be built together with the files in series [1]. > > [1] "ethdev: support metadata as flow rule criteria" > > Signed-off-by: Dekel Peled <dek...@mellanox.com> > --- > drivers/net/mlx5/mlx5_flow.c | 60 +++++++++++++---- > drivers/net/mlx5/mlx5_flow.h | 22 +++++-- > drivers/net/mlx5/mlx5_flow_dv.c | 120 > ++++++++++++++++++++++++++++++---- > drivers/net/mlx5/mlx5_flow_verbs.c | 21 ++++-- > drivers/net/mlx5/mlx5_prm.h | 2 +- > drivers/net/mlx5/mlx5_rxtx.c | 34 ++++++++-- > drivers/net/mlx5/mlx5_rxtx_vec.c | 28 ++++++-- > drivers/net/mlx5/mlx5_rxtx_vec.h | 1 + > drivers/net/mlx5/mlx5_rxtx_vec_neon.h | 4 +- > drivers/net/mlx5/mlx5_rxtx_vec_sse.h | 4 +- > drivers/net/mlx5/mlx5_txq.c | 6 ++ > 11 files changed, 255 insertions(+), 47 deletions(-) > > diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c > index 4234be6..7932e0f > 100644 > --- a/drivers/net/mlx5/mlx5_flow.c > +++ b/drivers/net/mlx5/mlx5_flow.c > @@ -402,7 +402,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev > *dev, > * @return > * 0 on success, a negative errno value otherwise and rte_errno is set. > */ > -static int > +int > mlx5_flow_item_acceptable(const struct rte_flow_item *item, > const uint8_t *mask, > const uint8_t *nic_mask, > @@ -602,7 +602,8 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev > *dev, > * 0 on success, a negative errno value otherwise and rte_ernno is set. > */ > int mlx5_flow_validate_action_flag(uint64_t action_flags, > - struct rte_flow_error *error) > + const struct rte_flow_attr *attr, > + struct rte_flow_error *error) > { > > if (action_flags & MLX5_ACTION_DROP) > @@ -624,6 +625,11 @@ int mlx5_flow_validate_action_flag(uint64_t action_flags, > NULL, > "can't have 2 flag" > " actions in same flow"); > + if (attr->egress) > + return rte_flow_error_set(error, ENOTSUP, > + RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, > + NULL, > + "flag action not supported for egress"); > return 0; > } > > @@ -642,8 +648,9 @@ int mlx5_flow_validate_action_flag(uint64_t action_flags, > * 0 on success, a negative errno value otherwise and rte_ernno is set. > */ > int mlx5_flow_validate_action_mark(uint64_t action_flags, > - const struct rte_flow_action *action, > - struct rte_flow_error *error) > + const struct rte_flow_action *action, > + const struct rte_flow_attr *attr, > + struct rte_flow_error *error) > { > const struct rte_flow_action_mark *mark = action->conf; > > @@ -677,6 +684,11 @@ int mlx5_flow_validate_action_mark(uint64_t action_flags, > NULL, > "can't have 2 flag actions in same" > " flow"); > + if (attr->egress) > + return rte_flow_error_set(error, ENOTSUP, > + RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, > + NULL, > + "mark action not supported for egress"); > return 0; > } > > @@ -693,7 +705,8 @@ int mlx5_flow_validate_action_mark(uint64_t action_flags, > * 0 on success, a negative errno value otherwise and rte_ernno is set. > */ > int mlx5_flow_validate_action_drop(uint64_t action_flags, > - struct rte_flow_error *error) > + const struct rte_flow_attr *attr, > + struct rte_flow_error *error) > { > if (action_flags & MLX5_ACTION_FLAG) > return rte_flow_error_set(error, > @@ -715,6 +728,11 @@ int mlx5_flow_validate_action_drop(uint64_t action_flags, > NULL, > "can't have 2 fate actions in" > " same flow"); > + if (attr->egress) > + return rte_flow_error_set(error, ENOTSUP, > + RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, > + NULL, > + "drop action not supported for egress"); > return 0; > } > > @@ -735,9 +753,10 @@ int mlx5_flow_validate_action_drop(uint64_t action_flags, > * 0 on success, a negative errno value otherwise and rte_ernno is set. > */ > int mlx5_flow_validate_action_queue(uint64_t action_flags, > - struct rte_eth_dev *dev, > - const struct rte_flow_action *action, > - struct rte_flow_error *error) > + struct rte_eth_dev *dev, > + const struct rte_flow_action *action, > + const struct rte_flow_attr *attr, > + struct rte_flow_error *error) > { > struct priv *priv = dev->data->dev_private; > const struct rte_flow_action_queue *queue = action->conf; @@ -760,6 > +779,11 @@ int > mlx5_flow_validate_action_queue(uint64_t action_flags, > RTE_FLOW_ERROR_TYPE_ACTION_CONF, > &queue->index, > "queue is not configured"); > + if (attr->egress) > + return rte_flow_error_set(error, ENOTSUP, > + RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, > + NULL, > + "queue action not supported for > egress"); > return 0; > } > > @@ -780,9 +804,10 @@ int mlx5_flow_validate_action_queue(uint64_t > action_flags, > * 0 on success, a negative errno value otherwise and rte_ernno is set. > */ > int mlx5_flow_validate_action_rss(uint64_t action_flags, > - struct rte_eth_dev *dev, > - const struct rte_flow_action *action, > - struct rte_flow_error *error) > + struct rte_eth_dev *dev, > + const struct rte_flow_action *action, > + const struct rte_flow_attr *attr, > + struct rte_flow_error *error) > { > struct priv *priv = dev->data->dev_private; > const struct rte_flow_action_rss *rss = action->conf; @@ -839,6 +864,11 > @@ int > mlx5_flow_validate_action_rss(uint64_t action_flags, > &rss->queue[i], > "queue is not configured"); > } > + if (attr->egress) > + return rte_flow_error_set(error, ENOTSUP, > + RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, > + NULL, > + "rss action not supported for egress"); > return 0; > } > > @@ -855,7 +885,8 @@ int mlx5_flow_validate_action_rss(uint64_t action_flags, > * 0 on success, a negative errno value otherwise and rte_ernno is set. > */ > int mlx5_flow_validate_action_count(struct rte_eth_dev *dev, > - struct rte_flow_error *error) > + const struct rte_flow_attr *attr, > + struct rte_flow_error *error) > { > struct priv *priv = dev->data->dev_private; > > @@ -864,6 +895,11 @@ int mlx5_flow_validate_action_count(struct rte_eth_dev > *dev, > RTE_FLOW_ERROR_TYPE_ACTION, > NULL, > "flow counters are not supported."); > + if (attr->egress) > + return rte_flow_error_set(error, ENOTSUP, > + RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, > + NULL, > + "count action not supported for > egress"); > return 0; > } > > diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h > index f1a72d4..e0446c5 > 100644 > --- a/drivers/net/mlx5/mlx5_flow.h > +++ b/drivers/net/mlx5/mlx5_flow.h > @@ -43,6 +43,9 @@ > #define MLX5_FLOW_LAYER_GRE (1u << 14) > #define MLX5_FLOW_LAYER_MPLS (1u << 15) > > +/* General pattern items bits. */ > +#define MLX5_FLOW_ITEM_METADATA (1u << 16) > + > /* Outer Masks. */ > #define MLX5_FLOW_LAYER_OUTER_L3 \ > (MLX5_FLOW_LAYER_OUTER_L3_IPV4 | MLX5_FLOW_LAYER_OUTER_L3_IPV6) @@ > -237,21 +240,27 @@ struct > mlx5_flow_driver_ops { > > /* mlx5_flow.c */ > int mlx5_flow_validate_action_flag(uint64_t action_flags, > - struct rte_flow_error *error); > + const struct rte_flow_attr *attr, > + struct rte_flow_error *error); > int mlx5_flow_validate_action_mark(uint64_t action_flags, > - const struct rte_flow_action *action, > - struct rte_flow_error *error); > + const struct rte_flow_action *action, > + const struct rte_flow_attr *attr, > + struct rte_flow_error *error); > int mlx5_flow_validate_action_drop(uint64_t action_flags, > - struct rte_flow_error *error); > + const struct rte_flow_attr *attr, > + struct rte_flow_error *error); > int mlx5_flow_validate_action_queue(uint64_t action_flags, > struct rte_eth_dev *dev, > const struct rte_flow_action *action, > + const struct rte_flow_attr *attr, > struct rte_flow_error *error); > int mlx5_flow_validate_action_rss(uint64_t action_flags, > struct rte_eth_dev *dev, > const struct rte_flow_action *action, > + const struct rte_flow_attr *attr, > struct rte_flow_error *error); > int mlx5_flow_validate_action_count(struct rte_eth_dev *dev, > + const struct rte_flow_attr *attr, > struct rte_flow_error *error); > int mlx5_flow_validate_attributes(struct rte_eth_dev *dev, > const struct rte_flow_attr *attributes, @@ > -294,6 +303,11 @@ int > mlx5_flow_validate_item_mpls(uint64_t item_flags, void > mlx5_flow_init_driver_ops(struct rte_eth_dev > *dev); uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t > priority, > uint32_t subpriority); > +int mlx5_flow_item_acceptable(const struct rte_flow_item *item, > + const uint8_t *mask, > + const uint8_t *nic_mask, > + unsigned int size, > + struct rte_flow_error *error);
Above invalid egress actions checks seems less relation to metadata, how about split this patch into: 1. egress support 2. metadata support > > /* mlx5_flow_dv.c */ > void mlx5_flow_dv_get_driver_ops(struct mlx5_flow_driver_ops *flow_ops); > diff --git > a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index > 4090c5f..3b52181 100644 > --- a/drivers/net/mlx5/mlx5_flow_dv.c > +++ b/drivers/net/mlx5/mlx5_flow_dv.c > @@ -37,6 +37,47 @@ > #ifdef HAVE_IBV_FLOW_DV_SUPPORT > > /** > + * Validate META item. > + * > + * @param[in] item > + * Item specification. > + * @param[out] error > + * Pointer to error structure. > + * > + * @return > + * 0 on success, a negative errno value otherwise and rte_errno is set. > + */ > +static int > +mlx5_flow_validate_item_meta(const struct rte_flow_item *item, > + const struct rte_flow_attr *attributes, > + struct rte_flow_error *error) > +{ > + const struct rte_flow_item_meta *mask = item->mask; > + > + const struct rte_flow_item_meta nic_mask = { > + .data = RTE_BE32(UINT32_MAX) > + }; > + > + int ret; > + > + if (!mask) > + mask = &rte_flow_item_meta_mask; > + ret = mlx5_flow_item_acceptable > + (item, (const uint8_t *)mask, > + (const uint8_t *)&nic_mask, > + sizeof(struct rte_flow_item_meta), error); Please follow line wrapping format. > + if (ret < 0) > + return ret; > + > + if (attributes->ingress) > + return rte_flow_error_set(error, ENOTSUP, > + RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, > + NULL, > + "pattern not supported for ingress"); > + return 0; What if spec not specified? > +} > + > +/** > * Verify the @p attributes will be correctly understood by the NIC and store > * them in the @p flow if everything is correct. > * > @@ -68,21 +109,17 @@ static int flow_dv_validate_attributes(struct > rte_eth_dev *dev, > RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, > NULL, > "priority out of range"); > - if (attributes->egress) > - return rte_flow_error_set(error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, > - NULL, > - "egress is not supported"); > if (attributes->transfer) > return rte_flow_error_set(error, ENOTSUP, > RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, > NULL, > "transfer is not supported"); > - if (!attributes->ingress) > + if (!(attributes->egress ^ attributes->ingress)) > return rte_flow_error_set(error, ENOTSUP, > - RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, > + RTE_FLOW_ERROR_TYPE_ATTR, > NULL, > - "ingress attribute is mandatory"); > + "must specify exactly one of " > + "ingress or egress"); > return 0; > } > > @@ -219,6 +256,12 @@ static int flow_dv_validate_attributes(struct > rte_eth_dev *dev, > return ret; > item_flags |= MLX5_FLOW_LAYER_MPLS; > break; > + case RTE_FLOW_ITEM_TYPE_META: > + ret = mlx5_flow_validate_item_meta(items, attr, error); > + if (ret < 0) > + return ret; > + item_flags |= MLX5_FLOW_ITEM_METADATA; > + break; > default: > return rte_flow_error_set(error, ENOTSUP, > RTE_FLOW_ERROR_TYPE_ITEM, > @@ -233,6 +276,7 @@ static int flow_dv_validate_attributes(struct rte_eth_dev > *dev, > break; > case RTE_FLOW_ACTION_TYPE_FLAG: > ret = mlx5_flow_validate_action_flag(action_flags, > + attr, > error); > if (ret < 0) > return ret; > @@ -241,6 +285,7 @@ static int flow_dv_validate_attributes(struct rte_eth_dev > *dev, > case RTE_FLOW_ACTION_TYPE_MARK: > ret = mlx5_flow_validate_action_mark(action_flags, > actions, > + attr, > error); > if (ret < 0) > return ret; > @@ -248,27 +293,36 @@ static int flow_dv_validate_attributes(struct > rte_eth_dev *dev, > break; > case RTE_FLOW_ACTION_TYPE_DROP: > ret = mlx5_flow_validate_action_drop(action_flags, > + attr, > error); > if (ret < 0) > return ret; > action_flags |= MLX5_ACTION_DROP; > break; > case RTE_FLOW_ACTION_TYPE_QUEUE: > - ret = mlx5_flow_validate_action_queue(action_flags, dev, > - actions, error); > + ret = mlx5_flow_validate_action_queue(action_flags, > + dev, > + actions, > + attr, > + error); > if (ret < 0) > return ret; > action_flags |= MLX5_ACTION_QUEUE; > break; > case RTE_FLOW_ACTION_TYPE_RSS: > - ret = mlx5_flow_validate_action_rss(action_flags, dev, > - actions, error); > + ret = mlx5_flow_validate_action_rss(action_flags, > + dev, > + actions, > + attr, > + error); > if (ret < 0) > return ret; > action_flags |= MLX5_ACTION_RSS; > break; > case RTE_FLOW_ACTION_TYPE_COUNT: > - ret = mlx5_flow_validate_action_count(dev, error); > + ret = mlx5_flow_validate_action_count(dev, > + attr, > + error); > if (ret < 0) > return ret; > action_flags |= MLX5_ACTION_COUNT; > @@ -865,6 +919,43 @@ static int flow_dv_validate_attributes(struct > rte_eth_dev *dev, } > > /** > + * Add META item to matcher > + * > + * @param[in, out] matcher > + * Flow matcher. > + * @param[in, out] key > + * Flow matcher value. > + * @param[in] item > + * Flow pattern to translate. > + * @param[in] inner > + * Item is inner pattern. > + */ > +static void > +flow_dv_translate_item_meta(void *matcher, void *key, > + const struct rte_flow_item *item) > +{ > + const struct rte_flow_item_meta *metam; > + const struct rte_flow_item_meta *metav; > + > + void *misc2_m = > + MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2); > + void *misc2_v = > + MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2); > + > + metam = (const void *)item->mask; > + if (!metam) > + metam = &rte_flow_item_meta_mask; > + > + metav = (const void *)item->spec; > + if (metav) { > + MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a, > + RTE_BE32((uint32_t)rte_be_to_cpu_64(metam->data))); > + MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a, > + RTE_BE32((uint32_t)rte_be_to_cpu_64(metav->data))); Data size of rte_flow_item_meta.data is 32 bits in [1], no need to convert the size. > + } > +} > + > +/** > * > * Translate flow item. > * > @@ -946,6 +1037,9 @@ static int flow_dv_validate_attributes(struct > rte_eth_dev *dev, > case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: > flow_dv_translate_item_vxlan(tmatcher->key, key, item, inner); > break; > + case RTE_FLOW_ITEM_TYPE_META: > + flow_dv_translate_item_meta(tmatcher->key, key, item); > + break; > case RTE_FLOW_ITEM_TYPE_ICMP: > case RTE_FLOW_ITEM_TYPE_MPLS: > case RTE_FLOW_ITEM_TYPE_SCTP: > diff --git a/drivers/net/mlx5/mlx5_flow_verbs.c > b/drivers/net/mlx5/mlx5_flow_verbs.c > index 48e816d..3c42016 100644 > --- a/drivers/net/mlx5/mlx5_flow_verbs.c > +++ b/drivers/net/mlx5/mlx5_flow_verbs.c > @@ -1272,6 +1272,7 @@ struct ibv_spec_header { > break; > case RTE_FLOW_ACTION_TYPE_FLAG: > ret = mlx5_flow_validate_action_flag(action_flags, > + attr, > error); > if (ret < 0) > return ret; > @@ -1280,6 +1281,7 @@ struct ibv_spec_header { > case RTE_FLOW_ACTION_TYPE_MARK: > ret = mlx5_flow_validate_action_mark(action_flags, > actions, > + attr, > error); > if (ret < 0) > return ret; > @@ -1287,27 +1289,36 @@ struct ibv_spec_header { > break; > case RTE_FLOW_ACTION_TYPE_DROP: > ret = mlx5_flow_validate_action_drop(action_flags, > + attr, > error); > if (ret < 0) > return ret; > action_flags |= MLX5_ACTION_DROP; > break; > case RTE_FLOW_ACTION_TYPE_QUEUE: > - ret = mlx5_flow_validate_action_queue(action_flags, dev, > - actions, error); > + ret = mlx5_flow_validate_action_queue(action_flags, > + dev, > + actions, > + attr, > + error); > if (ret < 0) > return ret; > action_flags |= MLX5_ACTION_QUEUE; > break; > case RTE_FLOW_ACTION_TYPE_RSS: > - ret = mlx5_flow_validate_action_rss(action_flags, dev, > - actions, error); > + ret = mlx5_flow_validate_action_rss(action_flags, > + dev, > + actions, > + attr, > + error); > if (ret < 0) > return ret; > action_flags |= MLX5_ACTION_RSS; > break; > case RTE_FLOW_ACTION_TYPE_COUNT: > - ret = mlx5_flow_validate_action_count(dev, error); > + ret = mlx5_flow_validate_action_count(dev, > + attr, > + error); > if (ret < 0) > return ret; > action_flags |= MLX5_ACTION_COUNT; > diff --git a/drivers/net/mlx5/mlx5_prm.h b/drivers/net/mlx5/mlx5_prm.h index > 117cec7..2f33aef 100644 > --- a/drivers/net/mlx5/mlx5_prm.h > +++ b/drivers/net/mlx5/mlx5_prm.h > @@ -159,7 +159,7 @@ struct mlx5_wqe_eth_seg_small { > uint8_t cs_flags; > uint8_t rsvd1; > uint16_t mss; > - uint32_t rsvd2; > + uint32_t flow_table_metadata; > uint16_t inline_hdr_sz; > uint8_t inline_hdr[2]; > } __rte_aligned(MLX5_WQE_DWORD_SIZE); > diff --git a/drivers/net/mlx5/mlx5_rxtx.c b/drivers/net/mlx5/mlx5_rxtx.c > index 2d14f8a..080de57 > 100644 > --- a/drivers/net/mlx5/mlx5_rxtx.c > +++ b/drivers/net/mlx5/mlx5_rxtx.c > @@ -523,6 +523,7 @@ > uint8_t tso = txq->tso_en && (buf->ol_flags & PKT_TX_TCP_SEG); > uint32_t swp_offsets = 0; > uint8_t swp_types = 0; > + uint32_t metadata = 0; > uint16_t tso_segsz = 0; > #ifdef MLX5_PMD_SOFT_COUNTERS > uint32_t total_length = 0; > @@ -566,6 +567,9 @@ > cs_flags = txq_ol_cksum_to_cs(buf); > txq_mbuf_to_swp(txq, buf, (uint8_t *)&swp_offsets, &swp_types); > raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE; > + /* Copy metadata from mbuf if valid */ > + if (buf->ol_flags & PKT_TX_METADATA) > + metadata = buf->hash.fdir.hi; > /* Replace the Ethernet type by the VLAN if necessary. */ > if (buf->ol_flags & PKT_TX_VLAN_PKT) { > uint32_t vlan = rte_cpu_to_be_32(0x81000000 | @@ -781,7 > +785,7 @@ > swp_offsets, > cs_flags | (swp_types << 8) | > (rte_cpu_to_be_16(tso_segsz) << 16), > - 0, > + rte_cpu_to_be_32(metadata), > (ehdr << 16) | rte_cpu_to_be_16(tso_header_sz), > }; > } else { > @@ -795,7 +799,7 @@ > wqe->eseg = (rte_v128u32_t){ > swp_offsets, > cs_flags | (swp_types << 8), > - 0, > + rte_cpu_to_be_32(metadata), > (ehdr << 16) | rte_cpu_to_be_16(pkt_inline_sz), > }; > } > @@ -861,7 +865,7 @@ > mpw->wqe->eseg.inline_hdr_sz = 0; > mpw->wqe->eseg.rsvd0 = 0; > mpw->wqe->eseg.rsvd1 = 0; > - mpw->wqe->eseg.rsvd2 = 0; > + mpw->wqe->eseg.flow_table_metadata = 0; > mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) | > (txq->wqe_ci << 8) | > MLX5_OPCODE_TSO); > @@ -971,6 +975,8 @@ > if ((mpw.state == MLX5_MPW_STATE_OPENED) && > ((mpw.len != length) || > (segs_n != 1) || > + (mpw.wqe->eseg.flow_table_metadata != > + rte_cpu_to_be_32(buf->hash.fdir.hi)) || > (mpw.wqe->eseg.cs_flags != cs_flags))) > mlx5_mpw_close(txq, &mpw); > if (mpw.state == MLX5_MPW_STATE_CLOSED) { @@ -984,6 +990,8 @@ > max_wqe -= 2; > mlx5_mpw_new(txq, &mpw, length); > mpw.wqe->eseg.cs_flags = cs_flags; > + mpw.wqe->eseg.flow_table_metadata = > + rte_cpu_to_be_32(buf->hash.fdir.hi); > } > /* Multi-segment packets must be alone in their MPW. */ > assert((segs_n == 1) || (mpw.pkts_n == 0)); @@ -1082,7 +1090,7 > @@ > mpw->wqe->eseg.cs_flags = 0; > mpw->wqe->eseg.rsvd0 = 0; > mpw->wqe->eseg.rsvd1 = 0; > - mpw->wqe->eseg.rsvd2 = 0; > + mpw->wqe->eseg.flow_table_metadata = 0; > inl = (struct mlx5_wqe_inl_small *) > (((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE); > mpw->data.raw = (uint8_t *)&inl->raw; > @@ -1199,12 +1207,16 @@ > if (mpw.state == MLX5_MPW_STATE_OPENED) { > if ((mpw.len != length) || > (segs_n != 1) || > + (mpw.wqe->eseg.flow_table_metadata != > + rte_cpu_to_be_32(buf->hash.fdir.hi)) || Shall we check buf->ol_flags & PKT_TX_METADATA here? Same question to similar code below. > (mpw.wqe->eseg.cs_flags != cs_flags)) > mlx5_mpw_close(txq, &mpw); > } else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) { > if ((mpw.len != length) || > (segs_n != 1) || > (length > inline_room) || > + (mpw.wqe->eseg.flow_table_metadata != > + rte_cpu_to_be_32(buf->hash.fdir.hi)) || > (mpw.wqe->eseg.cs_flags != cs_flags)) { > mlx5_mpw_inline_close(txq, &mpw); > inline_room = > @@ -1224,12 +1236,20 @@ > max_wqe -= 2; > mlx5_mpw_new(txq, &mpw, length); > mpw.wqe->eseg.cs_flags = cs_flags; > + /* Copy metadata from mbuf if valid */ > + if (buf->ol_flags & PKT_TX_METADATA) > + mpw.wqe->eseg.flow_table_metadata = > + rte_cpu_to_be_32(buf->hash.fdir.hi); > } else { > if (unlikely(max_wqe < wqe_inl_n)) > break; > max_wqe -= wqe_inl_n; > mlx5_mpw_inline_new(txq, &mpw, length); > mpw.wqe->eseg.cs_flags = cs_flags; > + /* Copy metadata from mbuf if valid */ > + if (buf->ol_flags & PKT_TX_METADATA) > + mpw.wqe->eseg.flow_table_metadata = > + rte_cpu_to_be_32(buf->hash.fdir.hi); > } > } > /* Multi-segment packets must be alone in their MPW. */ @@ > -1482,6 +1502,8 @@ > (length <= txq->inline_max_packet_sz && > inl_pad + sizeof(inl_hdr) + length > > mpw_room) || > + (mpw.wqe->eseg.flow_table_metadata != > + rte_cpu_to_be_32(buf->hash.fdir.hi)) || > (mpw.wqe->eseg.cs_flags != cs_flags)) > max_wqe -= mlx5_empw_close(txq, &mpw); > } > @@ -1505,6 +1527,10 @@ > sizeof(inl_hdr) + length <= mpw_room && > !txq->mpw_hdr_dseg; > mpw.wqe->eseg.cs_flags = cs_flags; > + /* Copy metadata from mbuf if valid */ > + if (buf->ol_flags & PKT_TX_METADATA) > + mpw.wqe->eseg.flow_table_metadata = > + rte_cpu_to_be_32(buf->hash.fdir.hi); > } else { > /* Evaluate whether the next packet can be inlined. > * Inlininig is possible when: > diff --git a/drivers/net/mlx5/mlx5_rxtx_vec.c > b/drivers/net/mlx5/mlx5_rxtx_vec.c > index 0a4aed8..db36699 100644 > --- a/drivers/net/mlx5/mlx5_rxtx_vec.c > +++ b/drivers/net/mlx5/mlx5_rxtx_vec.c > @@ -48,25 +48,39 @@ > * Number of packets. > * @param cs_flags > * Pointer of flags to be returned. > + * @param txq_offloads > + * Offloads enabled on Tx queue > * > * @return > * Number of packets having same ol_flags. > + * If PKT_TX_METADATA is set in ol_flags, packets must have same metadata > + * as well. Please move such function description above member description. > */ > static inline unsigned int > -txq_calc_offload(struct rte_mbuf **pkts, uint16_t pkts_n, uint8_t *cs_flags) > +txq_calc_offload(struct rte_mbuf **pkts, uint16_t pkts_n, > + uint8_t *cs_flags, const uint64_t txq_offloads) > { > unsigned int pos; > const uint64_t ol_mask = > PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | > PKT_TX_UDP_CKSUM | PKT_TX_TUNNEL_GRE | > - PKT_TX_TUNNEL_VXLAN | PKT_TX_OUTER_IP_CKSUM; > + PKT_TX_TUNNEL_VXLAN | PKT_TX_OUTER_IP_CKSUM | PKT_TX_METADATA; > > if (!pkts_n) > return 0; > /* Count the number of packets having same ol_flags. */ > - for (pos = 1; pos < pkts_n; ++pos) > - if ((pkts[pos]->ol_flags ^ pkts[0]->ol_flags) & ol_mask) > + for (pos = 1; pos < pkts_n; ++pos) { > + if ((txq_offloads & MLX5_VEC_TX_CKSUM_OFFLOAD_CAP) && > + ((pkts[pos]->ol_flags ^ pkts[0]->ol_flags) & ol_mask)) > break; > + /* If the metadata ol_flag is set, > + * metadata must be same in all packets. > + */ > + if ((txq_offloads & DEV_TX_OFFLOAD_MATCH_METADATA) && > + (pkts[pos]->ol_flags & PKT_TX_METADATA) && > + pkts[0]->hash.fdir.hi != pkts[pos]->hash.fdir.hi) > + break; > + } > *cs_flags = txq_ol_cksum_to_cs(pkts[0]); > return pos; > } > @@ -137,8 +151,10 @@ > n = RTE_MIN((uint16_t)(pkts_n - nb_tx), MLX5_VPMD_TX_MAX_BURST); > if (txq->offloads & DEV_TX_OFFLOAD_MULTI_SEGS) > n = txq_count_contig_single_seg(&pkts[nb_tx], n); > - if (txq->offloads & MLX5_VEC_TX_CKSUM_OFFLOAD_CAP) > - n = txq_calc_offload(&pkts[nb_tx], n, &cs_flags); > + if (txq->offloads & (MLX5_VEC_TX_CKSUM_OFFLOAD_CAP | > + DEV_TX_OFFLOAD_MATCH_METADATA)) > + n = txq_calc_offload(&pkts[nb_tx], n, > + &cs_flags, txq->offloads); > ret = txq_burst_v(txq, &pkts[nb_tx], n, cs_flags); > nb_tx += ret; > if (!ret) > diff --git a/drivers/net/mlx5/mlx5_rxtx_vec.h > b/drivers/net/mlx5/mlx5_rxtx_vec.h > index fb884f9..fda7004 100644 > --- a/drivers/net/mlx5/mlx5_rxtx_vec.h > +++ b/drivers/net/mlx5/mlx5_rxtx_vec.h > @@ -22,6 +22,7 @@ > /* HW offload capabilities of vectorized Tx. */ #define > MLX5_VEC_TX_OFFLOAD_CAP \ > (MLX5_VEC_TX_CKSUM_OFFLOAD_CAP | \ > + DEV_TX_OFFLOAD_MATCH_METADATA | \ > DEV_TX_OFFLOAD_MULTI_SEGS) > > /* > diff --git a/drivers/net/mlx5/mlx5_rxtx_vec_neon.h > b/drivers/net/mlx5/mlx5_rxtx_vec_neon.h > index b37b738..20c9427 100644 > --- a/drivers/net/mlx5/mlx5_rxtx_vec_neon.h > +++ b/drivers/net/mlx5/mlx5_rxtx_vec_neon.h > @@ -237,6 +237,7 @@ > uint8x16_t *t_wqe; > uint8_t *dseg; > uint8x16_t ctrl; > + uint32_t md; /* metadata */ > > /* Make sure all packets can fit into a single WQE. */ > assert(elts_n > pkts_n); > @@ -293,10 +294,11 @@ > ctrl = vqtbl1q_u8(ctrl, ctrl_shuf_m); > vst1q_u8((void *)t_wqe, ctrl); > /* Fill ESEG in the header. */ > + md = pkts[0]->hash.fdir.hi; > vst1q_u8((void *)(t_wqe + 1), > ((uint8x16_t) { 0, 0, 0, 0, > cs_flags, 0, 0, 0, > - 0, 0, 0, 0, > + md >> 24, md >> 16, md >> 8, md, > 0, 0, 0, 0 })); > #ifdef MLX5_PMD_SOFT_COUNTERS > txq->stats.opackets += pkts_n; > diff --git a/drivers/net/mlx5/mlx5_rxtx_vec_sse.h > b/drivers/net/mlx5/mlx5_rxtx_vec_sse.h > index 54b3783..7c8535c 100644 > --- a/drivers/net/mlx5/mlx5_rxtx_vec_sse.h > +++ b/drivers/net/mlx5/mlx5_rxtx_vec_sse.h > @@ -236,6 +236,7 @@ > 0, 1, 2, 3 /* bswap32 */); > __m128i *t_wqe, *dseg; > __m128i ctrl; > + uint32_t md; /* metadata */ > > /* Make sure all packets can fit into a single WQE. */ > assert(elts_n > pkts_n); > @@ -292,9 +293,10 @@ > ctrl = _mm_shuffle_epi8(ctrl, shuf_mask_ctrl); > _mm_store_si128(t_wqe, ctrl); > /* Fill ESEG in the header. */ > + md = pkts[0]->hash.fdir.hi; > _mm_store_si128(t_wqe + 1, > _mm_set_epi8(0, 0, 0, 0, > - 0, 0, 0, 0, > + md, md >> 8, md >> 16, md >> 24, > 0, 0, 0, cs_flags, > 0, 0, 0, 0)); > #ifdef MLX5_PMD_SOFT_COUNTERS > diff --git a/drivers/net/mlx5/mlx5_txq.c b/drivers/net/mlx5/mlx5_txq.c index > f9bc473..7263fb1 100644 > --- a/drivers/net/mlx5/mlx5_txq.c > +++ b/drivers/net/mlx5/mlx5_txq.c > @@ -128,6 +128,12 @@ > offloads |= (DEV_TX_OFFLOAD_VXLAN_TNL_TSO | > DEV_TX_OFFLOAD_GRE_TNL_TSO); > } > + > +#ifdef HAVE_IBV_FLOW_DV_SUPPORT > + if (config->dv_flow_en) > + offloads |= DEV_TX_OFFLOAD_MATCH_METADATA; #endif > + > return offloads; > } > > -- > 1.8.3.1