ethdev: add pre-defined meter policy API

Currently, the flow meter policy does not support multiple actions
per color; also the allowed action types per color are very limited.
In addition, the policy cannot be pre-defined.

Due to the growing in flow actions offload abilities there is a potential
for the user to use variety of actions per color differently.
This new meter policy API comes to allow this potential in the most ethdev
common way using rte_flow action definition.
A list of rte_flow actions will be provided by the user per color
in order to create a meter policy.
In addition, the API forces to pre-define the policy before
the meters creation in order to allow sharing of single policy
with multiple meters efficiently.

meter_policy_id is added into struct rte_mtr_params.
So that it can get the policy during the meters creation.

Allow coloring the packet using a new rte_flow_action_color
as could be done by the old policy API.

Add two common policy template as macros in the head file.

The next API function were added:
- rte_mtr_meter_policy_add
- rte_mtr_meter_policy_delete
- rte_mtr_meter_policy_update
- rte_mtr_meter_policy_validate
The next struct was changed:
- rte_mtr_params
- rte_mtr_capabilities
The next API was deleted:
- rte_mtr_policer_actions_update

To support this API the following app were changed:
app/test-flow-perf: clean meter policer
app/testpmd: clean meter policer

To support this API the following drivers were changed:
net/softnic: support meter policy API
1. Cleans meter rte_mtr_policer_action.
2. Supports policy API to get color action as policer action did.
   The color action will be mapped into rte_table_action_policer.

net/mlx5: clean meter creation management
Cleans and breaks part of the current meter management
in order to allow better design with policy API.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Signed-off-by: Haifei Luo <haifeil@nvidia.com>
Signed-off-by: Jiawei Wang <jiaweiw@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
Acked-by: Ray Kinsella <mdr@ashroe.eu>
Acked-by: Ori Kam <orika@nvidia.com>
Acked-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Acked-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
This commit is contained in:
Li Zhang 2021-04-20 17:04:49 +03:00 committed by Ferruh Yigit
parent fa1d598844
commit 5f0d54f372
22 changed files with 609 additions and 1270 deletions

View File

@ -928,13 +928,6 @@ create_meter_rule(int port_id, uint32_t counter)
/*create meter*/
params.meter_profile_id = default_prof_id;
params.action[RTE_COLOR_GREEN] =
MTR_POLICER_ACTION_COLOR_GREEN;
params.action[RTE_COLOR_YELLOW] =
MTR_POLICER_ACTION_COLOR_YELLOW;
params.action[RTE_COLOR_RED] =
MTR_POLICER_ACTION_DROP;
ret = rte_mtr_create(port_id, counter, &params, 1, &error);
if (ret != 0) {
printf("Port %u create meter idx(%d) error(%d) message: %s\n",

View File

@ -17427,7 +17427,6 @@ cmdline_parse_ctx_t main_ctx[] = {
(cmdline_parse_inst_t *)&cmd_del_port_meter,
(cmdline_parse_inst_t *)&cmd_set_port_meter_profile,
(cmdline_parse_inst_t *)&cmd_set_port_meter_dscp_table,
(cmdline_parse_inst_t *)&cmd_set_port_meter_policer_action,
(cmdline_parse_inst_t *)&cmd_set_port_meter_stats_mask,
(cmdline_parse_inst_t *)&cmd_show_port_meter_stats,
(cmdline_parse_inst_t *)&cmd_mcast_addr,

View File

@ -146,53 +146,6 @@ parse_meter_color_str(char *c_str, uint32_t *use_prev_meter_color,
return 0;
}
static int
string_to_policer_action(char *s)
{
if ((strcmp(s, "G") == 0) || (strcmp(s, "g") == 0))
return MTR_POLICER_ACTION_COLOR_GREEN;
if ((strcmp(s, "Y") == 0) || (strcmp(s, "y") == 0))
return MTR_POLICER_ACTION_COLOR_YELLOW;
if ((strcmp(s, "R") == 0) || (strcmp(s, "r") == 0))
return MTR_POLICER_ACTION_COLOR_RED;
if ((strcmp(s, "D") == 0) || (strcmp(s, "d") == 0))
return MTR_POLICER_ACTION_DROP;
return -1;
}
static int
parse_policer_action_string(char *p_str, uint32_t action_mask,
enum rte_mtr_policer_action actions[])
{
char *token;
int count = __builtin_popcount(action_mask);
int g_color = 0, y_color = 0, action, i;
for (i = 0; i < count; i++) {
token = strtok_r(p_str, PARSE_DELIMITER, &p_str);
if (token == NULL)
return -1;
action = string_to_policer_action(token);
if (action == -1)
return -1;
if (g_color == 0 && (action_mask & 0x1)) {
actions[RTE_COLOR_GREEN] = action;
g_color = 1;
} else if (y_color == 0 && (action_mask & 0x2)) {
actions[RTE_COLOR_YELLOW] = action;
y_color = 1;
} else
actions[RTE_COLOR_RED] = action;
}
return 0;
}
static int
parse_multi_token_string(char *t_str, uint16_t *port_id,
uint32_t *mtr_id, enum rte_color **dscp_table)
@ -302,10 +255,6 @@ static void cmd_show_port_meter_cap_parsed(void *parsed_result,
cap.color_aware_trtcm_rfc2698_supported);
printf("cap.color_aware_trtcm_rfc4115_supported %" PRId32 "\n",
cap.color_aware_trtcm_rfc4115_supported);
printf("cap.policer_action_recolor_supported %" PRId32 "\n",
cap.policer_action_recolor_supported);
printf("cap.policer_action_drop_supported %" PRId32 "\n",
cap.policer_action_drop_supported);
printf("cap.srtcm_rfc2697_byte_mode_supported %" PRId32 "\n",
cap.srtcm_rfc2697_byte_mode_supported);
printf("cap.srtcm_rfc2697_packet_mode_supported %" PRId32 "\n",
@ -842,12 +791,6 @@ static void cmd_create_port_meter_parsed(void *parsed_result,
else
params.meter_enable = 0;
params.action[RTE_COLOR_GREEN] =
string_to_policer_action(res->g_action);
params.action[RTE_COLOR_YELLOW] =
string_to_policer_action(res->y_action);
params.action[RTE_COLOR_RED] =
string_to_policer_action(res->r_action);
params.stats_mask = res->statistics_mask;
ret = rte_mtr_create(port_id, mtr_id, &params, shared, &error);
@ -1215,121 +1158,6 @@ cmdline_parse_inst_t cmd_set_port_meter_dscp_table = {
},
};
/* *** Set Port Meter Policer Action *** */
struct cmd_set_port_meter_policer_action_result {
cmdline_fixed_string_t set;
cmdline_fixed_string_t port;
cmdline_fixed_string_t meter;
cmdline_fixed_string_t policer;
cmdline_fixed_string_t action;
uint16_t port_id;
uint32_t mtr_id;
uint32_t action_mask;
cmdline_multi_string_t policer_action;
};
cmdline_parse_token_string_t cmd_set_port_meter_policer_action_set =
TOKEN_STRING_INITIALIZER(
struct cmd_set_port_meter_policer_action_result, set, "set");
cmdline_parse_token_string_t cmd_set_port_meter_policer_action_port =
TOKEN_STRING_INITIALIZER(
struct cmd_set_port_meter_policer_action_result, port, "port");
cmdline_parse_token_string_t cmd_set_port_meter_policer_action_meter =
TOKEN_STRING_INITIALIZER(
struct cmd_set_port_meter_policer_action_result, meter,
"meter");
cmdline_parse_token_string_t cmd_set_port_meter_policer_action_policer =
TOKEN_STRING_INITIALIZER(
struct cmd_set_port_meter_policer_action_result, policer,
"policer");
cmdline_parse_token_string_t cmd_set_port_meter_policer_action_action =
TOKEN_STRING_INITIALIZER(
struct cmd_set_port_meter_policer_action_result, action,
"action");
cmdline_parse_token_num_t cmd_set_port_meter_policer_action_port_id =
TOKEN_NUM_INITIALIZER(
struct cmd_set_port_meter_policer_action_result, port_id,
RTE_UINT16);
cmdline_parse_token_num_t cmd_set_port_meter_policer_action_mtr_id =
TOKEN_NUM_INITIALIZER(
struct cmd_set_port_meter_policer_action_result, mtr_id,
RTE_UINT32);
cmdline_parse_token_num_t cmd_set_port_meter_policer_action_action_mask =
TOKEN_NUM_INITIALIZER(
struct cmd_set_port_meter_policer_action_result, action_mask,
RTE_UINT32);
cmdline_parse_token_string_t cmd_set_port_meter_policer_action_policer_action =
TOKEN_STRING_INITIALIZER(
struct cmd_set_port_meter_policer_action_result,
policer_action, TOKEN_STRING_MULTI);
static void cmd_set_port_meter_policer_action_parsed(void *parsed_result,
__rte_unused struct cmdline *cl,
__rte_unused void *data)
{
struct cmd_set_port_meter_policer_action_result *res = parsed_result;
enum rte_mtr_policer_action *actions;
struct rte_mtr_error error;
uint32_t mtr_id = res->mtr_id;
uint32_t action_mask = res->action_mask;
uint16_t port_id = res->port_id;
char *p_str = res->policer_action;
int ret;
if (port_id_is_invalid(port_id, ENABLED_WARN))
return;
/* Check: action mask */
if (action_mask == 0 || (action_mask & (~0x7UL))) {
printf(" Policer action mask not correct (error)\n");
return;
}
/* Allocate memory for policer actions */
actions = (enum rte_mtr_policer_action *)malloc(RTE_COLORS *
sizeof(enum rte_mtr_policer_action));
if (actions == NULL) {
printf("Memory for policer actions not allocated (error)\n");
return;
}
/* Parse policer action string */
ret = parse_policer_action_string(p_str, action_mask, actions);
if (ret) {
printf(" Policer action string parse error\n");
free(actions);
return;
}
ret = rte_mtr_policer_actions_update(port_id, mtr_id,
action_mask, actions, &error);
if (ret != 0) {
free(actions);
print_err_msg(&error);
return;
}
free(actions);
}
cmdline_parse_inst_t cmd_set_port_meter_policer_action = {
.f = cmd_set_port_meter_policer_action_parsed,
.data = NULL,
.help_str = "set port meter policer action <port_id> <mtr_id> "
"<action_mask> <action0> [<action1> <action2>]",
.tokens = {
(void *)&cmd_set_port_meter_policer_action_set,
(void *)&cmd_set_port_meter_policer_action_port,
(void *)&cmd_set_port_meter_policer_action_meter,
(void *)&cmd_set_port_meter_policer_action_policer,
(void *)&cmd_set_port_meter_policer_action_action,
(void *)&cmd_set_port_meter_policer_action_port_id,
(void *)&cmd_set_port_meter_policer_action_mtr_id,
(void *)&cmd_set_port_meter_policer_action_action_mask,
(void *)&cmd_set_port_meter_policer_action_policer_action,
NULL,
},
};
/* *** Set Port Meter Stats Mask *** */
struct cmd_set_port_meter_stats_mask_result {
cmdline_fixed_string_t set;

View File

@ -17,7 +17,6 @@ extern cmdline_parse_inst_t cmd_disable_port_meter;
extern cmdline_parse_inst_t cmd_del_port_meter;
extern cmdline_parse_inst_t cmd_set_port_meter_profile;
extern cmdline_parse_inst_t cmd_set_port_meter_dscp_table;
extern cmdline_parse_inst_t cmd_set_port_meter_policer_action;
extern cmdline_parse_inst_t cmd_set_port_meter_stats_mask;
extern cmdline_parse_inst_t cmd_show_port_meter_stats;

View File

@ -2982,6 +2982,27 @@ The current conntrack context information could be queried via the
| ``reserved`` | reserved bits |
+----------------+-------------------------------------------------+
Action: ``METER_COLOR``
^^^^^^^^^^^^^^^^^^^^^^^
Color the packet to reflect the meter color result.
The meter action must be configured before meter color action.
Meter color action is set to a color to reflect the meter color result.
Set the meter color in the mbuf to the selected color.
The meter color action output color is the output color of the packet,
which is set in the packet meta-data (i.e. struct ``rte_mbuf::sched::color``)
.. _table_rte_flow_action_meter_color:
.. table:: METER_COLOR
+-----------------+--------------+
| Field | Value |
+=================+==============+
| ``meter_color`` | Packet color |
+-----------------+--------------+
Negative types
~~~~~~~~~~~~~~

View File

@ -56,18 +56,10 @@ The processing done for each input packet hitting an MTR object is:
color blind mode, which is equivalent to considering all input packets
initially colored as green.
* Policing: There is a separate policer action configured for each meter
output color, which can:
* Drop the packet.
* Keep the same packet color: the policer output color matches the meter
output color (essentially a no-op action).
* Recolor the packet: the policer output color is set to a different color
than the meter output color. The policer output color is the output color
of the packet, which is set in the packet meta-data (i.e. struct
``rte_mbuf::sched::color``).
* There is a meter policy API to manage pre-defined policies for meter.
Any rte_flow action list can be configured per color for each policy.
A meter object configured with a policy executes the actions per packet
according to the packet color.
* Statistics: The set of counters maintained for each MTR object is
configurable and subject to the implementation support. This set includes

View File

@ -88,11 +88,12 @@ New Features
* Added new field ``queue_state`` to ``rte_eth_txq_info`` structure to
provide indicated Tx queue state.
* **Added support for meter PPS profile.**
* **Updated meter API.**
Added packet mode in the meter profile parameters data structures
to support metering traffic by packet per second (PPS),
in addition to the initial bytes per second (BPS) mode (value 0).
* Added packet mode in the meter profile parameters data structures
to support metering traffic by packet per second (PPS),
in addition to the initial bytes per second (BPS) mode (value 0).
* Added support of pre-defined meter policy via flow action list per color.
* **Added packet integrity match to flow rules.**
@ -308,6 +309,11 @@ API Changes
The action ``RTE_FLOW_ACTION_TYPE_SHARED`` is deprecated and can be
replaced with ``RTE_FLOW_ACTION_TYPE_INDIRECT``.
* ethdev: The experimental function ``rte_mtr_policer_actions_update()``,
the enum ``rte_mtr_policer_action``, and the struct members
``policer_action_recolor_supported`` and ``policer_action_drop_supported``
have been removed.
ABI Changes
-----------

View File

@ -2831,24 +2831,6 @@ Set meter dscp table for the ethernet device::
testpmd> set port meter dscp table (port_id) (mtr_id) [(dscp_tbl_entry0) \
(dscp_tbl_entry1)...(dscp_tbl_entry63)]
set port meter policer action
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set meter policer action for the ethernet device::
testpmd> set port meter policer action (port_id) (mtr_id) (action_mask) \
(action0) [(action1) (action1)]
where:
* ``action_mask``: Bit mask indicating which policer actions need to be
updated. One or more policer actions can be updated in a single function
invocation. To update the policer action associated with color C, bit
(1 << C) needs to be set in *action_mask* and element at position C
in the *actions* array needs to be valid.
* ``actionx``: Policer action for the color x,
RTE_MTR_GREEN <= x < RTE_MTR_COLORS
set port meter stats mask
~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -593,14 +593,6 @@ struct mlx5_dev_shared_port {
/* Modify this value if enum rte_mtr_color changes. */
#define RTE_MTR_DROPPED RTE_COLORS
/* Meter policer statistics */
struct mlx5_flow_policer_stats {
uint32_t pass_cnt;
/**< Color counter for pass. */
uint32_t drop_cnt;
/**< Color counter for drop. */
};
/* Meter table structure. */
struct mlx5_meter_domain_info {
struct mlx5_flow_tbl_resource *tbl;
@ -639,24 +631,12 @@ struct mlx5_meter_domains_infos {
/* Meter parameter structure. */
struct mlx5_flow_meter_info {
uint32_t meter_id;
/**< Meter id. */
struct mlx5_flow_meter_profile *profile;
/**< Meter profile parameters. */
rte_spinlock_t sl; /**< Meter action spinlock. */
/** Policer actions (per meter output color). */
enum rte_mtr_policer_action action[RTE_COLORS];
/** Set of stats counters to be enabled.
* @see enum rte_mtr_stats_type
*/
uint32_t green_bytes:1;
/** Set green bytes stats to be enabled. */
uint32_t green_pkts:1;
/** Set green packets stats to be enabled. */
uint32_t red_bytes:1;
/** Set red bytes stats to be enabled. */
uint32_t red_pkts:1;
/** Set red packets stats to be enabled. */
uint32_t bytes_dropped:1;
/** Set bytes dropped stats to be enabled. */
uint32_t pkts_dropped:1;
@ -691,8 +671,8 @@ struct mlx5_flow_meter_info {
uint32_t transfer:1;
struct mlx5_meter_domains_infos *mfts;
/**< Flow table created for this meter. */
struct mlx5_flow_policer_stats policer_stats;
/**< Meter policer statistics. */
uint32_t drop_cnt;
/**< Color counter for drop. */
uint32_t ref_cnt;
/**< Use count. */
struct mlx5_indexed_pool *flow_ipool;

View File

@ -6655,52 +6655,6 @@ mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
return fops->destroy_mtr_tbls(dev, tbls);
}
/**
* Prepare policer rules.
*
* @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_prepare_policer_rules(struct rte_eth_dev *dev,
struct mlx5_flow_meter_info *fm,
const struct rte_flow_attr *attr)
{
const struct mlx5_flow_driver_ops *fops;
fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
return fops->prepare_policer_rules(dev, fm, attr);
}
/**
* Destroy policer rules.
*
* @param[in] fm
* Pointer to flow meter structure.
* @param[in] attr
* Pointer to flow attributes.
*
* @return
* 0 on success, -1 otherwise.
*/
int
mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
struct mlx5_flow_meter_info *fm,
const struct rte_flow_attr *attr)
{
const struct mlx5_flow_driver_ops *fops;
fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
return fops->destroy_policer_rules(dev, fm, attr);
}
/**
* Allocate the needed aso flow meter id.
*

View File

@ -838,6 +838,8 @@ struct mlx5_legacy_flow_meter {
/* Must be the first in struct. */
TAILQ_ENTRY(mlx5_legacy_flow_meter) next;
/**< Pointer to the next flow meter structure. */
uint32_t meter_id;
/**< Meter id. */
uint32_t idx; /* Index to meter object. */
};
@ -1096,14 +1098,6 @@ 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);
typedef int (*mlx5_flow_create_policer_rules_t)
(struct rte_eth_dev *dev,
struct mlx5_flow_meter_info *fm,
const struct rte_flow_attr *attr);
typedef int (*mlx5_flow_destroy_policer_rules_t)
(struct rte_eth_dev *dev,
const struct mlx5_flow_meter_info *fm,
const struct rte_flow_attr *attr);
typedef uint32_t (*mlx5_flow_mtr_alloc_t)
(struct rte_eth_dev *dev);
typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@ -1160,8 +1154,6 @@ struct mlx5_flow_driver_ops {
mlx5_flow_query_t query;
mlx5_flow_create_mtr_tbls_t create_mtr_tbls;
mlx5_flow_destroy_mtr_tbls_t destroy_mtr_tbls;
mlx5_flow_create_policer_rules_t prepare_policer_rules;
mlx5_flow_destroy_policer_rules_t destroy_policer_rules;
mlx5_flow_mtr_alloc_t create_meter;
mlx5_flow_mtr_free_t free_meter;
mlx5_flow_counter_alloc_t counter_alloc;
@ -1391,12 +1383,6 @@ 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);
int mlx5_flow_prepare_policer_rules(struct rte_eth_dev *dev,
struct mlx5_flow_meter_info *fm,
const struct rte_flow_attr *attr);
int mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
struct mlx5_flow_meter_info *fm,
const struct rte_flow_attr *attr);
int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
struct rte_mtr_error *error);
int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);

View File

@ -808,8 +808,8 @@ mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh,
/* Waiting for wqe resource. */
rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
} while (--poll_wqe_times);
DRV_LOG(ERR, "Fail to send WQE for ASO meter %d",
mtr->fm.meter_id);
DRV_LOG(ERR, "Fail to send WQE for ASO meter offset %d",
mtr->offset);
return -1;
}
@ -844,7 +844,7 @@ mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh,
/* Waiting for CQE ready. */
rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
} while (--poll_cqe_times);
DRV_LOG(ERR, "Fail to poll CQE ready for ASO meter %d",
mtr->fm.meter_id);
DRV_LOG(ERR, "Fail to poll CQE ready for ASO meter offset %d",
mtr->offset);
return -1;
}

View File

@ -185,31 +185,6 @@ flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,
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. */
@ -6026,12 +6001,10 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
mtrmng->n_valid++;
for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
pool->mtrs[i].offset = i;
pool->mtrs[i].fm.meter_id = UINT32_MAX;
LIST_INSERT_HEAD(&mtrmng->meters,
&pool->mtrs[i], next);
}
pool->mtrs[0].offset = 0;
pool->mtrs[0].fm.meter_id = UINT32_MAX;
*mtr_free = &pool->mtrs[0];
return pool;
}
@ -6055,7 +6028,6 @@ flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
rte_spinlock_lock(&mtrmng->mtrsl);
memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info));
aso_mtr->state = ASO_METER_FREE;
aso_mtr->fm.meter_id = UINT32_MAX;
LIST_INSERT_HEAD(&mtrmng->meters, aso_mtr, next);
rte_spinlock_unlock(&mtrmng->mtrsl);
}
@ -6095,8 +6067,8 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
mtr_free->state = ASO_METER_WAIT;
rte_spinlock_unlock(&mtrmng->mtrsl);
pool = container_of(mtr_free,
struct mlx5_aso_mtr_pool,
mtrs[mtr_free->offset]);
struct mlx5_aso_mtr_pool,
mtrs[mtr_free->offset]);
mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset);
if (!mtr_free->fm.meter_action) {
#ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
@ -13721,433 +13693,6 @@ flow_dv_create_mtr_tbl(struct rte_eth_dev *dev)
return NULL;
}
/**
* Destroy the meter table matchers.
* Lock free, (mutex should be acquired by caller).
*
* @param[in] dev
* Pointer to Ethernet device.
* @param[in,out] dtb
* Pointer to DV meter table.
*
* @return
* Always 0.
*/
static int
flow_dv_destroy_mtr_matchers(struct rte_eth_dev *dev,
struct mlx5_meter_domain_info *dtb)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_flow_tbl_data_entry *tbl;
if (!priv->config.dv_flow_en)
return 0;
if (dtb->drop_matcher) {
tbl = container_of(dtb->drop_matcher->tbl, typeof(*tbl), tbl);
mlx5_cache_unregister(&tbl->matchers,
&dtb->drop_matcher->entry);
dtb->drop_matcher = NULL;
}
if (dtb->color_matcher) {
tbl = container_of(dtb->color_matcher->tbl, typeof(*tbl), tbl);
mlx5_cache_unregister(&tbl->matchers,
&dtb->color_matcher->entry);
dtb->color_matcher = NULL;
}
return 0;
}
/**
* Create the matchers for meter table.
*
* @param[in] dev
* Pointer to Ethernet device.
* @param[in] color_reg_c_idx
* Reg C index for color match.
* @param[in] mtr_id_reg_c_idx
* Reg C index for meter_id match.
* @param[in] mtr_id_mask
* Mask for meter_id match criteria.
* @param[in,out] dtb
* Pointer to DV meter table.
* @param[out] error
* Perform verbose error reporting if not NULL.
*
* @return
* 0 on success, a negative errno value otherwise and rte_errno is set.
*/
static int
flow_dv_prepare_mtr_matchers(struct rte_eth_dev *dev,
uint32_t color_reg_c_idx,
uint32_t mtr_id_reg_c_idx,
uint32_t mtr_id_mask,
struct mlx5_meter_domain_info *dtb,
struct rte_flow_error *error)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_flow_tbl_data_entry *tbl_data;
struct mlx5_cache_entry *entry;
struct mlx5_flow_dv_matcher matcher = {
.mask = {
.size = sizeof(matcher.mask.buf) -
MLX5_ST_SZ_BYTES(fte_match_set_misc4),
},
.tbl = dtb->tbl,
};
struct mlx5_flow_dv_match_params value = {
.size = sizeof(value.buf) -
MLX5_ST_SZ_BYTES(fte_match_set_misc4),
};
struct mlx5_flow_cb_ctx ctx = {
.error = error,
.data = &matcher,
};
uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
tbl_data = container_of(dtb->tbl, struct mlx5_flow_tbl_data_entry, tbl);
if (!dtb->drop_matcher) {
/* Create matchers for Drop. */
flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
mtr_id_reg_c_idx, 0, mtr_id_mask);
matcher.priority = MLX5_REG_BITS * 2 - priv->max_mtr_bits;
matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
matcher.mask.size);
entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
if (!entry) {
DRV_LOG(ERR, "Failed to register meter drop matcher.");
return -1;
}
dtb->drop_matcher =
container_of(entry, struct mlx5_flow_dv_matcher, entry);
}
if (!dtb->color_matcher) {
/* Create matchers for Color + meter_id. */
if (priv->mtr_reg_share) {
flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
color_reg_c_idx, 0,
(mtr_id_mask | color_mask));
} else {
flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
color_reg_c_idx, 0, color_mask);
flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
mtr_id_reg_c_idx, 0, mtr_id_mask);
}
matcher.priority = MLX5_REG_BITS - priv->max_mtr_bits;
matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
matcher.mask.size);
entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
if (!entry) {
DRV_LOG(ERR, "Failed to register meter color matcher.");
return -1;
}
dtb->color_matcher =
container_of(entry, struct mlx5_flow_dv_matcher, entry);
}
return 0;
}
/**
* Destroy domain policer rule.
*
* @param[in] dev
* Pointer to Ethernet device.
* @param[in] dt
* Pointer to domain table.
*/
static void
flow_dv_destroy_domain_policer_rule(struct rte_eth_dev *dev,
struct mlx5_meter_domain_info *dt)
{
if (dt->drop_rule) {
claim_zero(mlx5_flow_os_destroy_flow(dt->drop_rule));
dt->drop_rule = NULL;
}
if (dt->green_rule) {
claim_zero(mlx5_flow_os_destroy_flow(dt->green_rule));
dt->green_rule = NULL;
}
flow_dv_destroy_mtr_matchers(dev, dt);
if (dt->jump_actn) {
claim_zero(mlx5_flow_os_destroy_flow_action(dt->jump_actn));
dt->jump_actn = NULL;
}
}
/**
* Destroy policer rules.
*
* @param[in] dev
* Pointer to Ethernet device.
* @param[in] fm
* Pointer to flow meter structure.
* @param[in] attr
* Pointer to flow attributes.
*
* @return
* Always 0.
*/
static int
flow_dv_destroy_policer_rules(struct rte_eth_dev *dev,
const struct mlx5_flow_meter_info *fm,
const struct rte_flow_attr *attr)
{
struct mlx5_meter_domains_infos *mtb = fm ? fm->mfts : NULL;
if (!mtb)
return 0;
if (attr->egress)
flow_dv_destroy_domain_policer_rule(dev, &mtb->egress);
if (attr->ingress)
flow_dv_destroy_domain_policer_rule(dev, &mtb->ingress);
if (attr->transfer)
flow_dv_destroy_domain_policer_rule(dev, &mtb->transfer);
return 0;
}
/**
* Create specify domain meter policer rule.
*
* @param[in] dev
* Pointer to Ethernet device.
* @param[in] fm
* Pointer to flow meter structure.
* @param[in] mtr_idx
* meter index.
* @param[in] mtb
* Pointer to DV meter table set.
* @param[out] drop_rule
* The address of pointer saving drop rule.
* @param[out] color_rule
* The address of pointer saving green rule.
*
* @return
* 0 on success, -1 otherwise.
*/
static int
flow_dv_create_policer_forward_rule(struct rte_eth_dev *dev,
struct mlx5_flow_meter_info *fm,
uint32_t mtr_idx,
struct mlx5_meter_domain_info *dtb,
void **drop_rule,
void **green_rule)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_flow_dv_match_params matcher = {
.size = sizeof(matcher.buf) -
MLX5_ST_SZ_BYTES(fte_match_set_misc4),
};
struct mlx5_flow_dv_match_params value = {
.size = sizeof(value.buf) -
MLX5_ST_SZ_BYTES(fte_match_set_misc4),
};
struct mlx5_meter_domains_infos *mtb = fm->mfts;
struct rte_flow_error error;
uint32_t color_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR,
0, &error);
uint32_t mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
0, &error);
uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
uint32_t mtr_id_mask =
((UINT32_C(1) << priv->max_mtr_bits) - 1) << mtr_id_offset;
void *actions[METER_ACTIONS];
int i;
int ret = 0;
/* Create jump action. */
if (!dtb->jump_actn)
ret = mlx5_flow_os_create_flow_action_dest_flow_tbl
(dtb->sfx_tbl->obj, &dtb->jump_actn);
if (ret) {
DRV_LOG(ERR, "Failed to create policer jump action.");
goto error;
}
/* Prepare matchers. */
if (!dtb->drop_matcher || !dtb->color_matcher) {
ret = flow_dv_prepare_mtr_matchers(dev, color_reg_c,
mtr_id_reg_c, mtr_id_mask,
dtb, &error);
if (ret) {
DRV_LOG(ERR, "Failed to setup matchers for mtr table.");
goto error;
}
}
/* Create Drop flow, matching meter_id only. */
i = 0;
flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_id_reg_c,
(mtr_idx << mtr_id_offset), UINT32_MAX);
if (mtb->drop_count)
actions[i++] = mtb->drop_count;
actions[i++] = priv->sh->dr_drop_action;
ret = mlx5_flow_os_create_flow(dtb->drop_matcher->matcher_object,
(void *)&value, i, actions, drop_rule);
if (ret) {
DRV_LOG(ERR, "Failed to create meter policer drop rule.");
goto error;
}
/* Create flow matching Green color + meter_id. */
i = 0;
if (priv->mtr_reg_share) {
flow_dv_match_meta_reg(matcher.buf, value.buf, color_reg_c,
((mtr_idx << mtr_id_offset) |
rte_col_2_mlx5_col(RTE_COLOR_GREEN)),
UINT32_MAX);
} else {
flow_dv_match_meta_reg(matcher.buf, value.buf, color_reg_c,
rte_col_2_mlx5_col(RTE_COLOR_GREEN),
UINT32_MAX);
flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_id_reg_c,
mtr_idx, UINT32_MAX);
}
if (mtb->green_count)
actions[i++] = mtb->green_count;
actions[i++] = dtb->jump_actn;
ret = mlx5_flow_os_create_flow(dtb->color_matcher->matcher_object,
(void *)&value, i, actions, green_rule);
if (ret) {
DRV_LOG(ERR, "Failed to create meter policer color rule.");
goto error;
}
return 0;
error:
rte_errno = errno;
return -1;
}
/**
* Prepare policer rules for all domains.
* If meter already initialized, this will replace all old rules with new ones.
*
* @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.
*/
static int
flow_dv_prepare_policer_rules(struct rte_eth_dev *dev,
struct mlx5_flow_meter_info *fm,
const struct rte_flow_attr *attr)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_meter_domains_infos *mtb = fm->mfts;
bool initialized = false;
struct mlx5_flow_counter *cnt;
void *egress_drop_rule = NULL;
void *egress_green_rule = NULL;
void *ingress_drop_rule = NULL;
void *ingress_green_rule = NULL;
void *transfer_drop_rule = NULL;
void *transfer_green_rule = NULL;
uint32_t mtr_idx;
int ret;
/* Get the statistics counters for green/drop. */
if (fm->policer_stats.pass_cnt) {
cnt = flow_dv_counter_get_by_idx(dev,
fm->policer_stats.pass_cnt,
NULL);
mtb->green_count = cnt->action;
} else {
mtb->green_count = NULL;
}
if (fm->policer_stats.drop_cnt) {
cnt = flow_dv_counter_get_by_idx(dev,
fm->policer_stats.drop_cnt,
NULL);
mtb->drop_count = cnt->action;
} else {
mtb->drop_count = NULL;
}
/**
* If flow meter has been initialized, all policer rules
* are created. So can get if meter initialized by checking
* any policer rule.
*/
if (mtb->egress.drop_rule)
initialized = true;
if (priv->sh->meter_aso_en) {
struct mlx5_aso_mtr *aso_mtr = NULL;
struct mlx5_aso_mtr_pool *pool;
aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool,
mtrs[aso_mtr->offset]);
mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, aso_mtr->offset);
} else {
struct mlx5_legacy_flow_meter *legacy_fm;
legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
mtr_idx = legacy_fm->idx;
}
if (attr->egress) {
ret = flow_dv_create_policer_forward_rule(dev,
fm, mtr_idx, &mtb->egress,
&egress_drop_rule, &egress_green_rule);
if (ret) {
DRV_LOG(ERR, "Failed to create egress policer.");
goto error;
}
}
if (attr->ingress) {
ret = flow_dv_create_policer_forward_rule(dev,
fm, mtr_idx, &mtb->ingress,
&ingress_drop_rule, &ingress_green_rule);
if (ret) {
DRV_LOG(ERR, "Failed to create ingress policer.");
goto error;
}
}
if (attr->transfer) {
ret = flow_dv_create_policer_forward_rule(dev,
fm, mtr_idx, &mtb->transfer,
&transfer_drop_rule, &transfer_green_rule);
if (ret) {
DRV_LOG(ERR, "Failed to create transfer policer.");
goto error;
}
}
/* Replace old flows if existing. */
if (mtb->egress.drop_rule)
claim_zero(mlx5_flow_os_destroy_flow(mtb->egress.drop_rule));
if (mtb->egress.green_rule)
claim_zero(mlx5_flow_os_destroy_flow(mtb->egress.green_rule));
if (mtb->ingress.drop_rule)
claim_zero(mlx5_flow_os_destroy_flow(mtb->ingress.drop_rule));
if (mtb->ingress.green_rule)
claim_zero(mlx5_flow_os_destroy_flow(mtb->ingress.green_rule));
if (mtb->transfer.drop_rule)
claim_zero(mlx5_flow_os_destroy_flow(mtb->transfer.drop_rule));
if (mtb->transfer.green_rule)
claim_zero(mlx5_flow_os_destroy_flow(mtb->transfer.green_rule));
mtb->egress.drop_rule = egress_drop_rule;
mtb->egress.green_rule = egress_green_rule;
mtb->ingress.drop_rule = ingress_drop_rule;
mtb->ingress.green_rule = ingress_green_rule;
mtb->transfer.drop_rule = transfer_drop_rule;
mtb->transfer.green_rule = transfer_green_rule;
return 0;
error:
if (egress_drop_rule)
claim_zero(mlx5_flow_os_destroy_flow(egress_drop_rule));
if (egress_green_rule)
claim_zero(mlx5_flow_os_destroy_flow(egress_green_rule));
if (ingress_drop_rule)
claim_zero(mlx5_flow_os_destroy_flow(ingress_drop_rule));
if (ingress_green_rule)
claim_zero(mlx5_flow_os_destroy_flow(ingress_green_rule));
if (transfer_drop_rule)
claim_zero(mlx5_flow_os_destroy_flow(transfer_drop_rule));
if (transfer_green_rule)
claim_zero(mlx5_flow_os_destroy_flow(transfer_green_rule));
if (!initialized)
flow_dv_destroy_policer_rules(dev, fm, attr);
return -1;
}
/**
* Validate the batch counter support in root table.
*
@ -14442,8 +13987,6 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
.query = flow_dv_query,
.create_mtr_tbls = flow_dv_create_mtr_tbl,
.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
.prepare_policer_rules = flow_dv_prepare_policer_rules,
.destroy_policer_rules = flow_dv_destroy_policer_rules,
.create_meter = flow_dv_mtr_alloc,
.free_meter = flow_dv_aso_mtr_release_to_pool,
.counter_alloc = flow_dv_counter_allocate,

View File

@ -329,7 +329,6 @@ mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
cap->meter_srtcm_rfc2697_n_max = qattr->flow_meter_old ? cap->n_max : 0;
cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
cap->policer_action_drop_supported = 1;
cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
RTE_MTR_STATS_N_PKTS_DROPPED;
return 0;
@ -436,90 +435,6 @@ mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
return 0;
}
/**
* Convert wrong color setting action to verbose error.
*
* @param[in] action
* Policy color action.
*
* @return
* Verbose meter color error type.
*/
static inline enum rte_mtr_error_type
action2error(enum rte_mtr_policer_action action)
{
switch (action) {
case MTR_POLICER_ACTION_COLOR_GREEN:
return RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN;
case MTR_POLICER_ACTION_COLOR_YELLOW:
return RTE_MTR_ERROR_TYPE_POLICER_ACTION_YELLOW;
case MTR_POLICER_ACTION_COLOR_RED:
return RTE_MTR_ERROR_TYPE_POLICER_ACTION_RED;
default:
break;
}
return RTE_MTR_ERROR_TYPE_UNSPECIFIED;
}
/**
* Check meter validation.
*
* @param[in] priv
* Pointer to mlx5 private data structure.
* @param[in] meter_id
* Meter id.
* @param[in] params
* Pointer to rte meter parameters.
* @param[out] error
* Pointer to rte meter error structure.
*
* @return
* 0 on success, a negative errno value otherwise and rte_errno is set.
*/
static int
mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
struct rte_mtr_params *params,
struct rte_mtr_error *error)
{
/* Meter must use global drop action. */
if (!priv->sh->dr_drop_action)
return -rte_mtr_error_set(error, ENOTSUP,
RTE_MTR_ERROR_TYPE_MTR_PARAMS,
NULL,
"No drop action ready for meter.");
/* Meter params must not be NULL. */
if (params == NULL)
return -rte_mtr_error_set(error, EINVAL,
RTE_MTR_ERROR_TYPE_MTR_PARAMS,
NULL, "Meter object params null.");
/* Previous meter color is not supported. */
if (params->use_prev_mtr_color)
return -rte_mtr_error_set(error, ENOTSUP,
RTE_MTR_ERROR_TYPE_MTR_PARAMS,
NULL,
"Previous meter color "
"not supported.");
/* Validate policer settings. */
if (params->action[RTE_COLOR_RED] != MTR_POLICER_ACTION_DROP)
return -rte_mtr_error_set
(error, ENOTSUP,
action2error(params->action[RTE_COLOR_RED]),
NULL,
"Red color only supports drop action.");
if (params->action[RTE_COLOR_GREEN] != MTR_POLICER_ACTION_COLOR_GREEN)
return -rte_mtr_error_set
(error, ENOTSUP,
action2error(params->action[RTE_COLOR_GREEN]),
NULL,
"Green color only supports recolor green action.");
/* Validate meter id. */
if (mlx5_flow_meter_find(priv, meter_id, NULL))
return -rte_mtr_error_set(error, EEXIST,
RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
"Meter object already exists.");
return 0;
}
/**
* Modify the flow meter action.
*
@ -629,167 +544,14 @@ static void
mlx5_flow_meter_stats_enable_update(struct mlx5_flow_meter_info *fm,
uint64_t stats_mask)
{
fm->green_bytes = (stats_mask & RTE_MTR_STATS_N_BYTES_GREEN) ? 1 : 0;
fm->green_pkts = (stats_mask & RTE_MTR_STATS_N_PKTS_GREEN) ? 1 : 0;
fm->red_bytes = (stats_mask & RTE_MTR_STATS_N_BYTES_RED) ? 1 : 0;
fm->red_pkts = (stats_mask & RTE_MTR_STATS_N_PKTS_RED) ? 1 : 0;
fm->bytes_dropped =
(stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
}
/**
* Create meter rules.
*
* @param[in] dev
* Pointer to Ethernet device.
* @param[in] meter_id
* Meter id.
* @param[in] params
* Pointer to rte meter parameters.
* @param[in] shared
* Meter shared with other flow or not.
* @param[out] error
* Pointer to rte meter error structure.
*
* @return
* 0 on success, a negative errno value otherwise and rte_errno is set.
*/
static int
mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
struct rte_mtr_params *params, int shared,
struct rte_mtr_error *error)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
struct mlx5_flow_meter_profile *fmp;
struct mlx5_legacy_flow_meter *legacy_fm;
struct mlx5_flow_meter_info *fm;
const struct rte_flow_attr attr = {
.ingress = 1,
.egress = 1,
.transfer = priv->config.dv_esw_en ? 1 : 0,
};
struct mlx5_indexed_pool_config flow_ipool_cfg = {
.size = 0,
.trunk_size = 64,
.need_lock = 1,
.type = "mlx5_flow_mtr_flow_id_pool",
};
struct mlx5_aso_mtr *aso_mtr;
union mlx5_l3t_data data;
uint32_t mtr_idx;
int ret;
uint8_t mtr_id_bits;
uint8_t mtr_reg_bits = priv->mtr_reg_share ?
MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
if (!priv->mtr_en)
return -rte_mtr_error_set(error, ENOTSUP,
RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
"Meter is not supported");
/* Validate the parameters. */
ret = mlx5_flow_meter_validate(priv, meter_id, params, error);
if (ret)
return ret;
/* Meter profile must exist. */
fmp = mlx5_flow_meter_profile_find(priv, params->meter_profile_id);
if (fmp == NULL)
return -rte_mtr_error_set(error, ENOENT,
RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
NULL, "Meter profile id not valid.");
/* Allocate the flow meter memory. */
if (priv->sh->meter_aso_en) {
mtr_idx = mlx5_flow_mtr_alloc(dev);
if (!mtr_idx)
return -rte_mtr_error_set(error, ENOMEM,
RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
"Memory alloc failed for meter.");
aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
fm = &aso_mtr->fm;
} else {
legacy_fm = mlx5_ipool_zmalloc
(priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx);
if (legacy_fm == NULL)
return -rte_mtr_error_set(error, ENOMEM,
RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
"Memory alloc failed for meter.");
legacy_fm->idx = mtr_idx;
fm = &legacy_fm->fm;
}
mtr_id_bits = MLX5_REG_BITS - __builtin_clz(mtr_idx);
if ((mtr_id_bits + priv->max_mtr_flow_bits) > mtr_reg_bits) {
DRV_LOG(ERR, "Meter number exceeds max limit.");
goto error;
}
if (mtr_id_bits > priv->max_mtr_bits)
priv->max_mtr_bits = mtr_id_bits;
/* Fill the flow meter parameters. */
fm->meter_id = meter_id;
fm->profile = fmp;
memcpy(fm->action, params->action, sizeof(params->action));
mlx5_flow_meter_stats_enable_update(fm, params->stats_mask);
/* Alloc policer counters. */
if (fm->green_bytes || fm->green_pkts) {
fm->policer_stats.pass_cnt = mlx5_counter_alloc(dev);
if (!fm->policer_stats.pass_cnt)
goto error;
}
if (fm->red_bytes || fm->red_pkts ||
fm->bytes_dropped || fm->pkts_dropped) {
fm->policer_stats.drop_cnt = mlx5_counter_alloc(dev);
if (!fm->policer_stats.drop_cnt)
goto error;
}
fm->mfts = mlx5_flow_create_mtr_tbls(dev);
if (!fm->mfts)
goto error;
ret = mlx5_flow_prepare_policer_rules(dev, fm, &attr);
if (ret)
goto error;
/* Add to the flow meter list. */
if (!priv->sh->meter_aso_en)
TAILQ_INSERT_TAIL(fms, legacy_fm, next);
fm->active_state = 1; /* Config meter starts as active. */
fm->is_enable = 1;
fm->shared = !!shared;
__atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED);
fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
if (!fm->flow_ipool)
goto error;
rte_spinlock_init(&fm->sl);
/* If ASO meter supported, allocate ASO flow meter. */
if (priv->sh->meter_aso_en) {
aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
if (ret)
goto error;
data.dword = mtr_idx;
if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data))
goto error;
}
return 0;
error:
mlx5_flow_destroy_policer_rules(dev, fm, &attr);
mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
/* Free policer counters. */
if (fm->policer_stats.pass_cnt)
mlx5_counter_free(dev, fm->policer_stats.pass_cnt);
if (fm->policer_stats.drop_cnt)
mlx5_counter_free(dev, fm->policer_stats.drop_cnt);
if (priv->sh->meter_aso_en)
mlx5_flow_mtr_free(dev, mtr_idx);
else
mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx);
return -rte_mtr_error_set(error, -ret,
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
NULL, "Failed to create devx meter.");
}
static int
mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
struct mlx5_flow_meter_info *fm,
const struct rte_flow_attr *attr,
uint32_t mtr_idx)
{
struct mlx5_priv *priv = dev->data->dev_private;
@ -810,15 +572,12 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
TAILQ_REMOVE(fms, legacy_fm, next);
}
/* Free policer counters. */
if (fm->policer_stats.pass_cnt)
mlx5_counter_free(dev, fm->policer_stats.pass_cnt);
if (fm->policer_stats.drop_cnt)
mlx5_counter_free(dev, fm->policer_stats.drop_cnt);
/* Free drop counters. */
if (fm->drop_cnt)
mlx5_counter_free(dev, fm->drop_cnt);
/* Free meter flow table. */
if (fm->flow_ipool)
mlx5_ipool_destroy(fm->flow_ipool);
mlx5_flow_destroy_policer_rules(dev, fm, attr);
mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
if (priv->sh->meter_aso_en)
mlx5_flow_mtr_free(dev, mtr_idx);
@ -847,11 +606,6 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_flow_meter_info *fm;
const struct rte_flow_attr attr = {
.ingress = 1,
.egress = 1,
.transfer = priv->config.dv_esw_en ? 1 : 0,
};
uint32_t mtr_idx = 0;
if (!priv->mtr_en)
@ -876,7 +630,7 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
"Fail to delete ASO Meter in index table.");
}
/* Destroy the meter profile. */
if (mlx5_flow_meter_params_flush(dev, fm, &attr, mtr_idx))
if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
return -rte_mtr_error_set(error, EINVAL,
RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
NULL, "MTR object meter profile invalid.");
@ -1102,13 +856,6 @@ mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_flow_meter_info *fm;
const struct rte_flow_attr attr = {
.ingress = 1,
.egress = 1,
.transfer = priv->config.dv_esw_en ? 1 : 0,
};
bool need_updated = false;
struct mlx5_flow_policer_stats old_policer_stats;
if (!priv->mtr_en)
return -rte_mtr_error_set(error, ENOTSUP,
@ -1120,69 +867,6 @@ mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
return -rte_mtr_error_set(error, ENOENT,
RTE_MTR_ERROR_TYPE_MTR_ID,
NULL, "Meter object id not valid.");
old_policer_stats.pass_cnt = 0;
old_policer_stats.drop_cnt = 0;
if (!!((RTE_MTR_STATS_N_PKTS_GREEN |
RTE_MTR_STATS_N_BYTES_GREEN) & stats_mask) !=
!!fm->policer_stats.pass_cnt) {
need_updated = true;
if (fm->policer_stats.pass_cnt) {
old_policer_stats.pass_cnt = fm->policer_stats.pass_cnt;
fm->policer_stats.pass_cnt = 0;
} else {
fm->policer_stats.pass_cnt =
mlx5_counter_alloc(dev);
if (!fm->policer_stats.pass_cnt)
return -rte_mtr_error_set(error, ENOMEM,
RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
"Counter alloc failed for meter.");
}
}
if (!!((RTE_MTR_STATS_N_PKTS_RED | RTE_MTR_STATS_N_BYTES_RED |
RTE_MTR_STATS_N_PKTS_DROPPED | RTE_MTR_STATS_N_BYTES_DROPPED) &
stats_mask) !=
!!fm->policer_stats.drop_cnt) {
need_updated = true;
if (fm->policer_stats.drop_cnt) {
old_policer_stats.drop_cnt = fm->policer_stats.drop_cnt;
fm->policer_stats.drop_cnt = 0;
} else {
fm->policer_stats.drop_cnt =
mlx5_counter_alloc(dev);
if (!fm->policer_stats.drop_cnt)
return -rte_mtr_error_set(error, ENOMEM,
RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
"Counter alloc failed for meter.");
}
}
if (need_updated) {
if (mlx5_flow_prepare_policer_rules(dev, fm, &attr)) {
if (fm->policer_stats.pass_cnt &&
fm->policer_stats.pass_cnt !=
old_policer_stats.pass_cnt)
mlx5_counter_free(dev,
fm->policer_stats.pass_cnt);
fm->policer_stats.pass_cnt =
old_policer_stats.pass_cnt;
if (fm->policer_stats.drop_cnt &&
fm->policer_stats.drop_cnt !=
old_policer_stats.drop_cnt)
mlx5_counter_free(dev,
fm->policer_stats.drop_cnt);
fm->policer_stats.pass_cnt =
old_policer_stats.pass_cnt;
return -rte_mtr_error_set(error, ENOTSUP,
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
NULL, "Failed to create meter policer rules.");
}
/* Free old policer counters. */
if (old_policer_stats.pass_cnt)
mlx5_counter_free(dev,
old_policer_stats.pass_cnt);
if (old_policer_stats.drop_cnt)
mlx5_counter_free(dev,
old_policer_stats.drop_cnt);
}
mlx5_flow_meter_stats_enable_update(fm, stats_mask);
return 0;
}
@ -1216,7 +900,6 @@ mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_flow_meter_info *fm;
struct mlx5_flow_policer_stats *ps;
uint64_t pkts;
uint64_t bytes;
int ret = 0;
@ -1231,35 +914,14 @@ mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
return -rte_mtr_error_set(error, ENOENT,
RTE_MTR_ERROR_TYPE_MTR_ID,
NULL, "Meter object id not valid.");
ps = &fm->policer_stats;
*stats_mask = 0;
if (fm->green_bytes)
*stats_mask |= RTE_MTR_STATS_N_BYTES_GREEN;
if (fm->green_pkts)
*stats_mask |= RTE_MTR_STATS_N_PKTS_GREEN;
if (fm->red_bytes)
*stats_mask |= RTE_MTR_STATS_N_BYTES_RED;
if (fm->red_pkts)
*stats_mask |= RTE_MTR_STATS_N_PKTS_RED;
if (fm->bytes_dropped)
*stats_mask |= RTE_MTR_STATS_N_BYTES_DROPPED;
if (fm->pkts_dropped)
*stats_mask |= RTE_MTR_STATS_N_PKTS_DROPPED;
memset(stats, 0, sizeof(*stats));
if (ps->pass_cnt) {
ret = mlx5_counter_query(dev, ps->pass_cnt, clear, &pkts,
&bytes);
if (ret)
goto error;
/* If need to read the packets, set it. */
if (fm->green_pkts)
stats->n_pkts[RTE_COLOR_GREEN] = pkts;
/* If need to read the bytes, set it. */
if (fm->green_bytes)
stats->n_bytes[RTE_COLOR_GREEN] = bytes;
}
if (ps->drop_cnt) {
ret = mlx5_counter_query(dev, ps->drop_cnt, clear, &pkts,
if (fm->drop_cnt) {
ret = mlx5_counter_query(dev, fm->drop_cnt, clear, &pkts,
&bytes);
if (ret)
goto error;
@ -1273,20 +935,18 @@ mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
return 0;
error:
return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
"Failed to read policer counters.");
"Failed to read meter drop counters.");
}
static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
.capabilities_get = mlx5_flow_mtr_cap_get,
.meter_profile_add = mlx5_flow_meter_profile_add,
.meter_profile_delete = mlx5_flow_meter_profile_delete,
.create = mlx5_flow_meter_create,
.destroy = mlx5_flow_meter_destroy,
.meter_enable = mlx5_flow_meter_enable,
.meter_disable = mlx5_flow_meter_disable,
.meter_profile_update = mlx5_flow_meter_profile_update,
.meter_dscp_table_update = NULL,
.policer_actions_update = NULL,
.stats_update = mlx5_flow_meter_stats_update,
.stats_read = mlx5_flow_meter_stats_read,
};
@ -1344,12 +1004,11 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
/* Remove reference taken by the mlx5_l3t_get_entry. */
mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
MLX5_ASSERT(meter_id == aso_mtr->fm.meter_id);
rte_spinlock_unlock(&mtrmng->mtrsl);
return &aso_mtr->fm;
}
TAILQ_FOREACH(legacy_fm, fms, next)
if (meter_id == legacy_fm->fm.meter_id) {
if (meter_id == legacy_fm->meter_id) {
if (mtr_idx)
*mtr_idx = legacy_fm->idx;
return &legacy_fm->fm;
@ -1517,11 +1176,6 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
struct mlx5_legacy_flow_meter *legacy_fm;
struct mlx5_flow_meter_info *fm;
struct mlx5_aso_mtr_pool *mtr_pool;
const struct rte_flow_attr attr = {
.ingress = 1,
.egress = 1,
.transfer = priv->config.dv_esw_en ? 1 : 0,
};
void *tmp;
uint32_t i, offset, mtr_idx;
@ -1533,9 +1187,8 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
offset++) {
fm = &mtr_pool->mtrs[offset].fm;
mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
if (fm->meter_id != UINT32_MAX &&
mlx5_flow_meter_params_flush(dev,
fm, &attr, mtr_idx))
if (mlx5_flow_meter_params_flush(dev,
fm, mtr_idx))
return -rte_mtr_error_set
(error, EINVAL,
RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
@ -1545,7 +1198,7 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
} else {
TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
fm = &legacy_fm->fm;
if (mlx5_flow_meter_params_flush(dev, fm, &attr, 0))
if (mlx5_flow_meter_params_flush(dev, fm, 0))
return -rte_mtr_error_set(error, EINVAL,
RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
NULL, "MTR object meter profile invalid.");

View File

@ -1166,6 +1166,7 @@ flow_rule_action_get(struct pmd_internals *softnic,
{
struct softnic_table_action_profile *profile;
struct softnic_table_action_profile_params *params;
struct softnic_mtr_meter_policy *policy;
int n_jump_queue_rss_drop = 0;
int n_count = 0;
int n_mark = 0;
@ -1621,15 +1622,25 @@ flow_rule_action_get(struct pmd_internals *softnic,
return -1;
}
}
/* Meter policy must exist */
policy = softnic_mtr_meter_policy_find(softnic,
m->params.meter_policy_id);
if (policy == NULL) {
rte_flow_error_set(error,
EINVAL,
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
NULL,
"METER: fail to find meter policy");
return -1;
}
/* RTE_TABLE_ACTION_METER */
rule_action->mtr.mtr[0].meter_profile_id = meter_profile_id;
rule_action->mtr.mtr[0].policer[RTE_COLOR_GREEN] =
softnic_table_action_policer(m->params.action[RTE_COLOR_GREEN]);
policy->policer[RTE_COLOR_GREEN];
rule_action->mtr.mtr[0].policer[RTE_COLOR_YELLOW] =
softnic_table_action_policer(m->params.action[RTE_COLOR_YELLOW]);
policy->policer[RTE_COLOR_YELLOW];
rule_action->mtr.mtr[0].policer[RTE_COLOR_RED] =
softnic_table_action_policer(m->params.action[RTE_COLOR_RED]);
policy->policer[RTE_COLOR_RED];
rule_action->mtr.tc_mask = 1;
rule_action->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
break;

View File

@ -83,6 +83,16 @@ struct softnic_mtr_meter_profile {
TAILQ_HEAD(softnic_mtr_meter_profile_list, softnic_mtr_meter_profile);
/* MTR meter policy */
struct softnic_mtr_meter_policy {
TAILQ_ENTRY(softnic_mtr_meter_policy) node;
uint32_t meter_policy_id;
enum rte_table_action_policer policer[RTE_COLORS];
uint32_t n_users;
};
TAILQ_HEAD(softnic_mtr_meter_policy_list, softnic_mtr_meter_policy);
/* MTR meter object */
struct softnic_mtr {
TAILQ_ENTRY(softnic_mtr) node;
@ -95,6 +105,7 @@ TAILQ_HEAD(softnic_mtr_list, softnic_mtr);
struct mtr_internals {
struct softnic_mtr_meter_profile_list meter_profiles;
struct softnic_mtr_meter_policy_list meter_policies;
struct softnic_mtr_list mtrs;
};
@ -678,6 +689,10 @@ struct softnic_mtr_meter_profile *
softnic_mtr_meter_profile_find(struct pmd_internals *p,
uint32_t meter_profile_id);
struct softnic_mtr_meter_policy *
softnic_mtr_meter_policy_find(struct pmd_internals *p,
uint32_t meter_policy_id);
extern const struct rte_mtr_ops pmd_mtr_ops;
/**
@ -841,9 +856,6 @@ softnic_table_action_profile_create(struct pmd_internals *p,
const char *name,
struct softnic_table_action_profile_params *params);
enum rte_table_action_policer
softnic_table_action_policer(enum rte_mtr_policer_action action);
/**
* Pipeline
*/

View File

@ -65,27 +65,6 @@ softnic_mtr_meter_profile_find(struct pmd_internals *p,
return NULL;
}
enum rte_table_action_policer
softnic_table_action_policer(enum rte_mtr_policer_action action)
{
switch (action) {
case MTR_POLICER_ACTION_COLOR_GREEN:
return RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
/* FALLTHROUGH */
case MTR_POLICER_ACTION_COLOR_YELLOW:
return RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
/* FALLTHROUGH */
case MTR_POLICER_ACTION_COLOR_RED:
return RTE_TABLE_ACTION_POLICER_COLOR_RED;
/* FALLTHROUGH */
default:
return RTE_TABLE_ACTION_POLICER_DROP;
}
}
static int
meter_profile_check(struct rte_eth_dev *dev,
uint32_t meter_profile_id,
@ -208,6 +187,160 @@ pmd_mtr_meter_profile_delete(struct rte_eth_dev *dev,
return 0;
}
struct softnic_mtr_meter_policy *
softnic_mtr_meter_policy_find(struct pmd_internals *p,
uint32_t meter_policy_id)
{
struct softnic_mtr_meter_policy_list *mpl = &p->mtr.meter_policies;
struct softnic_mtr_meter_policy *mp;
TAILQ_FOREACH(mp, mpl, node)
if (meter_policy_id == mp->meter_policy_id)
return mp;
return NULL;
}
/* MTR meter policy add */
static int
pmd_mtr_meter_policy_add(struct rte_eth_dev *dev,
uint32_t meter_policy_id,
struct rte_mtr_meter_policy_params *policy,
struct rte_mtr_error *error)
{
struct pmd_internals *p = dev->data->dev_private;
struct softnic_mtr_meter_policy_list *mpl = &p->mtr.meter_policies;
struct softnic_mtr_meter_policy *mp;
const struct rte_flow_action *act;
const struct rte_flow_action_meter_color *recolor;
uint32_t i;
bool valid_act_found;
if (policy == NULL)
return -rte_mtr_error_set(error,
EINVAL,
RTE_MTR_ERROR_TYPE_METER_POLICY,
NULL,
"Null meter policy invalid");
/* Meter policy must not exist. */
mp = softnic_mtr_meter_policy_find(p, meter_policy_id);
if (mp != NULL)
return -rte_mtr_error_set(error,
EINVAL,
RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
NULL,
"Meter policy already exists");
for (i = 0; i < RTE_COLORS; i++) {
if (policy->actions[i] == NULL)
return -rte_mtr_error_set(error,
EINVAL,
RTE_MTR_ERROR_TYPE_METER_POLICY,
NULL,
"Null action list");
for (act = policy->actions[i], valid_act_found = false;
act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
if (act->type == RTE_FLOW_ACTION_TYPE_VOID)
continue;
/*
* Support one (and one only) of
* METER_COLOR or DROP action.
*/
if ((act->type != RTE_FLOW_ACTION_TYPE_METER_COLOR &&
act->type != RTE_FLOW_ACTION_TYPE_DROP) ||
valid_act_found)
return -rte_mtr_error_set(error,
EINVAL,
RTE_MTR_ERROR_TYPE_METER_POLICY,
NULL,
"Action invalid");
valid_act_found = true;
}
if (!valid_act_found)
return -rte_mtr_error_set(error,
EINVAL,
RTE_MTR_ERROR_TYPE_METER_POLICY,
NULL,
"No valid action found");
}
/* Memory allocation */
mp = calloc(1, sizeof(struct softnic_mtr_meter_policy));
if (mp == NULL)
return -rte_mtr_error_set(error,
ENOMEM,
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
NULL,
"Memory alloc failed");
/* Fill in */
mp->meter_policy_id = meter_policy_id;
for (i = 0; i < RTE_COLORS; i++) {
mp->policer[i] = RTE_TABLE_ACTION_POLICER_DROP;
act = policy->actions[i];
if (!act)
continue;
if (act->type == RTE_FLOW_ACTION_TYPE_METER_COLOR) {
recolor = act->conf;
switch (recolor->color) {
case RTE_COLOR_GREEN:
mp->policer[i] =
RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
break;
case RTE_COLOR_YELLOW:
mp->policer[i] =
RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
break;
case RTE_COLOR_RED:
mp->policer[i] =
RTE_TABLE_ACTION_POLICER_COLOR_RED;
break;
default:
break;
}
}
}
/* Add to list */
TAILQ_INSERT_TAIL(mpl, mp, node);
return 0;
}
/* MTR meter policy delete */
static int
pmd_mtr_meter_policy_delete(struct rte_eth_dev *dev,
uint32_t meter_policy_id,
struct rte_mtr_error *error)
{
struct pmd_internals *p = dev->data->dev_private;
struct softnic_mtr_meter_policy *mp;
/* Meter policy must exist */
mp = softnic_mtr_meter_policy_find(p, meter_policy_id);
if (mp == NULL)
return -rte_mtr_error_set(error,
EINVAL,
RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
NULL,
"Meter policy id invalid");
/* Check unused */
if (mp->n_users)
return -rte_mtr_error_set(error,
EBUSY,
RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
NULL,
"Meter policy in use");
/* Remove from list */
TAILQ_REMOVE(&p->mtr.meter_policies, mp, node);
free(mp);
return 0;
}
struct softnic_mtr *
softnic_mtr_find(struct pmd_internals *p, uint32_t mtr_id)
{
@ -275,6 +408,7 @@ pmd_mtr_create(struct rte_eth_dev *dev,
struct pmd_internals *p = dev->data->dev_private;
struct softnic_mtr_list *ml = &p->mtr.mtrs;
struct softnic_mtr_meter_profile *mp;
struct softnic_mtr_meter_policy *policy;
struct softnic_mtr *m;
int status;
@ -292,6 +426,16 @@ pmd_mtr_create(struct rte_eth_dev *dev,
NULL,
"Meter profile id not valid");
/* Meter policy must exist */
policy = softnic_mtr_meter_policy_find(p, params->meter_policy_id);
if (policy == NULL) {
return -rte_mtr_error_set(error,
EINVAL,
RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
NULL,
"Meter policy id invalid");
}
/* Memory allocation */
m = calloc(1, sizeof(struct softnic_mtr));
if (m == NULL)
@ -310,6 +454,7 @@ pmd_mtr_create(struct rte_eth_dev *dev,
/* Update dependencies */
mp->n_users++;
policy->n_users++;
return 0;
}
@ -324,6 +469,7 @@ pmd_mtr_destroy(struct rte_eth_dev *dev,
struct softnic_mtr_list *ml = &p->mtr.mtrs;
struct softnic_mtr_meter_profile *mp;
struct softnic_mtr *m;
struct softnic_mtr_meter_policy *policy;
/* MTR object must exist */
m = softnic_mtr_find(p, mtr_id);
@ -351,8 +497,18 @@ pmd_mtr_destroy(struct rte_eth_dev *dev,
NULL,
"MTR object meter profile invalid");
/* Meter policy must exist */
policy = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
if (policy == NULL)
return -rte_mtr_error_set(error,
EINVAL,
RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
NULL,
"MTR object meter policy invalid");
/* Update dependencies */
mp->n_users--;
policy->n_users--;
/* Remove from list */
TAILQ_REMOVE(ml, m, node);
@ -514,18 +670,18 @@ pmd_mtr_meter_dscp_table_update(struct rte_eth_dev *dev,
return 0;
}
/* MTR object policer action update */
/* MTR object policy update */
static int
pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
pmd_mtr_meter_policy_update(struct rte_eth_dev *dev,
uint32_t mtr_id,
uint32_t action_mask,
enum rte_mtr_policer_action *actions,
uint32_t meter_policy_id,
struct rte_mtr_error *error)
{
struct pmd_internals *p = dev->data->dev_private;
struct softnic_mtr *m;
uint32_t i;
int status;
struct softnic_mtr_meter_policy *mp_new, *mp_old;
/* MTR object id must be valid */
m = softnic_mtr_find(p, mtr_id);
@ -536,28 +692,17 @@ pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
NULL,
"MTR object id not valid");
/* Valid policer actions */
if (actions == NULL)
if (m->params.meter_policy_id == meter_policy_id)
return 0;
/* Meter policy must exist */
mp_new = softnic_mtr_meter_policy_find(p, meter_policy_id);
if (mp_new == NULL)
return -rte_mtr_error_set(error,
EINVAL,
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
NULL,
"Invalid actions");
for (i = 0; i < RTE_COLORS; i++) {
if (action_mask & (1 << i)) {
if (actions[i] != MTR_POLICER_ACTION_COLOR_GREEN &&
actions[i] != MTR_POLICER_ACTION_COLOR_YELLOW &&
actions[i] != MTR_POLICER_ACTION_COLOR_RED &&
actions[i] != MTR_POLICER_ACTION_DROP) {
return -rte_mtr_error_set(error,
EINVAL,
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
NULL,
" Invalid action value");
}
}
}
"Meter policy id invalid");
/* MTR object owner valid? */
if (m->flow) {
@ -569,9 +714,7 @@ pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
/* Set action */
for (i = 0; i < RTE_COLORS; i++)
if (action_mask & (1 << i))
action.mtr.mtr[0].policer[i] =
softnic_table_action_policer(actions[i]);
action.mtr.mtr[0].policer[i] = mp_new->policer[i];
/* Re-add the rule */
status = softnic_pipeline_table_rule_add(p,
@ -595,10 +738,20 @@ pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
1, NULL, 1);
}
/* Meter: Update policer actions */
for (i = 0; i < RTE_COLORS; i++)
if (action_mask & (1 << i))
m->params.action[i] = actions[i];
mp_old = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
if (mp_old == NULL)
return -rte_mtr_error_set(error,
EINVAL,
RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
NULL,
"Old meter policy id invalid");
/* Meter: Set meter profile */
m->params.meter_policy_id = meter_policy_id;
/* Update dependencies*/
mp_old->n_users--;
mp_new->n_users++;
return 0;
}
@ -615,28 +768,40 @@ pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
/* MTR object stats read */
static void
mtr_stats_convert(struct softnic_mtr *m,
mtr_stats_convert(struct pmd_internals *p,
struct softnic_mtr *m,
struct rte_table_action_mtr_counters_tc *in,
struct rte_mtr_stats *out,
uint64_t *out_mask)
{
struct softnic_mtr_meter_policy *mp;
memset(&out, 0, sizeof(out));
*out_mask = 0;
/* Meter policy must exist */
mp = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
if (mp == NULL)
return;
if (in->n_packets_valid) {
uint32_t i;
for (i = 0; i < RTE_COLORS; i++) {
if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_GREEN)
if (mp->policer[i] ==
RTE_TABLE_ACTION_POLICER_COLOR_GREEN)
out->n_pkts[RTE_COLOR_GREEN] += in->n_packets[i];
if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_YELLOW)
if (mp->policer[i] ==
RTE_TABLE_ACTION_POLICER_COLOR_YELLOW)
out->n_pkts[RTE_COLOR_YELLOW] += in->n_packets[i];
if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_RED)
if (mp->policer[i] ==
RTE_TABLE_ACTION_POLICER_COLOR_RED)
out->n_pkts[RTE_COLOR_RED] += in->n_packets[i];
if (m->params.action[i] == MTR_POLICER_ACTION_DROP)
if (mp->policer[i] ==
RTE_TABLE_ACTION_POLICER_DROP)
out->n_pkts_dropped += in->n_packets[i];
}
@ -647,16 +812,20 @@ mtr_stats_convert(struct softnic_mtr *m,
uint32_t i;
for (i = 0; i < RTE_COLORS; i++) {
if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_GREEN)
if (mp->policer[i] ==
RTE_TABLE_ACTION_POLICER_COLOR_GREEN)
out->n_bytes[RTE_COLOR_GREEN] += in->n_bytes[i];
if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_YELLOW)
if (mp->policer[i] ==
RTE_TABLE_ACTION_POLICER_COLOR_YELLOW)
out->n_bytes[RTE_COLOR_YELLOW] += in->n_bytes[i];
if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_RED)
if (mp->policer[i] ==
RTE_TABLE_ACTION_POLICER_COLOR_RED)
out->n_bytes[RTE_COLOR_RED] += in->n_bytes[i];
if (m->params.action[i] == MTR_POLICER_ACTION_DROP)
if (mp->policer[i] ==
RTE_TABLE_ACTION_POLICER_DROP)
out->n_bytes_dropped += in->n_bytes[i];
}
@ -722,7 +891,8 @@ pmd_mtr_stats_read(struct rte_eth_dev *dev,
struct rte_mtr_stats s;
uint64_t s_mask = 0;
mtr_stats_convert(m,
mtr_stats_convert(p,
m,
&counters.stats[0],
&s,
&s_mask);
@ -743,6 +913,9 @@ const struct rte_mtr_ops pmd_mtr_ops = {
.meter_profile_add = pmd_mtr_meter_profile_add,
.meter_profile_delete = pmd_mtr_meter_profile_delete,
.meter_policy_add = pmd_mtr_meter_policy_add,
.meter_policy_delete = pmd_mtr_meter_policy_delete,
.create = pmd_mtr_create,
.destroy = pmd_mtr_destroy,
.meter_enable = NULL,
@ -750,7 +923,7 @@ const struct rte_mtr_ops pmd_mtr_ops = {
.meter_profile_update = pmd_mtr_meter_profile_update,
.meter_dscp_table_update = pmd_mtr_meter_dscp_table_update,
.policer_actions_update = pmd_mtr_policer_actions_update,
.meter_policy_update = pmd_mtr_meter_policy_update,
.stats_update = NULL,
.stats_read = pmd_mtr_stats_read,

View File

@ -33,6 +33,7 @@
#include <rte_bitops.h>
#include <rte_mbuf.h>
#include <rte_mbuf_dyn.h>
#include <rte_meter.h>
#ifdef __cplusplus
extern "C" {
@ -2392,6 +2393,14 @@ enum rte_flow_action_type {
* @see struct rte_flow_action_conntrack.
*/
RTE_FLOW_ACTION_TYPE_CONNTRACK,
/**
* Color the packet to reflect the meter color result.
* Set the meter color in the mbuf to the selected color.
*
* See struct rte_flow_action_meter_color.
*/
RTE_FLOW_ACTION_TYPE_METER_COLOR,
};
/**
@ -3138,6 +3147,19 @@ struct rte_flow_modify_conntrack {
uint32_t reserved:30;
};
/**
* @warning
* @b EXPERIMENTAL: this structure may change without prior notice
*
* RTE_FLOW_ACTION_TYPE_METER_COLOR
*
* The meter color should be set in the packet meta-data
* (i.e. struct rte_mbuf::sched::color).
*/
struct rte_flow_action_meter_color {
enum rte_color color; /**< Packet color. */
};
/**
* Field IDs for MODIFY_FIELD action.
*/

View File

@ -91,6 +91,40 @@ rte_mtr_meter_profile_delete(uint16_t port_id,
meter_profile_id, error);
}
/* MTR meter policy validate */
int
rte_mtr_meter_policy_validate(uint16_t port_id,
struct rte_mtr_meter_policy_params *policy,
struct rte_mtr_error *error)
{
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
return RTE_MTR_FUNC(port_id, meter_policy_validate)(dev,
policy, error);
}
/* MTR meter policy add */
int
rte_mtr_meter_policy_add(uint16_t port_id,
uint32_t policy_id,
struct rte_mtr_meter_policy_params *policy,
struct rte_mtr_error *error)
{
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
return RTE_MTR_FUNC(port_id, meter_policy_add)(dev,
policy_id, policy, error);
}
/** MTR meter policy delete */
int
rte_mtr_meter_policy_delete(uint16_t port_id,
uint32_t policy_id,
struct rte_mtr_error *error)
{
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
return RTE_MTR_FUNC(port_id, meter_policy_delete)(dev,
policy_id, error);
}
/** MTR object create */
int
rte_mtr_create(uint16_t port_id,
@ -149,6 +183,18 @@ rte_mtr_meter_profile_update(uint16_t port_id,
mtr_id, meter_profile_id, error);
}
/** MTR object meter policy update */
int
rte_mtr_meter_policy_update(uint16_t port_id,
uint32_t mtr_id,
uint32_t meter_policy_id,
struct rte_mtr_error *error)
{
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
return RTE_MTR_FUNC(port_id, meter_policy_update)(dev,
mtr_id, meter_policy_id, error);
}
/** MTR object meter DSCP table update */
int
rte_mtr_meter_dscp_table_update(uint16_t port_id,
@ -161,19 +207,6 @@ rte_mtr_meter_dscp_table_update(uint16_t port_id,
mtr_id, dscp_table, error);
}
/** MTR object policer action update */
int
rte_mtr_policer_actions_update(uint16_t port_id,
uint32_t mtr_id,
uint32_t action_mask,
enum rte_mtr_policer_action *actions,
struct rte_mtr_error *error)
{
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
return RTE_MTR_FUNC(port_id, policer_actions_update)(dev,
mtr_id, action_mask, actions, error);
}
/** MTR object enabled stats update */
int
rte_mtr_stats_update(uint16_t port_id,

View File

@ -49,6 +49,7 @@
#include <rte_compat.h>
#include <rte_common.h>
#include <rte_meter.h>
#include <rte_flow.h>
#ifdef __cplusplus
extern "C" {
@ -200,20 +201,16 @@ struct rte_mtr_meter_profile {
};
/**
* Policer actions
* Meter policy
*/
enum rte_mtr_policer_action {
/** Recolor the packet as green. */
MTR_POLICER_ACTION_COLOR_GREEN = 0,
/** Recolor the packet as yellow. */
MTR_POLICER_ACTION_COLOR_YELLOW,
/** Recolor the packet as red. */
MTR_POLICER_ACTION_COLOR_RED,
/** Drop the packet. */
MTR_POLICER_ACTION_DROP,
struct rte_mtr_meter_policy_params {
/**
* Policy action list per color.
* actions[i] potentially represents a chain of rte_flow actions
* terminated by the END action, exactly as specified by the rte_flow
* API for the flow definition, and not just a single action.
*/
const struct rte_flow_action *actions[RTE_COLORS];
};
/**
@ -257,13 +254,13 @@ struct rte_mtr_params {
*/
int meter_enable;
/** Policer actions (per meter output color). */
enum rte_mtr_policer_action action[RTE_COLORS];
/** Set of stats counters to be enabled.
* @see enum rte_mtr_stats_type
*/
uint64_t stats_mask;
/** Meter policy ID. */
uint32_t meter_policy_id;
};
/**
@ -349,6 +346,13 @@ struct rte_mtr_capabilities {
*/
uint64_t meter_rate_max;
/**
* Maximum number of policy objects that can have.
* The value of 0 is invalid. Policy must be supported for meter.
* The maximum value is *n_max*.
*/
uint64_t meter_policy_n_max;
/**
* When non-zero, it indicates that color aware mode is supported for
* the srTCM RFC 2697 metering algorithm.
@ -367,18 +371,6 @@ struct rte_mtr_capabilities {
*/
int color_aware_trtcm_rfc4115_supported;
/** When non-zero, it indicates that the policer packet recolor actions
* are supported.
* @see enum rte_mtr_policer_action
*/
int policer_action_recolor_supported;
/** When non-zero, it indicates that the policer packet drop action is
* supported.
* @see enum rte_mtr_policer_action
*/
int policer_action_drop_supported;
/**
* srTCM rfc2697 byte mode supported.
* When non-zero, it indicates that byte mode is supported for
@ -447,6 +439,8 @@ enum rte_mtr_error_type {
RTE_MTR_ERROR_TYPE_STATS_MASK,
RTE_MTR_ERROR_TYPE_STATS,
RTE_MTR_ERROR_TYPE_SHARED,
RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
RTE_MTR_ERROR_TYPE_METER_POLICY,
};
/**
@ -530,6 +524,144 @@ rte_mtr_meter_profile_delete(uint16_t port_id,
uint32_t meter_profile_id,
struct rte_mtr_error *error);
/**
* Check whether a meter policy can be created on a given port.
*
* The meter policy is validated for correctness and
* whether it could be accepted by the device given sufficient resources.
* The policy is checked against the current capability information
* meter_policy_n_max configuration.
* The policy may also optionally be validated against existing
* device policy resources.
* This function has no effect on the target device.
*
* @param[in] port_id
* The port identifier of the Ethernet device.
* @param[in] policy
* Associated action list per color.
* list NULL is legal and means no special action.
* (list terminated by the END action).
* @param[out] error
* Error details. Filled in only on error, when not NULL.
* @return
* 0 on success, non-zero error code otherwise.
*/
__rte_experimental
int
rte_mtr_meter_policy_validate(uint16_t port_id,
struct rte_mtr_meter_policy_params *policy,
struct rte_mtr_error *error);
/**
* Meter policy add
*
* Create a new meter policy. The new policy
* is used to create single or multiple MTR objects.
* The same policy can be used to create multiple MTR objects.
*
* @param[in] port_id
* The port identifier of the Ethernet device.
* @param[in] policy_id
* Policy identifier for the new meter policy.
* @param[in] policy
* Associated actions per color.
* list NULL is legal and means no special action.
* Non-NULL list must be terminated.
* (list terminated by the END action).
* @param[out] error
* Error details. Filled in only on error, when not NULL.
* @return
* 0 on success, non-zero error code otherwise.
*/
__rte_experimental
int
rte_mtr_meter_policy_add(uint16_t port_id,
uint32_t policy_id,
struct rte_mtr_meter_policy_params *policy,
struct rte_mtr_error *error);
/**
* Define meter policy action list:
* GREEN - GREEN, YELLOW - YELLOW, RED - RED
*/
#define rte_mtr_policy_pass_color(policy) \
struct rte_mtr_meter_policy_params policy = \
{ \
.actions[RTE_COLOR_GREEN] = (struct rte_flow_action[]) { \
{ \
.type = RTE_FLOW_ACTION_TYPE_METER_COLOR, \
.conf = &(struct rte_flow_action_meter_color) { \
.color = RTE_COLOR_GREEN, \
}, \
}, \
{ \
.type = RTE_FLOW_ACTION_TYPE_END, \
}, \
}, \
.actions[RTE_COLOR_YELLOW] = (struct rte_flow_action[]) { \
{ \
.type = RTE_FLOW_ACTION_TYPE_METER_COLOR, \
.conf = &(struct rte_flow_action_meter_color) { \
.color = RTE_COLOR_YELLOW, \
}, \
}, \
{ \
.type = RTE_FLOW_ACTION_TYPE_END, \
}, \
}, \
.actions[RTE_COLOR_RED] = (struct rte_flow_action[]) { \
{ \
.type = RTE_FLOW_ACTION_TYPE_METER_COLOR, \
.conf = &(struct rte_flow_action_meter_color) { \
.color = RTE_COLOR_RED, \
}, \
}, \
{ \
.type = RTE_FLOW_ACTION_TYPE_END, \
}, \
}, \
}
/**
* Define meter policy action list:
* GREEN - Do nothing, YELLOW - Do nothing, RED - DROP
*/
#define rte_mtr_policy_drop_red(policy) \
struct rte_mtr_meter_policy_params policy = \
{ \
.actions[RTE_COLOR_GREEN] = NULL, \
.actions[RTE_COLOR_YELLOW] = NULL, \
.actions[RTE_COLOR_RED] = (struct rte_flow_action[]) { \
{ \
.type = RTE_FLOW_ACTION_TYPE_DROP, \
}, \
{ \
.type = RTE_FLOW_ACTION_TYPE_END, \
}, \
}, \
}
/**
* Meter policy delete
*
* Delete an existing meter policy. This operation fails when there is
* currently at least one user (i.e. MTR object) of this policy.
*
* @param[in] port_id
* The port identifier of the Ethernet device.
* @param[in] policy_id
* Policy identifier.
* @param[out] error
* Error details. Filled in only on error, when not NULL.
* @return
* 0 on success, non-zero error code otherwise.
*/
__rte_experimental
int
rte_mtr_meter_policy_delete(uint16_t port_id,
uint32_t policy_id,
struct rte_mtr_error *error);
/**
* MTR object create
*
@ -654,6 +786,27 @@ rte_mtr_meter_profile_update(uint16_t port_id,
uint32_t meter_profile_id,
struct rte_mtr_error *error);
/**
* MTR object meter policy update
*
* @param[in] port_id
* The port identifier of the Ethernet device.
* @param[in] mtr_id
* MTR object ID. Needs to be valid.
* @param[in] meter_policy_id
* Meter policy ID for the current MTR object. Needs to be valid.
* @param[out] error
* Error details. Filled in only on error, when not NULL.
* @return
* 0 on success, non-zero error code otherwise.
*/
__rte_experimental
int
rte_mtr_meter_policy_update(uint16_t port_id,
uint32_t mtr_id,
uint32_t meter_policy_id,
struct rte_mtr_error *error);
/**
* MTR object DSCP table update
*
@ -665,7 +818,7 @@ rte_mtr_meter_profile_update(uint16_t port_id,
* When non-NULL: it points to a pre-allocated and pre-populated table with
* exactly 64 elements providing the input color for each value of the
* IPv4/IPv6 Differentiated Services Code Point (DSCP) input packet field.
* When NULL: it is equivalent to setting this parameter to an all-green
* When NULL: it is equivalent to setting this parameter to an "all-green"
* populated table (i.e. table with all the 64 elements set to green color).
* @param[out] error
* Error details. Filled in only on error, when not NULL.
@ -679,34 +832,6 @@ rte_mtr_meter_dscp_table_update(uint16_t port_id,
enum rte_color *dscp_table,
struct rte_mtr_error *error);
/**
* MTR object policer actions update
*
* @param[in] port_id
* The port identifier of the Ethernet device.
* @param[in] mtr_id
* MTR object ID. Needs to be valid.
* @param[in] action_mask
* Bit mask indicating which policer actions need to be updated. One or more
* policer actions can be updated in a single function invocation. To update
* the policer action associated with color C, bit (1 << C) needs to be set in
* *action_mask* and element at position C in the *actions* array needs to be
* valid.
* @param[in] actions
* Pre-allocated and pre-populated array of policer actions.
* @param[out] error
* Error details. Filled in only on error, when not NULL.
* @return
* 0 on success, non-zero error code otherwise.
*/
__rte_experimental
int
rte_mtr_policer_actions_update(uint16_t port_id,
uint32_t mtr_id,
uint32_t action_mask,
enum rte_mtr_policer_action *actions,
struct rte_mtr_error *error);
/**
* MTR object enabled statistics counters update
*

View File

@ -41,6 +41,22 @@ typedef int (*rte_mtr_meter_profile_delete_t)(struct rte_eth_dev *dev,
struct rte_mtr_error *error);
/**< @internal MTR meter profile delete */
typedef int (*rte_mtr_meter_policy_validate_t)(struct rte_eth_dev *dev,
struct rte_mtr_meter_policy_params *policy,
struct rte_mtr_error *error);
/**< @internal MTR meter policy validate */
typedef int (*rte_mtr_meter_policy_add_t)(struct rte_eth_dev *dev,
uint32_t policy_id,
struct rte_mtr_meter_policy_params *policy,
struct rte_mtr_error *error);
/**< @internal MTR meter policy add */
typedef int (*rte_mtr_meter_policy_delete_t)(struct rte_eth_dev *dev,
uint32_t policy_id,
struct rte_mtr_error *error);
/**< @internal MTR meter policy delete */
typedef int (*rte_mtr_create_t)(struct rte_eth_dev *dev,
uint32_t mtr_id,
struct rte_mtr_params *params,
@ -69,19 +85,18 @@ typedef int (*rte_mtr_meter_profile_update_t)(struct rte_eth_dev *dev,
struct rte_mtr_error *error);
/**< @internal MTR object meter profile update */
typedef int (*rte_mtr_meter_policy_update_t)(struct rte_eth_dev *dev,
uint32_t mtr_id,
uint32_t meter_policy_id,
struct rte_mtr_error *error);
/**< @internal MTR object meter policy update */
typedef int (*rte_mtr_meter_dscp_table_update_t)(struct rte_eth_dev *dev,
uint32_t mtr_id,
enum rte_color *dscp_table,
struct rte_mtr_error *error);
/**< @internal MTR object meter DSCP table update */
typedef int (*rte_mtr_policer_actions_update_t)(struct rte_eth_dev *dev,
uint32_t mtr_id,
uint32_t action_mask,
enum rte_mtr_policer_action *actions,
struct rte_mtr_error *error);
/**< @internal MTR object policer action update*/
typedef int (*rte_mtr_stats_update_t)(struct rte_eth_dev *dev,
uint32_t mtr_id,
uint64_t stats_mask,
@ -124,14 +139,23 @@ struct rte_mtr_ops {
/** MTR object meter DSCP table update */
rte_mtr_meter_dscp_table_update_t meter_dscp_table_update;
/** MTR object policer action update */
rte_mtr_policer_actions_update_t policer_actions_update;
/** MTR object enabled stats update */
rte_mtr_stats_update_t stats_update;
/** MTR object stats read */
rte_mtr_stats_read_t stats_read;
/** MTR meter policy validate */
rte_mtr_meter_policy_validate_t meter_policy_validate;
/** MTR meter policy add */
rte_mtr_meter_policy_add_t meter_policy_add;
/** MTR meter policy delete */
rte_mtr_meter_policy_delete_t meter_policy_delete;
/** MTR object meter policy update */
rte_mtr_meter_policy_update_t meter_policy_update;
};
/**

View File

@ -138,7 +138,6 @@ EXPERIMENTAL {
rte_mtr_meter_profile_add;
rte_mtr_meter_profile_delete;
rte_mtr_meter_profile_update;
rte_mtr_policer_actions_update;
rte_mtr_stats_read;
rte_mtr_stats_update;
@ -246,6 +245,10 @@ EXPERIMENTAL {
rte_flow_action_handle_destroy;
rte_flow_action_handle_update;
rte_flow_action_handle_query;
rte_mtr_meter_policy_add;
rte_mtr_meter_policy_delete;
rte_mtr_meter_policy_update;
rte_mtr_meter_policy_validate;
};
INTERNAL {