File Index
Files and directories
Sign in
FILE

police.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/police.c C
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  3
  4#include "act.h"
  5#include "en/tc_priv.h"
  6#include "fs_core.h"
  7
  8static bool police_act_validate_control(enum flow_action_id act_id,
  9					struct netlink_ext_ack *extack)
 10{
 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");
 17		return false;
 18	}
 19
 20	return true;
 21}
 22
 23static int police_act_validate(const struct flow_action_entry *act,
 24			       struct netlink_ext_ack *extack)
 25{
 26	if (!police_act_validate_control(act->police.exceed.act_id, extack) ||
 27	    !police_act_validate_control(act->police.notexceed.act_id, extack))
 28		return -EOPNOTSUPP;
 29
 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");
 34		return -EOPNOTSUPP;
 35	}
 36
 37	return 0;
 38}
 39
 40static bool
 41tc_act_can_offload_police(struct mlx5e_tc_act_parse_state *parse_state,
 42			  const struct flow_action_entry *act,
 43			  int act_index,
 44			  struct mlx5_flow_attr *attr)
 45{
 46	int err;
 47
 48	err = police_act_validate(act, parse_state->extack);
 49	if (err)
 50		return false;
 51
 52	return !!mlx5e_get_flow_meters(parse_state->flow->priv->mdev);
 53}
 54
 55static int
 56fill_meter_params_from_act(const struct flow_action_entry *act,
 57			   struct mlx5e_flow_meter_params *params)
 58{
 59	params->index = act->hw_index;
 60	if (act->police.rate_bytes_ps) {
 61		params->mode = MLX5_RATE_LIMIT_BPS;
 62		/* change rate to bits per second */
 63		params->rate = act->police.rate_bytes_ps << 3;
 64		params->burst = act->police.burst;
 65	} else if (act->police.rate_pkt_ps) {
 66		params->mode = MLX5_RATE_LIMIT_PPS;
 67		params->rate = act->police.rate_pkt_ps;
 68		params->burst = act->police.burst_pkt;
 69	} else if (act->police.mtu) {
 70		params->mtu = act->police.mtu;
 71	} else {
 72		return -EOPNOTSUPP;
 73	}
 74
 75	return 0;
 76}
 77
 78static int
 79tc_act_parse_police(struct mlx5e_tc_act_parse_state *parse_state,
 80		    const struct flow_action_entry *act,
 81		    struct mlx5e_priv *priv,
 82		    struct mlx5_flow_attr *attr)
 83{
 84	enum mlx5_flow_namespace_type ns =  mlx5e_get_flow_namespace(parse_state->flow);
 85	struct mlx5e_flow_meter_params *params = &attr->meter_attr.params;
 86	int err;
 87
 88	err = fill_meter_params_from_act(act, params);
 89	if (err)
 90		return err;
 91
 92	if (params->mtu) {
 93		if (!(mlx5_fs_get_capabilities(priv->mdev, ns) &
 94		      MLX5_FLOW_STEERING_CAP_MATCH_RANGES))
 95			return -EOPNOTSUPP;
 96
 97		attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
 98		attr->flags |= MLX5_ATTR_FLAG_MTU;
 99	} else {
100		attr->action |= MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO;
101		attr->exe_aso_type = MLX5_EXE_ASO_FLOW_METER;
102	}
103
104	return 0;
105}
106
107static bool
108tc_act_is_multi_table_act_police(struct mlx5e_priv *priv,
109				 const struct flow_action_entry *act,
110				 struct mlx5_flow_attr *attr)
111{
112	return true;
113}
114
115static int
116tc_act_police_offload(struct mlx5e_priv *priv,
117		      struct flow_offload_action *fl_act,
118		      struct flow_action_entry *act)
119{
120	struct mlx5e_flow_meter_params params = {};
121	struct mlx5e_flow_meter_handle *meter;
122	int err = 0;
123
124	err = police_act_validate(act, fl_act->extack);
125	if (err)
126		return err;
127
128	err = fill_meter_params_from_act(act, &params);
129	if (err)
130		return err;
131
132	meter = mlx5e_tc_meter_get(priv->mdev, &params);
133	if (IS_ERR(meter) && PTR_ERR(meter) == -ENOENT) {
134		meter = mlx5e_tc_meter_replace(priv->mdev, &params);
135	} else if (!IS_ERR(meter)) {
136		err = mlx5e_tc_meter_update(meter, &params);
137		mlx5e_tc_meter_put(meter);
138	}
139
140	if (IS_ERR(meter)) {
141		NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
142		mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
143		err = PTR_ERR(meter);
144	}
145
146	return err;
147}
148
149static int
150tc_act_police_destroy(struct mlx5e_priv *priv,
151		      struct flow_offload_action *fl_act)
152{
153	struct mlx5e_flow_meter_params params = {};
154	struct mlx5e_flow_meter_handle *meter;
155
156	params.index = fl_act->index;
157	meter = mlx5e_tc_meter_get(priv->mdev, &params);
158	if (IS_ERR(meter)) {
159		NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
160		mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
161		return PTR_ERR(meter);
162	}
163	/* first put for the get and second for cleanup */
164	mlx5e_tc_meter_put(meter);
165	mlx5e_tc_meter_put(meter);
166	return 0;
167}
168
169static int
170tc_act_police_stats(struct mlx5e_priv *priv,
171		    struct flow_offload_action *fl_act)
172{
173	struct mlx5e_flow_meter_params params = {};
174	struct mlx5e_flow_meter_handle *meter;
175	u64 bytes, packets, drops, lastuse;
176
177	params.index = fl_act->index;
178	meter = mlx5e_tc_meter_get(priv->mdev, &params);
179	if (IS_ERR(meter)) {
180		NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
181		return PTR_ERR(meter);
182	}
183
184	mlx5e_tc_meter_get_stats(meter, &bytes, &packets, &drops, &lastuse);
185	flow_stats_update(&fl_act->stats, bytes, packets, drops, lastuse,
186			  FLOW_ACTION_HW_STATS_DELAYED);
187	mlx5e_tc_meter_put(meter);
188	return 0;
189}
190
191static bool
192tc_act_police_get_branch_ctrl(const struct flow_action_entry *act,
193			      struct mlx5e_tc_act_branch_ctrl *cond_true,
194			      struct mlx5e_tc_act_branch_ctrl *cond_false)
195{
196	cond_true->act_id = act->police.notexceed.act_id;
197	cond_true->extval = act->police.notexceed.extval;
198
199	cond_false->act_id = act->police.exceed.act_id;
200	cond_false->extval = act->police.exceed.extval;
201	return true;
202}
203
204struct mlx5e_tc_act mlx5e_tc_act_police = {
205	.can_offload = tc_act_can_offload_police,
206	.parse_action = tc_act_parse_police,
207	.is_multi_table_act = tc_act_is_multi_table_act_police,
208	.offload_action = tc_act_police_offload,
209	.destroy_action = tc_act_police_destroy,
210	.stats_action = tc_act_police_stats,
211	.get_branch_ctrl = tc_act_police_get_branch_ctrl,
212};
~/ Read-only file preview.