FILE
post_meter.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.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.