1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 #include "en/tc_priv.h"
8 static bool police_act_validate_control(enum flow_action_id act_id,
9 struct netlink_ext_ack *extack)
11 if (act_id != FLOW_ACTION_PIPE &&
12 act_id != FLOW_ACTION_ACCEPT &&
13 act_id != FLOW_ACTION_JUMP &&
14 act_id != FLOW_ACTION_DROP) {
15 NL_SET_ERR_MSG_MOD(extack,
16 "Offload not supported when conform-exceed action is not pipe, ok, jump or drop");
23 static int police_act_validate(const struct flow_action_entry *act,
24 struct netlink_ext_ack *extack)
26 if (!police_act_validate_control(act->police.exceed.act_id, extack) ||
27 !police_act_validate_control(act->police.notexceed.act_id, extack))
30 if (act->police.peakrate_bytes_ps ||
31 act->police.avrate || act->police.overhead) {
32 NL_SET_ERR_MSG_MOD(extack,
33 "Offload not supported when peakrate/avrate/overhead is configured");
37 if (act->police.rate_pkt_ps) {
38 NL_SET_ERR_MSG_MOD(extack,
39 "QoS offload not support packets per second");
47 tc_act_can_offload_police(struct mlx5e_tc_act_parse_state *parse_state,
48 const struct flow_action_entry *act,
50 struct mlx5_flow_attr *attr)
54 err = police_act_validate(act, parse_state->extack);
58 return !!mlx5e_get_flow_meters(parse_state->flow->priv->mdev);
62 fill_meter_params_from_act(const struct flow_action_entry *act,
63 struct mlx5e_flow_meter_params *params)
65 params->index = act->hw_index;
66 if (act->police.rate_bytes_ps) {
67 params->mode = MLX5_RATE_LIMIT_BPS;
68 /* change rate to bits per second */
69 params->rate = act->police.rate_bytes_ps << 3;
70 params->burst = act->police.burst;
71 } else if (act->police.rate_pkt_ps) {
72 params->mode = MLX5_RATE_LIMIT_PPS;
73 params->rate = act->police.rate_pkt_ps;
74 params->burst = act->police.burst_pkt;
75 } else if (act->police.mtu) {
76 params->mtu = act->police.mtu;
85 tc_act_parse_police(struct mlx5e_tc_act_parse_state *parse_state,
86 const struct flow_action_entry *act,
87 struct mlx5e_priv *priv,
88 struct mlx5_flow_attr *attr)
90 enum mlx5_flow_namespace_type ns = mlx5e_get_flow_namespace(parse_state->flow);
91 struct mlx5e_flow_meter_params *params = &attr->meter_attr.params;
94 err = fill_meter_params_from_act(act, params);
99 if (!(mlx5_fs_get_capabilities(priv->mdev, ns) &
100 MLX5_FLOW_STEERING_CAP_MATCH_RANGES))
103 attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
104 attr->flags |= MLX5_ATTR_FLAG_MTU;
106 attr->action |= MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO;
107 attr->exe_aso_type = MLX5_EXE_ASO_FLOW_METER;
114 tc_act_is_multi_table_act_police(struct mlx5e_priv *priv,
115 const struct flow_action_entry *act,
116 struct mlx5_flow_attr *attr)
122 tc_act_police_offload(struct mlx5e_priv *priv,
123 struct flow_offload_action *fl_act,
124 struct flow_action_entry *act)
126 struct mlx5e_flow_meter_params params = {};
127 struct mlx5e_flow_meter_handle *meter;
130 err = police_act_validate(act, fl_act->extack);
134 err = fill_meter_params_from_act(act, ¶ms);
138 meter = mlx5e_tc_meter_get(priv->mdev, ¶ms);
139 if (IS_ERR(meter) && PTR_ERR(meter) == -ENOENT) {
140 meter = mlx5e_tc_meter_replace(priv->mdev, ¶ms);
141 } else if (!IS_ERR(meter)) {
142 err = mlx5e_tc_meter_update(meter, ¶ms);
143 mlx5e_tc_meter_put(meter);
147 NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
148 mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
149 err = PTR_ERR(meter);
156 tc_act_police_destroy(struct mlx5e_priv *priv,
157 struct flow_offload_action *fl_act)
159 struct mlx5e_flow_meter_params params = {};
160 struct mlx5e_flow_meter_handle *meter;
162 params.index = fl_act->index;
163 meter = mlx5e_tc_meter_get(priv->mdev, ¶ms);
165 NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
166 mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
167 return PTR_ERR(meter);
169 /* first put for the get and second for cleanup */
170 mlx5e_tc_meter_put(meter);
171 mlx5e_tc_meter_put(meter);
176 tc_act_police_stats(struct mlx5e_priv *priv,
177 struct flow_offload_action *fl_act)
179 struct mlx5e_flow_meter_params params = {};
180 struct mlx5e_flow_meter_handle *meter;
181 u64 bytes, packets, drops, lastuse;
183 params.index = fl_act->index;
184 meter = mlx5e_tc_meter_get(priv->mdev, ¶ms);
186 NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
187 mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
188 return PTR_ERR(meter);
191 mlx5e_tc_meter_get_stats(meter, &bytes, &packets, &drops, &lastuse);
192 flow_stats_update(&fl_act->stats, bytes, packets, drops, lastuse,
193 FLOW_ACTION_HW_STATS_DELAYED);
194 mlx5e_tc_meter_put(meter);
199 tc_act_police_get_branch_ctrl(const struct flow_action_entry *act,
200 struct mlx5e_tc_act_branch_ctrl *cond_true,
201 struct mlx5e_tc_act_branch_ctrl *cond_false)
203 cond_true->act_id = act->police.notexceed.act_id;
204 cond_true->extval = act->police.notexceed.extval;
206 cond_false->act_id = act->police.exceed.act_id;
207 cond_false->extval = act->police.exceed.extval;
211 struct mlx5e_tc_act mlx5e_tc_act_police = {
212 .can_offload = tc_act_can_offload_police,
213 .parse_action = tc_act_parse_police,
214 .is_multi_table_act = tc_act_is_multi_table_act_police,
215 .offload_action = tc_act_police_offload,
216 .destroy_action = tc_act_police_destroy,
217 .stats_action = tc_act_police_stats,
218 .get_branch_ctrl = tc_act_police_get_branch_ctrl,