};
#define MLX5_MAN_WIDTH 8
+/* Modify this value if enum rte_mtr_color changes. */
+#define RTE_MTR_DROPPED RTE_COLORS
+
+/* Meter table structure. */
+struct mlx5_meter_domain_info {
+ struct mlx5_flow_tbl_resource *tbl;
+ /**< Meter table. */
+ void *any_matcher;
+ /**< Meter color not match default criteria. */
+ void *color_matcher;
+ /**< Meter color match criteria. */
+ void *jump_actn;
+ /**< Meter match action. */
+ void *policer_rules[RTE_MTR_DROPPED + 1];
+ /**< Meter policer for the match. */
+};
+
+/* Meter table set for TX RX FDB. */
+struct mlx5_meter_domains_infos {
+ uint32_t ref_cnt;
+ /**< Table user count. */
+ struct mlx5_meter_domain_info egress;
+ /**< TX meter table. */
+ struct mlx5_meter_domain_info ingress;
+ /**< RX meter table. */
+ struct mlx5_meter_domain_info transfer;
+ /**< FDB meter table. */
+ void *drop_actn;
+ /**< Drop action as not matched. */
+};
+
+/* Meter parameter structure. */
+struct mlx5_flow_meter {
+ uint32_t meter_id;
+ /**< Meter id. */
+ struct mlx5_meter_domains_infos *mfts;
+ /**< Flow table created for this meter. */
+ uint32_t ref_cnt;
+ /**< Use count. */
+};
/* RFC2697 parameter structure. */
struct mlx5_flow_meter_srtcm_rfc2697_prm {
const struct rte_flow_action *actions,
void *data,
struct rte_flow_error *error);
+typedef struct mlx5_meter_domains_infos *(*mlx5_flow_create_mtr_tbls_t)
+ (struct rte_eth_dev *dev);
+typedef int (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
+ struct mlx5_meter_domains_infos *tbls);
struct mlx5_flow_driver_ops {
mlx5_flow_validate_t validate;
mlx5_flow_prepare_t prepare;
mlx5_flow_remove_t remove;
mlx5_flow_destroy_t destroy;
mlx5_flow_query_t query;
+ mlx5_flow_create_mtr_tbls_t create_mtr_tbls;
+ mlx5_flow_destroy_mtr_tbls_t destroy_mtr_tbls;
};
uint64_t item_flags,
struct rte_eth_dev *dev,
struct rte_flow_error *error);
+struct mlx5_meter_domains_infos *mlx5_flow_create_mtr_tbls
+ (struct rte_eth_dev *dev);
+int mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
+ struct mlx5_meter_domains_infos *tbl);
#endif /* RTE_PMD_MLX5_FLOW_H_ */
attr->valid = 1;
}
+/**
+ * Convert rte_mtr_color to mlx5 color.
+ *
+ * @param[in] rcol
+ * rte_mtr_color.
+ *
+ * @return
+ * mlx5 color.
+ */
+static int
+rte_col_2_mlx5_col(enum rte_color rcol)
+{
+ switch (rcol) {
+ case RTE_COLOR_GREEN:
+ return MLX5_FLOW_COLOR_GREEN;
+ case RTE_COLOR_YELLOW:
+ return MLX5_FLOW_COLOR_YELLOW;
+ case RTE_COLOR_RED:
+ return MLX5_FLOW_COLOR_RED;
+ default:
+ break;
+ }
+ return MLX5_FLOW_COLOR_UNDEFINED;
+}
+
struct field_modify_info {
uint32_t size; /* Size of field in protocol header, in bytes. */
uint32_t offset; /* Offset of field in protocol header, in bytes. */
return ret;
}
+/**
+ * Destroy the meter table set.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] tbl
+ * Pointer to the meter table set.
+ *
+ * @return
+ * Always 0.
+ */
+static int
+flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
+ struct mlx5_meter_domains_infos *tbl)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_meter_domains_infos *mtd =
+ (struct mlx5_meter_domains_infos *)tbl;
+
+ if (!mtd || !priv->config.dv_flow_en)
+ return 0;
+ if (mtd->ingress.policer_rules[RTE_MTR_DROPPED])
+ claim_zero(mlx5_glue->dv_destroy_flow
+ (mtd->ingress.policer_rules[RTE_MTR_DROPPED]));
+ if (mtd->egress.policer_rules[RTE_MTR_DROPPED])
+ claim_zero(mlx5_glue->dv_destroy_flow
+ (mtd->egress.policer_rules[RTE_MTR_DROPPED]));
+ if (mtd->transfer.policer_rules[RTE_MTR_DROPPED])
+ claim_zero(mlx5_glue->dv_destroy_flow
+ (mtd->transfer.policer_rules[RTE_MTR_DROPPED]));
+ if (mtd->egress.color_matcher)
+ claim_zero(mlx5_glue->dv_destroy_flow_matcher
+ (mtd->egress.color_matcher));
+ if (mtd->egress.any_matcher)
+ claim_zero(mlx5_glue->dv_destroy_flow_matcher
+ (mtd->egress.any_matcher));
+ if (mtd->egress.tbl)
+ claim_zero(flow_dv_tbl_resource_release(mtd->egress.tbl));
+ if (mtd->ingress.color_matcher)
+ claim_zero(mlx5_glue->dv_destroy_flow_matcher
+ (mtd->ingress.color_matcher));
+ if (mtd->ingress.any_matcher)
+ claim_zero(mlx5_glue->dv_destroy_flow_matcher
+ (mtd->ingress.any_matcher));
+ if (mtd->ingress.tbl)
+ claim_zero(flow_dv_tbl_resource_release(mtd->ingress.tbl));
+ if (mtd->transfer.color_matcher)
+ claim_zero(mlx5_glue->dv_destroy_flow_matcher
+ (mtd->transfer.color_matcher));
+ if (mtd->transfer.any_matcher)
+ claim_zero(mlx5_glue->dv_destroy_flow_matcher
+ (mtd->transfer.any_matcher));
+ if (mtd->transfer.tbl)
+ claim_zero(flow_dv_tbl_resource_release(mtd->transfer.tbl));
+ if (mtd->drop_actn)
+ claim_zero(mlx5_glue->destroy_flow_action(mtd->drop_actn));
+ rte_free(mtd);
+ return 0;
+}
+
+/**
+ * Create specify domain meter table and suffix table.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in,out] mtb
+ * Pointer to DV meter table set.
+ * @param[in] egress
+ * Table attribute.
+ * @param[in] transfer
+ * Table attribute.
+ * @param[in] color_reg_c_idx
+ * Reg C index for color match.
+ *
+ * @return
+ * 0 on success, -1 otherwise and rte_errno is set.
+ */
+static int
+flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
+ struct mlx5_meter_domains_infos *mtb,
+ uint8_t egress, uint8_t transfer,
+ uint32_t color_reg_c_idx)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_ibv_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,
+ };
+ /*
+ * Need reserve two actions here. As for the meter flow, the action
+ * to be performed will be jump or drop. The other reserve action is
+ * for count.
+ */
+#define METER_ACTIONS 2
+ void *actions[METER_ACTIONS];
+ struct mlx5_flow_tbl_resource **sfx_tbl;
+ struct mlx5_meter_domain_info *dtb;
+ struct rte_flow_error error;
+ int i = 0;
+
+ if (transfer) {
+ sfx_tbl = &sh->fdb_mtr_sfx_tbl;
+ dtb = &mtb->transfer;
+ } else if (egress) {
+ sfx_tbl = &sh->tx_mtr_sfx_tbl;
+ dtb = &mtb->egress;
+ } else {
+ sfx_tbl = &sh->rx_mtr_sfx_tbl;
+ dtb = &mtb->ingress;
+ }
+ /* If the suffix table in missing, create it. */
+ if (!(*sfx_tbl)) {
+ *sfx_tbl = flow_dv_tbl_resource_get(dev,
+ MLX5_FLOW_TABLE_LEVEL_SUFFIX,
+ egress, transfer, &error);
+ if (!(*sfx_tbl)) {
+ DRV_LOG(ERR, "Failed to create meter suffix table.");
+ return -1;
+ }
+ }
+ /* Create the meter table with METER level. */
+ dtb->tbl = flow_dv_tbl_resource_get(dev, MLX5_FLOW_TABLE_LEVEL_METER,
+ egress, transfer, &error);
+ if (!dtb->tbl) {
+ DRV_LOG(ERR, "Failed to create meter policer table.");
+ return -1;
+ }
+ /* Create matchers, Any and Color. */
+ dv_attr.priority = 3;
+ dv_attr.match_criteria_enable = 0;
+ dtb->any_matcher = mlx5_glue->dv_create_flow_matcher(sh->ctx,
+ &dv_attr,
+ dtb->tbl->obj);
+ if (!dtb->any_matcher) {
+ DRV_LOG(ERR, "Failed to create meter"
+ " policer default matcher.");
+ goto error_exit;
+ }
+ dv_attr.priority = 0;
+ dv_attr.match_criteria_enable =
+ 1 << MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
+ flow_dv_match_meta_reg(mask.buf, value.buf, color_reg_c_idx,
+ rte_col_2_mlx5_col(RTE_COLORS), UINT32_MAX);
+ dtb->color_matcher = mlx5_glue->dv_create_flow_matcher(sh->ctx,
+ &dv_attr,
+ dtb->tbl->obj);
+ if (!dtb->color_matcher) {
+ DRV_LOG(ERR, "Failed to create meter policer color matcher.");
+ goto error_exit;
+ }
+ actions[i++] = mtb->drop_actn;
+ /* Default rule: lowest priority, match any, actions: drop. */
+ dtb->policer_rules[RTE_MTR_DROPPED] =
+ mlx5_glue->dv_create_flow(dtb->any_matcher,
+ (void *)&value, i, actions);
+ if (!dtb->policer_rules[RTE_MTR_DROPPED]) {
+ DRV_LOG(ERR, "Failed to create meter policer drop rule.");
+ goto error_exit;
+ }
+ return 0;
+error_exit:
+ return -1;
+}
+
+/**
+ * Create the needed meter and suffix tables.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ *
+ * @return
+ * Pointer to table set on success, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_meter_domains_infos *
+flow_dv_create_mtr_tbl(struct rte_eth_dev *dev)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_meter_domains_infos *mtb;
+ int ret;
+
+ if (!priv->mtr_en) {
+ rte_errno = ENOTSUP;
+ return NULL;
+ }
+ mtb = rte_calloc(__func__, 1, sizeof(*mtb), 0);
+ if (!mtb) {
+ DRV_LOG(ERR, "Failed to allocate memory for meter.");
+ return NULL;
+ }
+ /* Create drop action. */
+ mtb->drop_actn = mlx5_glue->dr_create_flow_action_drop();
+ if (!mtb->drop_actn) {
+ DRV_LOG(ERR, "Failed to create drop action.");
+ goto error_exit;
+ }
+ /* Egress meter table. */
+ ret = flow_dv_prepare_mtr_tables(dev, mtb, 1, 0, priv->mtr_color_reg);
+ if (ret) {
+ DRV_LOG(ERR, "Failed to prepare egress meter table.");
+ goto error_exit;
+ }
+ /* Ingress meter table. */
+ ret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 0, priv->mtr_color_reg);
+ if (ret) {
+ DRV_LOG(ERR, "Failed to prepare ingress meter table.");
+ goto error_exit;
+ }
+ /* FDB meter table. */
+ if (priv->config.dv_esw_en) {
+ ret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 1,
+ priv->mtr_color_reg);
+ if (ret) {
+ DRV_LOG(ERR, "Failed to prepare fdb meter table.");
+ goto error_exit;
+ }
+ }
+ return mtb;
+error_exit:
+ flow_dv_destroy_mtr_tbl(dev, mtb);
+ return NULL;
+}
+
/*
* Mutex-protected thunk to lock-free __flow_dv_translate().
*/
.remove = flow_dv_remove,
.destroy = flow_dv_destroy,
.query = flow_dv_query,
+ .create_mtr_tbls = flow_dv_create_mtr_tbl,
+ .destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
};
#endif /* HAVE_IBV_FLOW_DV_SUPPORT */