X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmlx5%2Fmlx5_flow_dv.c;h=23ee6a2a8bfe14d83d6389290756e686ea200611;hb=c2450e933f01d4d31448240f7304730292db7ee8;hp=cd7783507616af9b140603176aaeb1e0eb61038c;hpb=fa31a5ed0196a3d0ea61c27030d7fd515cc8c62d;p=dpdk.git diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index cd77835076..23ee6a2a8b 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -1157,29 +1157,10 @@ flow_dv_convert_action_copy_mreg(struct rte_eth_dev *dev, if (conf->dst == REG_C_0) { /* Copy to reg_c[0], within mask only. */ reg_dst.offset = rte_bsf32(reg_c0); - /* - * Mask is ignoring the enianness, because - * there is no conversion in datapath. - */ -#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN - /* Copy from destination lower bits to reg_c[0]. */ - mask = reg_c0 >> reg_dst.offset; -#else - /* Copy from destination upper bits to reg_c[0]. */ - mask = reg_c0 << (sizeof(reg_c0) * CHAR_BIT - - rte_fls_u32(reg_c0)); -#endif + mask = rte_cpu_to_be_32(reg_c0 >> reg_dst.offset); } else { - mask = rte_cpu_to_be_32(reg_c0); -#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN - /* Copy from reg_c[0] to destination lower bits. */ reg_dst.offset = 0; -#else - /* Copy from reg_c[0] to destination upper bits. */ - reg_dst.offset = sizeof(reg_c0) * CHAR_BIT - - (rte_fls_u32(reg_c0) - - rte_bsf32(reg_c0)); -#endif + mask = rte_cpu_to_be_32(reg_c0); } } return flow_dv_convert_modify_action(&item, @@ -1409,8 +1390,8 @@ flow_dv_convert_action_modify_ipv6_dscp } static int -mlx5_flow_item_field_width(struct mlx5_dev_config *config, - enum rte_flow_field_id field) +mlx5_flow_item_field_width(struct mlx5_priv *priv, + enum rte_flow_field_id field, int inherit) { switch (field) { case RTE_FLOW_FIELD_START: @@ -1456,17 +1437,12 @@ mlx5_flow_item_field_width(struct mlx5_dev_config *config, case RTE_FLOW_FIELD_TAG: return 32; case RTE_FLOW_FIELD_MARK: - return 24; + return __builtin_popcount(priv->sh->dv_mark_mask); case RTE_FLOW_FIELD_META: - if (config->dv_xmeta_en == MLX5_XMETA_MODE_META16) - return 16; - else if (config->dv_xmeta_en == MLX5_XMETA_MODE_META32) - return 32; - else - return 0; + return __builtin_popcount(priv->sh->dv_meta_mask); case RTE_FLOW_FIELD_POINTER: case RTE_FLOW_FIELD_VALUE: - return 64; + return inherit < 0 ? 0 : inherit; default: MLX5_ASSERT(false); } @@ -1476,18 +1452,14 @@ mlx5_flow_item_field_width(struct mlx5_dev_config *config, 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, uint32_t dst_width, - struct rte_eth_dev *dev, - const struct rte_flow_attr *attr, - struct rte_flow_error *error) + struct field_modify_info *info, uint32_t *mask, + uint32_t width, uint32_t *shift, struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; - struct mlx5_dev_config *config = &priv->config; uint32_t idx = 0; uint32_t off = 0; - uint64_t val = 0; + switch (data->field) { case RTE_FLOW_FIELD_START: /* not supported yet */ @@ -1497,7 +1469,7 @@ mlx5_flow_field_id_to_modify_info off = data->offset > 16 ? data->offset - 16 : 0; if (mask) { if (data->offset < 16) { - info[idx] = (struct field_modify_info){2, 0, + info[idx] = (struct field_modify_info){2, 4, MLX5_MODI_OUT_DMAC_15_0}; if (width < 16) { mask[idx] = rte_cpu_to_be_16(0xffff >> @@ -1511,15 +1483,15 @@ mlx5_flow_field_id_to_modify_info break; ++idx; } - info[idx] = (struct field_modify_info){4, 4 * idx, + info[idx] = (struct field_modify_info){4, 0, MLX5_MODI_OUT_DMAC_47_16}; mask[idx] = rte_cpu_to_be_32((0xffffffff >> (32 - width)) << off); } else { if (data->offset < 16) - info[idx++] = (struct field_modify_info){2, 0, + info[idx++] = (struct field_modify_info){2, 4, MLX5_MODI_OUT_DMAC_15_0}; - info[idx] = (struct field_modify_info){4, off, + info[idx] = (struct field_modify_info){4, 0, MLX5_MODI_OUT_DMAC_47_16}; } break; @@ -1527,7 +1499,7 @@ mlx5_flow_field_id_to_modify_info off = data->offset > 16 ? data->offset - 16 : 0; if (mask) { if (data->offset < 16) { - info[idx] = (struct field_modify_info){2, 0, + info[idx] = (struct field_modify_info){2, 4, MLX5_MODI_OUT_SMAC_15_0}; if (width < 16) { mask[idx] = rte_cpu_to_be_16(0xffff >> @@ -1541,15 +1513,15 @@ mlx5_flow_field_id_to_modify_info break; ++idx; } - info[idx] = (struct field_modify_info){4, 4 * idx, + info[idx] = (struct field_modify_info){4, 0, MLX5_MODI_OUT_SMAC_47_16}; mask[idx] = rte_cpu_to_be_32((0xffffffff >> (32 - width)) << off); } else { if (data->offset < 16) - info[idx++] = (struct field_modify_info){2, 0, + info[idx++] = (struct field_modify_info){2, 4, MLX5_MODI_OUT_SMAC_15_0}; - info[idx] = (struct field_modify_info){4, off, + info[idx] = (struct field_modify_info){4, 0, MLX5_MODI_OUT_SMAC_47_16}; } break; @@ -1609,8 +1581,7 @@ mlx5_flow_field_id_to_modify_info case RTE_FLOW_FIELD_IPV6_SRC: if (mask) { if (data->offset < 32) { - info[idx] = (struct field_modify_info){4, - 4 * idx, + info[idx] = (struct field_modify_info){4, 12, MLX5_MODI_OUT_SIPV6_31_0}; if (width < 32) { mask[idx] = @@ -1626,8 +1597,7 @@ mlx5_flow_field_id_to_modify_info ++idx; } if (data->offset < 64) { - info[idx] = (struct field_modify_info){4, - 4 * idx, + info[idx] = (struct field_modify_info){4, 8, MLX5_MODI_OUT_SIPV6_63_32}; if (width < 32) { mask[idx] = @@ -1643,8 +1613,7 @@ mlx5_flow_field_id_to_modify_info ++idx; } if (data->offset < 96) { - info[idx] = (struct field_modify_info){4, - 4 * idx, + info[idx] = (struct field_modify_info){4, 4, MLX5_MODI_OUT_SIPV6_95_64}; if (width < 32) { mask[idx] = @@ -1659,19 +1628,19 @@ mlx5_flow_field_id_to_modify_info break; ++idx; } - info[idx] = (struct field_modify_info){4, 4 * idx, + info[idx] = (struct field_modify_info){4, 0, MLX5_MODI_OUT_SIPV6_127_96}; mask[idx] = rte_cpu_to_be_32(0xffffffff >> (32 - width)); } else { if (data->offset < 32) - info[idx++] = (struct field_modify_info){4, 0, + info[idx++] = (struct field_modify_info){4, 12, MLX5_MODI_OUT_SIPV6_31_0}; if (data->offset < 64) - info[idx++] = (struct field_modify_info){4, 0, + info[idx++] = (struct field_modify_info){4, 8, MLX5_MODI_OUT_SIPV6_63_32}; if (data->offset < 96) - info[idx++] = (struct field_modify_info){4, 0, + info[idx++] = (struct field_modify_info){4, 4, MLX5_MODI_OUT_SIPV6_95_64}; if (data->offset < 128) info[idx++] = (struct field_modify_info){4, 0, @@ -1681,8 +1650,7 @@ mlx5_flow_field_id_to_modify_info case RTE_FLOW_FIELD_IPV6_DST: if (mask) { if (data->offset < 32) { - info[idx] = (struct field_modify_info){4, - 4 * idx, + info[idx] = (struct field_modify_info){4, 12, MLX5_MODI_OUT_DIPV6_31_0}; if (width < 32) { mask[idx] = @@ -1698,8 +1666,7 @@ mlx5_flow_field_id_to_modify_info ++idx; } if (data->offset < 64) { - info[idx] = (struct field_modify_info){4, - 4 * idx, + info[idx] = (struct field_modify_info){4, 8, MLX5_MODI_OUT_DIPV6_63_32}; if (width < 32) { mask[idx] = @@ -1715,8 +1682,7 @@ mlx5_flow_field_id_to_modify_info ++idx; } if (data->offset < 96) { - info[idx] = (struct field_modify_info){4, - 4 * idx, + info[idx] = (struct field_modify_info){4, 4, MLX5_MODI_OUT_DIPV6_95_64}; if (width < 32) { mask[idx] = @@ -1731,19 +1697,19 @@ mlx5_flow_field_id_to_modify_info break; ++idx; } - info[idx] = (struct field_modify_info){4, 4 * idx, + info[idx] = (struct field_modify_info){4, 0, MLX5_MODI_OUT_DIPV6_127_96}; mask[idx] = rte_cpu_to_be_32(0xffffffff >> (32 - width)); } else { if (data->offset < 32) - info[idx++] = (struct field_modify_info){4, 0, + info[idx++] = (struct field_modify_info){4, 12, MLX5_MODI_OUT_DIPV6_31_0}; if (data->offset < 64) - info[idx++] = (struct field_modify_info){4, 0, + info[idx++] = (struct field_modify_info){4, 8, MLX5_MODI_OUT_DIPV6_63_32}; if (data->offset < 96) - info[idx++] = (struct field_modify_info){4, 0, + info[idx++] = (struct field_modify_info){4, 4, MLX5_MODI_OUT_DIPV6_95_64}; if (data->offset < 128) info[idx++] = (struct field_modify_info){4, 0, @@ -1825,6 +1791,8 @@ mlx5_flow_field_id_to_modify_info break; case RTE_FLOW_FIELD_MARK: { + uint32_t mark_mask = priv->sh->dv_mark_mask; + uint32_t mark_count = __builtin_popcount(mark_mask); int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); if (reg < 0) @@ -1834,66 +1802,33 @@ mlx5_flow_field_id_to_modify_info info[idx] = (struct field_modify_info){4, 0, reg_to_field[reg]}; if (mask) - mask[idx] = - rte_cpu_to_be_32(0xffffffff >> - (32 - width)); + mask[idx] = rte_cpu_to_be_32((mark_mask >> + (mark_count - width)) & mark_mask); } break; case RTE_FLOW_FIELD_META: { - unsigned int xmeta = config->dv_xmeta_en; + uint32_t meta_mask = priv->sh->dv_meta_mask; + uint32_t meta_count = __builtin_popcount(meta_mask); + uint32_t msk_c0 = + rte_cpu_to_be_32(priv->sh->dv_regc0_mask); + uint32_t shl_c0 = rte_bsf32(msk_c0); 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)); - if (xmeta == MLX5_XMETA_MODE_META16) { - info[idx] = (struct field_modify_info){2, 0, - reg_to_field[reg]}; - if (mask) - mask[idx] = rte_cpu_to_be_16(0xffff >> - (16 - width)); - } else if (xmeta == MLX5_XMETA_MODE_META32) { - info[idx] = (struct field_modify_info){4, 0, - reg_to_field[reg]}; - if (mask) - mask[idx] = - rte_cpu_to_be_32(0xffffffff >> - (32 - width)); - } else { - MLX5_ASSERT(false); - } + if (reg == REG_C_0) + *shift = shl_c0; + info[idx] = (struct field_modify_info){4, 0, + reg_to_field[reg]}; + if (mask) + mask[idx] = rte_cpu_to_be_32((meta_mask >> + (meta_count - width)) & meta_mask); } break; case RTE_FLOW_FIELD_POINTER: case RTE_FLOW_FIELD_VALUE: - if (data->field == RTE_FLOW_FIELD_POINTER) - memcpy(&val, (void *)(uintptr_t)data->value, - sizeof(uint64_t)); - else - val = data->value; - for (idx = 0; idx < MLX5_ACT_MAX_MOD_FIELDS; idx++) { - if (mask[idx]) { - if (dst_width == 48) { - /*special case for MAC addresses */ - value[idx] = rte_cpu_to_be_16(val); - val >>= 16; - dst_width -= 16; - } else if (dst_width > 16) { - value[idx] = rte_cpu_to_be_32(val); - val >>= 32; - } else if (dst_width > 8) { - value[idx] = rte_cpu_to_be_16(val); - val >>= 16; - } else { - value[idx] = (uint8_t)val; - val >>= 8; - } - if (!val) - break; - } - } - break; default: MLX5_ASSERT(false); break; @@ -1925,39 +1860,40 @@ flow_dv_convert_action_modify_field const struct rte_flow_attr *attr, struct rte_flow_error *error) { - struct mlx5_priv *priv = dev->data->dev_private; - struct mlx5_dev_config *config = &priv->config; const struct rte_flow_action_modify_field *conf = (const struct rte_flow_action_modify_field *)(action->conf); - struct rte_flow_item item; + struct rte_flow_item item = { + .spec = NULL, + .mask = NULL + }; 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; - uint32_t dst_width = mlx5_flow_item_field_width(config, - conf->dst.field); + uint32_t shift = 0; if (conf->src.field == RTE_FLOW_FIELD_POINTER || - conf->src.field == RTE_FLOW_FIELD_VALUE) { + 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, dst_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, dst_width, dev, attr, error); - item.spec = &value; + conf->width, &shift, dev, + attr, error); + item.spec = conf->src.field == RTE_FLOW_FIELD_POINTER ? + (void *)(uintptr_t)conf->src.pvalue : + (void *)(uintptr_t)&conf->src.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, dst_width, dev, attr, error); + conf->width, &shift, 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, dst_width, dev, attr, error); + conf->width, &shift, + dev, attr, error); } item.mask = &mask; return flow_dv_convert_modify_action(&item, @@ -2436,11 +2372,10 @@ flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item, { const struct rte_flow_item_gtp *gtp_spec; const struct rte_flow_item_gtp *gtp_mask; - const struct rte_flow_item_gtp_psc *spec; const struct rte_flow_item_gtp_psc *mask; const struct rte_flow_item_gtp_psc nic_mask = { - .pdu_type = 0xFF, - .qfi = 0xFF, + .hdr.type = 0xF, + .hdr.qfi = 0x3F, }; if (!gtp_item || !(last_item & MLX5_FLOW_LAYER_GTP)) @@ -2464,12 +2399,7 @@ flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item, /* GTP spec is here and E flag is requested to match zero. */ if (!item->spec) return 0; - spec = item->spec; mask = item->mask ? item->mask : &rte_flow_item_gtp_psc_mask; - if (spec->pdu_type > MLX5_GTP_EXT_MAX_PDU_TYPE) - return rte_flow_error_set - (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, - "PDU type should be smaller than 16"); return mlx5_flow_item_acceptable(item, (const uint8_t *)mask, (const uint8_t *)&nic_mask, sizeof(struct rte_flow_item_gtp_psc), @@ -2790,20 +2720,30 @@ flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_dev_ctx_shared *sh = priv->sh; + bool direction_error = false; - (void)action; - (void)attr; if (!priv->sh->pop_vlan_action) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "pop vlan action is not supported"); - if (attr->egress) + /* Pop VLAN is not supported in egress except for CX6 FDB mode. */ + if (attr->transfer) { + bool fdb_tx = priv->representor_id != UINT16_MAX; + bool is_cx5 = sh->steering_format_version == + MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5; + + if (fdb_tx && is_cx5) + direction_error = true; + } else if (attr->egress) { + direction_error = true; + } + if (direction_error) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, NULL, - "pop vlan action not supported for " - "egress"); + "pop vlan action not supported for egress"); if (action_flags & MLX5_FLOW_VLAN_ACTIONS) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, action, @@ -2927,6 +2867,8 @@ flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev, { const struct rte_flow_action_of_push_vlan *push_vlan = action->conf; const struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_dev_ctx_shared *sh = priv->sh; + bool direction_error = false; if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) && push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ)) @@ -2938,6 +2880,22 @@ flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_ACTION, action, "wrong action order, port_id should " "be after push VLAN"); + /* Push VLAN is not supported in ingress except for CX6 FDB mode. */ + if (attr->transfer) { + bool fdb_tx = priv->representor_id != UINT16_MAX; + bool is_cx5 = sh->steering_format_version == + MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5; + + if (!fdb_tx && is_cx5) + direction_error = true; + } else if (attr->ingress) { + direction_error = true; + } + if (direction_error) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, + NULL, + "push vlan action not supported for ingress"); if (!attr->transfer && priv->representor) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -3310,26 +3268,6 @@ flow_dv_validate_action_set_tag(struct rte_eth_dev *dev, return 0; } -/** - * Check if action counter is shared by either old or new mechanism. - * - * @param[in] action - * Pointer to the action structure. - * - * @return - * True when counter is shared, false otherwise. - */ -static inline bool -is_shared_action_count(const struct rte_flow_action *action) -{ - const struct rte_flow_action_count *count = - (const struct rte_flow_action_count *)action->conf; - - if ((int)action->type == MLX5_RTE_FLOW_ACTION_TYPE_COUNT) - return true; - return !!(count && count->shared); -} - /** * Validate count action. * @@ -4875,10 +4813,10 @@ flow_dv_validate_action_modify_field(struct rte_eth_dev *dev, struct mlx5_dev_config *config = &priv->config; const struct rte_flow_action_modify_field *action_modify_field = action->conf; - uint32_t dst_width = mlx5_flow_item_field_width(config, - action_modify_field->dst.field); - uint32_t src_width = mlx5_flow_item_field_width(config, - action_modify_field->src.field); + uint32_t dst_width = mlx5_flow_item_field_width(priv, + action_modify_field->dst.field, -1); + uint32_t src_width = mlx5_flow_item_field_width(priv, + action_modify_field->src.field, dst_width); ret = flow_dv_validate_action_modify_hdr(action_flags, action, error); if (ret) @@ -4940,10 +4878,11 @@ flow_dv_validate_action_modify_field(struct rte_eth_dev *dev, "source and destination fields" " cannot be the same"); if (action_modify_field->dst.field == RTE_FLOW_FIELD_VALUE || - action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER) + action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER || + action_modify_field->dst.field == RTE_FLOW_FIELD_MARK) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, action, - "immediate value or a pointer to it" + "mark, immediate value or a pointer to it" " cannot be used as a destination"); if (action_modify_field->dst.field == RTE_FLOW_FIELD_START || action_modify_field->src.field == RTE_FLOW_FIELD_START) @@ -5049,14 +4988,14 @@ flow_dv_validate_action_jump(struct rte_eth_dev *dev, } /* - * Validate the port_id action. + * Validate action PORT_ID / REPRESENTED_PORT. * * @param[in] dev * Pointer to rte_eth_dev structure. * @param[in] action_flags * Bit-fields that holds the actions detected until now. * @param[in] action - * Port_id RTE action structure. + * PORT_ID / REPRESENTED_PORT action structure. * @param[in] attr * Attributes of flow that includes this action. * @param[out] error @@ -5073,6 +5012,7 @@ flow_dv_validate_action_port_id(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct rte_flow_action_port_id *port_id; + const struct rte_flow_action_ethdev *ethdev; struct mlx5_priv *act_priv; struct mlx5_priv *dev_priv; uint16_t port; @@ -5081,13 +5021,13 @@ flow_dv_validate_action_port_id(struct rte_eth_dev *dev, return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, - "port id action is valid in transfer" + "port action is valid in transfer" " mode only"); if (!action || !action->conf) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL, - "port id action parameters must be" + "port action parameters must be" " specified"); if (action_flags & (MLX5_FLOW_FATE_ACTIONS | MLX5_FLOW_FATE_ESWITCH_ACTIONS)) @@ -5101,13 +5041,27 @@ flow_dv_validate_action_port_id(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "failed to obtain E-Switch info"); - port_id = action->conf; - port = port_id->original ? dev->data->port_id : port_id->id; + switch (action->type) { + case RTE_FLOW_ACTION_TYPE_PORT_ID: + port_id = action->conf; + port = port_id->original ? dev->data->port_id : port_id->id; + break; + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: + ethdev = action->conf; + port = ethdev->port_id; + break; + default: + MLX5_ASSERT(false); + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "unknown E-Switch action"); + } act_priv = mlx5_port_to_eswitch_info(port, false); if (!act_priv) return rte_flow_error_set (error, rte_errno, - RTE_FLOW_ERROR_TYPE_ACTION_CONF, port_id, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, action->conf, "failed to obtain E-Switch port id for port"); if (act_priv->domain_id != dev_priv->domain_id) return rte_flow_error_set @@ -5659,8 +5613,7 @@ flow_dv_validate_action_sample(uint64_t *action_flags, break; case RTE_FLOW_ACTION_TYPE_COUNT: ret = flow_dv_validate_action_count - (dev, is_shared_action_count(act), - *action_flags | sub_action_flags, + (dev, false, *action_flags | sub_action_flags, error); if (ret < 0) return ret; @@ -5670,6 +5623,7 @@ flow_dv_validate_action_sample(uint64_t *action_flags, ++actions_n; break; case RTE_FLOW_ACTION_TYPE_PORT_ID: + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: ret = flow_dv_validate_action_port_id(dev, sub_action_flags, act, @@ -6231,60 +6185,6 @@ err: return 0; } -/** - * Allocate a shared flow counter. - * - * @param[in] ctx - * Pointer to the shared counter configuration. - * @param[in] data - * Pointer to save the allocated counter index. - * - * @return - * Index to flow counter on success, 0 otherwise and rte_errno is set. - */ - -static int32_t -flow_dv_counter_alloc_shared_cb(void *ctx, union mlx5_l3t_data *data) -{ - struct mlx5_shared_counter_conf *conf = ctx; - struct rte_eth_dev *dev = conf->dev; - struct mlx5_flow_counter *cnt; - - data->dword = flow_dv_counter_alloc(dev, 0); - data->dword |= MLX5_CNT_SHARED_OFFSET; - cnt = flow_dv_counter_get_by_idx(dev, data->dword, NULL); - cnt->shared_info.id = conf->id; - return 0; -} - -/** - * Get a shared flow counter. - * - * @param[in] dev - * Pointer to the Ethernet device structure. - * @param[in] id - * Counter identifier. - * - * @return - * Index to flow counter on success, 0 otherwise and rte_errno is set. - */ -static uint32_t -flow_dv_counter_get_shared(struct rte_eth_dev *dev, uint32_t id) -{ - struct mlx5_priv *priv = dev->data->dev_private; - struct mlx5_shared_counter_conf conf = { - .dev = dev, - .id = id, - }; - union mlx5_l3t_data data = { - .dword = 0, - }; - - mlx5_l3t_prepare_entry(priv->sh->cnt_id_tbl, id, &data, - flow_dv_counter_alloc_shared_cb, &conf); - return data.dword; -} - /** * Get age param from counter index. * @@ -6367,27 +6267,16 @@ flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter) if (pool->is_aged) { flow_dv_counter_remove_from_age(dev, counter, cnt); } else { - /* - * If the counter action is shared by ID, the l3t_clear_entry - * function reduces its references counter. If after the - * reduction the action is still referenced, the function - * returns here and does not release it. - */ - if (IS_LEGACY_SHARED_CNT(counter) && - mlx5_l3t_clear_entry(priv->sh->cnt_id_tbl, - cnt->shared_info.id)) - return; /* * If the counter action is shared by indirect action API, * the atomic function reduces its references counter. * If after the reduction the action is still referenced, the * function returns here and does not release it. - * When the counter action is not shared neither by ID nor by + * When the counter action is not shared by * indirect action API, shared info is 1 before the reduction, * so this condition is failed and function doesn't return here. */ - if (!IS_LEGACY_SHARED_CNT(counter) && - __atomic_sub_fetch(&cnt->shared_info.refcnt, 1, + if (__atomic_sub_fetch(&cnt->shared_info.refcnt, 1, __ATOMIC_RELAXED)) return; } @@ -6921,6 +6810,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, const struct rte_flow_item *rule_items = items; const struct rte_flow_item *port_id_item = NULL; bool def_policy = false; + uint16_t udp_dport = 0; if (items == NULL) return -1; @@ -7095,6 +6985,14 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, ret = mlx5_flow_validate_item_udp(items, item_flags, next_protocol, error); + const struct rte_flow_item_udp *spec = items->spec; + const struct rte_flow_item_udp *mask = items->mask; + if (!mask) + mask = &rte_flow_item_udp_mask; + if (spec != NULL) + udp_dport = rte_be_to_cpu_16 + (spec->hdr.dst_port & + mask->hdr.dst_port); if (ret < 0) return ret; last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : @@ -7124,9 +7022,9 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, last_item = MLX5_FLOW_LAYER_GRE_KEY; break; case RTE_FLOW_ITEM_TYPE_VXLAN: - ret = mlx5_flow_validate_item_vxlan(dev, items, - item_flags, attr, - error); + ret = mlx5_flow_validate_item_vxlan(dev, udp_dport, + items, item_flags, + attr, error); if (ret < 0) return ret; last_item = MLX5_FLOW_LAYER_VXLAN; @@ -7288,6 +7186,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, case RTE_FLOW_ACTION_TYPE_VOID: break; case RTE_FLOW_ACTION_TYPE_PORT_ID: + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: ret = flow_dv_validate_action_port_id(dev, action_flags, actions, @@ -7418,8 +7317,9 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, ++actions_n; break; case MLX5_RTE_FLOW_ACTION_TYPE_COUNT: + shared_count = true; + /* fall-through. */ case RTE_FLOW_ACTION_TYPE_COUNT: - shared_count = is_shared_action_count(actions); ret = flow_dv_validate_action_count(dev, shared_count, action_flags, error); @@ -8922,6 +8822,7 @@ flow_dv_translate_item_vxlan(struct rte_eth_dev *dev, MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF); MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport); } + dport = MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport); if (!vxlan_v) return; if (!vxlan_m) { @@ -8931,7 +8832,10 @@ flow_dv_translate_item_vxlan(struct rte_eth_dev *dev, else vxlan_m = &nic_mask; } - if ((!attr->group && !attr->transfer && !priv->sh->tunnel_header_0_1) || + if ((priv->sh->steering_format_version == + MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 && + dport != MLX5_UDP_PORT_VXLAN) || + (!attr->group && !attr->transfer && !priv->sh->tunnel_header_0_1) || ((attr->group || attr->transfer) && !priv->sh->misc5_cap)) { void *misc_m; void *misc_v; @@ -9249,6 +9153,8 @@ flow_dv_translate_item_geneve_opt(struct rte_eth_dev *dev, void *matcher, MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len, geneve_opt_v->option_len + 1); } + MLX5_SET(fte_match_set_misc, misc_m, geneve_tlv_option_0_exist, 1); + MLX5_SET(fte_match_set_misc, misc_v, geneve_tlv_option_0_exist, 1); /* Set the data. */ if (geneve_opt_v->data) { memcpy(&opt_data_key, geneve_opt_v->data, @@ -9933,14 +9839,14 @@ flow_dv_translate_item_gtp_psc(void *matcher, void *key, if (!gtp_psc_m) gtp_psc_m = &rte_flow_item_gtp_psc_mask; dw_0.w32 = 0; - dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_m->pdu_type); - dw_0.qfi = gtp_psc_m->qfi; + dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_m->hdr.type); + dw_0.qfi = gtp_psc_m->hdr.qfi; MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_first_ext_dw_0, rte_cpu_to_be_32(dw_0.w32)); dw_0.w32 = 0; - dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->pdu_type & - gtp_psc_m->pdu_type); - dw_0.qfi = gtp_psc_v->qfi & gtp_psc_m->qfi; + dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->hdr.type & + gtp_psc_m->hdr.type); + dw_0.qfi = gtp_psc_v->hdr.qfi & gtp_psc_m->hdr.qfi; MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_first_ext_dw_0, rte_cpu_to_be_32(dw_0.w32)); } @@ -9958,12 +9864,13 @@ flow_dv_translate_item_gtp_psc(void *matcher, void *key, * Flow matcher value. * @param[in] item * Flow pattern to translate. - * @param[in] samples - * Sample IDs to be used in the matching. + * @param[in] last_item + * Last item flags. */ static void flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *matcher, - void *key, const struct rte_flow_item *item) + void *key, const struct rte_flow_item *item, + uint64_t last_item) { struct mlx5_priv *priv = dev->data->dev_private; const struct rte_flow_item_ecpri *ecpri_m = item->mask; @@ -9976,6 +9883,22 @@ flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *matcher, void *dw_m; void *dw_v; + /* + * In case of eCPRI over Ethernet, if EtherType is not specified, + * match on eCPRI EtherType implicitly. + */ + if (last_item & MLX5_FLOW_LAYER_OUTER_L2) { + void *hdrs_m, *hdrs_v, *l2m, *l2v; + + hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers); + hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); + l2m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, ethertype); + l2v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype); + if (*(uint16_t *)l2m == 0 && *(uint16_t *)l2v == 0) { + *(uint16_t *)l2m = UINT16_MAX; + *(uint16_t *)l2v = RTE_BE16(RTE_ETHER_TYPE_ECPRI); + } + } if (!ecpri_v) return; if (!ecpri_m) @@ -10739,12 +10662,12 @@ flow_dv_tag_release(struct rte_eth_dev *dev, } /** - * Translate port ID action to vport. + * Translate action PORT_ID / REPRESENTED_PORT to vport. * * @param[in] dev * Pointer to rte_eth_dev structure. * @param[in] action - * Pointer to the port ID action. + * Pointer to action PORT_ID / REPRESENTED_PORT. * @param[out] dst_port_id * The target port ID. * @param[out] error @@ -10761,10 +10684,29 @@ flow_dv_translate_action_port_id(struct rte_eth_dev *dev, { uint32_t port; struct mlx5_priv *priv; - const struct rte_flow_action_port_id *conf = - (const struct rte_flow_action_port_id *)action->conf; - port = conf->original ? dev->data->port_id : conf->id; + switch (action->type) { + case RTE_FLOW_ACTION_TYPE_PORT_ID: { + const struct rte_flow_action_port_id *conf; + + conf = (const struct rte_flow_action_port_id *)action->conf; + port = conf->original ? dev->data->port_id : conf->id; + break; + } + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: { + const struct rte_flow_action_ethdev *ethdev; + + ethdev = (const struct rte_flow_action_ethdev *)action->conf; + port = ethdev->port_id; + break; + } + default: + MLX5_ASSERT(false); + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "unknown E-Switch action"); + } + priv = mlx5_port_to_eswitch_info(port, false); if (!priv) return rte_flow_error_set(error, -rte_errno, @@ -10806,16 +10748,14 @@ flow_dv_translate_action_port_id(struct rte_eth_dev *dev, static uint32_t flow_dv_translate_create_counter(struct rte_eth_dev *dev, struct mlx5_flow *dev_flow, - const struct rte_flow_action_count *count, + const struct rte_flow_action_count *count + __rte_unused, const struct rte_flow_action_age *age) { uint32_t counter; struct mlx5_age_param *age_param; - if (count && count->shared) - counter = flow_dv_counter_get_shared(dev, count->id); - else - counter = flow_dv_counter_alloc(dev, !!age); + counter = flow_dv_counter_alloc(dev, !!age); if (!counter || age == NULL) return counter; age_param = flow_dv_counter_idx_get_age(dev, counter); @@ -10891,10 +10831,8 @@ flow_dv_hashfields_set(struct mlx5_flow *dev_flow, dev_flow->hash_fields = 0; #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT - if (rss_desc->level >= 2) { - dev_flow->hash_fields |= IBV_RX_HASH_INNER; + if (rss_desc->level >= 2) rss_inner = 1; - } #endif if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) || (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) { @@ -10917,6 +10855,12 @@ flow_dv_hashfields_set(struct mlx5_flow *dev_flow, dev_flow->hash_fields |= MLX5_IPV6_IBV_RX_HASH; } } + if (dev_flow->hash_fields == 0) + /* + * There is no match between the RSS types and the + * L3 protocol (IPv4/IPv6) defined in the flow rule. + */ + return; if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) || (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) { if (rss_types & ETH_RSS_UDP) { @@ -10942,6 +10886,8 @@ flow_dv_hashfields_set(struct mlx5_flow *dev_flow, dev_flow->hash_fields |= MLX5_TCP_IBV_RX_HASH; } } + if (rss_inner) + dev_flow->hash_fields |= IBV_RX_HASH_INNER; } /** @@ -10974,6 +10920,8 @@ flow_dv_hrxq_prepare(struct rte_eth_dev *dev, rss_desc->hash_fields = dev_flow->hash_fields; rss_desc->tunnel = !!(dh->layers & MLX5_FLOW_LAYER_TUNNEL); rss_desc->shared_rss = 0; + if (rss_desc->hash_fields == 0) + rss_desc->queue_num = 1; *hrxq_idx = mlx5_hrxq_get(dev, rss_desc); if (!*hrxq_idx) return NULL; @@ -11595,6 +11543,7 @@ flow_dv_translate_action_sample(struct rte_eth_dev *dev, break; } case RTE_FLOW_ACTION_TYPE_PORT_ID: + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: { struct mlx5_flow_dv_port_id_action_resource port_id_resource; @@ -12259,17 +12208,27 @@ flow_dv_aso_ct_dev_release(struct rte_eth_dev *dev, uint32_t idx) } static inline int -flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx) +flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx, + struct rte_flow_error *error) { uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(own_idx); uint32_t idx = MLX5_INDIRECT_ACT_CT_GET_IDX(own_idx); struct rte_eth_dev *owndev = &rte_eth_devices[owner]; - RTE_SET_USED(dev); + int ret; MLX5_ASSERT(owner < RTE_MAX_ETHPORTS); if (dev->data->dev_started != 1) - return -1; - return flow_dv_aso_ct_dev_release(owndev, idx); + return rte_flow_error_set(error, EAGAIN, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "Indirect CT action cannot be destroyed when the port is stopped"); + ret = flow_dv_aso_ct_dev_release(owndev, idx); + if (ret < 0) + return rte_flow_error_set(error, EAGAIN, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "Current state prevents indirect CT action from being destroyed"); + return ret; } /* @@ -12665,6 +12624,7 @@ flow_dv_translate(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_VOID: break; case RTE_FLOW_ACTION_TYPE_PORT_ID: + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: if (flow_dv_translate_action_port_id(dev, action, &port_id, error)) return -rte_errno; @@ -12785,10 +12745,13 @@ flow_dv_translate(struct rte_eth_dev *dev, MLX5_FLOW_FATE_QUEUE; break; case MLX5_RTE_FLOW_ACTION_TYPE_AGE: - flow->age = (uint32_t)(uintptr_t)(action->conf); - age_act = flow_aso_age_get_by_idx(dev, flow->age); - __atomic_fetch_add(&age_act->refcnt, 1, - __ATOMIC_RELAXED); + owner_idx = (uint32_t)(uintptr_t)action->conf; + age_act = flow_aso_age_get_by_idx(dev, owner_idx); + if (flow->age == 0) { + flow->age = owner_idx; + __atomic_fetch_add(&age_act->refcnt, 1, + __ATOMIC_RELAXED); + } age_act_pos = actions_n++; action_flags |= MLX5_FLOW_ACTION_AGE; break; @@ -12798,13 +12761,28 @@ flow_dv_translate(struct rte_eth_dev *dev, action_flags |= MLX5_FLOW_ACTION_AGE; break; case MLX5_RTE_FLOW_ACTION_TYPE_COUNT: - flow->counter = (uint32_t)(uintptr_t)(action->conf); - cnt_act = flow_dv_counter_get_by_idx(dev, flow->counter, + owner_idx = (uint32_t)(uintptr_t)action->conf; + cnt_act = flow_dv_counter_get_by_idx(dev, owner_idx, NULL); - __atomic_fetch_add(&cnt_act->shared_info.refcnt, 1, - __ATOMIC_RELAXED); - /* Save information first, will apply later. */ - action_flags |= MLX5_FLOW_ACTION_COUNT; + MLX5_ASSERT(cnt_act != NULL); + /** + * When creating meter drop flow in drop table, the + * counter should not overwrite the rte flow counter. + */ + if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER && + dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP) { + dev_flow->dv.actions[actions_n++] = + cnt_act->action; + } else { + if (flow->counter == 0) { + flow->counter = owner_idx; + __atomic_fetch_add + (&cnt_act->shared_info.refcnt, + 1, __ATOMIC_RELAXED); + } + /* Save information first, will apply later. */ + action_flags |= MLX5_FLOW_ACTION_COUNT; + } break; case RTE_FLOW_ACTION_TYPE_COUNT: if (!dev_conf->devx) { @@ -13124,9 +13102,13 @@ flow_dv_translate(struct rte_eth_dev *dev, else dev_flow->dv.actions[actions_n] = ct->dr_action_rply; - flow->indirect_type = MLX5_INDIRECT_ACTION_TYPE_CT; - flow->ct = owner_idx; - __atomic_fetch_add(&ct->refcnt, 1, __ATOMIC_RELAXED); + if (flow->ct == 0) { + flow->indirect_type = + MLX5_INDIRECT_ACTION_TYPE_CT; + flow->ct = owner_idx; + __atomic_fetch_add(&ct->refcnt, 1, + __ATOMIC_RELAXED); + } actions_n++; action_flags |= MLX5_FLOW_ACTION_CT; break; @@ -13145,8 +13127,7 @@ flow_dv_translate(struct rte_eth_dev *dev, * when they are not shared. */ if (action_flags & MLX5_FLOW_ACTION_AGE) { - if ((non_shared_age && - count && !count->shared) || + if ((non_shared_age && count) || !(priv->sh->flow_hit_aso_en && (attr->group || attr->transfer))) { /* Creates age by counters. */ @@ -13435,7 +13416,8 @@ flow_dv_translate(struct rte_eth_dev *dev, "cannot create eCPRI parser"); } flow_dv_translate_item_ecpri(dev, match_mask, - match_value, items); + match_value, items, + last_item); /* No other protocol should follow eCPRI layer. */ last_item = MLX5_FLOW_LAYER_ECPRI; break; @@ -13760,7 +13742,9 @@ flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow, #ifdef HAVE_MLX5DV_DR /* DR supports drop action placeholder. */ MLX5_ASSERT(priv->sh->dr_drop_action); - dv->actions[n++] = priv->sh->dr_drop_action; + dv->actions[n++] = dv->group ? + priv->sh->dr_drop_action : + priv->root_drop_action; #else /* For DV we use the explicit drop queue. */ MLX5_ASSERT(priv->drop_queue.hrxq); @@ -14304,7 +14288,7 @@ flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow) } /* Keep the current age handling by default. */ if (flow->indirect_type == MLX5_INDIRECT_ACTION_TYPE_CT && flow->ct) - flow_dv_aso_ct_release(dev, flow->ct); + flow_dv_aso_ct_release(dev, flow->ct, NULL); else if (flow->age) flow_dv_aso_age_release(dev, flow->age); if (flow->geneve_tlv_option) { @@ -14681,12 +14665,6 @@ __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx, return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "invalid shared action"); - remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss); - if (remaining) - return rte_flow_error_set(error, EBUSY, - RTE_FLOW_ERROR_TYPE_ACTION, - NULL, - "shared rss hrxq has references"); if (!__atomic_compare_exchange_n(&shared_rss->refcnt, &old_refcnt, 0, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) @@ -14694,6 +14672,12 @@ __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "shared rss has references"); + remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss); + if (remaining) + return rte_flow_error_set(error, EBUSY, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "shared rss hrxq has references"); queue = shared_rss->ind_tbl->queues; remaining = mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true); if (remaining) @@ -14839,7 +14823,7 @@ flow_dv_action_destroy(struct rte_eth_dev *dev, " released with references %d.", idx, ret); return 0; case MLX5_INDIRECT_ACTION_TYPE_CT: - ret = flow_dv_aso_ct_release(dev, idx); + ret = flow_dv_aso_ct_release(dev, idx, error); if (ret < 0) return ret; if (ret > 0) @@ -15058,15 +15042,15 @@ __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev, policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) next_fm = mlx5_flow_meter_find(priv, policy->act_cnt[i].next_mtr_id, NULL); - TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i], + RTE_TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i], next_port, tmp) { claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule)); tbl = container_of(color_rule->matcher->tbl, - typeof(*tbl), tbl); + typeof(*tbl), tbl); mlx5_list_unregister(tbl->matchers, - &color_rule->matcher->entry); + &color_rule->matcher->entry); TAILQ_REMOVE(&sub_policy->color_rules[i], - color_rule, next_port); + color_rule, next_port); mlx5_free(color_rule); if (next_fm) mlx5_flow_meter_detach(priv, next_fm); @@ -15080,13 +15064,13 @@ __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev, } if (sub_policy->jump_tbl[i]) { flow_dv_tbl_resource_release(MLX5_SH(dev), - sub_policy->jump_tbl[i]); + sub_policy->jump_tbl[i]); sub_policy->jump_tbl[i] = NULL; } } if (sub_policy->tbl_rsc) { flow_dv_tbl_resource_release(MLX5_SH(dev), - sub_policy->tbl_rsc); + sub_policy->tbl_rsc); sub_policy->tbl_rsc = NULL; } } @@ -15103,7 +15087,7 @@ __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev, */ static void flow_dv_destroy_policy_rules(struct rte_eth_dev *dev, - struct mlx5_flow_meter_policy *mtr_policy) + struct mlx5_flow_meter_policy *mtr_policy) { uint32_t i, j; struct mlx5_flow_meter_sub_policy *sub_policy; @@ -15116,8 +15100,8 @@ flow_dv_destroy_policy_rules(struct rte_eth_dev *dev, for (j = 0; j < sub_policy_num; j++) { sub_policy = mtr_policy->sub_policys[i][j]; if (sub_policy) - __flow_dv_destroy_sub_policy_rules - (dev, sub_policy); + __flow_dv_destroy_sub_policy_rules(dev, + sub_policy); } } } @@ -15237,6 +15221,10 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev, for (i = 0; i < RTE_COLORS; i++) { if (i < MLX5_MTR_RTE_COLORS) act_cnt = &mtr_policy->act_cnt[i]; + /* Skip the color policy actions creation. */ + if ((i == RTE_COLOR_YELLOW && mtr_policy->skip_y) || + (i == RTE_COLOR_GREEN && mtr_policy->skip_g)) + continue; action_flags = 0; for (act = actions[i]; act && act->type != RTE_FLOW_ACTION_TYPE_END; act++) { @@ -15397,6 +15385,7 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev, break; } case RTE_FLOW_ACTION_TYPE_PORT_ID: + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: { struct mlx5_flow_dv_port_id_action_resource port_id_resource; @@ -16150,6 +16139,7 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev, bool match_src_port = false; int i; + /* If RSS or Queue, no previous actions / rules is created. */ for (i = 0; i < RTE_COLORS; i++) { acts[i].actions_n = 0; if (i == RTE_COLOR_RED) { @@ -16649,37 +16639,36 @@ __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev, sub_policy_num = (mtr_policy->sub_policy_num >> (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & MLX5_MTR_SUB_POLICY_NUM_MASK; - for (i = 0; i < sub_policy_num; - i++) { - for (j = 0; j < MLX5_MTR_RTE_COLORS; j++) { - if (rss_desc[j] && - hrxq_idx[j] != - mtr_policy->sub_policys[domain][i]->rix_hrxq[j]) + for (j = 0; j < sub_policy_num; j++) { + for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { + if (rss_desc[i] && + hrxq_idx[i] != + mtr_policy->sub_policys[domain][j]->rix_hrxq[i]) break; } - if (j >= MLX5_MTR_RTE_COLORS) { + if (i >= MLX5_MTR_RTE_COLORS) { /* * Found the sub policy table with - * the same queue per color + * the same queue per color. */ rte_spinlock_unlock(&mtr_policy->sl); - for (j = 0; j < MLX5_MTR_RTE_COLORS; j++) - mlx5_hrxq_release(dev, hrxq_idx[j]); + for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) + mlx5_hrxq_release(dev, hrxq_idx[i]); *is_reuse = true; - return mtr_policy->sub_policys[domain][i]; + return mtr_policy->sub_policys[domain][j]; } } /* Create sub policy. */ if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) { - /* Reuse the first dummy sub_policy*/ + /* Reuse the first pre-allocated sub_policy. */ sub_policy = mtr_policy->sub_policys[domain][0]; sub_policy_idx = sub_policy->idx; } else { sub_policy = mlx5_ipool_zmalloc (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], - &sub_policy_idx); + &sub_policy_idx); if (!sub_policy || - sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) { + sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) { for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) mlx5_hrxq_release(dev, hrxq_idx[i]); goto rss_sub_policy_error; @@ -16701,9 +16690,9 @@ __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev, * RSS action to Queue action. */ hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ], - hrxq_idx[i]); + hrxq_idx[i]); if (!hrxq) { - DRV_LOG(ERR, "Failed to create policy hrxq"); + DRV_LOG(ERR, "Failed to get policy hrxq"); goto rss_sub_policy_error; } act_cnt = &mtr_policy->act_cnt[i]; @@ -16718,19 +16707,21 @@ __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev, } } if (__flow_dv_create_policy_acts_rules(dev, mtr_policy, - sub_policy, domain)) { + sub_policy, domain)) { DRV_LOG(ERR, "Failed to create policy " - "rules per domain."); + "rules for ingress domain."); goto rss_sub_policy_error; } if (sub_policy != mtr_policy->sub_policys[domain][0]) { i = (mtr_policy->sub_policy_num >> (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & MLX5_MTR_SUB_POLICY_NUM_MASK; + if (i >= MLX5_MTR_RSS_MAX_SUB_POLICY) { + DRV_LOG(ERR, "No free sub-policy slot."); + goto rss_sub_policy_error; + } mtr_policy->sub_policys[domain][i] = sub_policy; i++; - if (i > MLX5_MTR_RSS_MAX_SUB_POLICY) - goto rss_sub_policy_error; mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK << (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)); mtr_policy->sub_policy_num |= @@ -16748,8 +16739,7 @@ rss_sub_policy_error: (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) & MLX5_MTR_SUB_POLICY_NUM_MASK; mtr_policy->sub_policys[domain][i] = NULL; - mlx5_ipool_free - (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], + mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], sub_policy->idx); } } @@ -16810,7 +16800,7 @@ flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev, while (i) { /** * From last policy to the first one in hierarchy, - * create/get the sub policy for each of them. + * create / get the sub policy for each of them. */ sub_policy = __flow_dv_meter_get_rss_sub_policy(dev, policies[--i], @@ -17014,7 +17004,7 @@ err_exit: */ static void flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev, - struct mlx5_flow_meter_policy *mtr_policy) + struct mlx5_flow_meter_policy *mtr_policy) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_flow_meter_sub_policy *sub_policy = NULL; @@ -17060,7 +17050,7 @@ flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev, case MLX5_FLOW_FATE_QUEUE: sub_policy = mtr_policy->sub_policys[domain][0]; __flow_dv_destroy_sub_policy_rules(dev, - sub_policy); + sub_policy); break; default: /*Other actions without queue and do nothing*/ @@ -17069,6 +17059,74 @@ flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev, } rte_spinlock_unlock(&mtr_policy->sl); } +/** + * Check whether the DR drop action is supported on the root table or not. + * + * Create a simple flow with DR drop action on root table to validate + * if DR drop action on root table is supported or not. + * + * @param[in] dev + * Pointer to rte_eth_dev structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_flow_discover_dr_action_support(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_dev_ctx_shared *sh = priv->sh; + struct mlx5_flow_dv_match_params mask = { + .size = sizeof(mask.buf), + }; + struct mlx5_flow_dv_match_params value = { + .size = sizeof(value.buf), + }; + struct mlx5dv_flow_matcher_attr dv_attr = { + .type = IBV_FLOW_ATTR_NORMAL, + .priority = 0, + .match_criteria_enable = 0, + .match_mask = (void *)&mask, + }; + struct mlx5_flow_tbl_resource *tbl = NULL; + void *matcher = NULL; + void *flow = NULL; + int ret = -1; + + tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL, + 0, 0, 0, NULL); + if (!tbl) + goto err; + dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf); + __flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable); + ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj, + &matcher); + if (ret) + goto err; + __flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable); + ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1, + &sh->dr_drop_action, &flow); +err: + /* + * If DR drop action is not supported on root table, flow create will + * be failed with EOPNOTSUPP or EPROTONOSUPPORT. + */ + if (!flow) { + if (matcher && + (errno == EPROTONOSUPPORT || errno == EOPNOTSUPP)) + DRV_LOG(INFO, "DR drop action is not supported in root table."); + else + DRV_LOG(ERR, "Unexpected error in DR drop action support detection"); + ret = -1; + } else { + claim_zero(mlx5_flow_os_destroy_flow(flow)); + } + if (matcher) + claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher)); + if (tbl) + flow_dv_tbl_resource_release(MLX5_SH(dev), tbl); + return ret; +} /** * Validate the batch counter support in root table. @@ -17221,7 +17279,7 @@ flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear, * @note: only stub for now */ static int -flow_get_aged_flows(struct rte_eth_dev *dev, +flow_dv_get_aged_flows(struct rte_eth_dev *dev, void **context, uint32_t nb_contexts, struct rte_flow_error *error) @@ -17322,18 +17380,6 @@ flow_dv_action_validate(struct rte_eth_dev *dev, "Indirect age action not supported"); return flow_dv_validate_action_age(0, action, dev, err); case RTE_FLOW_ACTION_TYPE_COUNT: - /* - * There are two mechanisms to share the action count. - * The old mechanism uses the shared field to share, while the - * new mechanism uses the indirect action API. - * This validation comes to make sure that the two mechanisms - * are not combined. - */ - if (is_shared_action_count(action)) - return rte_flow_error_set(err, ENOTSUP, - RTE_FLOW_ERROR_TYPE_ACTION, - NULL, - "Mix shared and indirect counter is not supported"); return flow_dv_validate_action_count(dev, true, 0, err); case RTE_FLOW_ACTION_TYPE_CONNTRACK: if (!priv->sh->ct_aso_en) @@ -17349,6 +17395,31 @@ flow_dv_action_validate(struct rte_eth_dev *dev, } } +/* + * Check if the RSS configurations for colors of a meter policy match + * each other, except the queues. + * + * @param[in] r1 + * Pointer to the first RSS flow action. + * @param[in] r2 + * Pointer to the second RSS flow action. + * + * @return + * 0 on match, 1 on conflict. + */ +static inline int +flow_dv_mtr_policy_rss_compare(const struct rte_flow_action_rss *r1, + const struct rte_flow_action_rss *r2) +{ + if (!r1 || !r2) + return 0; + if (r1->func != r2->func || r1->level != r2->level || + r1->types != r2->types || r1->key_len != r2->key_len || + memcmp(r1->key, r2->key, r1->key_len)) + return 1; + return 0; +} + /** * Validate the meter hierarchy chain for meter policy. * @@ -17388,6 +17459,7 @@ flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev, RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN, NULL, "Multiple fate actions not supported."); + *hierarchy_domain = 0; while (true) { fm = mlx5_flow_meter_find(priv, meter_id, NULL); if (!fm) @@ -17400,7 +17472,12 @@ flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev, "Non termination meter not supported in hierarchy."); policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL); MLX5_ASSERT(policy); - if (!policy->is_hierarchy) { + /** + * Only inherit the supported domains of the first meter in + * hierarchy. + * One meter supports at least one domain. + */ + if (!*hierarchy_domain) { if (policy->transfer) *hierarchy_domain |= MLX5_MTR_DOMAIN_TRANSFER_BIT; @@ -17409,6 +17486,8 @@ flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev, MLX5_MTR_DOMAIN_INGRESS_BIT; if (policy->egress) *hierarchy_domain |= MLX5_MTR_DOMAIN_EGRESS_BIT; + } + if (!policy->is_hierarchy) { *is_rss = policy->is_rss; break; } @@ -17444,13 +17523,13 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, struct rte_flow_attr *attr, bool *is_rss, uint8_t *domain_bitmap, - bool *is_def_policy, + uint8_t *policy_mode, struct rte_mtr_error *error) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_dev_config *dev_conf = &priv->config; const struct rte_flow_action *act; - uint64_t action_flags = 0; + uint64_t action_flags[RTE_COLORS] = {0}; int actions_n; int i, ret; struct rte_flow_error flow_err; @@ -17458,42 +17537,52 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT; uint8_t hierarchy_domain = 0; const struct rte_flow_action_meter *mtr; + bool def_green = false; + bool def_yellow = false; + const struct rte_flow_action_rss *rss_color[RTE_COLORS] = {NULL}; if (!priv->config.dv_esw_en) def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT; *domain_bitmap = def_domain; - if (actions[RTE_COLOR_YELLOW] && - actions[RTE_COLOR_YELLOW]->type != RTE_FLOW_ACTION_TYPE_END) - return -rte_mtr_error_set(error, ENOTSUP, - RTE_MTR_ERROR_TYPE_METER_POLICY, - NULL, - "Yellow color does not support any action."); - if (actions[RTE_COLOR_YELLOW] && - actions[RTE_COLOR_YELLOW]->type != RTE_FLOW_ACTION_TYPE_DROP) + /* Red color could only support DROP action. */ + if (!actions[RTE_COLOR_RED] || + actions[RTE_COLOR_RED]->type != RTE_FLOW_ACTION_TYPE_DROP) return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, "Red color only supports drop action."); /* * Check default policy actions: - * Green/Yellow: no action, Red: drop action + * Green / Yellow: no action, Red: drop action + * Either G or Y will trigger default policy actions to be created. */ - if ((!actions[RTE_COLOR_GREEN] || - actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END)) { - *is_def_policy = true; + if (!actions[RTE_COLOR_GREEN] || + actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END) + def_green = true; + if (!actions[RTE_COLOR_YELLOW] || + actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END) + def_yellow = true; + if (def_green && def_yellow) { + *policy_mode = MLX5_MTR_POLICY_MODE_DEF; return 0; + } else if (!def_green && def_yellow) { + *policy_mode = MLX5_MTR_POLICY_MODE_OG; + } else if (def_green && !def_yellow) { + *policy_mode = MLX5_MTR_POLICY_MODE_OY; } - flow_err.message = NULL; + /* Set to empty string in case of NULL pointer access by user. */ + flow_err.message = ""; for (i = 0; i < RTE_COLORS; i++) { act = actions[i]; - for (action_flags = 0, actions_n = 0; - act && act->type != RTE_FLOW_ACTION_TYPE_END; - act++) { + for (action_flags[i] = 0, actions_n = 0; + act && act->type != RTE_FLOW_ACTION_TYPE_END; + act++) { if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS) return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, "too many actions"); switch (act->type) { case RTE_FLOW_ACTION_TYPE_PORT_ID: + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: if (!priv->config.dv_esw_en) return -rte_mtr_error_set(error, ENOTSUP, @@ -17501,7 +17590,7 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, NULL, "PORT action validate check" " fail for ESW disable"); ret = flow_dv_validate_action_port_id(dev, - action_flags, + action_flags[i], act, attr, &flow_err); if (ret) return -rte_mtr_error_set(error, @@ -17511,11 +17600,11 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, flow_err.message : "PORT action validate check fail"); ++actions_n; - action_flags |= MLX5_FLOW_ACTION_PORT_ID; + action_flags[i] |= MLX5_FLOW_ACTION_PORT_ID; break; case RTE_FLOW_ACTION_TYPE_MARK: ret = flow_dv_validate_action_mark(dev, act, - action_flags, + action_flags[i], attr, &flow_err); if (ret < 0) return -rte_mtr_error_set(error, @@ -17532,12 +17621,12 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, NULL, "Extend MARK action is " "not supported. Please try use " "default policy for meter."); - action_flags |= MLX5_FLOW_ACTION_MARK; + action_flags[i] |= MLX5_FLOW_ACTION_MARK; ++actions_n; break; case RTE_FLOW_ACTION_TYPE_SET_TAG: ret = flow_dv_validate_action_set_tag(dev, - act, action_flags, + act, action_flags[i], attr, &flow_err); if (ret) return -rte_mtr_error_set(error, @@ -17546,19 +17635,12 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, NULL, flow_err.message ? flow_err.message : "Set tag action validate check fail"); - /* - * Count all modify-header actions - * as one action. - */ - if (!(action_flags & - MLX5_FLOW_MODIFY_HDR_ACTIONS)) - ++actions_n; - action_flags |= MLX5_FLOW_ACTION_SET_TAG; + action_flags[i] |= MLX5_FLOW_ACTION_SET_TAG; + ++actions_n; break; case RTE_FLOW_ACTION_TYPE_DROP: ret = mlx5_flow_validate_action_drop - (action_flags, - attr, &flow_err); + (action_flags[i], attr, &flow_err); if (ret < 0) return -rte_mtr_error_set(error, ENOTSUP, @@ -17566,7 +17648,7 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, NULL, flow_err.message ? flow_err.message : "Drop action validate check fail"); - action_flags |= MLX5_FLOW_ACTION_DROP; + action_flags[i] |= MLX5_FLOW_ACTION_DROP; ++actions_n; break; case RTE_FLOW_ACTION_TYPE_QUEUE: @@ -17575,9 +17657,9 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, * metadata feature is engaged. */ if (dev_conf->dv_flow_en && - (dev_conf->dv_xmeta_en != - MLX5_XMETA_MODE_LEGACY) && - mlx5_flow_ext_mreg_supported(dev)) + (dev_conf->dv_xmeta_en != + MLX5_XMETA_MODE_LEGACY) && + mlx5_flow_ext_mreg_supported(dev)) return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_POLICY, @@ -17585,7 +17667,7 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, "is not supported. Please try use " "default policy for meter."); ret = mlx5_flow_validate_action_queue(act, - action_flags, dev, + action_flags[i], dev, attr, &flow_err); if (ret < 0) return -rte_mtr_error_set(error, @@ -17594,14 +17676,14 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, NULL, flow_err.message ? flow_err.message : "Queue action validate check fail"); - action_flags |= MLX5_FLOW_ACTION_QUEUE; + action_flags[i] |= MLX5_FLOW_ACTION_QUEUE; ++actions_n; break; case RTE_FLOW_ACTION_TYPE_RSS: if (dev_conf->dv_flow_en && - (dev_conf->dv_xmeta_en != - MLX5_XMETA_MODE_LEGACY) && - mlx5_flow_ext_mreg_supported(dev)) + (dev_conf->dv_xmeta_en != + MLX5_XMETA_MODE_LEGACY) && + mlx5_flow_ext_mreg_supported(dev)) return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_POLICY, @@ -17609,7 +17691,7 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, "is not supported. Please try use " "default policy for meter."); ret = mlx5_validate_action_rss(dev, act, - &flow_err); + &flow_err); if (ret < 0) return -rte_mtr_error_set(error, ENOTSUP, @@ -17617,13 +17699,14 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, NULL, flow_err.message ? flow_err.message : "RSS action validate check fail"); - action_flags |= MLX5_FLOW_ACTION_RSS; + action_flags[i] |= MLX5_FLOW_ACTION_RSS; ++actions_n; - *is_rss = true; + /* Either G or Y will set the RSS. */ + rss_color[i] = act->conf; break; case RTE_FLOW_ACTION_TYPE_JUMP: ret = flow_dv_validate_action_jump(dev, - NULL, act, action_flags, + NULL, act, action_flags[i], attr, true, &flow_err); if (ret) return -rte_mtr_error_set(error, @@ -17633,27 +17716,37 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, flow_err.message : "Jump action validate check fail"); ++actions_n; - action_flags |= MLX5_FLOW_ACTION_JUMP; + action_flags[i] |= MLX5_FLOW_ACTION_JUMP; break; + /* + * Only the last meter in the hierarchy will support + * the YELLOW color steering. Then in the meter policy + * actions list, there should be no other meter inside. + */ case RTE_FLOW_ACTION_TYPE_METER: if (i != RTE_COLOR_GREEN) return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_POLICY, - NULL, flow_err.message ? - flow_err.message : - "Meter hierarchy only supports GREEN color."); + NULL, + "Meter hierarchy only supports GREEN color."); + if (*policy_mode != MLX5_MTR_POLICY_MODE_OG) + return -rte_mtr_error_set(error, + ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY, + NULL, + "No yellow policy should be provided in meter hierarchy."); mtr = act->conf; ret = flow_dv_validate_policy_mtr_hierarchy(dev, mtr->mtr_id, - action_flags, + action_flags[i], is_rss, &hierarchy_domain, error); if (ret) return ret; ++actions_n; - action_flags |= + action_flags[i] |= MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY; break; default: @@ -17663,31 +17756,38 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, "Doesn't support optional action"); } } - /* Yellow is not supported, just skip. */ - if (i == RTE_COLOR_YELLOW) - continue; - if (action_flags & MLX5_FLOW_ACTION_PORT_ID) + if (action_flags[i] & MLX5_FLOW_ACTION_PORT_ID) domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT; - else if ((action_flags & - (MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) || - (action_flags & MLX5_FLOW_ACTION_MARK)) + else if ((action_flags[i] & + (MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) || + (action_flags[i] & MLX5_FLOW_ACTION_MARK)) /* * Only support MLX5_XMETA_MODE_LEGACY - * so MARK action only in ingress domain. + * so MARK action is only in ingress domain. */ domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT; - else if (action_flags & - MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) - domain_color[i] = hierarchy_domain; else domain_color[i] = def_domain; + if (action_flags[i] & + MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) + domain_color[i] &= hierarchy_domain; + /* + * Non-termination actions only support NIC Tx domain. + * The adjustion should be skipped when there is no + * action or only END is provided. The default domains + * bit-mask is set to find the MIN intersection. + * The action flags checking should also be skipped. + */ + if ((def_green && i == RTE_COLOR_GREEN) || + (def_yellow && i == RTE_COLOR_YELLOW)) + continue; /* * Validate the drop action mutual exclusion * with other actions. Drop action is mutually-exclusive * with any other action, except for Count action. */ - if ((action_flags & MLX5_FLOW_ACTION_DROP) && - (action_flags & ~MLX5_FLOW_ACTION_DROP)) { + if ((action_flags[i] & MLX5_FLOW_ACTION_DROP) && + (action_flags[i] & ~MLX5_FLOW_ACTION_DROP)) { return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, "Drop action is mutually-exclusive " @@ -17696,40 +17796,60 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, /* Eswitch has few restrictions on using items and actions */ if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) { if (!mlx5_flow_ext_mreg_supported(dev) && - action_flags & MLX5_FLOW_ACTION_MARK) + action_flags[i] & MLX5_FLOW_ACTION_MARK) return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, "unsupported action MARK"); - if (action_flags & MLX5_FLOW_ACTION_QUEUE) + if (action_flags[i] & MLX5_FLOW_ACTION_QUEUE) return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, "unsupported action QUEUE"); - if (action_flags & MLX5_FLOW_ACTION_RSS) + if (action_flags[i] & MLX5_FLOW_ACTION_RSS) return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, "unsupported action RSS"); - if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) + if (!(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS)) return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, "no fate action is found"); } else { - if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && - (domain_color[i] & - MLX5_MTR_DOMAIN_INGRESS_BIT)) { + if (!(action_flags[i] & MLX5_FLOW_FATE_ACTIONS) && + (domain_color[i] & MLX5_MTR_DOMAIN_INGRESS_BIT)) { if ((domain_color[i] & - MLX5_MTR_DOMAIN_EGRESS_BIT)) + MLX5_MTR_DOMAIN_EGRESS_BIT)) domain_color[i] = - MLX5_MTR_DOMAIN_EGRESS_BIT; + MLX5_MTR_DOMAIN_EGRESS_BIT; else return -rte_mtr_error_set(error, - ENOTSUP, - RTE_MTR_ERROR_TYPE_METER_POLICY, - NULL, "no fate action is found"); + ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY, + NULL, + "no fate action is found"); } } - if (domain_color[i] != def_domain) - *domain_bitmap = domain_color[i]; } + /* If both colors have RSS, the attributes should be the same. */ + if (flow_dv_mtr_policy_rss_compare(rss_color[RTE_COLOR_GREEN], + rss_color[RTE_COLOR_YELLOW])) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_METER_POLICY, + NULL, "policy RSS attr conflict"); + if (rss_color[RTE_COLOR_GREEN] || rss_color[RTE_COLOR_YELLOW]) + *is_rss = true; + /* "domain_color[C]" is non-zero for each color, default is ALL. */ + if (!def_green && !def_yellow && + domain_color[RTE_COLOR_GREEN] != domain_color[RTE_COLOR_YELLOW] && + !(action_flags[RTE_COLOR_GREEN] & MLX5_FLOW_ACTION_DROP) && + !(action_flags[RTE_COLOR_YELLOW] & MLX5_FLOW_ACTION_DROP)) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_METER_POLICY, + NULL, "policy domains conflict"); + /* + * At least one color policy is listed in the actions, the domains + * to be supported should be the intersection. + */ + *domain_bitmap = domain_color[RTE_COLOR_GREEN] & + domain_color[RTE_COLOR_YELLOW]; return 0; } @@ -17784,7 +17904,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = { .counter_alloc = flow_dv_counter_allocate, .counter_free = flow_dv_counter_free, .counter_query = flow_dv_counter_query, - .get_aged_flows = flow_get_aged_flows, + .get_aged_flows = flow_dv_get_aged_flows, .action_validate = flow_dv_action_validate, .action_create = flow_dv_action_create, .action_destroy = flow_dv_action_destroy,