* Copyright 2016 Mellanox Technologies, Ltd
*/
-#include <netinet/in.h>
-#include <sys/queue.h>
#include <stdalign.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
+#include <sys/queue.h>
#include <rte_common.h>
#include <rte_ether.h>
#include "mlx5.h"
#include "mlx5_flow.h"
#include "mlx5_flow_os.h"
-#include "mlx5_rxtx.h"
+#include "mlx5_rx.h"
+#include "mlx5_tx.h"
#include "mlx5_common_os.h"
#include "rte_pmd_mlx5.h"
}
node = *next_node ? &graph[*next_node] : NULL;
};
- /* no expanded flows but we have missed item, create one rule for it */
- if (buf->entries == 1 && missed != 0) {
- elt = 2;
- lsize += elt * sizeof(*item) + user_pattern_size;
- if (lsize <= size) {
- buf->entry[buf->entries].priority = 1;
- buf->entry[buf->entries].pattern = addr;
- buf->entries++;
- flow_items[0].type = missed_item.type;
- flow_items[1].type = RTE_FLOW_ITEM_TYPE_END;
- rte_memcpy(addr, buf->entry[0].pattern,
- user_pattern_size);
- addr = (void *)(((uintptr_t)addr) + user_pattern_size);
- rte_memcpy(addr, flow_items, elt * sizeof(*item));
- }
- }
return lsize;
}
(MLX5_EXPANSION_OUTER_IPV6_UDP,
MLX5_EXPANSION_OUTER_IPV6_TCP,
MLX5_EXPANSION_IPV4,
- MLX5_EXPANSION_IPV6),
+ MLX5_EXPANSION_IPV6,
+ MLX5_EXPANSION_GRE),
.type = RTE_FLOW_ITEM_TYPE_IPV6,
.rss_types = ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 |
ETH_RSS_NONFRAG_IPV6_OTHER,
.type = RTE_FLOW_ITEM_TYPE_VXLAN_GPE,
},
[MLX5_EXPANSION_GRE] = {
- .next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4),
+ .next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4,
+ MLX5_EXPANSION_IPV6),
.type = RTE_FLOW_ITEM_TYPE_GRE,
},
[MLX5_EXPANSION_MPLS] = {
},
};
-static struct rte_flow_shared_action *
-mlx5_shared_action_create(struct rte_eth_dev *dev,
- const struct rte_flow_shared_action_conf *conf,
+static struct rte_flow_action_handle *
+mlx5_action_handle_create(struct rte_eth_dev *dev,
+ const struct rte_flow_indir_action_conf *conf,
const struct rte_flow_action *action,
struct rte_flow_error *error);
-static int mlx5_shared_action_destroy
+static int mlx5_action_handle_destroy
(struct rte_eth_dev *dev,
- struct rte_flow_shared_action *shared_action,
+ struct rte_flow_action_handle *handle,
struct rte_flow_error *error);
-static int mlx5_shared_action_update
+static int mlx5_action_handle_update
(struct rte_eth_dev *dev,
- struct rte_flow_shared_action *shared_action,
- const struct rte_flow_action *action,
+ struct rte_flow_action_handle *handle,
+ const void *update,
struct rte_flow_error *error);
-static int mlx5_shared_action_query
+static int mlx5_action_handle_query
(struct rte_eth_dev *dev,
- const struct rte_flow_shared_action *action,
+ const struct rte_flow_action_handle *handle,
void *data,
struct rte_flow_error *error);
static int
.query = mlx5_flow_query,
.dev_dump = mlx5_flow_dev_dump,
.get_aged_flows = mlx5_flow_get_aged_flows,
- .shared_action_create = mlx5_shared_action_create,
- .shared_action_destroy = mlx5_shared_action_destroy,
- .shared_action_update = mlx5_shared_action_update,
- .shared_action_query = mlx5_shared_action_query,
+ .action_handle_create = mlx5_action_handle_create,
+ .action_handle_destroy = mlx5_action_handle_destroy,
+ .action_handle_update = mlx5_action_handle_update,
+ .action_handle_query = mlx5_action_handle_query,
.tunnel_decap_set = mlx5_flow_tunnel_decap_set,
.tunnel_match = mlx5_flow_tunnel_match,
.tunnel_action_decap_release = mlx5_flow_tunnel_action_release,
return REG_C_0;
}
break;
- case MLX5_MTR_SFX:
+ case MLX5_MTR_ID:
/*
- * If meter color and flow match share one register, flow match
+ * If meter color and meter id share one register, flow match
* should use the meter color register for match.
*/
if (priv->mtr_reg_share)
return config->flow_mreg_c[2] != REG_NON;
}
+/**
+ * Get the lowest priority.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] attributes
+ * Pointer to device flow rule attributes.
+ *
+ * @return
+ * The value of lowest priority of flow.
+ */
+uint32_t
+mlx5_get_lowest_priority(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+
+ if (!attr->group && !attr->transfer)
+ return priv->config.flow_prio - 2;
+ return MLX5_NON_ROOT_FLOW_MAX_PRIO - 1;
+}
+
+/**
+ * Calculate matcher priority of the flow.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] attr
+ * Pointer to device flow rule attributes.
+ * @param[in] subpriority
+ * The priority based on the items.
+ * @return
+ * The matcher priority of the flow.
+ */
+uint16_t
+mlx5_get_matcher_priority(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ uint32_t subpriority)
+{
+ uint16_t priority = (uint16_t)attr->priority;
+ struct mlx5_priv *priv = dev->data->dev_private;
+
+ if (!attr->group && !attr->transfer) {
+ if (attr->priority == MLX5_FLOW_LOWEST_PRIO_INDICATOR)
+ priority = priv->config.flow_prio - 1;
+ return mlx5_os_flow_adjust_priority(dev, priority, subpriority);
+ }
+ if (attr->priority == MLX5_FLOW_LOWEST_PRIO_INDICATOR)
+ priority = MLX5_NON_ROOT_FLOW_MAX_PRIO;
+ return priority * 3 + subpriority;
+}
+
/**
* Verify the @p item specifications (spec, last, mask) are compatible with the
* NIC capabilities.
* @param[in] dev_handle
* Pointer to device flow handle structure.
*/
-static void
+void
flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
struct mlx5_flow_handle *dev_handle)
{
data->dynf_meta = 0;
data->flow_meta_mask = 0;
data->flow_meta_offset = -1;
+ data->flow_meta_port_mask = 0;
} else {
data->dynf_meta = 1;
data->flow_meta_mask = rte_flow_dynf_metadata_mask;
data->flow_meta_offset = rte_flow_dynf_metadata_offs;
+ data->flow_meta_port_mask = (uint32_t)~0;
+ if (priv->config.dv_xmeta_en == MLX5_XMETA_MODE_META16)
+ data->flow_meta_port_mask >>= 16;
}
}
}
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
NULL, "groups is not supported");
- if (attributes->priority != MLX5_FLOW_PRIO_RSVD &&
+ if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR &&
attributes->priority >= priority_max)
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
handle_idx, dev_handle, next)
- if (dev_handle->split_flow_id)
+ if (dev_handle->split_flow_id &&
+ !dev_handle->is_meter_flow_id)
mlx5_ipool_free(priv->sh->ipool
[MLX5_IPOOL_RSS_EXPANTION_FLOW_ID],
dev_handle->split_flow_id);
return &pool->actions[offset - 1];
}
-/* maps shared action to translated non shared in some actions array */
-struct mlx5_translated_shared_action {
- struct rte_flow_shared_action *action; /**< Shared action */
- int index; /**< Index in related array of rte_flow_action */
+/* maps indirect action to translated direct in some actions array */
+struct mlx5_translated_action_handle {
+ struct rte_flow_action_handle *action; /**< Indirect action handle. */
+ int index; /**< Index in related array of rte_flow_action. */
};
/**
- * Translates actions of type RTE_FLOW_ACTION_TYPE_SHARED to related
- * non shared action if translation possible.
- * This functionality used to run same execution path for both shared & non
- * shared actions on flow create. All necessary preparations for shared
- * action handling should be preformed on *shared* actions list returned
+ * Translates actions of type RTE_FLOW_ACTION_TYPE_INDIRECT to related
+ * direct action if translation possible.
+ * This functionality used to run same execution path for both direct and
+ * indirect actions on flow create. All necessary preparations for indirect
+ * action handling should be performed on *handle* actions list returned
* from this call.
*
* @param[in] dev
* Pointer to Ethernet device.
* @param[in] actions
* List of actions to translate.
- * @param[out] shared
- * List to store translated shared actions.
- * @param[in, out] shared_n
- * Size of *shared* array. On return should be updated with number of shared
- * actions retrieved from the *actions* list.
+ * @param[out] handle
+ * List to store translated indirect action object handles.
+ * @param[in, out] indir_n
+ * Size of *handle* array. On return should be updated with number of
+ * indirect actions retrieved from the *actions* list.
* @param[out] translated_actions
- * List of actions where all shared actions were translated to non shared
+ * List of actions where all indirect actions were translated to direct
* if possible. NULL if no translation took place.
* @param[out] error
* Pointer to the error structure.
* 0 on success, a negative errno value otherwise and rte_errno is set.
*/
static int
-flow_shared_actions_translate(struct rte_eth_dev *dev,
+flow_action_handles_translate(struct rte_eth_dev *dev,
const struct rte_flow_action actions[],
- struct mlx5_translated_shared_action *shared,
- int *shared_n,
+ struct mlx5_translated_action_handle *handle,
+ int *indir_n,
struct rte_flow_action **translated_actions,
struct rte_flow_error *error)
{
size_t actions_size;
int n;
int copied_n = 0;
- struct mlx5_translated_shared_action *shared_end = NULL;
+ struct mlx5_translated_action_handle *handle_end = NULL;
for (n = 0; actions[n].type != RTE_FLOW_ACTION_TYPE_END; n++) {
- if (actions[n].type != RTE_FLOW_ACTION_TYPE_SHARED)
+ if (actions[n].type != RTE_FLOW_ACTION_TYPE_INDIRECT)
continue;
- if (copied_n == *shared_n) {
+ if (copied_n == *indir_n) {
return rte_flow_error_set
(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION_NUM,
NULL, "too many shared actions");
}
- rte_memcpy(&shared[copied_n].action, &actions[n].conf,
+ rte_memcpy(&handle[copied_n].action, &actions[n].conf,
sizeof(actions[n].conf));
- shared[copied_n].index = n;
+ handle[copied_n].index = n;
copied_n++;
}
n++;
- *shared_n = copied_n;
+ *indir_n = copied_n;
if (!copied_n)
return 0;
actions_size = sizeof(struct rte_flow_action) * n;
return -ENOMEM;
}
memcpy(translated, actions, actions_size);
- for (shared_end = shared + copied_n; shared < shared_end; shared++) {
+ for (handle_end = handle + copied_n; handle < handle_end; handle++) {
struct mlx5_shared_action_rss *shared_rss;
- uint32_t act_idx = (uint32_t)(uintptr_t)shared->action;
- uint32_t type = act_idx >> MLX5_SHARED_ACTION_TYPE_OFFSET;
- uint32_t idx = act_idx & ((1u << MLX5_SHARED_ACTION_TYPE_OFFSET)
- - 1);
+ uint32_t act_idx = (uint32_t)(uintptr_t)handle->action;
+ uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
+ uint32_t idx = act_idx &
+ ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
switch (type) {
- case MLX5_SHARED_ACTION_TYPE_RSS:
+ case MLX5_INDIRECT_ACTION_TYPE_RSS:
shared_rss = mlx5_ipool_get
(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
- translated[shared->index].type =
+ translated[handle->index].type =
RTE_FLOW_ACTION_TYPE_RSS;
- translated[shared->index].conf =
+ translated[handle->index].conf =
&shared_rss->origin;
break;
- case MLX5_SHARED_ACTION_TYPE_AGE:
+ case MLX5_INDIRECT_ACTION_TYPE_AGE:
if (priv->sh->flow_hit_aso_en) {
- translated[shared->index].type =
+ translated[handle->index].type =
(enum rte_flow_action_type)
MLX5_RTE_FLOW_ACTION_TYPE_AGE;
- translated[shared->index].conf =
+ translated[handle->index].conf =
(void *)(uintptr_t)idx;
break;
}
mlx5_free(translated);
return rte_flow_error_set
(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
- NULL, "invalid shared action type");
+ NULL, "invalid indirect action type");
}
}
*translated_actions = translated;
*/
static uint32_t
flow_get_shared_rss_action(struct rte_eth_dev *dev,
- struct mlx5_translated_shared_action *shared,
+ struct mlx5_translated_action_handle *handle,
int shared_n)
{
- struct mlx5_translated_shared_action *shared_end;
+ struct mlx5_translated_action_handle *handle_end;
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_shared_action_rss *shared_rss;
- for (shared_end = shared + shared_n; shared < shared_end; shared++) {
- uint32_t act_idx = (uint32_t)(uintptr_t)shared->action;
- uint32_t type = act_idx >> MLX5_SHARED_ACTION_TYPE_OFFSET;
+ for (handle_end = handle + shared_n; handle < handle_end; handle++) {
+ uint32_t act_idx = (uint32_t)(uintptr_t)handle->action;
+ uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
uint32_t idx = act_idx &
- ((1u << MLX5_SHARED_ACTION_TYPE_OFFSET) - 1);
+ ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
switch (type) {
- case MLX5_SHARED_ACTION_TYPE_RSS:
+ case MLX5_INDIRECT_ACTION_TYPE_RSS:
shared_rss = mlx5_ipool_get
(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
idx);
*
* @param[in] actions
* Pointer to the list of actions.
- * @param[out] mtr
+ * @param[out] has_mtr
* Pointer to the meter exist flag.
+ * @param[out] meter_id
+ * Pointer to the meter id.
*
* @return
* Total number of actions.
*/
static int
-flow_check_meter_action(const struct rte_flow_action actions[], uint32_t *mtr)
+flow_check_meter_action(const struct rte_flow_action actions[],
+ bool *has_mtr,
+ uint32_t *meter_id)
{
+ const struct rte_flow_action_meter *mtr = NULL;
int actions_n = 0;
- MLX5_ASSERT(mtr);
- *mtr = 0;
+ MLX5_ASSERT(has_mtr);
+ *has_mtr = false;
for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
switch (actions->type) {
case RTE_FLOW_ACTION_TYPE_METER:
- *mtr = 1;
+ mtr = actions->conf;
+ *meter_id = mtr->mtr_id;
+ *has_mtr = true;
break;
default:
break;
};
} else {
/* Default rule, wildcard match. */
- attr.priority = MLX5_FLOW_PRIO_RSVD;
+ attr.priority = MLX5_FLOW_LOWEST_PRIO_INDICATOR;
items[0] = (struct rte_flow_item){
.type = RTE_FLOW_ITEM_TYPE_END,
};
rte_memcpy(actions_rx, actions, sizeof(struct rte_flow_action));
actions_rx++;
set_tag = (void *)actions_rx;
- set_tag->id = mlx5_flow_get_reg_id(dev, MLX5_HAIRPIN_RX, 0, NULL);
+ *set_tag = (struct mlx5_rte_flow_action_set_tag) {
+ .id = mlx5_flow_get_reg_id(dev, MLX5_HAIRPIN_RX, 0, NULL),
+ .data = flow_id,
+ };
MLX5_ASSERT(set_tag->id > REG_NON);
- set_tag->data = flow_id;
tag_action->conf = set_tag;
/* Create Tx item list. */
rte_memcpy(actions_tx, actions, sizeof(struct rte_flow_action));
dev_flow->handle->mark = 1;
if (sub_flow)
*sub_flow = dev_flow;
+#ifdef HAVE_IBV_FLOW_DV_SUPPORT
+ dev_flow->dv.table_id = flow_split_info->table_id;
+#endif
return flow_drv_translate(dev, dev_flow, attr, items, actions, error);
}
* header will be in the prefix sub flow, as not to take the
* L3 tunnel header into account.
*
- * @param dev
+ * @param[in] dev
* Pointer to Ethernet device.
+ * @param[in] flow
+ * Parent flow structure pointer.
+ * @param[in] fm
+ * Pointer to flow meter structure.
+ * @param[in] attr
+ * Flow rule attributes.
* @param[in] items
* Pattern specification (list terminated by the END pattern item).
* @param[out] sfx_items
* Suffix flow actions.
* @param[out] actions_pre
* Prefix flow actions.
- * @param[out] pattern_sfx
- * The pattern items for the suffix flow.
- * @param[out] tag_sfx
- * Pointer to suffix flow tag.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
*
* @return
- * 0 on success.
+ * The flow id, 0 otherwise and rte_errno is set.
*/
-static int
+static uint32_t
flow_meter_split_prep(struct rte_eth_dev *dev,
- const struct rte_flow_item items[],
- struct rte_flow_item sfx_items[],
- const struct rte_flow_action actions[],
- struct rte_flow_action actions_sfx[],
- struct rte_flow_action actions_pre[])
+ struct rte_flow *flow,
+ struct mlx5_flow_meter_info *fm,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item items[],
+ struct rte_flow_item sfx_items[],
+ const struct rte_flow_action actions[],
+ struct rte_flow_action actions_sfx[],
+ struct rte_flow_action actions_pre[],
+ struct rte_flow_error *error)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct rte_flow_action *tag_action = NULL;
struct rte_flow_item *tag_item;
struct mlx5_rte_flow_action_set_tag *set_tag;
- struct rte_flow_error error;
const struct rte_flow_action_raw_encap *raw_encap;
const struct rte_flow_action_raw_decap *raw_decap;
- struct mlx5_rte_flow_item_tag *tag_spec;
- struct mlx5_rte_flow_item_tag *tag_mask;
+ struct mlx5_rte_flow_item_tag *tag_item_spec;
+ struct mlx5_rte_flow_item_tag *tag_item_mask;
uint32_t tag_id = 0;
bool copy_vlan = false;
-
+ struct rte_flow_action *hw_mtr_action;
+ struct rte_flow_action_jump *jump_data;
+ struct rte_flow_action *action_pre_head = NULL;
+ bool mtr_first = priv->sh->meter_aso_en &&
+ (attr->egress ||
+ (attr->transfer && priv->representor_id != UINT16_MAX));
+ uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
+ uint8_t mtr_reg_bits = priv->mtr_reg_share ?
+ MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
+ uint32_t flow_id = 0;
+ uint32_t flow_id_reversed = 0;
+ uint8_t flow_id_bits = 0;
+ int shift;
+
+ /* For ASO meter, meter must be before tag in TX direction. */
+ if (mtr_first) {
+ action_pre_head = actions_pre++;
+ /* Leave space for tag action. */
+ tag_action = actions_pre++;
+ }
/* Prepare the actions for prefix and suffix flow. */
for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
- struct rte_flow_action **action_cur = NULL;
+ struct rte_flow_action *action_cur = NULL;
switch (actions->type) {
case RTE_FLOW_ACTION_TYPE_METER:
- /* Add the extra tag action first. */
- tag_action = actions_pre;
- tag_action->type = (enum rte_flow_action_type)
- MLX5_RTE_FLOW_ACTION_TYPE_TAG;
- actions_pre++;
- action_cur = &actions_pre;
+ if (mtr_first) {
+ action_cur = action_pre_head;
+ } else {
+ /* Leave space for tag action. */
+ tag_action = actions_pre++;
+ action_cur = actions_pre++;
+ }
break;
case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
- action_cur = &actions_pre;
+ action_cur = actions_pre++;
break;
case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
raw_encap = actions->conf;
if (raw_encap->size < MLX5_ENCAPSULATION_DECISION_SIZE)
- action_cur = &actions_pre;
+ action_cur = actions_pre++;
break;
case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
raw_decap = actions->conf;
if (raw_decap->size > MLX5_ENCAPSULATION_DECISION_SIZE)
- action_cur = &actions_pre;
+ action_cur = actions_pre++;
break;
case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
break;
}
if (!action_cur)
- action_cur = &actions_sfx;
- memcpy(*action_cur, actions, sizeof(struct rte_flow_action));
- (*action_cur)++;
+ action_cur = actions_sfx++;
+ memcpy(action_cur, actions, sizeof(struct rte_flow_action));
}
/* Add end action to the actions. */
actions_sfx->type = RTE_FLOW_ACTION_TYPE_END;
- actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
- actions_pre++;
- /* Set the tag. */
- set_tag = (void *)actions_pre;
- set_tag->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0, &error);
- mlx5_ipool_malloc(priv->sh->ipool[MLX5_IPOOL_RSS_EXPANTION_FLOW_ID],
- &tag_id);
- if (tag_id >= (1 << (sizeof(tag_id) * 8 - MLX5_MTR_COLOR_BITS))) {
- DRV_LOG(ERR, "Port %u meter flow id exceed max limit.",
- dev->data->port_id);
- mlx5_ipool_free(priv->sh->ipool
- [MLX5_IPOOL_RSS_EXPANTION_FLOW_ID], tag_id);
- return 0;
- } else if (!tag_id) {
- return 0;
+ if (priv->sh->meter_aso_en) {
+ /**
+ * For ASO meter, need to add an extra jump action explicitly,
+ * to jump from meter to policer table.
+ */
+ hw_mtr_action = actions_pre;
+ hw_mtr_action->type = RTE_FLOW_ACTION_TYPE_JUMP;
+ actions_pre++;
+ actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
+ actions_pre++;
+ jump_data = (struct rte_flow_action_jump *)actions_pre;
+ jump_data->group = attr->transfer ?
+ (MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :
+ MLX5_FLOW_TABLE_LEVEL_POLICY;
+ hw_mtr_action->conf = jump_data;
+ actions_pre = (struct rte_flow_action *)(jump_data + 1);
+ } else {
+ actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
+ actions_pre++;
}
- set_tag->data = tag_id << MLX5_MTR_COLOR_BITS;
- assert(tag_action);
- tag_action->conf = set_tag;
+ /* Generate meter flow_id only if support multiple flows per meter. */
+ mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
+ if (!tag_id)
+ return rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "Failed to allocate meter flow id.");
+ flow_id = tag_id - 1;
+ flow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);
+ flow_id_bits = flow_id_bits ? flow_id_bits : 1;
+ if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {
+ mlx5_ipool_free(fm->flow_ipool, tag_id);
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "Meter flow id exceeds max limit.");
+ }
+ if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
+ priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
/* Prepare the suffix subflow items. */
tag_item = sfx_items++;
for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
}
sfx_items->type = RTE_FLOW_ITEM_TYPE_END;
sfx_items++;
- tag_spec = (struct mlx5_rte_flow_item_tag *)sfx_items;
- tag_spec->data = tag_id << MLX5_MTR_COLOR_BITS;
- tag_spec->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0, &error);
- tag_mask = tag_spec + 1;
- tag_mask->data = 0xffffff00;
+ /* Build tag actions and items for meter_id/meter flow_id. */
+ assert(tag_action);
+ set_tag = (struct mlx5_rte_flow_action_set_tag *)actions_pre;
+ tag_item_spec = (struct mlx5_rte_flow_item_tag *)sfx_items;
+ tag_item_mask = tag_item_spec + 1;
+ /* Both flow_id and meter_id share the same register. */
+ *set_tag = (struct mlx5_rte_flow_action_set_tag) {
+ .id = (enum modify_reg)mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
+ 0, error),
+ .offset = mtr_id_offset,
+ .length = mtr_reg_bits,
+ .data = flow->meter,
+ };
+ /*
+ * The color Reg bits used by flow_id are growing from
+ * msb to lsb, so must do bit reverse for flow_id val in RegC.
+ */
+ for (shift = 0; shift < flow_id_bits; shift++)
+ flow_id_reversed = (flow_id_reversed << 1) |
+ ((flow_id >> shift) & 0x1);
+ set_tag->data |= flow_id_reversed << (mtr_reg_bits - flow_id_bits);
+ tag_item_spec->id = set_tag->id;
+ tag_item_spec->data = set_tag->data << mtr_id_offset;
+ tag_item_mask->data = UINT32_MAX << mtr_id_offset;
+ tag_action->type = (enum rte_flow_action_type)
+ MLX5_RTE_FLOW_ACTION_TYPE_TAG;
+ tag_action->conf = set_tag;
tag_item->type = (enum rte_flow_item_type)
- MLX5_RTE_FLOW_ITEM_TYPE_TAG;
- tag_item->spec = tag_spec;
+ MLX5_RTE_FLOW_ITEM_TYPE_TAG;
+ tag_item->spec = tag_item_spec;
tag_item->last = NULL;
- tag_item->mask = tag_mask;
+ tag_item->mask = tag_item_mask;
return tag_id;
}
* Pointer to the position of the matched action if exists, otherwise is -1.
* @param[out] qrss_action_pos
* Pointer to the position of the Queue/RSS action if exists, otherwise is -1.
+ * @param[out] modify_after_mirror
+ * Pointer to the flag of modify action after FDB mirroring.
*
* @return
* > 0 the total number of actions.
flow_check_match_action(const struct rte_flow_action actions[],
const struct rte_flow_attr *attr,
enum rte_flow_action_type action,
- int *match_action_pos, int *qrss_action_pos)
+ int *match_action_pos, int *qrss_action_pos,
+ int *modify_after_mirror)
{
const struct rte_flow_action_sample *sample;
int actions_n = 0;
uint32_t ratio = 0;
int sub_type = 0;
int flag = 0;
+ int fdb_mirror = 0;
*match_action_pos = -1;
*qrss_action_pos = -1;
flag = 1;
*match_action_pos = actions_n;
}
- if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE ||
- actions->type == RTE_FLOW_ACTION_TYPE_RSS)
+ switch (actions->type) {
+ case RTE_FLOW_ACTION_TYPE_QUEUE:
+ case RTE_FLOW_ACTION_TYPE_RSS:
*qrss_action_pos = actions_n;
- if (actions->type == RTE_FLOW_ACTION_TYPE_SAMPLE) {
+ break;
+ case RTE_FLOW_ACTION_TYPE_SAMPLE:
sample = actions->conf;
ratio = sample->ratio;
sub_type = ((const struct rte_flow_action *)
(sample->actions))->type;
+ if (ratio == 1 && attr->transfer)
+ fdb_mirror = 1;
+ break;
+ case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
+ case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
+ case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
+ case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
+ case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
+ case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
+ case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
+ case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
+ case RTE_FLOW_ACTION_TYPE_DEC_TTL:
+ case RTE_FLOW_ACTION_TYPE_SET_TTL:
+ case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
+ case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
+ case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
+ case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
+ case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
+ case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
+ case RTE_FLOW_ACTION_TYPE_FLAG:
+ case RTE_FLOW_ACTION_TYPE_MARK:
+ case RTE_FLOW_ACTION_TYPE_SET_META:
+ case RTE_FLOW_ACTION_TYPE_SET_TAG:
+ case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
+ case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+ case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
+ case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
+ case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+ case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
+ case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+ case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
+ if (fdb_mirror)
+ *modify_after_mirror = 1;
+ break;
+ default:
+ break;
}
actions_n++;
}
- if (flag && action == RTE_FLOW_ACTION_TYPE_SAMPLE && attr->transfer) {
- if (ratio == 1) {
- /* FDB mirroring uses the destination array to implement
- * instead of FLOW_SAMPLER object.
- */
- if (sub_type != RTE_FLOW_ACTION_TYPE_END)
- flag = 0;
- }
+ if (flag && fdb_mirror && !*modify_after_mirror) {
+ /* FDB mirroring uses the destination array to implement
+ * instead of FLOW_SAMPLER object.
+ */
+ if (sub_type != RTE_FLOW_ACTION_TYPE_END)
+ flag = 0;
}
/* Count RTE_FLOW_ACTION_TYPE_END. */
return flag ? actions_n + 1 : 0;
* The sample action position.
* @param[in] qrss_action_pos
* The Queue/RSS action position.
+ * @param[in] jump_table
+ * Add extra jump action flag.
* @param[out] error
* Perform verbose error reporting if not NULL.
*
int actions_n,
int sample_action_pos,
int qrss_action_pos,
+ int jump_table,
struct rte_flow_error *error)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_rte_flow_action_set_tag *set_tag;
struct mlx5_rte_flow_item_tag *tag_spec;
struct mlx5_rte_flow_item_tag *tag_mask;
+ struct rte_flow_action_jump *jump_action;
uint32_t tag_id = 0;
int index;
+ int append_index = 0;
int ret;
if (sample_action_pos < 0)
RTE_FLOW_ERROR_TYPE_ACTION,
NULL, "invalid position of sample "
"action in list");
+ /* Prepare the actions for prefix and suffix flow. */
+ if (qrss_action_pos >= 0 && qrss_action_pos < sample_action_pos) {
+ index = qrss_action_pos;
+ /* Put the preceding the Queue/RSS action into prefix flow. */
+ if (index != 0)
+ memcpy(actions_pre, actions,
+ sizeof(struct rte_flow_action) * index);
+ /* Put others preceding the sample action into prefix flow. */
+ if (sample_action_pos > index + 1)
+ memcpy(actions_pre + index, actions + index + 1,
+ sizeof(struct rte_flow_action) *
+ (sample_action_pos - index - 1));
+ index = sample_action_pos - 1;
+ /* Put Queue/RSS action into Suffix flow. */
+ memcpy(actions_sfx, actions + qrss_action_pos,
+ sizeof(struct rte_flow_action));
+ actions_sfx++;
+ } else {
+ index = sample_action_pos;
+ if (index != 0)
+ memcpy(actions_pre, actions,
+ sizeof(struct rte_flow_action) * index);
+ }
/* For CX5, add an extra tag action for NIC-RX and E-Switch ingress.
* For CX6DX and above, metadata registers Cx preserve their value,
- * add an extra tag action for NIC-RX and E-Switch ingress and egress.
+ * add an extra tag action for NIC-RX and E-Switch Domain.
*/
if (add_tag) {
/* Prepare the prefix tag action. */
- set_tag = (void *)(actions_pre + actions_n + 1);
+ append_index++;
+ set_tag = (void *)(actions_pre + actions_n + append_index);
ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, 0, error);
if (ret < 0)
return ret;
- set_tag->id = ret;
mlx5_ipool_malloc(priv->sh->ipool
[MLX5_IPOOL_RSS_EXPANTION_FLOW_ID], &tag_id);
- set_tag->data = tag_id;
+ *set_tag = (struct mlx5_rte_flow_action_set_tag) {
+ .id = ret,
+ .data = tag_id,
+ };
/* Prepare the suffix subflow items. */
tag_spec = (void *)(sfx_items + SAMPLE_SUFFIX_ITEM);
tag_spec->data = tag_id;
.type = (enum rte_flow_item_type)
RTE_FLOW_ITEM_TYPE_END,
};
- }
- /* Prepare the actions for prefix and suffix flow. */
- if (qrss_action_pos >= 0 && qrss_action_pos < sample_action_pos) {
- index = qrss_action_pos;
- /* Put the preceding the Queue/RSS action into prefix flow. */
- if (index != 0)
- memcpy(actions_pre, actions,
- sizeof(struct rte_flow_action) * index);
- /* Put others preceding the sample action into prefix flow. */
- if (sample_action_pos > index + 1)
- memcpy(actions_pre + index, actions + index + 1,
- sizeof(struct rte_flow_action) *
- (sample_action_pos - index - 1));
- index = sample_action_pos - 1;
- /* Put Queue/RSS action into Suffix flow. */
- memcpy(actions_sfx, actions + qrss_action_pos,
- sizeof(struct rte_flow_action));
- actions_sfx++;
- } else {
- index = sample_action_pos;
- if (index != 0)
- memcpy(actions_pre, actions,
- sizeof(struct rte_flow_action) * index);
- }
- if (add_tag) {
+ /* Prepare the tag action in prefix subflow. */
actions_pre[index++] =
(struct rte_flow_action){
.type = (enum rte_flow_action_type)
memcpy(actions_pre + index, actions + sample_action_pos,
sizeof(struct rte_flow_action));
index += 1;
+ /* For the modify action after the sample action in E-Switch mirroring,
+ * Add the extra jump action in prefix subflow and jump into the next
+ * table, then do the modify action in the new table.
+ */
+ if (jump_table) {
+ /* Prepare the prefix jump action. */
+ append_index++;
+ jump_action = (void *)(actions_pre + actions_n + append_index);
+ jump_action->group = jump_table;
+ actions_pre[index++] =
+ (struct rte_flow_action){
+ .type = (enum rte_flow_action_type)
+ RTE_FLOW_ACTION_TYPE_JUMP,
+ .conf = jump_action,
+ };
+ }
actions_pre[index] = (struct rte_flow_action){
.type = (enum rte_flow_action_type)
RTE_FLOW_ACTION_TYPE_END,
if (qrss) {
/* Check if it is in meter suffix table. */
mtr_sfx = attr->group == (attr->transfer ?
- (MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
- MLX5_FLOW_TABLE_LEVEL_SUFFIX);
+ (MLX5_FLOW_TABLE_LEVEL_METER - 1) :
+ MLX5_FLOW_TABLE_LEVEL_METER);
/*
* Q/RSS action on NIC Rx should be split in order to pass by
* the mreg copy table (RX_CP_TBL) and then it jumps to the
struct rte_flow_error *error)
{
struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
struct rte_flow_action *sfx_actions = NULL;
struct rte_flow_action *pre_actions = NULL;
struct rte_flow_item *sfx_items = NULL;
struct mlx5_flow *dev_flow = NULL;
struct rte_flow_attr sfx_attr = *attr;
- uint32_t mtr = 0;
+ struct mlx5_flow_meter_info *fm = NULL;
+ bool has_mtr = false;
+ uint32_t meter_id;
+ uint32_t mtr_idx = 0;
uint32_t mtr_tag_id = 0;
size_t act_size;
size_t item_size;
int actions_n = 0;
- int ret;
+ int ret = 0;
if (priv->mtr_en)
- actions_n = flow_check_meter_action(actions, &mtr);
- if (mtr) {
- /* The five prefix actions: meter, decap, encap, tag, end. */
- act_size = sizeof(struct rte_flow_action) * (actions_n + 5) +
- sizeof(struct mlx5_rte_flow_action_set_tag);
- /* tag, vlan, port id, end. */
+ actions_n = flow_check_meter_action(actions, &has_mtr,
+ &meter_id);
+ if (has_mtr) {
+ if (flow->meter) {
+ fm = flow_dv_meter_find_by_idx(priv, flow->meter);
+ if (!fm)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "Meter not found.");
+ } else {
+ fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
+ if (!fm)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "Meter not found.");
+ ret = mlx5_flow_meter_attach(priv, fm,
+ &sfx_attr, error);
+ if (ret)
+ return -rte_errno;
+ flow->meter = mtr_idx;
+ }
+ wks->fm = fm;
+ /* Prefix actions: meter, decap, encap, tag, jump, end. */
+ act_size = sizeof(struct rte_flow_action) * (actions_n + 6) +
+ sizeof(struct mlx5_rte_flow_action_set_tag) +
+ sizeof(struct rte_flow_action_jump);
+ /* Suffix items: tag, vlan, port id, end. */
#define METER_SUFFIX_ITEM 4
item_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM +
sizeof(struct mlx5_rte_flow_item_tag) * 2;
sfx_items = (struct rte_flow_item *)((char *)sfx_actions +
act_size);
pre_actions = sfx_actions + actions_n;
- mtr_tag_id = flow_meter_split_prep(dev, items, sfx_items,
- actions, sfx_actions,
- pre_actions);
+ mtr_tag_id = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
+ items, sfx_items, actions,
+ sfx_actions, pre_actions,
+ error);
if (!mtr_tag_id) {
ret = -rte_errno;
goto exit;
attr, items, pre_actions,
flow_split_info, error);
if (ret) {
+ mlx5_ipool_free(fm->flow_ipool, mtr_tag_id);
ret = -rte_errno;
goto exit;
}
dev_flow->handle->split_flow_id = mtr_tag_id;
+ dev_flow->handle->is_meter_flow_id = 1;
/* Setting the sfx group atrr. */
sfx_attr.group = sfx_attr.transfer ?
- (MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
- MLX5_FLOW_TABLE_LEVEL_SUFFIX;
+ (MLX5_FLOW_TABLE_LEVEL_METER - 1) :
+ MLX5_FLOW_TABLE_LEVEL_METER;
flow_split_info->prefix_layers =
flow_get_prefix_layer_flags(dev_flow);
flow_split_info->prefix_mark = dev_flow->handle->mark;
int sample_action_pos;
int qrss_action_pos;
int add_tag = 0;
+ int modify_after_mirror = 0;
+ uint16_t jump_table = 0;
+ const uint32_t next_ft_step = 1;
int ret = 0;
if (priv->sampler_en)
actions_n = flow_check_match_action(actions, attr,
RTE_FLOW_ACTION_TYPE_SAMPLE,
- &sample_action_pos, &qrss_action_pos);
+ &sample_action_pos, &qrss_action_pos,
+ &modify_after_mirror);
if (actions_n) {
/* The prefix actions must includes sample, tag, end. */
act_size = sizeof(struct rte_flow_action) * (actions_n * 2 + 1)
if (add_tag)
sfx_items = (struct rte_flow_item *)((char *)sfx_actions
+ act_size);
+ if (modify_after_mirror)
+ jump_table = attr->group * MLX5_FLOW_TABLE_FACTOR +
+ next_ft_step;
pre_actions = sfx_actions + actions_n;
tag_id = flow_sample_split_prep(dev, add_tag, sfx_items,
actions, sfx_actions,
pre_actions, actions_n,
sample_action_pos,
- qrss_action_pos, error);
+ qrss_action_pos, jump_table,
+ error);
if (tag_id < 0 || (add_tag && !tag_id)) {
ret = -rte_errno;
goto exit;
}
+ if (modify_after_mirror)
+ flow_split_info->skip_scale =
+ 1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT;
/* Add the prefix subflow. */
ret = flow_create_split_inner(dev, flow, &dev_flow, attr,
items, pre_actions,
}
dev_flow->handle->split_flow_id = tag_id;
#ifdef HAVE_IBV_FLOW_DV_SUPPORT
- /* Set the sfx group attr. */
- sample_res = (struct mlx5_flow_dv_sample_resource *)
- dev_flow->dv.sample_res;
- sfx_tbl = (struct mlx5_flow_tbl_resource *)
- sample_res->normal_path_tbl;
- sfx_tbl_data = container_of(sfx_tbl,
- struct mlx5_flow_tbl_data_entry, tbl);
- sfx_attr.group = sfx_attr.transfer ?
- (sfx_tbl_data->table_id - 1) :
- sfx_tbl_data->table_id;
+ if (!modify_after_mirror) {
+ /* Set the sfx group attr. */
+ sample_res = (struct mlx5_flow_dv_sample_resource *)
+ dev_flow->dv.sample_res;
+ sfx_tbl = (struct mlx5_flow_tbl_resource *)
+ sample_res->normal_path_tbl;
+ sfx_tbl_data = container_of(sfx_tbl,
+ struct mlx5_flow_tbl_data_entry,
+ tbl);
+ sfx_attr.group = sfx_attr.transfer ?
+ (sfx_tbl_data->level - 1) : sfx_tbl_data->level;
+ } else {
+ MLX5_ASSERT(attr->transfer);
+ sfx_attr.group = jump_table;
+ }
flow_split_info->prefix_layers =
flow_get_prefix_layer_flags(dev_flow);
flow_split_info->prefix_mark = dev_flow->handle->mark;
/* Suffix group level already be scaled with factor, set
- * skip_scale to 1 to avoid scale again in translation.
+ * MLX5_SCALE_FLOW_GROUP_BIT of skip_scale to 1 to avoid scale
+ * again in translation.
*/
flow_split_info->skip_scale = 1 << MLX5_SCALE_FLOW_GROUP_BIT;
#endif
struct rte_flow *flow = NULL;
struct mlx5_flow *dev_flow;
const struct rte_flow_action_rss *rss = NULL;
- struct mlx5_translated_shared_action
- shared_actions[MLX5_MAX_SHARED_ACTIONS];
- int shared_actions_n = MLX5_MAX_SHARED_ACTIONS;
+ struct mlx5_translated_action_handle
+ indir_actions[MLX5_MAX_INDIRECT_ACTIONS];
+ int indir_actions_n = MLX5_MAX_INDIRECT_ACTIONS;
union {
struct mlx5_flow_expand_rss buf;
uint8_t buffer[2048];
.skip_scale = 0,
.flow_idx = 0,
.prefix_mark = 0,
- .prefix_layers = 0
+ .prefix_layers = 0,
+ .table_id = 0
};
int ret;
MLX5_ASSERT(wks);
rss_desc = &wks->rss_desc;
- ret = flow_shared_actions_translate(dev, original_actions,
- shared_actions,
- &shared_actions_n,
+ ret = flow_action_handles_translate(dev, original_actions,
+ indir_actions,
+ &indir_actions_n,
&translated_actions, error);
if (ret < 0) {
MLX5_ASSERT(translated_actions == NULL);
buf->entries = 1;
buf->entry[0].pattern = (void *)(uintptr_t)items;
}
- rss_desc->shared_rss = flow_get_shared_rss_action(dev, shared_actions,
- shared_actions_n);
+ rss_desc->shared_rss = flow_get_shared_rss_action(dev, indir_actions,
+ indir_actions_n);
for (i = 0; i < buf->entries; ++i) {
/* Initialize flow split data. */
flow_split_info.prefix_layers = 0;
*/
if (external || dev->data->dev_started ||
(attr->group == MLX5_FLOW_MREG_CP_TABLE_GROUP &&
- attr->priority == MLX5_FLOW_PRIO_RSVD)) {
+ attr->priority == MLX5_FLOW_LOWEST_PRIO_INDICATOR)) {
ret = flow_drv_apply(dev, flow, error);
if (ret < 0)
goto error;
struct rte_flow_error *error)
{
int hairpin_flow;
- struct mlx5_translated_shared_action
- shared_actions[MLX5_MAX_SHARED_ACTIONS];
- int shared_actions_n = MLX5_MAX_SHARED_ACTIONS;
+ struct mlx5_translated_action_handle
+ indir_actions[MLX5_MAX_INDIRECT_ACTIONS];
+ int indir_actions_n = MLX5_MAX_INDIRECT_ACTIONS;
const struct rte_flow_action *actions;
struct rte_flow_action *translated_actions = NULL;
- int ret = flow_shared_actions_translate(dev, original_actions,
- shared_actions,
- &shared_actions_n,
+ int ret = flow_action_handles_translate(dev, original_actions,
+ indir_actions,
+ &indir_actions_n,
&translated_actions, error);
if (ret)
struct mlx5_priv *priv = dev->data->dev_private;
const struct rte_flow_attr attr = {
.ingress = 1,
- .priority = MLX5_FLOW_PRIO_RSVD,
+ .priority = MLX5_FLOW_LOWEST_PRIO_INDICATOR,
};
struct rte_flow_item items[] = {
{
}
/**
- * Manage filter operations.
+ * Get rte_flow callbacks.
*
* @param dev
* Pointer to Ethernet device structure.
- * @param filter_type
- * Filter type.
- * @param filter_op
- * Operation to perform.
- * @param arg
+ * @param ops
* Pointer to operation-specific structure.
*
- * @return
- * 0 on success, a negative errno value otherwise and rte_errno is set.
+ * @return 0
*/
int
-mlx5_dev_filter_ctrl(struct rte_eth_dev *dev,
- enum rte_filter_type filter_type,
- enum rte_filter_op filter_op,
- void *arg)
-{
- switch (filter_type) {
- case RTE_ETH_FILTER_GENERIC:
- if (filter_op != RTE_ETH_FILTER_GET) {
- rte_errno = EINVAL;
- return -rte_errno;
- }
- *(const void **)arg = &mlx5_flow_ops;
- return 0;
- default:
- DRV_LOG(ERR, "port %u filter type (%d) not supported",
- dev->data->port_id, filter_type);
- rte_errno = ENOTSUP;
- return -rte_errno;
- }
+mlx5_flow_ops_get(struct rte_eth_dev *dev __rte_unused,
+ const struct rte_flow_ops **ops)
+{
+ *ops = &mlx5_flow_ops;
return 0;
}
/**
- * Create the needed meter and suffix tables.
+ * Validate meter policy actions.
+ * Dispatcher for action type specific validation.
*
* @param[in] dev
- * Pointer to Ethernet device.
- * @param[in] fm
- * Pointer to the flow meter.
+ * Pointer to the Ethernet device structure.
+ * @param[in] action
+ * The meter policy action object to validate.
+ * @param[in] attr
+ * Attributes of flow to determine steering domain.
+ * @param[out] is_rss
+ * Is RSS or not.
+ * @param[out] domain_bitmap
+ * Domain bitmap.
+ * @param[out] is_def_policy
+ * Is default policy or not.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL. Initialized in case of
+ * error only.
*
* @return
- * Pointer to table set on success, NULL otherwise.
+ * 0 on success, otherwise negative errno value.
*/
-struct mlx5_meter_domains_infos *
-mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
- const struct mlx5_flow_meter *fm)
+int
+mlx5_flow_validate_mtr_acts(struct rte_eth_dev *dev,
+ const struct rte_flow_action *actions[RTE_COLORS],
+ struct rte_flow_attr *attr,
+ bool *is_rss,
+ uint8_t *domain_bitmap,
+ bool *is_def_policy,
+ struct rte_mtr_error *error)
{
const struct mlx5_flow_driver_ops *fops;
fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
- return fops->create_mtr_tbls(dev, fm);
+ return fops->validate_mtr_acts(dev, actions, attr,
+ is_rss, domain_bitmap, is_def_policy, error);
}
/**
*
* @param[in] dev
* Pointer to Ethernet device.
- * @param[in] tbl
- * Pointer to the meter table set.
+ * @param[in] mtr_policy
+ * Meter policy struct.
+ */
+void
+mlx5_flow_destroy_mtr_acts(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_policy *mtr_policy)
+{
+ const struct mlx5_flow_driver_ops *fops;
+
+ fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+ fops->destroy_mtr_acts(dev, mtr_policy);
+}
+
+/**
+ * Create policy action, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ * Meter policy struct.
+ * @param[in] action
+ * Action specification used to create meter actions.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL. Initialized in case of
+ * error only.
*
* @return
- * 0 on success.
+ * 0 on success, otherwise negative errno value.
*/
int
-mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
- struct mlx5_meter_domains_infos *tbls)
+mlx5_flow_create_mtr_acts(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_policy *mtr_policy,
+ const struct rte_flow_action *actions[RTE_COLORS],
+ struct rte_mtr_error *error)
+{
+ const struct mlx5_flow_driver_ops *fops;
+
+ fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+ return fops->create_mtr_acts(dev, mtr_policy, actions, error);
+}
+
+/**
+ * Create policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ * Meter policy struct.
+ *
+ * @return
+ * 0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_policy_rules(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_policy *mtr_policy)
+{
+ const struct mlx5_flow_driver_ops *fops;
+
+ fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+ return fops->create_policy_rules(dev, mtr_policy);
+}
+
+/**
+ * Destroy policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ * Meter policy struct.
+ */
+void
+mlx5_flow_destroy_policy_rules(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_policy *mtr_policy)
{
const struct mlx5_flow_driver_ops *fops;
fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
- return fops->destroy_mtr_tbls(dev, tbls);
+ fops->destroy_policy_rules(dev, mtr_policy);
}
/**
- * Create policer rules.
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ */
+void
+mlx5_flow_destroy_def_policy(struct rte_eth_dev *dev)
+{
+ const struct mlx5_flow_driver_ops *fops;
+
+ fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+ fops->destroy_def_policy(dev);
+}
+
+/**
+ * Destroy the default policy table set.
*
* @param[in] dev
* Pointer to Ethernet device.
- * @param[in] fm
- * Pointer to flow meter structure.
- * @param[in] attr
- * Pointer to flow attributes.
*
* @return
* 0 on success, -1 otherwise.
*/
int
-mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,
- struct mlx5_flow_meter *fm,
- const struct rte_flow_attr *attr)
+mlx5_flow_create_def_policy(struct rte_eth_dev *dev)
{
const struct mlx5_flow_driver_ops *fops;
fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
- return fops->create_policer_rules(dev, fm, attr);
+ return fops->create_def_policy(dev);
}
/**
- * Destroy policer rules.
+ * Create the needed meter and suffix tables.
*
- * @param[in] fm
- * Pointer to flow meter structure.
- * @param[in] attr
- * Pointer to flow attributes.
+ * @param[in] dev
+ * Pointer to Ethernet device.
*
* @return
* 0 on success, -1 otherwise.
*/
int
-mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
- struct mlx5_flow_meter *fm,
- const struct rte_flow_attr *attr)
+mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_info *fm,
+ uint32_t mtr_idx,
+ uint8_t domain_bitmap)
+{
+ const struct mlx5_flow_driver_ops *fops;
+
+ fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+ return fops->create_mtr_tbls(dev, fm, mtr_idx, domain_bitmap);
+}
+
+/**
+ * Destroy the meter table set.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] tbl
+ * Pointer to the meter table set.
+ */
+void
+mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_info *fm)
+{
+ const struct mlx5_flow_driver_ops *fops;
+
+ fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+ fops->destroy_mtr_tbls(dev, fm);
+}
+
+/**
+ * Destroy the global meter drop table.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ */
+void
+mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+{
+ const struct mlx5_flow_driver_ops *fops;
+
+ fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+ fops->destroy_mtr_drop_tbls(dev);
+}
+
+/**
+ * Allocate the needed aso flow meter id.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ *
+ * @return
+ * Index to aso flow meter on success, NULL otherwise.
+ */
+uint32_t
+mlx5_flow_mtr_alloc(struct rte_eth_dev *dev)
+{
+ const struct mlx5_flow_driver_ops *fops;
+
+ fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+ return fops->create_meter(dev);
+}
+
+/**
+ * Free the aso flow meter id.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] mtr_idx
+ * Index to aso flow meter to be free.
+ *
+ * @return
+ * 0 on success.
+ */
+void
+mlx5_flow_mtr_free(struct rte_eth_dev *dev, uint32_t mtr_idx)
{
const struct mlx5_flow_driver_ops *fops;
fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
- return fops->destroy_policer_rules(dev, fm, attr);
+ fops->free_meter(dev, mtr_idx);
}
/**
for (idx = REG_C_2; idx <= REG_C_7; ++idx) {
struct rte_flow_attr attr = {
.group = MLX5_FLOW_MREG_CP_TABLE_GROUP,
- .priority = MLX5_FLOW_PRIO_RSVD,
+ .priority = MLX5_FLOW_LOWEST_PRIO_INDICATOR,
.ingress = 1,
};
struct rte_flow_item items[] = {
* 0 on success, a nagative value otherwise.
*/
int
-mlx5_flow_dev_dump(struct rte_eth_dev *dev,
+mlx5_flow_dev_dump(struct rte_eth_dev *dev, struct rte_flow *flow_idx,
FILE *file,
struct rte_flow_error *error __rte_unused)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_dev_ctx_shared *sh = priv->sh;
+ uint32_t handle_idx;
+ int ret;
+ struct mlx5_flow_handle *dh;
+ struct rte_flow *flow;
if (!priv->config.dv_flow_en) {
if (fputs("device dv flow disabled\n", file) <= 0)
return -errno;
return -ENOTSUP;
}
- return mlx5_devx_cmd_flow_dump(sh->fdb_domain, sh->rx_domain,
- sh->tx_domain, file);
+
+ /* dump all */
+ if (!flow_idx)
+ return mlx5_devx_cmd_flow_dump(sh->fdb_domain,
+ sh->rx_domain,
+ sh->tx_domain, file);
+ /* dump one */
+ flow = mlx5_ipool_get(priv->sh->ipool
+ [MLX5_IPOOL_RTE_FLOW], (uintptr_t)(void *)flow_idx);
+ if (!flow)
+ return -ENOENT;
+
+ handle_idx = flow->dev_handles;
+ while (handle_idx) {
+ dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
+ handle_idx);
+ if (!dh)
+ return -ENOENT;
+ if (dh->drv_flow) {
+ ret = mlx5_devx_cmd_flow_single_dump(dh->drv_flow,
+ file);
+ if (ret)
+ return -ENOENT;
+ }
+ handle_idx = dh->next.next;
+ }
+ return 0;
}
/**
/* Wrapper for driver action_validate op callback */
static int
flow_drv_action_validate(struct rte_eth_dev *dev,
- const struct rte_flow_shared_action_conf *conf,
+ const struct rte_flow_indir_action_conf *conf,
const struct rte_flow_action *action,
const struct mlx5_flow_driver_ops *fops,
struct rte_flow_error *error)
{
- static const char err_msg[] = "shared action validation unsupported";
+ static const char err_msg[] = "indirect action validation unsupported";
if (!fops->action_validate) {
DRV_LOG(ERR, "port %u %s.", dev->data->port_id, err_msg);
*
* @param dev
* Pointer to Ethernet device structure.
- * @param[in] action
- * Handle for the shared action to be destroyed.
+ * @param[in] handle
+ * Handle for the indirect action object to be destroyed.
* @param[out] error
* Perform verbose error reporting if not NULL. PMDs initialize this
* structure in case of error only.
* @note: wrapper for driver action_create op callback.
*/
static int
-mlx5_shared_action_destroy(struct rte_eth_dev *dev,
- struct rte_flow_shared_action *action,
+mlx5_action_handle_destroy(struct rte_eth_dev *dev,
+ struct rte_flow_action_handle *handle,
struct rte_flow_error *error)
{
- static const char err_msg[] = "shared action destruction unsupported";
+ static const char err_msg[] = "indirect action destruction unsupported";
struct rte_flow_attr attr = { .transfer = 0 };
const struct mlx5_flow_driver_ops *fops =
flow_get_drv_ops(flow_get_drv_type(dev, &attr));
NULL, err_msg);
return -rte_errno;
}
- return fops->action_destroy(dev, action, error);
+ return fops->action_destroy(dev, handle, error);
}
/* Wrapper for driver action_destroy op callback */
static int
flow_drv_action_update(struct rte_eth_dev *dev,
- struct rte_flow_shared_action *action,
- const void *action_conf,
+ struct rte_flow_action_handle *handle,
+ const void *update,
const struct mlx5_flow_driver_ops *fops,
struct rte_flow_error *error)
{
- static const char err_msg[] = "shared action update unsupported";
+ static const char err_msg[] = "indirect action update unsupported";
if (!fops->action_update) {
DRV_LOG(ERR, "port %u %s.", dev->data->port_id, err_msg);
NULL, err_msg);
return -rte_errno;
}
- return fops->action_update(dev, action, action_conf, error);
+ return fops->action_update(dev, handle, update, error);
}
/* Wrapper for driver action_destroy op callback */
static int
flow_drv_action_query(struct rte_eth_dev *dev,
- const struct rte_flow_shared_action *action,
+ const struct rte_flow_action_handle *handle,
void *data,
const struct mlx5_flow_driver_ops *fops,
struct rte_flow_error *error)
{
- static const char err_msg[] = "shared action query unsupported";
+ static const char err_msg[] = "indirect action query unsupported";
if (!fops->action_query) {
DRV_LOG(ERR, "port %u %s.", dev->data->port_id, err_msg);
NULL, err_msg);
return -rte_errno;
}
- return fops->action_query(dev, action, data, error);
+ return fops->action_query(dev, handle, data, error);
}
/**
- * Create shared action for reuse in multiple flow rules.
+ * Create indirect action for reuse in multiple flow rules.
*
* @param dev
* Pointer to Ethernet device structure.
+ * @param conf
+ * Pointer to indirect action object configuration.
* @param[in] action
- * Action configuration for shared action creation.
+ * Action configuration for indirect action object creation.
* @param[out] error
* Perform verbose error reporting if not NULL. PMDs initialize this
* structure in case of error only.
* @return
* A valid handle in case of success, NULL otherwise and rte_errno is set.
*/
-static struct rte_flow_shared_action *
-mlx5_shared_action_create(struct rte_eth_dev *dev,
- const struct rte_flow_shared_action_conf *conf,
+static struct rte_flow_action_handle *
+mlx5_action_handle_create(struct rte_eth_dev *dev,
+ const struct rte_flow_indir_action_conf *conf,
const struct rte_flow_action *action,
struct rte_flow_error *error)
{
- static const char err_msg[] = "shared action creation unsupported";
+ static const char err_msg[] = "indirect action creation unsupported";
struct rte_flow_attr attr = { .transfer = 0 };
const struct mlx5_flow_driver_ops *fops =
flow_get_drv_ops(flow_get_drv_type(dev, &attr));
}
/**
- * Updates inplace the shared action configuration pointed by *action* handle
- * with the configuration provided as *action* argument.
- * The update of the shared action configuration effects all flow rules reusing
- * the action via handle.
+ * Updates inplace the indirect action configuration pointed by *handle*
+ * with the configuration provided as *update* argument.
+ * The update of the indirect action configuration effects all flow rules
+ * reusing the action via handle.
*
* @param dev
* Pointer to Ethernet device structure.
- * @param[in] shared_action
- * Handle for the shared action to be updated.
- * @param[in] action
+ * @param[in] handle
+ * Handle for the indirect action to be updated.
+ * @param[in] update
* Action specification used to modify the action pointed by handle.
- * *action* should be of same type with the action pointed by the *action*
- * handle argument, otherwise considered as invalid.
+ * *update* could be of same type with the action pointed by the *handle*
+ * handle argument, or some other structures like a wrapper, depending on
+ * the indirect action type.
* @param[out] error
* Perform verbose error reporting if not NULL. PMDs initialize this
* structure in case of error only.
* 0 on success, a negative errno value otherwise and rte_errno is set.
*/
static int
-mlx5_shared_action_update(struct rte_eth_dev *dev,
- struct rte_flow_shared_action *shared_action,
- const struct rte_flow_action *action,
+mlx5_action_handle_update(struct rte_eth_dev *dev,
+ struct rte_flow_action_handle *handle,
+ const void *update,
struct rte_flow_error *error)
{
struct rte_flow_attr attr = { .transfer = 0 };
flow_get_drv_ops(flow_get_drv_type(dev, &attr));
int ret;
- ret = flow_drv_action_validate(dev, NULL, action, fops, error);
+ ret = flow_drv_action_validate(dev, NULL,
+ (const struct rte_flow_action *)update, fops, error);
if (ret)
return ret;
- return flow_drv_action_update(dev, shared_action, action->conf, fops,
+ return flow_drv_action_update(dev, handle, update, fops,
error);
}
/**
- * Query the shared action by handle.
+ * Query the indirect action by handle.
*
* This function allows retrieving action-specific data such as counters.
* Data is gathered by special action which may be present/referenced in
* more than one flow rule definition.
*
- * \see RTE_FLOW_ACTION_TYPE_COUNT
+ * see @RTE_FLOW_ACTION_TYPE_COUNT
*
* @param dev
* Pointer to Ethernet device structure.
- * @param[in] action
- * Handle for the shared action to query.
+ * @param[in] handle
+ * Handle for the indirect action to query.
* @param[in, out] data
* Pointer to storage for the associated query data type.
* @param[out] error
* 0 on success, a negative errno value otherwise and rte_errno is set.
*/
static int
-mlx5_shared_action_query(struct rte_eth_dev *dev,
- const struct rte_flow_shared_action *action,
+mlx5_action_handle_query(struct rte_eth_dev *dev,
+ const struct rte_flow_action_handle *handle,
void *data,
struct rte_flow_error *error)
{
const struct mlx5_flow_driver_ops *fops =
flow_get_drv_ops(flow_get_drv_type(dev, &attr));
- return flow_drv_action_query(dev, action, data, fops, error);
+ return flow_drv_action_query(dev, handle, data, fops, error);
}
/**
- * Destroy all shared actions.
+ * Destroy all indirect actions (shared RSS).
*
* @param dev
* Pointer to Ethernet device.
* 0 on success, a negative errno value otherwise and rte_errno is set.
*/
int
-mlx5_shared_action_flush(struct rte_eth_dev *dev)
+mlx5_action_handle_flush(struct rte_eth_dev *dev)
{
struct rte_flow_error error;
struct mlx5_priv *priv = dev->data->dev_private;
- struct mlx5_shared_action_rss *action;
+ struct mlx5_shared_action_rss *shared_rss;
int ret = 0;
uint32_t idx;
ILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
- priv->rss_shared_actions, idx, action, next) {
- ret |= mlx5_shared_action_destroy(dev,
- (struct rte_flow_shared_action *)(uintptr_t)idx, &error);
+ priv->rss_shared_actions, idx, shared_rss, next) {
+ ret |= mlx5_action_handle_destroy(dev,
+ (struct rte_flow_action_handle *)(uintptr_t)idx, &error);
}
return ret;
}
union tunnel_offload_mark mbits = { .val = mark };
union mlx5_flow_tbl_key table_key = {
{
- .table_id = tunnel_id_to_flow_tbl(mbits.table_id),
+ .level = tunnel_id_to_flow_tbl(mbits.table_id),
+ .id = 0,
+ .reserved = 0,
.dummy = 0,
- .domain = !!mbits.transfer,
- .direction = 0,
+ .is_fdb = !!mbits.transfer,
+ .is_egress = 0,
}
};
he = mlx5_hlist_lookup(sh->flow_tbls, table_key.v64, NULL);
rte_spinlock_unlock(&thub->sl);
ctx->tunnel = mlx5_flow_tunnel_allocate(dev, ctx->app_tunnel);
- ctx->tunnel->refctn = 1;
rte_spinlock_lock(&thub->sl);
- if (ctx->tunnel)
+ if (ctx->tunnel) {
+ ctx->tunnel->refctn = 1;
LIST_INSERT_HEAD(&thub->tunnels, ctx->tunnel, chain);
+ }
}
if (!thub)
return;
if (!LIST_EMPTY(&thub->tunnels))
- DRV_LOG(WARNING, "port %u tunnels present\n", port_id);
+ DRV_LOG(WARNING, "port %u tunnels present", port_id);
mlx5_hlist_destroy(thub->groups);
mlx5_free(thub);
}
return -ENOMEM;
LIST_INIT(&thub->tunnels);
rte_spinlock_init(&thub->sl);
- thub->groups = mlx5_hlist_create("flow groups", MLX5_MAX_TABLES, 0,
+ thub->groups = mlx5_hlist_create("flow groups",
+ rte_align32pow2(MLX5_MAX_TABLES), 0,
0, mlx5_flow_tunnel_grp2tbl_create_cb,
mlx5_flow_tunnel_grp2tbl_match_cb,
mlx5_flow_tunnel_grp2tbl_remove_cb);
{
}
#endif /* HAVE_IBV_FLOW_DV_SUPPORT */
-