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 11 struct 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 20 struct 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 27 struct 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 32 struct 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 40 struct mlx5_flow_table * 41 mlx5e_post_meter_get_ft(struct mlx5e_post_meter_priv *post_meter) 42 { 43 return post_meter->rate_steering_table.ft; 44 } 45 46 struct mlx5_flow_table * 47 mlx5e_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 52 struct mlx5_flow_table * 53 mlx5e_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 58 static struct mlx5_flow_table * 59 mlx5e_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 79 static int 80 mlx5e_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 112 static struct mlx5_flow_handle * 113 mlx5e_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 145 static int 146 mlx5e_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 192 err_green: 193 mlx5_del_flow_rules(table->red_rule); 194 err_red: 195 kvfree(spec); 196 return err; 197 } 198 199 static void 200 mlx5e_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 209 static void 210 mlx5e_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 215 static void 216 mlx5e_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 221 static void 222 mlx5e_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 230 static void 231 mlx5e_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 239 static void 240 mlx5e_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 248 static int 249 mlx5e_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 284 err_rules: 285 mlx5e_post_meter_rate_fg_destroy(post_meter); 286 err_fg: 287 mlx5e_post_meter_rate_table_destroy(post_meter); 288 err_ft: 289 return err; 290 } 291 292 static int 293 mlx5e_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 326 err_miss_grp: 327 mlx5_destroy_flow_table(table->ft); 328 err_ft: 329 kvfree(flow_group_in); 330 return err; 331 } 332 333 static int 334 mlx5e_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 382 err_red_rule: 383 mlx5_destroy_flow_table(mtu_tables->red_table.ft); 384 err_red_ft: 385 mlx5_del_flow_rules(mtu_tables->green_table.rule); 386 err_green_rule: 387 mlx5_destroy_flow_table(mtu_tables->green_table.ft); 388 err_green_ft: 389 return err; 390 } 391 392 struct mlx5e_post_meter_priv * 393 mlx5e_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 429 err: 430 kfree(post_meter); 431 return ERR_PTR(err); 432 } 433 434 static void 435 mlx5e_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 442 static void 443 mlx5e_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 450 void 451 mlx5e_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 461