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_priv { 12 struct mlx5_flow_table *ft; 13 struct mlx5_flow_group *fg; 14 struct mlx5_flow_handle *fwd_green_rule; 15 struct mlx5_flow_handle *drop_red_rule; 16 }; 17 18 struct mlx5_flow_table * 19 mlx5e_post_meter_get_ft(struct mlx5e_post_meter_priv *post_meter) 20 { 21 return post_meter->ft; 22 } 23 24 static int 25 mlx5e_post_meter_table_create(struct mlx5e_priv *priv, 26 enum mlx5_flow_namespace_type ns_type, 27 struct mlx5e_post_meter_priv *post_meter) 28 { 29 struct mlx5_flow_table_attr ft_attr = {}; 30 struct mlx5_flow_namespace *root_ns; 31 32 root_ns = mlx5_get_flow_namespace(priv->mdev, ns_type); 33 if (!root_ns) { 34 mlx5_core_warn(priv->mdev, "Failed to get namespace for flow meter\n"); 35 return -EOPNOTSUPP; 36 } 37 38 ft_attr.flags = MLX5_FLOW_TABLE_UNMANAGED; 39 ft_attr.prio = FDB_SLOW_PATH; 40 ft_attr.max_fte = 2; 41 ft_attr.level = 1; 42 43 post_meter->ft = mlx5_create_flow_table(root_ns, &ft_attr); 44 if (IS_ERR(post_meter->ft)) { 45 mlx5_core_warn(priv->mdev, "Failed to create post_meter table\n"); 46 return PTR_ERR(post_meter->ft); 47 } 48 49 return 0; 50 } 51 52 static int 53 mlx5e_post_meter_fg_create(struct mlx5e_priv *priv, 54 struct mlx5e_post_meter_priv *post_meter) 55 { 56 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 57 void *misc2, *match_criteria; 58 u32 *flow_group_in; 59 int err = 0; 60 61 flow_group_in = kvzalloc(inlen, GFP_KERNEL); 62 if (!flow_group_in) 63 return -ENOMEM; 64 65 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, 66 MLX5_MATCH_MISC_PARAMETERS_2); 67 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, 68 match_criteria); 69 misc2 = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters_2); 70 MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_5, MLX5_PACKET_COLOR_MASK); 71 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); 72 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1); 73 74 post_meter->fg = mlx5_create_flow_group(post_meter->ft, flow_group_in); 75 if (IS_ERR(post_meter->fg)) { 76 mlx5_core_warn(priv->mdev, "Failed to create post_meter flow group\n"); 77 err = PTR_ERR(post_meter->fg); 78 } 79 80 kvfree(flow_group_in); 81 return err; 82 } 83 84 static int 85 mlx5e_post_meter_rules_create(struct mlx5e_priv *priv, 86 struct mlx5e_post_meter_priv *post_meter, 87 struct mlx5e_post_act *post_act, 88 struct mlx5_fc *green_counter, 89 struct mlx5_fc *red_counter) 90 { 91 struct mlx5_flow_destination dest[2] = {}; 92 struct mlx5_flow_act flow_act = {}; 93 struct mlx5_flow_handle *rule; 94 struct mlx5_flow_spec *spec; 95 int err; 96 97 spec = kvzalloc(sizeof(*spec), GFP_KERNEL); 98 if (!spec) 99 return -ENOMEM; 100 101 mlx5e_tc_match_to_reg_match(spec, PACKET_COLOR_TO_REG, 102 MLX5_FLOW_METER_COLOR_RED, MLX5_PACKET_COLOR_MASK); 103 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP | 104 MLX5_FLOW_CONTEXT_ACTION_COUNT; 105 flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL; 106 dest[0].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 107 dest[0].counter_id = mlx5_fc_id(red_counter); 108 109 rule = mlx5_add_flow_rules(post_meter->ft, spec, &flow_act, dest, 1); 110 if (IS_ERR(rule)) { 111 mlx5_core_warn(priv->mdev, "Failed to create post_meter flow drop rule\n"); 112 err = PTR_ERR(rule); 113 goto err_red; 114 } 115 post_meter->drop_red_rule = rule; 116 117 mlx5e_tc_match_to_reg_match(spec, PACKET_COLOR_TO_REG, 118 MLX5_FLOW_METER_COLOR_GREEN, MLX5_PACKET_COLOR_MASK); 119 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | 120 MLX5_FLOW_CONTEXT_ACTION_COUNT; 121 dest[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; 122 dest[0].ft = mlx5e_tc_post_act_get_ft(post_act); 123 dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 124 dest[1].counter_id = mlx5_fc_id(green_counter); 125 126 rule = mlx5_add_flow_rules(post_meter->ft, spec, &flow_act, dest, 2); 127 if (IS_ERR(rule)) { 128 mlx5_core_warn(priv->mdev, "Failed to create post_meter flow fwd rule\n"); 129 err = PTR_ERR(rule); 130 goto err_green; 131 } 132 post_meter->fwd_green_rule = rule; 133 134 kvfree(spec); 135 return 0; 136 137 err_green: 138 mlx5_del_flow_rules(post_meter->drop_red_rule); 139 err_red: 140 kvfree(spec); 141 return err; 142 } 143 144 static void 145 mlx5e_post_meter_rules_destroy(struct mlx5e_post_meter_priv *post_meter) 146 { 147 mlx5_del_flow_rules(post_meter->drop_red_rule); 148 mlx5_del_flow_rules(post_meter->fwd_green_rule); 149 } 150 151 static void 152 mlx5e_post_meter_fg_destroy(struct mlx5e_post_meter_priv *post_meter) 153 { 154 mlx5_destroy_flow_group(post_meter->fg); 155 } 156 157 static void 158 mlx5e_post_meter_table_destroy(struct mlx5e_post_meter_priv *post_meter) 159 { 160 mlx5_destroy_flow_table(post_meter->ft); 161 } 162 163 struct mlx5e_post_meter_priv * 164 mlx5e_post_meter_init(struct mlx5e_priv *priv, 165 enum mlx5_flow_namespace_type ns_type, 166 struct mlx5e_post_act *post_act, 167 struct mlx5_fc *green_counter, 168 struct mlx5_fc *red_counter) 169 { 170 struct mlx5e_post_meter_priv *post_meter; 171 int err; 172 173 post_meter = kzalloc(sizeof(*post_meter), GFP_KERNEL); 174 if (!post_meter) 175 return ERR_PTR(-ENOMEM); 176 177 err = mlx5e_post_meter_table_create(priv, ns_type, post_meter); 178 if (err) 179 goto err_ft; 180 181 err = mlx5e_post_meter_fg_create(priv, post_meter); 182 if (err) 183 goto err_fg; 184 185 err = mlx5e_post_meter_rules_create(priv, post_meter, post_act, green_counter, 186 red_counter); 187 if (err) 188 goto err_rules; 189 190 return post_meter; 191 192 err_rules: 193 mlx5e_post_meter_fg_destroy(post_meter); 194 err_fg: 195 mlx5e_post_meter_table_destroy(post_meter); 196 err_ft: 197 kfree(post_meter); 198 return ERR_PTR(err); 199 } 200 201 void 202 mlx5e_post_meter_cleanup(struct mlx5e_post_meter_priv *post_meter) 203 { 204 mlx5e_post_meter_rules_destroy(post_meter); 205 mlx5e_post_meter_fg_destroy(post_meter); 206 mlx5e_post_meter_table_destroy(post_meter); 207 kfree(post_meter); 208 } 209 210