[PATCH v2 38/47] net/dpaa2: support flow meter and policer actions
Prashant Gupta
prashant.gupta_3 at nxp.com
Thu Sep 10 15:51:49 CEST 2026
From: Hemant Agrawal <hemant.agrawal at nxp.com>
Add support for the METER and METER_MARK flow actions. A meter flow is
programmed per traffic class and configures the DPNI policer from the
meter profile and policy that were created through the meter ops.
Meter flows carry a single action and are tracked separately from the
regular QoS and flow steering entries, so flow create, destroy and
action update dispatch them through a dedicated path.
Signed-off-by: Hemant Agrawal <hemant.agrawal at nxp.com>
---
drivers/net/dpaa2/dpaa2_flow.c | 316 +++++++++++++++++++++++++++++++++
1 file changed, 316 insertions(+)
diff --git a/drivers/net/dpaa2/dpaa2_flow.c b/drivers/net/dpaa2/dpaa2_flow.c
index f86e1c0acc..e86e6d1f8b 100644
--- a/drivers/net/dpaa2/dpaa2_flow.c
+++ b/drivers/net/dpaa2/dpaa2_flow.c
@@ -111,6 +111,7 @@ struct dpaa2_dev_flow {
struct dpaa2_generic_flow *qos_flow;
struct dpaa2_generic_flow *fs_flow;
struct dpaa2_dev_priv *priv;
+ int is_meter_flow;
};
struct rte_dpaa2_flow_item {
@@ -158,6 +159,10 @@ static const enum rte_flow_action_type dpaa2_supported_qos_action_type[] = {
RTE_FLOW_ACTION_TYPE_DROP
};
+static const enum rte_flow_action_type dpaa2_supported_meter_action_type[] = {
+ RTE_FLOW_ACTION_TYPE_METER_MARK,
+ RTE_FLOW_ACTION_TYPE_METER
+};
#define DPAA2_FLOW_HDR_HEX_DUMP_SIZE \
(RTE_MAX(sizeof(struct rte_flow_item_eth), \
@@ -3619,6 +3624,10 @@ dpaa2_flow_verify_fs_action(struct dpaa2_dev_priv *priv,
/* Skip this action, have to add for vxlan*/
case RTE_FLOW_ACTION_TYPE_DROP:
break;
+ case RTE_FLOW_ACTION_TYPE_METER_MARK:
+ break;
+ case RTE_FLOW_ACTION_TYPE_METER:
+ break;
case RTE_FLOW_ACTION_TYPE_END:
end_of_list = 1;
break;
@@ -4062,7 +4071,146 @@ dpaa2_flow_table_update(struct dpaa2_dev_priv *priv,
return 0;
}
+static int
+dpaa2_flow_action_meter_mark_init(struct dpaa2_dev_priv *priv,
+ uint32_t mtr_id, struct rte_flow_action_meter_mark *meter_mark)
+{
+ struct dpaa2_dev_meter *meter;
+ struct dpaa2_dev_meter_profile *profile;
+ struct dpaa2_dev_meter_policy *policy;
+ int found = 0;
+
+ meter = LIST_FIRST(&priv->meters);
+ while (meter) {
+ if (meter->meter_id == mtr_id) {
+ found = 1;
+ break;
+ }
+ meter = LIST_NEXT(meter, next);
+ }
+
+ if (!found) {
+ DPAA2_PMD_ERR("Meter ID(%d) is not found!", mtr_id);
+ return -ENXIO;
+ }
+
+ found = 0;
+ profile = LIST_FIRST(&priv->profiles);
+ while (profile) {
+ if (profile->profile_id == meter->profile_id) {
+ found = 1;
+ break;
+ }
+ profile = LIST_NEXT(profile, next);
+ }
+ if (!found) {
+ DPAA2_PMD_ERR("Meter ID(%d)'s profile(%d) not exist!",
+ mtr_id, meter->profile_id);
+ return -ENXIO;
+ }
+
+ found = 0;
+ policy = LIST_FIRST(&priv->policies);
+ while (policy) {
+ if (policy->policy_id == meter->policy_id) {
+ found = 1;
+ break;
+ }
+ policy = LIST_NEXT(policy, next);
+ }
+ if (!found) {
+ /** Option.*/
+ DPAA2_PMD_WARN("Meter ID(%d)'s policy(%d) not exist!",
+ mtr_id, meter->policy_id);
+ policy = NULL;
+ }
+ meter_mark->profile = (void *)profile;
+ meter_mark->policy = (void *)policy;
+ meter_mark->color_mode = 1;
+
+ return 0;
+}
+
+static int
+dpaa2_flow_set_police_action(struct dpaa2_dev_priv *priv,
+ uint8_t tc_id, const struct rte_flow_action_meter_mark *meter_mark)
+{
+ struct rte_dpaa2_device *dpaa2_dev;
+ struct dpni_rx_tc_policing_cfg policing_cfg = {0};
+ const struct dpaa2_dev_meter_profile *dpaa2_profile;
+ const struct dpaa2_dev_meter_policy *dpaa2_policy = NULL;
+ int ret;
+
+ if (!(priv->options & DPNI_OPT_HAS_POLICING)) {
+ DPAA2_PMD_ERR("POLICING(0x%08x) was not added in DPNI creating options(0x%08x)",
+ DPNI_OPT_HAS_POLICING, priv->options);
+ return -ENOTSUP;
+ }
+
+ dpaa2_dev = DPAA2_DEV_PRIV_TO_DPAA2_DEV(priv);
+
+ dpaa2_profile = (void *)meter_mark->profile;
+ if (!dpaa2_profile) {
+ DPAA2_PMD_ERR("Meter profile not specified!");
+ return -EINVAL;
+ }
+
+ /** Blind as default.*/
+ policing_cfg.options = 0;
+ if (meter_mark->color_mode)
+ policing_cfg.options = DPNI_POLICER_OPT_COLOR_AWARE;
+ if (meter_mark->policy)
+ dpaa2_policy = (void *)meter_mark->policy;
+ if (dpaa2_policy && dpaa2_policy->red_drop) {
+ policing_cfg.options |= DPNI_POLICER_OPT_DISCARD_RED;
+ } else if (!dpaa2_policy) {
+ /** Default: Red is discarded if no policy specified.*/
+ policing_cfg.options |= DPNI_POLICER_OPT_DISCARD_RED;
+ }
+
+ if (priv->flow_profile.mtr_flow[tc_id]) {
+ /** Update existing policer.*/
+ dpaa2_dev = DPAA2_DEV_PRIV_TO_DPAA2_DEV(priv);
+ policing_cfg.options |= DPNI_POLICER_OPT_DO_NOT_RESET_COUNTERS;
+ if (dpaa2_dev->bus_info->mc_rev < DPAA2_POLICER_NOT_RESET_COUNTER_MC_REV)
+ DPAA2_PMD_WARN("The existing policer's counters will be cleaned.");
+ }
+
+ policing_cfg.mode = dpaa2_profile->mode;
+ if (policing_cfg.mode < DPNI_POLICER_MODE_NONE ||
+ policing_cfg.mode > DPNI_POLICER_MODE_RFC_4115) {
+ DPAA2_PMD_ERR("Invalid policer mode(%d)",
+ policing_cfg.mode);
+ return -EINVAL;
+ }
+ policing_cfg.units = dpaa2_profile->policer_unit;
+ if (policing_cfg.units < DPNI_POLICER_UNIT_BYTES_L3 ||
+ policing_cfg.units > DPNI_POLICER_UNIT_BYTES_L2_WITHOUT_FCS) {
+ DPAA2_PMD_ERR("Invalid policer units(%d)",
+ policing_cfg.units);
+ return -EINVAL;
+ }
+ policing_cfg.cir = dpaa2_profile->cir;
+ policing_cfg.cbs = dpaa2_profile->cbs;
+ policing_cfg.eir = dpaa2_profile->pir;
+ policing_cfg.ebs = dpaa2_profile->pbs;
+
+ if (dpaa2_dev->bus_info->mc_rev < DPAA2_POLICER_SET_V2_MC_REV) {
+ ret = dpni_set_rx_tc_policing_v1(priv->hw, CMD_PRI_LOW,
+ priv->token, tc_id, &policing_cfg);
+ } else {
+ ret = dpni_set_rx_tc_policing(priv->hw, CMD_PRI_LOW,
+ priv->token, tc_id, &policing_cfg);
+ }
+ DPAA2_PMD_INFO("%s RX TC%d policer configure %s.",
+ priv->eth_dev->data->name, tc_id,
+ ret ? "failed" : "successfully");
+ if (!ret)
+ priv->flow_profile.tc_mtr_profile[tc_id] = (void *)meter_mark->profile;
+
+ return ret;
+}
static int
dpaa2_flow_action_single_type_check(const struct rte_flow_action actions[],
@@ -4119,6 +4267,8 @@ dpaa2_flow_fs_action_update(struct dpaa2_dev_priv *priv,
const struct rte_flow_action actions[])
{
int end_of_list = 0, ret = 0, i = 0;
+ const struct rte_flow_action_meter *meter;
+ struct rte_flow_action_meter_mark meter_mark;
union dpaa2_dev_flow_action flow_action_rollback;
rte_memcpy(&flow_action_rollback, &fs_flow->flow_action,
@@ -4136,6 +4286,26 @@ dpaa2_flow_fs_action_update(struct dpaa2_dev_priv *priv,
if (ret)
goto end_action_set;
+ break;
+ case RTE_FLOW_ACTION_TYPE_METER_MARK:
+ rte_memcpy(&meter_mark, actions[i].conf,
+ sizeof(meter_mark));
+ ret = dpaa2_flow_set_police_action(priv,
+ fs_flow->tc_id, &meter_mark);
+ if (ret)
+ goto end_action_set;
+ break;
+ case RTE_FLOW_ACTION_TYPE_METER:
+ meter = actions[i].conf;
+ ret = dpaa2_flow_action_meter_mark_init(priv,
+ meter->mtr_id, &meter_mark);
+ if (ret)
+ goto end_action_set;
+ ret = dpaa2_flow_set_police_action(priv,
+ fs_flow->tc_id, &meter_mark);
+ if (ret)
+ goto end_action_set;
+
break;
case RTE_FLOW_ACTION_TYPE_PF:
/* Skip this action, have to add for vxlan*/
@@ -4557,6 +4727,29 @@ dpaa2_flow_validate(struct rte_eth_dev *dev,
}
}
+ supported = dpaa2_supported_meter_action_type;
+ supported_len = RTE_DIM(dpaa2_supported_meter_action_type);
+ if (dpaa2_flow_check_actions_support(actions, supported, supported_len)) {
+ DPAA2_PMD_DEBUG("This is meter flow.");
+ if (group_type == RTE_DPAA2_QOS_GROUP_FLOW) {
+ err_str = "Meter flow's type can't be QoS flow.";
+ cause = actions;
+ err_type = RTE_FLOW_ERROR_TYPE_ACTION;
+ ret = -EPERM;
+ goto invalid_params;
+ }
+ if (actions[1].type != RTE_FLOW_ACTION_TYPE_END) {
+ err_str = "Meter flow can't support multi-actions.";
+ cause = actions;
+ err_type = RTE_FLOW_ERROR_TYPE_ACTION_NUM;
+ ret = -EPERM;
+ goto invalid_params;
+ }
+ if (pattern)
+ DPAA2_PMD_WARN("Meter flow ingores flow items!");
+ return 0;
+ }
+
/* Verify input action list */
if (group_type == RTE_DPAA2_ONE_LEVEL_GROUP_FLOW ||
group_type == RTE_DPAA2_FS_GROUP_FLOW) {
@@ -5383,6 +5576,51 @@ dpaa2_flow_generic_flow_create(struct rte_eth_dev *dev,
return NULL;
}
+static struct rte_flow *
+dpaa2_flow_create_meter_flow(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_action meter_action[])
+{
+ struct dpaa2_dev_priv *priv = dev->data->dev_private;
+ struct dpaa2_dev_flow *flow = NULL;
+ struct dpaa2_generic_flow *fs_flow = NULL;
+ int ret;
+
+ if (attr->group >= priv->num_rx_tc)
+ return NULL;
+
+ if (priv->flow_profile.mtr_flow[attr->group])
+ return NULL;
+
+ fs_flow = rte_zmalloc(NULL, sizeof(struct dpaa2_generic_flow),
+ RTE_CACHE_LINE_SIZE);
+ if (!fs_flow) {
+ DPAA2_PMD_ERR("Failure to allocate memory for flow");
+ return NULL;
+ }
+ flow = rte_zmalloc(NULL, sizeof(struct dpaa2_dev_flow),
+ RTE_CACHE_LINE_SIZE);
+ if (!flow) {
+ rte_free(fs_flow);
+ DPAA2_PMD_ERR("Failure to allocate memory for flow");
+ return NULL;
+ }
+ fs_flow->tc_id = attr->group;
+ fs_flow->priv = priv;
+ flow->fs_flow = fs_flow;
+ flow->priv = priv;
+
+ ret = dpaa2_flow_fs_action_update(priv, fs_flow, meter_action);
+ if (ret) {
+ rte_free(fs_flow);
+ rte_free(flow);
+ return NULL;
+ }
+ flow->is_meter_flow = true;
+ priv->flow_profile.mtr_flow[fs_flow->tc_id] = flow;
+
+ return (struct rte_flow *)flow;
+}
static struct rte_flow *
dpaa2_flow_create(struct rte_eth_dev *dev,
@@ -5447,6 +5685,30 @@ dpaa2_flow_create(struct rte_eth_dev *dev,
rss_item = true;
}
+ if (dpaa2_flow_check_actions_support(actions,
+ dpaa2_supported_meter_action_type,
+ RTE_DIM(dpaa2_supported_meter_action_type))) {
+ /** Assume it's meter flow per TC.*/
+ if (group_type == RTE_DPAA2_QOS_GROUP_FLOW) {
+ error_type = RTE_FLOW_ERROR_TYPE_ATTR_GROUP;
+ err_code = -EINVAL;
+ err_str = "Failed to converts RSS config type to RSS items!";
+ goto flow_failure;
+ }
+ if (actions[1].type != RTE_FLOW_ACTION_TYPE_END) {
+ error_type = RTE_FLOW_ERROR_TYPE_ACTION_NUM;
+ err_code = -EPERM;
+ err_str = "Meter flow can't support multi-actions.";
+ goto flow_failure;
+ }
+ flow = (void *)dpaa2_flow_create_meter_flow(dev, &local_attr, actions);
+ if (flow)
+ return (struct rte_flow *)flow;
+ error_type = RTE_FLOW_ERROR_TYPE_ACTION;
+ err_code = -EINVAL;
+ err_str = "Failed to create meter flow!";
+ goto flow_failure;
+ }
DPAA2_PMD_DEBUG("Port %s-%s: group type:%d, group id:%d, total RX TCs:%d",
dev->data->name, __func__, group_type, group_id, priv->num_rx_tc);
@@ -5573,6 +5835,38 @@ dpaa2_flow_create(struct rte_eth_dev *dev,
return NULL;
}
+static int
+dpaa2_flow_destroy_meter_flow(struct rte_eth_dev *dev,
+ struct dpaa2_dev_flow *flow)
+{
+ struct rte_dpaa2_device *dpaa2_dev;
+ struct dpaa2_dev_priv *priv = dev->data->dev_private;
+ struct dpni_rx_tc_policing_cfg cfg;
+ int ret;
+ uint8_t tc_id;
+
+ RTE_ASSERT(!flow->qos_flow && flow->fs_flow);
+ dpaa2_dev = DPAA2_DEV_PRIV_TO_DPAA2_DEV(priv);
+ tc_id = flow->fs_flow->tc_id;
+ RTE_ASSERT(priv->flow_profile.mtr_flow[tc_id] == flow);
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.mode = DPNI_POLICER_MODE_NONE;
+ if (dpaa2_dev->bus_info->mc_rev < DPAA2_POLICER_SET_V2_MC_REV) {
+ ret = dpni_set_rx_tc_policing_v1(priv->hw, CMD_PRI_LOW,
+ priv->token, tc_id, &cfg);
+ } else {
+ ret = dpni_set_rx_tc_policing(priv->hw, CMD_PRI_LOW,
+ priv->token, tc_id, &cfg);
+ }
+ if (ret)
+ return ret;
+ priv->flow_profile.tc_mtr_profile[tc_id] = NULL;
+ priv->flow_profile.mtr_flow[tc_id] = NULL;
+ rte_free(flow->fs_flow);
+ rte_free(flow);
+
+ return 0;
+}
static int
dpaa2_flow_destroy(struct rte_eth_dev *dev,
@@ -5587,6 +5881,8 @@ dpaa2_flow_destroy(struct rte_eth_dev *dev,
RTE_SET_USED(error);
flow = (struct dpaa2_dev_flow *)_flow;
+ if (flow->is_meter_flow)
+ return dpaa2_flow_destroy_meter_flow(dev, flow);
LIST_REMOVE(flow, next);
@@ -5663,6 +5959,26 @@ dpaa2_flow_actions_update(struct rte_eth_dev *dev,
/* check for the valid flow */
flow = (void *)_flow;
+ if (flow->is_meter_flow) {
+ RTE_ASSERT(flow->fs_flow);
+ tc_id = flow->fs_flow->tc_id;
+ RTE_ASSERT(priv->flow_profile.mtr_flow[tc_id] == flow);
+ supported = dpaa2_supported_meter_action_type;
+ supported_len = RTE_DIM(dpaa2_supported_meter_action_type);
+ if (!dpaa2_flow_check_actions_support(actions, supported, supported_len)) {
+ error_type = RTE_FLOW_ERROR_TYPE_ACTION;
+ err_str = "Failed to verify meter action!";
+ err_code = -ENOTSUP;
+ goto quit;
+ }
+ ret = dpaa2_flow_fs_action_update(priv, flow->fs_flow, actions);
+ if (ret) {
+ error_type = RTE_FLOW_ERROR_TYPE_ACTION;
+ err_str = "Failed to update meter action!";
+ err_code = ret;
+ }
+ goto quit;
+ }
LIST_FOREACH(flow, &priv->flows, next) {
if ((struct rte_flow *)flow == _flow)
goto action_update;
--
2.43.0
More information about the dev
mailing list