1 /* 2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c 3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 4 * Copyright (c) 2017 Arkadi Sharshevsky <arakdis@mellanox.com> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the names of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * Alternatively, this software may be distributed under the terms of the 19 * GNU General Public License ("GPL") version 2 as published by the Free 20 * Software Foundation. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <linux/kernel.h> 36 #include <net/devlink.h> 37 38 #include "spectrum.h" 39 #include "spectrum_dpipe.h" 40 #include "spectrum_router.h" 41 42 enum mlxsw_sp_field_metadata_id { 43 MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT, 44 MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD, 45 MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP, 46 }; 47 48 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = { 49 { .name = "erif_port", 50 .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT, 51 .bitwidth = 32, 52 .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX, 53 }, 54 { .name = "l3_forward", 55 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD, 56 .bitwidth = 1, 57 }, 58 { .name = "l3_drop", 59 .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP, 60 .bitwidth = 1, 61 }, 62 }; 63 64 enum mlxsw_sp_dpipe_header_id { 65 MLXSW_SP_DPIPE_HEADER_METADATA, 66 }; 67 68 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = { 69 .name = "mlxsw_meta", 70 .id = MLXSW_SP_DPIPE_HEADER_METADATA, 71 .fields = mlxsw_sp_dpipe_fields_metadata, 72 .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata), 73 }; 74 75 static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = { 76 &mlxsw_sp_dpipe_header_metadata, 77 }; 78 79 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = { 80 .headers = mlxsw_dpipe_headers, 81 .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers), 82 }; 83 84 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv, 85 struct sk_buff *skb) 86 { 87 struct devlink_dpipe_action action = {0}; 88 int err; 89 90 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 91 action.header = &mlxsw_sp_dpipe_header_metadata; 92 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD; 93 94 err = devlink_dpipe_action_put(skb, &action); 95 if (err) 96 return err; 97 98 action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 99 action.header = &mlxsw_sp_dpipe_header_metadata; 100 action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP; 101 102 return devlink_dpipe_action_put(skb, &action); 103 } 104 105 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv, 106 struct sk_buff *skb) 107 { 108 struct devlink_dpipe_match match = {0}; 109 110 match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 111 match.header = &mlxsw_sp_dpipe_header_metadata; 112 match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 113 114 return devlink_dpipe_match_put(skb, &match); 115 } 116 117 static void mlxsw_sp_erif_entry_clear(struct devlink_dpipe_entry *entry) 118 { 119 unsigned int value_count, value_index; 120 struct devlink_dpipe_value *value; 121 122 value = entry->action_values; 123 value_count = entry->action_values_count; 124 for (value_index = 0; value_index < value_count; value_index++) { 125 kfree(value[value_index].value); 126 kfree(value[value_index].mask); 127 } 128 129 value = entry->match_values; 130 value_count = entry->match_values_count; 131 for (value_index = 0; value_index < value_count; value_index++) { 132 kfree(value[value_index].value); 133 kfree(value[value_index].mask); 134 } 135 } 136 137 static void 138 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match, 139 struct devlink_dpipe_action *action) 140 { 141 action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 142 action->header = &mlxsw_sp_dpipe_header_metadata; 143 action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD; 144 145 match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 146 match->header = &mlxsw_sp_dpipe_header_metadata; 147 match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 148 } 149 150 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry, 151 struct devlink_dpipe_value *match_value, 152 struct devlink_dpipe_match *match, 153 struct devlink_dpipe_value *action_value, 154 struct devlink_dpipe_action *action) 155 { 156 entry->match_values = match_value; 157 entry->match_values_count = 1; 158 159 entry->action_values = action_value; 160 entry->action_values_count = 1; 161 162 match_value->match = match; 163 match_value->value_size = sizeof(u32); 164 match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 165 if (!match_value->value) 166 return -ENOMEM; 167 168 action_value->action = action; 169 action_value->value_size = sizeof(u32); 170 action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 171 if (!action_value->value) 172 goto err_action_alloc; 173 return 0; 174 175 err_action_alloc: 176 kfree(match_value->value); 177 return -ENOMEM; 178 } 179 180 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp, 181 struct devlink_dpipe_entry *entry, 182 struct mlxsw_sp_rif *rif, 183 bool counters_enabled) 184 { 185 u32 *action_value; 186 u32 *rif_value; 187 u64 cnt; 188 int err; 189 190 /* Set Match RIF index */ 191 rif_value = entry->match_values->value; 192 *rif_value = mlxsw_sp_rif_index(rif); 193 entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif); 194 entry->match_values->mapping_valid = true; 195 196 /* Set Action Forwarding */ 197 action_value = entry->action_values->value; 198 *action_value = 1; 199 200 entry->counter_valid = false; 201 entry->counter = 0; 202 entry->index = mlxsw_sp_rif_index(rif); 203 204 if (!counters_enabled) 205 return 0; 206 207 err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif, 208 MLXSW_SP_RIF_COUNTER_EGRESS, 209 &cnt); 210 if (!err) { 211 entry->counter = cnt; 212 entry->counter_valid = true; 213 } 214 return 0; 215 } 216 217 static int 218 mlxsw_sp_table_erif_entries_dump(void *priv, bool counters_enabled, 219 struct devlink_dpipe_dump_ctx *dump_ctx) 220 { 221 struct devlink_dpipe_value match_value = {{0}}, action_value = {{0}}; 222 struct devlink_dpipe_action action = {0}; 223 struct devlink_dpipe_match match = {0}; 224 struct devlink_dpipe_entry entry = {0}; 225 struct mlxsw_sp *mlxsw_sp = priv; 226 unsigned int rif_count; 227 int i, j; 228 int err; 229 230 mlxsw_sp_erif_match_action_prepare(&match, &action); 231 err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match, 232 &action_value, &action); 233 if (err) 234 return err; 235 236 rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); 237 rtnl_lock(); 238 i = 0; 239 start_again: 240 err = devlink_dpipe_entry_ctx_prepare(dump_ctx); 241 if (err) 242 return err; 243 j = 0; 244 for (; i < rif_count; i++) { 245 if (!mlxsw_sp->rifs[i]) 246 continue; 247 err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, 248 mlxsw_sp->rifs[i], 249 counters_enabled); 250 if (err) 251 goto err_entry_get; 252 err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry); 253 if (err) { 254 if (err == -EMSGSIZE) { 255 if (!j) 256 goto err_entry_append; 257 break; 258 } 259 goto err_entry_append; 260 } 261 j++; 262 } 263 264 devlink_dpipe_entry_ctx_close(dump_ctx); 265 if (i != rif_count) 266 goto start_again; 267 rtnl_unlock(); 268 269 mlxsw_sp_erif_entry_clear(&entry); 270 return 0; 271 err_entry_append: 272 err_entry_get: 273 rtnl_unlock(); 274 mlxsw_sp_erif_entry_clear(&entry); 275 return err; 276 } 277 278 static int mlxsw_sp_table_erif_counters_update(void *priv, bool enable) 279 { 280 struct mlxsw_sp *mlxsw_sp = priv; 281 int i; 282 283 rtnl_lock(); 284 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 285 if (!mlxsw_sp->rifs[i]) 286 continue; 287 if (enable) 288 mlxsw_sp_rif_counter_alloc(mlxsw_sp, 289 mlxsw_sp->rifs[i], 290 MLXSW_SP_RIF_COUNTER_EGRESS); 291 else 292 mlxsw_sp_rif_counter_free(mlxsw_sp, 293 mlxsw_sp->rifs[i], 294 MLXSW_SP_RIF_COUNTER_EGRESS); 295 } 296 rtnl_unlock(); 297 return 0; 298 } 299 300 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = { 301 .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump, 302 .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump, 303 .entries_dump = mlxsw_sp_table_erif_entries_dump, 304 .counters_set_update = mlxsw_sp_table_erif_counters_update, 305 }; 306 307 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp) 308 { 309 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 310 u64 table_size; 311 312 table_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); 313 return devlink_dpipe_table_register(devlink, 314 MLXSW_SP_DPIPE_TABLE_NAME_ERIF, 315 &mlxsw_sp_erif_ops, 316 mlxsw_sp, table_size, 317 false); 318 } 319 320 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp) 321 { 322 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 323 324 devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF); 325 } 326 327 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp) 328 { 329 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 330 int err; 331 332 err = devlink_dpipe_headers_register(devlink, 333 &mlxsw_sp_dpipe_headers); 334 if (err) 335 return err; 336 err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp); 337 if (err) 338 goto err_erif_register; 339 return 0; 340 341 err_erif_register: 342 devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core)); 343 return err; 344 } 345 346 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp) 347 { 348 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 349 350 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp); 351 devlink_dpipe_headers_unregister(devlink); 352 } 353