File Index
Files and directories
Sign in
FILE

post_meter.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.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 "en/tc_priv.h"
  5#include "post_meter.h"
  6#include "en/tc/post_act.h"
  7
  8#define MLX5_PACKET_COLOR_BITS MLX5_REG_MAPPING_MBITS(PACKET_COLOR_TO_REG)
  9#define MLX5_PACKET_COLOR_MASK MLX5_REG_MAPPING_MASK(PACKET_COLOR_TO_REG)
 10
 11struct mlx5e_post_meter_rate_table {
 12	struct mlx5_flow_table *ft;
 13	struct mlx5_flow_group *fg;
 14	struct mlx5_flow_handle *green_rule;
 15	struct mlx5_flow_attr *green_attr;
 16	struct mlx5_flow_handle *red_rule;
 17	struct mlx5_flow_attr *red_attr;
 18};
 19
 20struct mlx5e_post_meter_mtu_table {
 21	struct mlx5_flow_table *ft;
 22	struct mlx5_flow_group *fg;
 23	struct mlx5_flow_handle *rule;
 24	struct mlx5_flow_attr *attr;
 25};
 26
 27struct mlx5e_post_meter_mtu_tables {
 28	struct mlx5e_post_meter_mtu_table green_table;
 29	struct mlx5e_post_meter_mtu_table red_table;
 30};
 31
 32struct mlx5e_post_meter_priv {
 33	enum mlx5e_post_meter_type type;
 34	union {
 35		struct mlx5e_post_meter_rate_table rate_steering_table;
 36		struct mlx5e_post_meter_mtu_tables  mtu_tables;
 37	};
 38};
 39
 40struct mlx5_flow_table *
 41mlx5e_post_meter_get_ft(struct mlx5e_post_meter_priv *post_meter)
 42{
 43	return post_meter->rate_steering_table.ft;
 44}
 45
 46struct mlx5_flow_table *
 47mlx5e_post_meter_get_mtu_true_ft(struct mlx5e_post_meter_priv *post_meter)
 48{
 49	return post_meter->mtu_tables.green_table.ft;
 50}
 51
 52struct mlx5_flow_table *
 53mlx5e_post_meter_get_mtu_false_ft(struct mlx5e_post_meter_priv *post_meter)
 54{
 55	return post_meter->mtu_tables.red_table.ft;
 56}
 57
 58static struct mlx5_flow_table *
 59mlx5e_post_meter_table_create(struct mlx5e_priv *priv,
 60			      enum mlx5_flow_namespace_type ns_type)
 61{
 62	struct mlx5_flow_table_attr ft_attr = {};
 63	struct mlx5_flow_namespace *root_ns;
 64
 65	root_ns = mlx5_get_flow_namespace(priv->mdev, ns_type);
 66	if (!root_ns) {
 67		mlx5_core_warn(priv->mdev, "Failed to get namespace for flow meter\n");
 68		return ERR_PTR(-EOPNOTSUPP);
 69	}
 70
 71	ft_attr.flags = MLX5_FLOW_TABLE_UNMANAGED;
 72	ft_attr.prio = FDB_SLOW_PATH;
 73	ft_attr.max_fte = 2;
 74	ft_attr.level = 1;
 75
 76	return mlx5_create_flow_table(root_ns, &ft_attr);
 77}
 78
 79static int
 80mlx5e_post_meter_rate_fg_create(struct mlx5e_priv *priv,
 81				struct mlx5e_post_meter_priv *post_meter)
 82{
 83	struct mlx5e_post_meter_rate_table *table = &post_meter->rate_steering_table;
 84	int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
 85	void *misc2, *match_criteria;
 86	u32 *flow_group_in;
 87	int err = 0;
 88
 89	flow_group_in = kvzalloc(inlen, GFP_KERNEL);
 90	if (!flow_group_in)
 91		return -ENOMEM;
 92
 93	MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
 94		 MLX5_MATCH_MISC_PARAMETERS_2);
 95	match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
 96				      match_criteria);
 97	misc2 = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters_2);
 98	MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_5, MLX5_PACKET_COLOR_MASK);
 99	MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
100	MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
101
102	table->fg = mlx5_create_flow_group(table->ft, flow_group_in);
103	if (IS_ERR(table->fg)) {
104		mlx5_core_warn(priv->mdev, "Failed to create post_meter flow group\n");
105		err = PTR_ERR(table->fg);
106	}
107
108	kvfree(flow_group_in);
109	return err;
110}
111
112static struct mlx5_flow_handle *
113mlx5e_post_meter_add_rule(struct mlx5e_priv *priv,
114			  struct mlx5e_post_meter_priv *post_meter,
115			  struct mlx5_flow_spec *spec,
116			  struct mlx5_flow_attr *attr,
117			  struct mlx5_fc *act_counter,
118			  struct mlx5_fc *drop_counter)
119{
120	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
121	struct mlx5_flow_handle *ret;
122
123	attr->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
124	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_DROP)
125		attr->counter = drop_counter;
126	else
127		attr->counter = act_counter;
128
129	attr->flags |= MLX5_ATTR_FLAG_NO_IN_PORT;
130	attr->inner_match_level = MLX5_MATCH_NONE;
131	attr->outer_match_level = MLX5_MATCH_NONE;
132	attr->chain = 0;
133	attr->prio = 0;
134
135	ret = mlx5_eswitch_add_offloaded_rule(esw, spec, attr);
136
137	/* We did not create the counter, so we can't delete it.
138	 * Avoid freeing the counter when the attr is deleted in free_branching_attr
139	 */
140	attr->action &= ~MLX5_FLOW_CONTEXT_ACTION_COUNT;
141
142	return ret;
143}
144
145static int
146mlx5e_post_meter_rate_rules_create(struct mlx5e_priv *priv,
147				   struct mlx5e_post_meter_priv *post_meter,
148				   struct mlx5e_post_act *post_act,
149				   struct mlx5_fc *act_counter,
150				   struct mlx5_fc *drop_counter,
151				   struct mlx5_flow_attr *green_attr,
152				   struct mlx5_flow_attr *red_attr)
153{
154	struct mlx5e_post_meter_rate_table *table = &post_meter->rate_steering_table;
155	struct mlx5_flow_handle *rule;
156	struct mlx5_flow_spec *spec;
157	int err;
158
159	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
160	if (!spec)
161		return -ENOMEM;
162
163	mlx5e_tc_match_to_reg_match(spec, PACKET_COLOR_TO_REG,
164				    MLX5_FLOW_METER_COLOR_RED, MLX5_PACKET_COLOR_MASK);
165	red_attr->ft = post_meter->rate_steering_table.ft;
166	rule = mlx5e_post_meter_add_rule(priv, post_meter, spec, red_attr,
167					 act_counter, drop_counter);
168	if (IS_ERR(rule)) {
169		mlx5_core_warn(priv->mdev, "Failed to create post_meter exceed rule\n");
170		err = PTR_ERR(rule);
171		goto err_red;
172	}
173	table->red_rule = rule;
174	table->red_attr = red_attr;
175
176	mlx5e_tc_match_to_reg_match(spec, PACKET_COLOR_TO_REG,
177				    MLX5_FLOW_METER_COLOR_GREEN, MLX5_PACKET_COLOR_MASK);
178	green_attr->ft = post_meter->rate_steering_table.ft;
179	rule = mlx5e_post_meter_add_rule(priv, post_meter, spec, green_attr,
180					 act_counter, drop_counter);
181	if (IS_ERR(rule)) {
182		mlx5_core_warn(priv->mdev, "Failed to create post_meter notexceed rule\n");
183		err = PTR_ERR(rule);
184		goto err_green;
185	}
186	table->green_rule = rule;
187	table->green_attr = green_attr;
188
189	kvfree(spec);
190	return 0;
191
192err_green:
193	mlx5_del_flow_rules(table->red_rule);
194err_red:
195	kvfree(spec);
196	return err;
197}
198
199static void
200mlx5e_post_meter_rate_rules_destroy(struct mlx5_eswitch *esw,
201				    struct mlx5e_post_meter_priv *post_meter)
202{
203	struct mlx5e_post_meter_rate_table *rate_table = &post_meter->rate_steering_table;
204
205	mlx5_eswitch_del_offloaded_rule(esw, rate_table->red_rule, rate_table->red_attr);
206	mlx5_eswitch_del_offloaded_rule(esw, rate_table->green_rule, rate_table->green_attr);
207}
208
209static void
210mlx5e_post_meter_rate_fg_destroy(struct mlx5e_post_meter_priv *post_meter)
211{
212	mlx5_destroy_flow_group(post_meter->rate_steering_table.fg);
213}
214
215static void
216mlx5e_post_meter_rate_table_destroy(struct mlx5e_post_meter_priv *post_meter)
217{
218	mlx5_destroy_flow_table(post_meter->rate_steering_table.ft);
219}
220
221static void
222mlx5e_post_meter_mtu_rules_destroy(struct mlx5e_post_meter_priv *post_meter)
223{
224	struct mlx5e_post_meter_mtu_tables *mtu_tables = &post_meter->mtu_tables;
225
226	mlx5_del_flow_rules(mtu_tables->green_table.rule);
227	mlx5_del_flow_rules(mtu_tables->red_table.rule);
228}
229
230static void
231mlx5e_post_meter_mtu_fg_destroy(struct mlx5e_post_meter_priv *post_meter)
232{
233	struct mlx5e_post_meter_mtu_tables *mtu_tables = &post_meter->mtu_tables;
234
235	mlx5_destroy_flow_group(mtu_tables->green_table.fg);
236	mlx5_destroy_flow_group(mtu_tables->red_table.fg);
237}
238
239static void
240mlx5e_post_meter_mtu_table_destroy(struct mlx5e_post_meter_priv *post_meter)
241{
242	struct mlx5e_post_meter_mtu_tables *mtu_tables = &post_meter->mtu_tables;
243
244	mlx5_destroy_flow_table(mtu_tables->green_table.ft);
245	mlx5_destroy_flow_table(mtu_tables->red_table.ft);
246}
247
248static int
249mlx5e_post_meter_rate_create(struct mlx5e_priv *priv,
250			     enum mlx5_flow_namespace_type ns_type,
251			     struct mlx5e_post_act *post_act,
252			     struct mlx5_fc *act_counter,
253			     struct mlx5_fc *drop_counter,
254			     struct mlx5e_post_meter_priv *post_meter,
255			     struct mlx5_flow_attr *green_attr,
256			     struct mlx5_flow_attr *red_attr)
257{
258	struct mlx5_flow_table *ft;
259	int err;
260
261	post_meter->type = MLX5E_POST_METER_RATE;
262
263	ft = mlx5e_post_meter_table_create(priv, ns_type);
264	if (IS_ERR(ft)) {
265		err = PTR_ERR(ft);
266		mlx5_core_warn(priv->mdev, "Failed to create post_meter table\n");
267		goto err_ft;
268	}
269
270	post_meter->rate_steering_table.ft = ft;
271
272	err = mlx5e_post_meter_rate_fg_create(priv, post_meter);
273	if (err)
274		goto err_fg;
275
276	err = mlx5e_post_meter_rate_rules_create(priv, post_meter, post_act,
277						 act_counter, drop_counter,
278						 green_attr, red_attr);
279	if (err)
280		goto err_rules;
281
282	return 0;
283
284err_rules:
285	mlx5e_post_meter_rate_fg_destroy(post_meter);
286err_fg:
287	mlx5e_post_meter_rate_table_destroy(post_meter);
288err_ft:
289	return err;
290}
291
292static int
293mlx5e_post_meter_create_mtu_table(struct mlx5e_priv *priv,
294				  enum mlx5_flow_namespace_type ns_type,
295				  struct mlx5e_post_meter_mtu_table *table)
296{
297	int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
298	struct mlx5_flow_group *fg;
299	u32 *flow_group_in;
300	int err;
301
302	flow_group_in = kvzalloc(inlen, GFP_KERNEL);
303	if (!flow_group_in)
304		return -ENOMEM;
305
306	table->ft = mlx5e_post_meter_table_create(priv, ns_type);
307	if (IS_ERR(table->ft)) {
308		err = PTR_ERR(table->ft);
309		goto err_ft;
310	}
311
312	/* create miss group */
313	memset(flow_group_in, 0, inlen);
314	MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1);
315	MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
316	fg = mlx5_create_flow_group(table->ft, flow_group_in);
317	if (IS_ERR(fg)) {
318		err = PTR_ERR(fg);
319		goto err_miss_grp;
320	}
321	table->fg = fg;
322
323	kvfree(flow_group_in);
324	return 0;
325
326err_miss_grp:
327	mlx5_destroy_flow_table(table->ft);
328err_ft:
329	kvfree(flow_group_in);
330	return err;
331}
332
333static int
334mlx5e_post_meter_mtu_create(struct mlx5e_priv *priv,
335			    enum mlx5_flow_namespace_type ns_type,
336			    struct mlx5e_post_act *post_act,
337			    struct mlx5_fc *act_counter,
338			    struct mlx5_fc *drop_counter,
339			    struct mlx5e_post_meter_priv *post_meter,
340			    struct mlx5_flow_attr *green_attr,
341			    struct mlx5_flow_attr *red_attr)
342{
343	struct mlx5e_post_meter_mtu_tables *mtu_tables = &post_meter->mtu_tables;
344	static struct mlx5_flow_spec zero_spec = {};
345	struct mlx5_flow_handle *rule;
346	int err;
347
348	post_meter->type = MLX5E_POST_METER_MTU;
349
350	err = mlx5e_post_meter_create_mtu_table(priv, ns_type, &mtu_tables->green_table);
351	if (err)
352		goto err_green_ft;
353
354	green_attr->ft = mtu_tables->green_table.ft;
355	rule = mlx5e_post_meter_add_rule(priv, post_meter, &zero_spec, green_attr,
356					 act_counter, drop_counter);
357	if (IS_ERR(rule)) {
358		mlx5_core_warn(priv->mdev, "Failed to create post_meter conform rule\n");
359		err = PTR_ERR(rule);
360		goto err_green_rule;
361	}
362	mtu_tables->green_table.rule = rule;
363	mtu_tables->green_table.attr = green_attr;
364
365	err = mlx5e_post_meter_create_mtu_table(priv, ns_type, &mtu_tables->red_table);
366	if (err)
367		goto err_red_ft;
368
369	red_attr->ft = mtu_tables->red_table.ft;
370	rule = mlx5e_post_meter_add_rule(priv, post_meter, &zero_spec, red_attr,
371					 act_counter, drop_counter);
372	if (IS_ERR(rule)) {
373		mlx5_core_warn(priv->mdev, "Failed to create post_meter exceed rule\n");
374		err = PTR_ERR(rule);
375		goto err_red_rule;
376	}
377	mtu_tables->red_table.rule = rule;
378	mtu_tables->red_table.attr = red_attr;
379
380	return 0;
381
382err_red_rule:
383	mlx5_destroy_flow_table(mtu_tables->red_table.ft);
384err_red_ft:
385	mlx5_del_flow_rules(mtu_tables->green_table.rule);
386err_green_rule:
387	mlx5_destroy_flow_table(mtu_tables->green_table.ft);
388err_green_ft:
389	return err;
390}
391
392struct mlx5e_post_meter_priv *
393mlx5e_post_meter_init(struct mlx5e_priv *priv,
394		      enum mlx5_flow_namespace_type ns_type,
395		      struct mlx5e_post_act *post_act,
396		      enum mlx5e_post_meter_type type,
397		      struct mlx5_fc *act_counter,
398		      struct mlx5_fc *drop_counter,
399		      struct mlx5_flow_attr *branch_true,
400		      struct mlx5_flow_attr *branch_false)
401{
402	struct mlx5e_post_meter_priv *post_meter;
403	int err;
404
405	post_meter = kzalloc(sizeof(*post_meter), GFP_KERNEL);
406	if (!post_meter)
407		return ERR_PTR(-ENOMEM);
408
409	switch (type) {
410	case MLX5E_POST_METER_MTU:
411		err = mlx5e_post_meter_mtu_create(priv, ns_type, post_act,
412						  act_counter, drop_counter, post_meter,
413						  branch_true, branch_false);
414		break;
415	case MLX5E_POST_METER_RATE:
416		err = mlx5e_post_meter_rate_create(priv, ns_type, post_act,
417						   act_counter, drop_counter, post_meter,
418						   branch_true, branch_false);
419		break;
420	default:
421		err = -EOPNOTSUPP;
422	}
423
424	if (err)
425		goto err;
426
427	return post_meter;
428
429err:
430	kfree(post_meter);
431	return ERR_PTR(err);
432}
433
434static void
435mlx5e_post_meter_rate_destroy(struct mlx5_eswitch *esw, struct mlx5e_post_meter_priv *post_meter)
436{
437	mlx5e_post_meter_rate_rules_destroy(esw, post_meter);
438	mlx5e_post_meter_rate_fg_destroy(post_meter);
439	mlx5e_post_meter_rate_table_destroy(post_meter);
440}
441
442static void
443mlx5e_post_meter_mtu_destroy(struct mlx5e_post_meter_priv *post_meter)
444{
445	mlx5e_post_meter_mtu_rules_destroy(post_meter);
446	mlx5e_post_meter_mtu_fg_destroy(post_meter);
447	mlx5e_post_meter_mtu_table_destroy(post_meter);
448}
449
450void
451mlx5e_post_meter_cleanup(struct mlx5_eswitch *esw, struct mlx5e_post_meter_priv *post_meter)
452{
453	if (post_meter->type == MLX5E_POST_METER_RATE)
454		mlx5e_post_meter_rate_destroy(esw, post_meter);
455	else
456		mlx5e_post_meter_mtu_destroy(post_meter);
457
458	kfree(post_meter);
459}
460
~/ Read-only file preview.